€•Œsphinx.addnodes”Œdocument”“”)”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)”}”(hhh]”(hŒ pending_xref”“”)”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…””}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ8/translations/zh_CN/driver-api/surface_aggregator/client”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)”}”(hhh]”hŒChinese (Traditional)”…””}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ8/translations/zh_TW/driver-api/surface_aggregator/client”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ8/translations/it_IT/driver-api/surface_aggregator/client”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ8/translations/ja_JP/driver-api/surface_aggregator/client”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ8/translations/ko_KR/driver-api/surface_aggregator/client”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒSpanish”…””}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ8/translations/sp_SP/driver-api/surface_aggregator/client”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒcomment”“”)”}”(hŒ!SPDX-License-Identifier: GPL-2.0+”h]”hŒ!SPDX-License-Identifier: GPL-2.0+”…””}”hh£sbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1h¡hhhžhhŸŒR/var/lib/git/docbuild/linux/Documentation/driver-api/surface_aggregator/client.rst”h KubhŒsubstitution_definition”“”)”}”(hŒQ.. |ssam_controller| replace:: :c:type:`struct ssam_controller `”h]”h)”}”(hŒ2:c:type:`struct ssam_controller `”h]”hŒliteral”“”)”}”(hh¼h]”hŒstruct ssam_controller”…””}”(hhÀhžhhŸNh Nubah}”(h]”h ]”(Œxref”Œc”Œc-type”eh"]”h$]”h&]”uh1h¾hhºubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”Œ$driver-api/surface_aggregator/client”Œ refdomain”hËŒreftype”Œtype”Œ refexplicit”ˆŒrefwarn”‰Œ reftarget”Œssam_controller”uh1hhŸh³h Khh¶ubah}”(h]”h ]”h"]”Œssam_controller”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒE.. |ssam_device| replace:: :c:type:`struct ssam_device `”h]”h)”}”(hŒ*:c:type:`struct ssam_device `”h]”h¿)”}”(hhìh]”hŒstruct ssam_device”…””}”(hhîhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-type”eh"]”h$]”h&]”uh1h¾hhêubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œtype”Œ refexplicit”ˆŒrefwarn”‰hÝŒ ssam_device”uh1hhŸh³h Khhæubah}”(h]”h ]”h"]”Œ ssam_device”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒZ.. |ssam_device_driver| replace:: :c:type:`struct ssam_device_driver `”h]”h)”}”(hŒ8:c:type:`struct ssam_device_driver `”h]”h¿)”}”(hjh]”hŒstruct ssam_device_driver”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-type”eh"]”h$]”h&]”uh1h¾hjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œtype”Œ refexplicit”ˆŒrefwarn”‰hÝŒssam_device_driver”uh1hhŸh³h Khjubah}”(h]”h ]”h"]”Œssam_device_driver”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒ:.. |ssam_client_bind| replace:: :c:func:`ssam_client_bind`”h]”h)”}”(hŒ:c:func:`ssam_client_bind`”h]”h¿)”}”(hj@h]”hŒssam_client_bind()”…””}”(hjBhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hj>ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_client_bind”uh1hhŸh³h Khj:ubah}”(h]”h ]”h"]”Œssam_client_bind”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒ:.. |ssam_client_link| replace:: :c:func:`ssam_client_link`”h]”h)”}”(hŒ:c:func:`ssam_client_link`”h]”h¿)”}”(hjjh]”hŒssam_client_link()”…””}”(hjlhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hjhubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_client_link”uh1hhŸh³h Khjdubah}”(h]”h ]”h"]”Œssam_client_link”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒ@.. |ssam_get_controller| replace:: :c:func:`ssam_get_controller`”h]”h)”}”(hŒ:c:func:`ssam_get_controller`”h]”h¿)”}”(hj”h]”hŒssam_get_controller()”…””}”(hj–hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hj’ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_get_controller”uh1hhŸh³h KhjŽubah}”(h]”h ]”h"]”Œssam_get_controller”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒ@.. |ssam_controller_get| replace:: :c:func:`ssam_controller_get`”h]”h)”}”(hŒ:c:func:`ssam_controller_get`”h]”h¿)”}”(hj¾h]”hŒssam_controller_get()”…””}”(hjÀhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hj¼ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_controller_get”uh1hhŸh³h K hj¸ubah}”(h]”h ]”h"]”Œssam_controller_get”ah$]”h&]”uh1h´hŸh³h K hhhžhubhµ)”}”(hŒ@.. |ssam_controller_put| replace:: :c:func:`ssam_controller_put`”h]”h)”}”(hŒ:c:func:`ssam_controller_put`”h]”h¿)”}”(hjèh]”hŒssam_controller_put()”…””}”(hjêhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hjæubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_controller_put”uh1hhŸh³h K hjâubah}”(h]”h ]”h"]”Œssam_controller_put”ah$]”h&]”uh1h´hŸh³h K hhhžhubhµ)”}”(hŒ<.. |ssam_device_alloc| replace:: :c:func:`ssam_device_alloc`”h]”h)”}”(hŒ:c:func:`ssam_device_alloc`”h]”h¿)”}”(hjh]”hŒssam_device_alloc()”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_device_alloc”uh1hhŸh³h K hj ubah}”(h]”h ]”h"]”Œssam_device_alloc”ah$]”h&]”uh1h´hŸh³h K hhhžhubhµ)”}”(hŒ8.. |ssam_device_add| replace:: :c:func:`ssam_device_add`”h]”h)”}”(hŒ:c:func:`ssam_device_add`”h]”h¿)”}”(hj<h]”hŒssam_device_add()”…””}”(hj>hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hj:ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_device_add”uh1hhŸh³h K hj6ubah}”(h]”h ]”h"]”Œssam_device_add”ah$]”h&]”uh1h´hŸh³h K hhhžhubhµ)”}”(hŒ>.. |ssam_device_remove| replace:: :c:func:`ssam_device_remove`”h]”h)”}”(hŒ:c:func:`ssam_device_remove`”h]”h¿)”}”(hjfh]”hŒssam_device_remove()”…””}”(hjhhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hjdubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_device_remove”uh1hhŸh³h K hj`ubah}”(h]”h ]”h"]”Œssam_device_remove”ah$]”h&]”uh1h´hŸh³h K hhhžhubhµ)”}”(hŒP.. |ssam_device_driver_register| replace:: :c:func:`ssam_device_driver_register`”h]”h)”}”(hŒ%:c:func:`ssam_device_driver_register`”h]”h¿)”}”(hjh]”hŒssam_device_driver_register()”…””}”(hj’hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hjŽubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_device_driver_register”uh1hhŸh³h KhjŠubah}”(h]”h ]”h"]”Œssam_device_driver_register”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒT.. |ssam_device_driver_unregister| replace:: :c:func:`ssam_device_driver_unregister`”h]”h)”}”(hŒ':c:func:`ssam_device_driver_unregister`”h]”h¿)”}”(hjºh]”hŒssam_device_driver_unregister()”…””}”(hj¼hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hj¸ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_device_driver_unregister”uh1hhŸh³h Khj´ubah}”(h]”h ]”h"]”Œssam_device_driver_unregister”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒL.. |module_ssam_device_driver| replace:: :c:func:`module_ssam_device_driver`”h]”h)”}”(hŒ#:c:func:`module_ssam_device_driver`”h]”h¿)”}”(hjäh]”hŒmodule_ssam_device_driver()”…””}”(hjæhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hjâubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒmodule_ssam_device_driver”uh1hhŸh³h KhjÞubah}”(h]”h ]”h"]”Œmodule_ssam_device_driver”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒ0.. |SSAM_DEVICE| replace:: :c:func:`SSAM_DEVICE`”h]”h)”}”(hŒ:c:func:`SSAM_DEVICE`”h]”h¿)”}”(hjh]”hŒ SSAM_DEVICE()”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hj ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒ SSAM_DEVICE”uh1hhŸh³h Khjubah}”(h]”h ]”h"]”Œ SSAM_DEVICE”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒF.. |ssam_notifier_register| replace:: :c:func:`ssam_notifier_register`”h]”h)”}”(hŒ :c:func:`ssam_notifier_register`”h]”h¿)”}”(hj8h]”hŒssam_notifier_register()”…””}”(hj:hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hj6ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_notifier_register”uh1hhŸh³h Khj2ubah}”(h]”h ]”h"]”Œssam_notifier_register”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒJ.. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister`”h]”h)”}”(hŒ":c:func:`ssam_notifier_unregister`”h]”h¿)”}”(hjbh]”hŒssam_notifier_unregister()”…””}”(hjdhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hj`ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_notifier_unregister”uh1hhŸh³h Khj\ubah}”(h]”h ]”h"]”Œssam_notifier_unregister”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒT.. |ssam_device_notifier_register| replace:: :c:func:`ssam_device_notifier_register`”h]”h)”}”(hŒ':c:func:`ssam_device_notifier_register`”h]”h¿)”}”(hjŒh]”hŒssam_device_notifier_register()”…””}”(hjŽhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hjŠubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_device_notifier_register”uh1hhŸh³h Khj†ubah}”(h]”h ]”h"]”Œssam_device_notifier_register”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒX.. |ssam_device_notifier_unregister| replace:: :c:func:`ssam_device_notifier_unregister`”h]”h)”}”(hŒ):c:func:`ssam_device_notifier_unregister`”h]”h¿)”}”(hj¶h]”hŒ!ssam_device_notifier_unregister()”…””}”(hj¸hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hj´ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_device_notifier_unregister”uh1hhŸh³h Khj°ubah}”(h]”h ]”h"]”Œssam_device_notifier_unregister”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒB.. |ssam_request_do_sync| replace:: :c:func:`ssam_request_do_sync`”h]”h)”}”(hŒ:c:func:`ssam_request_do_sync`”h]”h¿)”}”(hjàh]”hŒssam_request_do_sync()”…””}”(hjâhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hjÞubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒssam_request_do_sync”uh1hhŸh³h KhjÚubah}”(h]”h ]”h"]”Œssam_request_do_sync”ah$]”h&]”uh1h´hŸh³h Khhhžhubhµ)”}”(hŒQ.. |ssam_event_mask| replace:: :c:type:`enum ssam_event_mask ` ”h]”h)”}”(hŒ0:c:type:`enum ssam_event_mask `”h]”h¿)”}”(hj h]”hŒenum ssam_event_mask”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-type”eh"]”h$]”h&]”uh1h¾hjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œtype”Œ refexplicit”ˆŒrefwarn”‰hÝŒssam_event_mask”uh1hhŸh³h Khjubah}”(h]”h ]”h"]”Œssam_event_mask”ah$]”h&]”uh1h´hŸh³h KhhhžhubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒWriting Client Drivers”h]”hŒWriting Client Drivers”…””}”(hj5hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j3hj0hžhhŸh³h KubhŒ paragraph”“”)”}”(hŒ$For the API documentation, refer to:”h]”hŒ$For the API documentation, refer to:”…””}”(hjEhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h Khj0hžhubhŒcompound”“”)”}”(hhh]”hŒtoctree”“”)”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”hh׌entries”]”NŒ(driver-api/surface_aggregator/client-api”†”aŒ includefiles”]”jeaŒmaxdepth”KŒcaption”NŒglob”‰Œhidden”‰Œ includehidden”‰Œnumbered”KŒ titlesonly”‰Œ rawentries”]”uh1jXhŸh³h K hjUubah}”(h]”h ]”Œtoctree-wrapper”ah"]”h$]”h&]”uh1jShj0hžhhŸh³h Nubj/)”}”(hhh]”(j4)”}”(hŒOverview”h]”hŒOverview”…””}”(hj|hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j3hjyhžhhŸh³h K'ubjD)”}”(hX“Client drivers can be set up in two main ways, depending on how the corresponding device is made available to the system. We specifically differentiate between devices that are presented to the system via one of the conventional ways, e.g. as platform devices via ACPI, and devices that are non-discoverable and instead need to be explicitly provided by some other mechanism, as discussed further below.”h]”hX“Client drivers can be set up in two main ways, depending on how the corresponding device is made available to the system. We specifically differentiate between devices that are presented to the system via one of the conventional ways, e.g. as platform devices via ACPI, and devices that are non-discoverable and instead need to be explicitly provided by some other mechanism, as discussed further below.”…””}”(hjŠhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h K)hjyhžhubeh}”(h]”Œoverview”ah ]”h"]”Œoverview”ah$]”h&]”uh1j.hj0hžhhŸh³h K'ubj/)”}”(hhh]”(j4)”}”(hŒNon-SSAM Client Drivers”h]”hŒNon-SSAM Client Drivers”…””}”(hj£hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j3hj hžhhŸh³h K2ubjD)”}”(hXÏAll communication with the SAM EC is handled via the |ssam_controller| representing that EC to the kernel. Drivers targeting a non-SSAM device (and thus not being a |ssam_device_driver|) need to explicitly establish a connection/relation to that controller. This can be done via the |ssam_client_bind| function. Said function returns a reference to the SSAM controller, but, more importantly, also establishes a device link between client device and controller (this can also be done separate via |ssam_client_link|). It is important to do this, as it, first, guarantees that the returned controller is valid for use in the client driver for as long as this driver is bound to its device, i.e. that the driver gets unbound before the controller ever becomes invalid, and, second, as it ensures correct suspend/resume ordering. This setup should be done in the driver's probe function, and may be used to defer probing in case the SSAM subsystem is not ready yet, for example:”h]”(hŒ5All communication with the SAM EC is handled via the ”…””}”(hj±hžhhŸNh Nubh)”}”(hh¼h]”h¿)”}”(hh¼h]”hŒstruct ssam_controller”…””}”(hj¼hžhhŸNh Nubah}”(h]”h ]”(hÊhËhÌeh"]”h$]”h&]”uh1h¾hŸNh Nhj¹ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”hÚŒ refexplicit”ˆŒrefwarn”‰Œ reftarget”hÞuh1hhŸh³h Khj±hžhubhŒ_ representing that EC to the kernel. Drivers targeting a non-SSAM device (and thus not being a ”…””}”(hj±hžhhŸNh Nubh)”}”(hjh]”h¿)”}”(hjh]”hŒstruct ssam_device_driver”…””}”(hjÜhžhhŸNh Nubah}”(h]”h ]”(hÊhËj"eh"]”h$]”h&]”uh1h¾hŸNh NhjÙubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”j/Œ refexplicit”ˆŒrefwarn”‰Œ reftarget”j2uh1hhŸh³h Khj±hžhubhŒb) need to explicitly establish a connection/relation to that controller. This can be done via the ”…””}”(hj±hžhhŸNh Nubh)”}”(hj@h]”h¿)”}”(hj@h]”hŒssam_client_bind()”…””}”(hjühžhhŸNh Nubah}”(h]”h ]”(hÊhËjLeh"]”h$]”h&]”uh1h¾hŸNh Nhjùubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jYŒ refexplicit”‰Œrefwarn”‰Œ reftarget”j\uh1hhŸh³h Khj±hžhubhŒÄ function. Said function returns a reference to the SSAM controller, but, more importantly, also establishes a device link between client device and controller (this can also be done separate via ”…””}”(hj±hžhhŸNh Nubh)”}”(hjjh]”h¿)”}”(hjjh]”hŒssam_client_link()”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”(hÊhËjveh"]”h$]”h&]”uh1h¾hŸNh Nhjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jƒŒ refexplicit”‰Œrefwarn”‰Œ reftarget”j†uh1hhŸh³h Khj±hžhubhXÎ). It is important to do this, as it, first, guarantees that the returned controller is valid for use in the client driver for as long as this driver is bound to its device, i.e. that the driver gets unbound before the controller ever becomes invalid, and, second, as it ensures correct suspend/resume ordering. This setup should be done in the driver’s probe function, and may be used to defer probing in case the SSAM subsystem is not ready yet, for example:”…””}”(hj±hžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h K4hj hžhubhŒ literal_block”“”)”}”(hX"static int client_driver_probe(struct platform_device *pdev) { struct ssam_controller *ctrl; ctrl = ssam_client_bind(&pdev->dev); if (IS_ERR(ctrl)) return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl); // ... return 0; }”h]”hX"static int client_driver_probe(struct platform_device *pdev) { struct ssam_controller *ctrl; ctrl = ssam_client_bind(&pdev->dev); if (IS_ERR(ctrl)) return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl); // ... return 0; }”…””}”hjAsbah}”(h]”h ]”h"]”h$]”h&]”h±h²Œforce”‰Œlanguage”hËŒhighlight_args”}”uh1j?hŸh³h KChj hžhubjD)”}”(hX¬The controller may be separately obtained via |ssam_get_controller| and its lifetime be guaranteed via |ssam_controller_get| and |ssam_controller_put|. Note that none of these functions, however, guarantee that the controller will not be shut down or suspended. These functions essentially only operate on the reference, i.e. only guarantee a bare minimum of accessibility without any guarantees at all on practical operability.”h]”(hŒ.The controller may be separately obtained via ”…””}”(hjShžhhŸNh Nubh)”}”(hj”h]”h¿)”}”(hj”h]”hŒssam_get_controller()”…””}”(hj^hžhhŸNh Nubah}”(h]”h ]”(hÊhËj eh"]”h$]”h&]”uh1h¾hŸNh Nhj[ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”j­Œ refexplicit”‰Œrefwarn”‰Œ reftarget”j°uh1hhŸh³h KhjShžhubhŒ$ and its lifetime be guaranteed via ”…””}”(hjShžhhŸNh Nubh)”}”(hj¾h]”h¿)”}”(hj¾h]”hŒssam_controller_get()”…””}”(hj~hžhhŸNh Nubah}”(h]”h ]”(hÊhËjÊeh"]”h$]”h&]”uh1h¾hŸNh Nhj{ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”j׌ refexplicit”‰Œrefwarn”‰Œ reftarget”jÚuh1hhŸh³h K hjShžhubhŒ and ”…””}”(hjShžhhŸNh Nubh)”}”(hjèh]”h¿)”}”(hjèh]”hŒssam_controller_put()”…””}”(hjžhžhhŸNh Nubah}”(h]”h ]”(hÊhËjôeh"]”h$]”h&]”uh1h¾hŸNh Nhj›ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jŒ refexplicit”‰Œrefwarn”‰Œ reftarget”juh1hhŸh³h K hjShžhubhX. Note that none of these functions, however, guarantee that the controller will not be shut down or suspended. These functions essentially only operate on the reference, i.e. only guarantee a bare minimum of accessibility without any guarantees at all on practical operability.”…””}”(hjShžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h KRhj hžhubeh}”(h]”Œnon-ssam-client-drivers”ah ]”h"]”Œnon-ssam client drivers”ah$]”h&]”uh1j.hj0hžhhŸh³h K2ubj/)”}”(hhh]”(j4)”}”(hŒAdding SSAM Devices”h]”hŒAdding SSAM Devices”…””}”(hjÌhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j3hjÉhžhhŸh³h K[ubjD)”}”(hX—If a device does not already exist/is not already provided via conventional means, it should be provided as |ssam_device| via the SSAM client device hub. New devices can be added to this hub by entering their UID into the corresponding registry. SSAM devices can also be manually allocated via |ssam_device_alloc|, subsequently to which they have to be added via |ssam_device_add| and eventually removed via |ssam_device_remove|. By default, the parent of the device is set to the controller device provided for allocation, however this may be changed before the device is added. Note that, when changing the parent device, care must be taken to ensure that the controller lifetime and suspend/resume ordering guarantees, in the default setup provided through the parent-child relation, are preserved. If necessary, by use of |ssam_client_link| as is done for non-SSAM client drivers and described in more detail above.”h]”(hŒlIf a device does not already exist/is not already provided via conventional means, it should be provided as ”…””}”(hjÚhžhhŸNh Nubh)”}”(hhìh]”h¿)”}”(hhìh]”hŒstruct ssam_device”…””}”(hjåhžhhŸNh Nubah}”(h]”h ]”(hÊhËhøeh"]”h$]”h&]”uh1h¾hŸNh Nhjâubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jŒ refexplicit”ˆŒrefwarn”‰Œ reftarget”juh1hhŸh³h KhjÚhžhubhŒ­ via the SSAM client device hub. New devices can be added to this hub by entering their UID into the corresponding registry. SSAM devices can also be manually allocated via ”…””}”(hjÚhžhhŸNh Nubh)”}”(hjh]”h¿)”}”(hjh]”hŒssam_device_alloc()”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”(hÊhËjeh"]”h$]”h&]”uh1h¾hŸNh Nhjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”j+Œ refexplicit”‰Œrefwarn”‰Œ reftarget”j.uh1hhŸh³h K hjÚhžhubhŒ2, subsequently to which they have to be added via ”…””}”(hjÚhžhhŸNh Nubh)”}”(hj<h]”h¿)”}”(hj<h]”hŒssam_device_add()”…””}”(hj%hžhhŸNh Nubah}”(h]”h ]”(hÊhËjHeh"]”h$]”h&]”uh1h¾hŸNh Nhj"ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jUŒ refexplicit”‰Œrefwarn”‰Œ reftarget”jXuh1hhŸh³h K hjÚhžhubhŒ and eventually removed via ”…””}”(hjÚhžhhŸNh Nubh)”}”(hjfh]”h¿)”}”(hjfh]”hŒssam_device_remove()”…””}”(hjEhžhhŸNh Nubah}”(h]”h ]”(hÊhËjreh"]”h$]”h&]”uh1h¾hŸNh NhjBubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jŒ refexplicit”‰Œrefwarn”‰Œ reftarget”j‚uh1hhŸh³h K hjÚhžhubhXŽ. By default, the parent of the device is set to the controller device provided for allocation, however this may be changed before the device is added. Note that, when changing the parent device, care must be taken to ensure that the controller lifetime and suspend/resume ordering guarantees, in the default setup provided through the parent-child relation, are preserved. If necessary, by use of ”…””}”(hjÚhžhhŸNh Nubh)”}”(hjjh]”h¿)”}”(hjjh]”hŒssam_client_link()”…””}”(hjehžhhŸNh Nubah}”(h]”h ]”(hÊhËjveh"]”h$]”h&]”uh1h¾hŸNh Nhjbubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jƒŒ refexplicit”‰Œrefwarn”‰Œ reftarget”j†uh1hhŸh³h KhjÚhžhubhŒK as is done for non-SSAM client drivers and described in more detail above.”…””}”(hjÚhžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h K]hjÉhžhubjD)”}”(hXA client device must always be removed by the party which added the respective device before the controller shuts down. Such removal can be guaranteed by linking the driver providing the SSAM device to the controller via |ssam_client_link|, causing it to unbind before the controller driver unbinds. Client devices registered with the controller as parent are automatically removed when the controller shuts down, but this should not be relied upon, especially as this does not extend to client devices with a different parent.”h]”(hŒÝA client device must always be removed by the party which added the respective device before the controller shuts down. Such removal can be guaranteed by linking the driver providing the SSAM device to the controller via ”…””}”(hjˆhžhhŸNh Nubh)”}”(hjjh]”h¿)”}”(hjjh]”hŒssam_client_link()”…””}”(hj“hžhhŸNh Nubah}”(h]”h ]”(hÊhËjveh"]”h$]”h&]”uh1h¾hŸNh Nhjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jƒŒ refexplicit”‰Œrefwarn”‰Œ reftarget”j†uh1hhŸh³h KhjˆhžhubhX , causing it to unbind before the controller driver unbinds. Client devices registered with the controller as parent are automatically removed when the controller shuts down, but this should not be relied upon, especially as this does not extend to client devices with a different parent.”…””}”(hjˆhžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h KkhjÉhžhubeh}”(h]”Œadding-ssam-devices”ah ]”h"]”Œadding ssam devices”ah$]”h&]”uh1j.hj0hžhhŸh³h K[ubj/)”}”(hhh]”(j4)”}”(hŒSSAM Client Drivers”h]”hŒSSAM Client Drivers”…””}”(hjÁhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j3hj¾hžhhŸh³h KvubjD)”}”(hX÷SSAM client device drivers are, in essence, no different than other device driver types. They are represented via |ssam_device_driver| and bind to a |ssam_device| via its UID (:c:type:`struct ssam_device.uid `) member and the match table (:c:type:`struct ssam_device_driver.match_table `), which should be set when declaring the driver struct instance. Refer to the |SSAM_DEVICE| macro documentation for more details on how to define members of the driver's match table.”h]”(hŒrSSAM client device drivers are, in essence, no different than other device driver types. They are represented via ”…””}”(hjÏhžhhŸNh Nubh)”}”(hjh]”h¿)”}”(hjh]”hŒstruct ssam_device_driver”…””}”(hjÚhžhhŸNh Nubah}”(h]”h ]”(hÊhËj"eh"]”h$]”h&]”uh1h¾hŸNh Nhj×ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”j/Œ refexplicit”ˆŒrefwarn”‰Œ reftarget”j2uh1hhŸh³h KhjÏhžhubhŒ and bind to a ”…””}”(hjÏhžhhŸNh Nubh)”}”(hhìh]”h¿)”}”(hhìh]”hŒstruct ssam_device”…””}”(hjúhžhhŸNh Nubah}”(h]”h ]”(hÊhËhøeh"]”h$]”h&]”uh1h¾hŸNh Nhj÷ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jŒ refexplicit”ˆŒrefwarn”‰Œ reftarget”juh1hhŸh³h KhjÏhžhubhŒ via its UID (”…””}”(hjÏhžhhŸNh Nubh)”}”(hŒ.:c:type:`struct ssam_device.uid `”h]”h¿)”}”(hjh]”hŒstruct ssam_device.uid”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-type”eh"]”h$]”h&]”uh1h¾hjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œtype”Œ refexplicit”ˆŒrefwarn”‰hÝŒ ssam_device”uh1hhŸh³h KxhjÏubhŒ) member and the match table (”…””}”(hjÏhžhhŸNh Nubh)”}”(hŒD:c:type:`struct ssam_device_driver.match_table `”h]”h¿)”}”(hj<h]”hŒ%struct ssam_device_driver.match_table”…””}”(hj>hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-type”eh"]”h$]”h&]”uh1h¾hj:ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œtype”Œ refexplicit”ˆŒrefwarn”‰hÝŒssam_device_driver”uh1hhŸh³h KxhjÏubhŒO), which should be set when declaring the driver struct instance. Refer to the ”…””}”(hjÏhžhhŸNh Nubh)”}”(hjh]”h¿)”}”(hjh]”hŒ SSAM_DEVICE()”…””}”(hj`hžhhŸNh Nubah}”(h]”h ]”(hÊhËjeh"]”h$]”h&]”uh1h¾hŸNh Nhj]ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”j'Œ refexplicit”‰Œrefwarn”‰Œ reftarget”j*uh1hhŸh³h KhjÏhžhubhŒ] macro documentation for more details on how to define members of the driver’s match table.”…””}”(hjÏhžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h Kxhj¾hžhubjD)”}”(hXHThe UID for SSAM client devices consists of a ``domain``, a ``category``, a ``target``, an ``instance``, and a ``function``. The ``domain`` is used differentiate between physical SAM devices (:c:type:`SSAM_DOMAIN_SERIALHUB `), i.e. devices that can be accessed via the Surface Serial Hub, and virtual ones (:c:type:`SSAM_DOMAIN_VIRTUAL `), such as client-device hubs, that have no real representation on the SAM EC and are solely used on the kernel/driver-side. For physical devices, ``category`` represents the target category, ``target`` the target ID, and ``instance`` the instance ID used to access the physical SAM device. In addition, ``function`` references a specific device functionality, but has no meaning to the SAM EC. The (default) name of a client device is generated based on its UID.”h]”(hŒ.The UID for SSAM client devices consists of a ”…””}”(hjƒhžhhŸNh Nubh¿)”}”(hŒ ``domain``”h]”hŒdomain”…””}”(hj‹hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¾hjƒubhŒ, a ”…””}”(hjƒhžhhŸNh Nubh¿)”}”(hŒ ``category``”h]”hŒcategory”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¾hjƒubhŒ, a ”…””}”(hjƒhžhhŸNh Nubh¿)”}”(hŒ ``target``”h]”hŒtarget”…””}”(hj¯hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¾hjƒubhŒ, an ”…””}”(hjƒhžhhŸNh Nubh¿)”}”(hŒ ``instance``”h]”hŒinstance”…””}”(hjÁhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¾hjƒubhŒ, and a ”…””}”(hjƒhžhhŸNh Nubh¿)”}”(hŒ ``function``”h]”hŒfunction”…””}”(hjÓhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¾hjƒubhŒ. The ”…””}”(hjƒhžhhŸNh Nubh¿)”}”(hŒ ``domain``”h]”hŒdomain”…””}”(hjåhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¾hjƒubhŒ5 is used differentiate between physical SAM devices (”…””}”(hjƒhžhhŸNh Nubh)”}”(hŒ4:c:type:`SSAM_DOMAIN_SERIALHUB `”h]”h¿)”}”(hjùh]”hŒSSAM_DOMAIN_SERIALHUB”…””}”(hjûhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-type”eh"]”h$]”h&]”uh1h¾hj÷ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œtype”Œ refexplicit”ˆŒrefwarn”‰hÝŒssam_device_domain”uh1hhŸh³h KhjƒubhŒS), i.e. devices that can be accessed via the Surface Serial Hub, and virtual ones (”…””}”(hjƒhžhhŸNh Nubh)”}”(hŒ2:c:type:`SSAM_DOMAIN_VIRTUAL `”h]”h¿)”}”(hjh]”hŒSSAM_DOMAIN_VIRTUAL”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-type”eh"]”h$]”h&]”uh1h¾hjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œtype”Œ refexplicit”ˆŒrefwarn”‰hÝŒssam_device_domain”uh1hhŸh³h KhjƒubhŒ“), such as client-device hubs, that have no real representation on the SAM EC and are solely used on the kernel/driver-side. For physical devices, ”…””}”(hjƒhžhhŸNh Nubh¿)”}”(hŒ ``category``”h]”hŒcategory”…””}”(hj=hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¾hjƒubhŒ! represents the target category, ”…””}”(hjƒhžhhŸNh Nubh¿)”}”(hŒ ``target``”h]”hŒtarget”…””}”(hjOhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¾hjƒubhŒ the target ID, and ”…””}”(hjƒhžhhŸNh Nubh¿)”}”(hŒ ``instance``”h]”hŒinstance”…””}”(hjahžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¾hjƒubhŒF the instance ID used to access the physical SAM device. In addition, ”…””}”(hjƒhžhhŸNh Nubh¿)”}”(hŒ ``function``”h]”hŒfunction”…””}”(hjshžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¾hjƒubhŒ“ references a specific device functionality, but has no meaning to the SAM EC. The (default) name of a client device is generated based on its UID.”…””}”(hjƒhžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h Khj¾hžhubjD)”}”(hXA driver instance can be registered via |ssam_device_driver_register| and unregistered via |ssam_device_driver_unregister|. For convenience, the |module_ssam_device_driver| macro may be used to define module init- and exit-functions registering the driver.”h]”(hŒ(A driver instance can be registered via ”…””}”(hj‹hžhhŸNh Nubh)”}”(hjh]”h¿)”}”(hjh]”hŒssam_device_driver_register()”…””}”(hj–hžhhŸNh Nubah}”(h]”h ]”(hÊhËjœeh"]”h$]”h&]”uh1h¾hŸNh Nhj“ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”j©Œ refexplicit”‰Œrefwarn”‰Œ reftarget”j¬uh1hhŸh³h Khj‹hžhubhŒ and unregistered via ”…””}”(hj‹hžhhŸNh Nubh)”}”(hjºh]”h¿)”}”(hjºh]”hŒssam_device_driver_unregister()”…””}”(hj¶hžhhŸNh Nubah}”(h]”h ]”(hÊhËjÆeh"]”h$]”h&]”uh1h¾hŸNh Nhj³ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jÓŒ refexplicit”‰Œrefwarn”‰Œ reftarget”jÖuh1hhŸh³h Khj‹hžhubhŒ. For convenience, the ”…””}”(hj‹hžhhŸNh Nubh)”}”(hjäh]”h¿)”}”(hjäh]”hŒmodule_ssam_device_driver()”…””}”(hjÖhžhhŸNh Nubah}”(h]”h ]”(hÊhËjðeh"]”h$]”h&]”uh1h¾hŸNh NhjÓubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jýŒ refexplicit”‰Œrefwarn”‰Œ reftarget”juh1hhŸh³h Khj‹hžhubhŒT macro may be used to define module init- and exit-functions registering the driver.”…””}”(hj‹hžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h KŽhj¾hžhubjD)”}”(hXRThe controller associated with a SSAM client device can be found in its :c:type:`struct ssam_device.ctrl ` member. This reference is guaranteed to be valid for at least as long as the client driver is bound, but should also be valid for as long as the client device exists. Note, however, that access outside of the bound client driver must ensure that the controller device is not suspended while making any requests or (un-)registering event notifiers (and thus should generally be avoided). This is guaranteed when the controller is accessed from inside the bound client driver.”h]”(hŒHThe controller associated with a SSAM client device can be found in its ”…””}”(hjùhžhhŸNh Nubh)”}”(hŒ/:c:type:`struct ssam_device.ctrl `”h]”h¿)”}”(hj h]”hŒstruct ssam_device.ctrl”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-type”eh"]”h$]”h&]”uh1h¾hj ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œtype”Œ refexplicit”ˆŒrefwarn”‰hÝŒ ssam_device”uh1hhŸh³h K“hjùubhXÛ member. This reference is guaranteed to be valid for at least as long as the client driver is bound, but should also be valid for as long as the client device exists. Note, however, that access outside of the bound client driver must ensure that the controller device is not suspended while making any requests or (un-)registering event notifiers (and thus should generally be avoided). This is guaranteed when the controller is accessed from inside the bound client driver.”…””}”(hjùhžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h K“hj¾hžhubeh}”(h]”Œssam-client-drivers”ah ]”h"]”Œssam client drivers”ah$]”h&]”uh1j.hj0hžhhŸh³h Kvubj/)”}”(hhh]”(j4)”}”(hŒMaking Synchronous Requests”h]”hŒMaking Synchronous Requests”…””}”(hj5 hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j3hj2 hžhhŸh³h KŸubjD)”}”(hXÕSynchronous requests are (currently) the main form of host-initiated communication with the EC. There are a couple of ways to define and execute such requests, however, most of them boil down to something similar as shown in the example below. This example defines a write-read request, meaning that the caller provides an argument to the SAM EC and receives a response. The caller needs to know the (maximum) length of the response payload and provide a buffer for it.”h]”hXÕSynchronous requests are (currently) the main form of host-initiated communication with the EC. There are a couple of ways to define and execute such requests, however, most of them boil down to something similar as shown in the example below. This example defines a write-read request, meaning that the caller provides an argument to the SAM EC and receives a response. The caller needs to know the (maximum) length of the response payload and provide a buffer for it.”…””}”(hjC hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h K¡hj2 hžhubjD)”}”(hŒâCare must be taken to ensure that any command payload data passed to the SAM EC is provided in little-endian format and, similarly, any response payload data received from it is converted from little-endian to host endianness.”h]”hŒâCare must be taken to ensure that any command payload data passed to the SAM EC is provided in little-endian format and, similarly, any response payload data received from it is converted from little-endian to host endianness.”…””}”(hjQ hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h K©hj2 hžhubj@)”}”(hXôint perform_request(struct ssam_controller *ctrl, u32 arg, u32 *ret) { struct ssam_request rqst; struct ssam_response resp; int status; /* Convert request argument to little-endian. */ __le32 arg_le = cpu_to_le32(arg); __le32 ret_le = cpu_to_le32(0); /* * Initialize request specification. Replace this with your values. * The rqst.payload field may be NULL if rqst.length is zero, * indicating that the request does not have any argument. * * Note: The request parameters used here are not valid, i.e. * they do not correspond to an actual SAM/EC request. */ rqst.target_category = SSAM_SSH_TC_SAM; rqst.target_id = SSAM_SSH_TID_SAM; rqst.command_id = 0x02; rqst.instance_id = 0x03; rqst.flags = SSAM_REQUEST_HAS_RESPONSE; rqst.length = sizeof(arg_le); rqst.payload = (u8 *)&arg_le; /* Initialize request response. */ resp.capacity = sizeof(ret_le); resp.length = 0; resp.pointer = (u8 *)&ret_le; /* * Perform actual request. The response pointer may be null in case * the request does not have any response. This must be consistent * with the SSAM_REQUEST_HAS_RESPONSE flag set in the specification * above. */ status = ssam_request_do_sync(ctrl, &rqst, &resp); /* * Alternatively use * * ssam_request_do_sync_onstack(ctrl, &rqst, &resp, sizeof(arg_le)); * * to perform the request, allocating the message buffer directly * on the stack as opposed to allocation via kzalloc(). */ /* * Convert request response back to native format. Note that in the * error case, this value is not touched by the SSAM core, i.e. * 'ret_le' will be zero as specified in its initialization. */ *ret = le32_to_cpu(ret_le); return status; }”h]”hXôint perform_request(struct ssam_controller *ctrl, u32 arg, u32 *ret) { struct ssam_request rqst; struct ssam_response resp; int status; /* Convert request argument to little-endian. */ __le32 arg_le = cpu_to_le32(arg); __le32 ret_le = cpu_to_le32(0); /* * Initialize request specification. Replace this with your values. * The rqst.payload field may be NULL if rqst.length is zero, * indicating that the request does not have any argument. * * Note: The request parameters used here are not valid, i.e. * they do not correspond to an actual SAM/EC request. */ rqst.target_category = SSAM_SSH_TC_SAM; rqst.target_id = SSAM_SSH_TID_SAM; rqst.command_id = 0x02; rqst.instance_id = 0x03; rqst.flags = SSAM_REQUEST_HAS_RESPONSE; rqst.length = sizeof(arg_le); rqst.payload = (u8 *)&arg_le; /* Initialize request response. */ resp.capacity = sizeof(ret_le); resp.length = 0; resp.pointer = (u8 *)&ret_le; /* * Perform actual request. The response pointer may be null in case * the request does not have any response. This must be consistent * with the SSAM_REQUEST_HAS_RESPONSE flag set in the specification * above. */ status = ssam_request_do_sync(ctrl, &rqst, &resp); /* * Alternatively use * * ssam_request_do_sync_onstack(ctrl, &rqst, &resp, sizeof(arg_le)); * * to perform the request, allocating the message buffer directly * on the stack as opposed to allocation via kzalloc(). */ /* * Convert request response back to native format. Note that in the * error case, this value is not touched by the SSAM core, i.e. * 'ret_le' will be zero as specified in its initialization. */ *ret = le32_to_cpu(ret_le); return status; }”…””}”hj_ sbah}”(h]”h ]”h"]”h$]”h&]”h±h²jO‰jPhËjQ}”uh1j?hŸh³h K­hj2 hžhubjD)”}”(hŒÍNote that |ssam_request_do_sync| in its essence is a wrapper over lower-level request primitives, which may also be used to perform requests. Refer to its implementation and documentation for more details.”h]”(hŒ Note that ”…””}”(hjn hžhhŸNh Nubh)”}”(hjàh]”h¿)”}”(hjàh]”hŒssam_request_do_sync()”…””}”(hjy hžhhŸNh Nubah}”(h]”h ]”(hÊhËjìeh"]”h$]”h&]”uh1h¾hŸNh Nhjv ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jùŒ refexplicit”‰Œrefwarn”‰Œ reftarget”jüuh1hhŸh³h Khjn hžhubhŒ­ in its essence is a wrapper over lower-level request primitives, which may also be used to perform requests. Refer to its implementation and documentation for more details.”…””}”(hjn hžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h Kéhj2 hžhubjD)”}”(hŒwAn arguably more user-friendly way of defining such functions is by using one of the generator macros, for example via:”h]”hŒwAn arguably more user-friendly way of defining such functions is by using one of the generator macros, for example via:”…””}”(hjœ hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h Kíhj2 hžhubj@)”}”(hŒÝSSAM_DEFINE_SYNC_REQUEST_W(__ssam_tmp_perf_mode_set, __le32, { .target_category = SSAM_SSH_TC_TMP, .target_id = SSAM_SSH_TID_SAM, .command_id = 0x03, .instance_id = 0x00, });”h]”hŒÝSSAM_DEFINE_SYNC_REQUEST_W(__ssam_tmp_perf_mode_set, __le32, { .target_category = SSAM_SSH_TC_TMP, .target_id = SSAM_SSH_TID_SAM, .command_id = 0x03, .instance_id = 0x00, });”…””}”hjª sbah}”(h]”h ]”h"]”h$]”h&]”h±h²jO‰jPhËjQ}”uh1j?hŸh³h Kðhj2 hžhubjD)”}”(hŒThis example defines a function”h]”hŒThis example defines a function”…””}”(hj¹ hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h Kùhj2 hžhubj@)”}”(hŒUstatic int __ssam_tmp_perf_mode_set(struct ssam_controller *ctrl, const __le32 *arg);”h]”hŒUstatic int __ssam_tmp_perf_mode_set(struct ssam_controller *ctrl, const __le32 *arg);”…””}”hjÇ sbah}”(h]”h ]”h"]”h$]”h&]”h±h²jO‰jPhËjQ}”uh1j?hŸh³h Kûhj2 hžhubjD)”}”(hXfexecuting the specified request, with the controller passed in when calling said function. In this example, the argument is provided via the ``arg`` pointer. Note that the generated function allocates the message buffer on the stack. Thus, if the argument provided via the request is large, these kinds of macros should be avoided. Also note that, in contrast to the previous non-macro example, this function does not do any endianness conversion, which has to be handled by the caller. Apart from those differences the function generated by the macro is similar to the one provided in the non-macro example above.”h]”(hŒexecuting the specified request, with the controller passed in when calling said function. In this example, the argument is provided via the ”…””}”(hjÖ hžhhŸNh Nubh¿)”}”(hŒ``arg``”h]”hŒarg”…””}”(hjÞ hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¾hjÖ ubhXÒ pointer. Note that the generated function allocates the message buffer on the stack. Thus, if the argument provided via the request is large, these kinds of macros should be avoided. Also note that, in contrast to the previous non-macro example, this function does not do any endianness conversion, which has to be handled by the caller. Apart from those differences the function generated by the macro is similar to the one provided in the non-macro example above.”…””}”(hjÖ hžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h Kÿhj2 hžhubjD)”}”(hŒ3The full list of such function-generating macros is”h]”hŒ3The full list of such function-generating macros is”…””}”(hjö hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h M hj2 hžhubhŒ bullet_list”“”)”}”(hhh]”(hŒ list_item”“”)”}”(hŒ\:c:func:`SSAM_DEFINE_SYNC_REQUEST_N` for requests without return value and without argument.”h]”jD)”}”(hŒ\:c:func:`SSAM_DEFINE_SYNC_REQUEST_N` for requests without return value and without argument.”h]”(h)”}”(hŒ$:c:func:`SSAM_DEFINE_SYNC_REQUEST_N`”h]”h¿)”}”(hj h]”hŒSSAM_DEFINE_SYNC_REQUEST_N()”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hj ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒSSAM_DEFINE_SYNC_REQUEST_N”uh1hhŸh³h M hj ubhŒ8 for requests without return value and without argument.”…””}”(hj hžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h M hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj hžhhŸh³h Nubj )”}”(hŒT:c:func:`SSAM_DEFINE_SYNC_REQUEST_R` for requests with return value but no argument.”h]”jD)”}”(hŒT:c:func:`SSAM_DEFINE_SYNC_REQUEST_R` for requests with return value but no argument.”h]”(h)”}”(hŒ$:c:func:`SSAM_DEFINE_SYNC_REQUEST_R`”h]”h¿)”}”(hjL h]”hŒSSAM_DEFINE_SYNC_REQUEST_R()”…””}”(hjN hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hjJ ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒSSAM_DEFINE_SYNC_REQUEST_R”uh1hhŸh³h M hjF ubhŒ0 for requests with return value but no argument.”…””}”(hjF hžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h M hjB ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj hžhhŸh³h Nubj )”}”(hŒZ:c:func:`SSAM_DEFINE_SYNC_REQUEST_W` for requests without return value but with argument. ”h]”jD)”}”(hŒY:c:func:`SSAM_DEFINE_SYNC_REQUEST_W` for requests without return value but with argument.”h]”(h)”}”(hŒ$:c:func:`SSAM_DEFINE_SYNC_REQUEST_W`”h]”h¿)”}”(hjƒ h]”hŒSSAM_DEFINE_SYNC_REQUEST_W()”…””}”(hj… hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hj ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒSSAM_DEFINE_SYNC_REQUEST_W”uh1hhŸh³h Mhj} ubhŒ5 for requests without return value but with argument.”…””}”(hj} hžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h Mhjy ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj hžhhŸh³h Nubeh}”(h]”h ]”h"]”h$]”h&]”Œbullet”Œ-”uh1j hŸh³h M hj2 hžhubjD)”}”(hŒÌRefer to their respective documentation for more details. For each one of these macros, a special variant is provided, which targets request types applicable to multiple instances of the same device type:”h]”hŒÌRefer to their respective documentation for more details. For each one of these macros, a special variant is provided, which targets request types applicable to multiple instances of the same device type:”…””}”(hj¸ hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h Mhj2 hžhubj )”}”(hhh]”(j )”}”(hŒ':c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_N`”h]”jD)”}”(hjË h]”h)”}”(hjË h]”h¿)”}”(hjË h]”hŒSSAM_DEFINE_SYNC_REQUEST_MD_N()”…””}”(hjÓ hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hjÐ ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒSSAM_DEFINE_SYNC_REQUEST_MD_N”uh1hhŸh³h MhjÍ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h MhjÉ ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjÆ hžhhŸh³h Nubj )”}”(hŒ':c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_R`”h]”jD)”}”(hjü h]”h)”}”(hjü h]”h¿)”}”(hjü h]”hŒSSAM_DEFINE_SYNC_REQUEST_MD_R()”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hj ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒSSAM_DEFINE_SYNC_REQUEST_MD_R”uh1hhŸh³h Mhjþ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h Mhjú ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjÆ hžhhŸh³h Nubj )”}”(hŒ(:c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_W` ”h]”jD)”}”(hŒ':c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_W`”h]”h)”}”(hj1 h]”h¿)”}”(hj1 h]”hŒSSAM_DEFINE_SYNC_REQUEST_MD_W()”…””}”(hj6 hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hj3 ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒSSAM_DEFINE_SYNC_REQUEST_MD_W”uh1hhŸh³h Mhj/ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h Mhj+ ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjÆ hžhhŸh³h Nubeh}”(h]”h ]”h"]”h$]”h&]”j¶ j· uh1j hŸh³h Mhj2 hžhubjD)”}”(hŒÙThe difference of those macros to the previously mentioned versions is, that the device target and instance IDs are not fixed for the generated function, but instead have to be provided by the caller of said function.”h]”hŒÙThe difference of those macros to the previously mentioned versions is, that the device target and instance IDs are not fixed for the generated function, but instead have to be provided by the caller of said function.”…””}”(hjc hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h Mhj2 hžhubjD)”}”(hŒAdditionally, variants for direct use with client devices, i.e. |ssam_device|, are also provided. These can, for example, be used as follows:”h]”(hŒ@Additionally, variants for direct use with client devices, i.e. ”…””}”(hjq hžhhŸNh Nubh)”}”(hhìh]”h¿)”}”(hhìh]”hŒstruct ssam_device”…””}”(hj| hžhhŸNh Nubah}”(h]”h ]”(hÊhËhøeh"]”h$]”h&]”uh1h¾hŸNh Nhjy ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jŒ refexplicit”ˆŒrefwarn”‰Œ reftarget”juh1hhŸh³h Khjq hžhubhŒ@, are also provided. These can, for example, be used as follows:”…””}”(hjq hžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h Mhj2 hžhubj@)”}”(hŒŠSSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta, __le32, { .target_category = SSAM_SSH_TC_BAT, .command_id = 0x01, });”h]”hŒŠSSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta, __le32, { .target_category = SSAM_SSH_TC_BAT, .command_id = 0x01, });”…””}”hjŸ sbah}”(h]”h ]”h"]”h$]”h&]”h±h²jO‰jPhËjQ}”uh1j?hŸh³h M"hj2 hžhubjD)”}”(hŒ/This invocation of the macro defines a function”h]”hŒ/This invocation of the macro defines a function”…””}”(hj® hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h M)hj2 hžhubj@)”}”(hŒCstatic int ssam_bat_get_sta(struct ssam_device *sdev, __le32 *ret);”h]”hŒCstatic int ssam_bat_get_sta(struct ssam_device *sdev, __le32 *ret);”…””}”hj¼ sbah}”(h]”h ]”h"]”h$]”h&]”h±h²jO‰jPhËjQ}”uh1j?hŸh³h M+hj2 hžhubjD)”}”(hŒ”executing the specified request, using the device IDs and controller given in the client device. The full list of such macros for client devices is:”h]”hŒ”executing the specified request, using the device IDs and controller given in the client device. The full list of such macros for client devices is:”…””}”(hjË hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h M/hj2 hžhubj )”}”(hhh]”(j )”}”(hŒ':c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_N`”h]”jD)”}”(hjÞ h]”h)”}”(hjÞ h]”h¿)”}”(hjÞ h]”hŒSSAM_DEFINE_SYNC_REQUEST_CL_N()”…””}”(hjæ hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hjã ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒSSAM_DEFINE_SYNC_REQUEST_CL_N”uh1hhŸh³h M2hjà ubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h M2hjÜ ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjÙ hžhhŸh³h Nubj )”}”(hŒ':c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_R`”h]”jD)”}”(hj h]”h)”}”(hj h]”h¿)”}”(hj h]”hŒSSAM_DEFINE_SYNC_REQUEST_CL_R()”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hj ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒSSAM_DEFINE_SYNC_REQUEST_CL_R”uh1hhŸh³h M3hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h M3hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjÙ hžhhŸh³h Nubj )”}”(hŒ):c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_W` ”h]”jD)”}”(hŒ':c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_W`”h]”h)”}”(hjD h]”h¿)”}”(hjD h]”hŒSSAM_DEFINE_SYNC_REQUEST_CL_W()”…””}”(hjI hžhhŸNh Nubah}”(h]”h ]”(hÊhËŒc-func”eh"]”h$]”h&]”uh1h¾hjF ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hÝŒSSAM_DEFINE_SYNC_REQUEST_CL_W”uh1hhŸh³h M4hjB ubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h M4hj> ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjÙ hžhhŸh³h Nubeh}”(h]”h ]”h"]”h$]”h&]”j¶ j· uh1j hŸh³h M2hj2 hžhubeh}”(h]”Œmaking-synchronous-requests”ah ]”h"]”Œmaking synchronous requests”ah$]”h&]”uh1j.hj0hžhhŸh³h KŸubj/)”}”(hhh]”(j4)”}”(hŒHandling Events”h]”hŒHandling Events”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j3hj~ hžhhŸh³h M8ubjD)”}”(hXœTo receive events from the SAM EC, an event notifier must be registered for the desired event via |ssam_notifier_register|. The notifier must be unregistered via |ssam_notifier_unregister| once it is not required any more. For |ssam_device| type clients, the |ssam_device_notifier_register| and |ssam_device_notifier_unregister| wrappers should be preferred as they properly handle hot-removal of client devices.”h]”(hŒbTo receive events from the SAM EC, an event notifier must be registered for the desired event via ”…””}”(hj hžhhŸNh Nubh)”}”(hj8h]”h¿)”}”(hj8h]”hŒssam_notifier_register()”…””}”(hjš hžhhŸNh Nubah}”(h]”h ]”(hÊhËjDeh"]”h$]”h&]”uh1h¾hŸNh Nhj— ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jQŒ refexplicit”‰Œrefwarn”‰Œ reftarget”jTuh1hhŸh³h Khj hžhubhŒ(. The notifier must be unregistered via ”…””}”(hj hžhhŸNh Nubh)”}”(hjbh]”h¿)”}”(hjbh]”hŒssam_notifier_unregister()”…””}”(hjº hžhhŸNh Nubah}”(h]”h ]”(hÊhËjneh"]”h$]”h&]”uh1h¾hŸNh Nhj· ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”j{Œ refexplicit”‰Œrefwarn”‰Œ reftarget”j~uh1hhŸh³h Khj hžhubhŒ' once it is not required any more. For ”…””}”(hj hžhhŸNh Nubh)”}”(hhìh]”h¿)”}”(hhìh]”hŒstruct ssam_device”…””}”(hjÚ hžhhŸNh Nubah}”(h]”h ]”(hÊhËhøeh"]”h$]”h&]”uh1h¾hŸNh Nhj× ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jŒ refexplicit”ˆŒrefwarn”‰Œ reftarget”juh1hhŸh³h Khj hžhubhŒ type clients, the ”…””}”(hj hžhhŸNh Nubh)”}”(hjŒh]”h¿)”}”(hjŒh]”hŒssam_device_notifier_register()”…””}”(hjú hžhhŸNh Nubah}”(h]”h ]”(hÊhËj˜eh"]”h$]”h&]”uh1h¾hŸNh Nhj÷ ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”j¥Œ refexplicit”‰Œrefwarn”‰Œ reftarget”j¨uh1hhŸh³h Khj hžhubhŒ and ”…””}”(hj hžhhŸNh Nubh)”}”(hj¶h]”h¿)”}”(hj¶h]”hŒ!ssam_device_notifier_unregister()”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”(hÊhËjÂeh"]”h$]”h&]”uh1h¾hŸNh Nhj ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”jÏŒ refexplicit”‰Œrefwarn”‰Œ reftarget”jÒuh1hhŸh³h Khj hžhubhŒT wrappers should be preferred as they properly handle hot-removal of client devices.”…””}”(hj hžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h M:hj~ hžhubjD)”}”(hXEvent notifiers are registered by providing (at minimum) a callback to call in case an event has been received, the registry specifying how the event should be enabled, an event ID specifying for which target category and, optionally and depending on the registry used, for which instance ID events should be enabled, and finally, flags describing how the EC will send these events. If the specific registry does not enable events by instance ID, the instance ID must be set to zero. Additionally, a priority for the respective notifier may be specified, which determines its order in relation to any other notifier registered for the same target category.”h]”hXEvent notifiers are registered by providing (at minimum) a callback to call in case an event has been received, the registry specifying how the event should be enabled, an event ID specifying for which target category and, optionally and depending on the registry used, for which instance ID events should be enabled, and finally, flags describing how the EC will send these events. If the specific registry does not enable events by instance ID, the instance ID must be set to zero. Additionally, a priority for the respective notifier may be specified, which determines its order in relation to any other notifier registered for the same target category.”…””}”(hj= hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h MAhj~ hžhubjD)”}”(hXœBy default, event notifiers will receive all events for the specific target category, regardless of the instance ID specified when registering the notifier. The core may be instructed to only call a notifier if the target ID or instance ID (or both) of the event match the ones implied by the notifier IDs (in case of target ID, the target ID of the registry), by providing an event mask (see |ssam_event_mask|).”h]”(hX‰By default, event notifiers will receive all events for the specific target category, regardless of the instance ID specified when registering the notifier. The core may be instructed to only call a notifier if the target ID or instance ID (or both) of the event match the ones implied by the notifier IDs (in case of target ID, the target ID of the registry), by providing an event mask (see ”…””}”(hjK hžhhŸNh Nubh)”}”(hj h]”h¿)”}”(hj h]”hŒenum ssam_event_mask”…””}”(hjV hžhhŸNh Nubah}”(h]”h ]”(hÊhËjeh"]”h$]”h&]”uh1h¾hŸNh NhjS ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”h׌ refdomain”hËŒreftype”j#Œ refexplicit”ˆŒrefwarn”‰Œ reftarget”j&uh1hhŸh³h KhjK hžhubhŒ).”…””}”(hjK hžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h MKhj~ hžhubjD)”}”(hXIn general, the target ID of the registry is also the target ID of the enabled event (with the notable exception being keyboard input events on the Surface Laptop 1 and 2, which are enabled via a registry with target ID 1, but provide events with target ID 2).”h]”hXIn general, the target ID of the registry is also the target ID of the enabled event (with the notable exception being keyboard input events on the Surface Laptop 1 and 2, which are enabled via a registry with target ID 1, but provide events with target ID 2).”…””}”(hjy hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h MRhj~ hžhubjD)”}”(hŒ`A full example for registering an event notifier and handling received events is provided below:”h]”hŒ`A full example for registering an event notifier and handling received events is provided below:”…””}”(hj‡ hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h MWhj~ hžhubj@)”}”(hX7u32 notifier_callback(struct ssam_event_notifier *nf, const struct ssam_event *event) { int status = ... /* Handle the event here ... */ /* Convert return value and indicate that we handled the event. */ return ssam_notifier_from_errno(status) | SSAM_NOTIF_HANDLED; } int setup_notifier(struct ssam_device *sdev, struct ssam_event_notifier *nf) { /* Set priority wrt. other handlers of same target category. */ nf->base.priority = 1; /* Set event/notifier callback. */ nf->base.fn = notifier_callback; /* Specify event registry, i.e. how events get enabled/disabled. */ nf->event.reg = SSAM_EVENT_REGISTRY_KIP; /* Specify which event to enable/disable */ nf->event.id.target_category = sdev->uid.category; nf->event.id.instance = sdev->uid.instance; /* * Specify for which events the notifier callback gets executed. * This essentially tells the core if it can skip notifiers that * don't have target or instance IDs matching those of the event. */ nf->event.mask = SSAM_EVENT_MASK_STRICT; /* Specify event flags. */ nf->event.flags = SSAM_EVENT_SEQUENCED; return ssam_notifier_register(sdev->ctrl, nf); }”h]”hX7u32 notifier_callback(struct ssam_event_notifier *nf, const struct ssam_event *event) { int status = ... /* Handle the event here ... */ /* Convert return value and indicate that we handled the event. */ return ssam_notifier_from_errno(status) | SSAM_NOTIF_HANDLED; } int setup_notifier(struct ssam_device *sdev, struct ssam_event_notifier *nf) { /* Set priority wrt. other handlers of same target category. */ nf->base.priority = 1; /* Set event/notifier callback. */ nf->base.fn = notifier_callback; /* Specify event registry, i.e. how events get enabled/disabled. */ nf->event.reg = SSAM_EVENT_REGISTRY_KIP; /* Specify which event to enable/disable */ nf->event.id.target_category = sdev->uid.category; nf->event.id.instance = sdev->uid.instance; /* * Specify for which events the notifier callback gets executed. * This essentially tells the core if it can skip notifiers that * don't have target or instance IDs matching those of the event. */ nf->event.mask = SSAM_EVENT_MASK_STRICT; /* Specify event flags. */ nf->event.flags = SSAM_EVENT_SEQUENCED; return ssam_notifier_register(sdev->ctrl, nf); }”…””}”hj• sbah}”(h]”h ]”h"]”h$]”h&]”h±h²jO‰jPhËjQ}”uh1j?hŸh³h MZhj~ hžhubjD)”}”(hXàMultiple event notifiers can be registered for the same event. The event handler core takes care of enabling and disabling events when notifiers are registered and unregistered, by keeping track of how many notifiers for a specific event (combination of registry, event target category, and event instance ID) are currently registered. This means that a specific event will be enabled when the first notifier for it is being registered and disabled when the last notifier for it is being unregistered. Note that the event flags are therefore only used on the first registered notifier, however, one should take care that notifiers for a specific event are always registered with the same flag and it is considered a bug to do otherwise.”h]”hXàMultiple event notifiers can be registered for the same event. The event handler core takes care of enabling and disabling events when notifiers are registered and unregistered, by keeping track of how many notifiers for a specific event (combination of registry, event target category, and event instance ID) are currently registered. This means that a specific event will be enabled when the first notifier for it is being registered and disabled when the last notifier for it is being unregistered. Note that the event flags are therefore only used on the first registered notifier, however, one should take care that notifiers for a specific event are always registered with the same flag and it is considered a bug to do otherwise.”…””}”(hj¤ hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jChŸh³h M„hj~ hžhubeh}”(h]”Œhandling-events”ah ]”h"]”Œhandling events”ah$]”h&]”uh1j.hj0hžhhŸh³h M8ubeh}”(h]”Œwriting-client-drivers”ah ]”h"]”Œwriting client drivers”ah$]”h&]”uh1j.hhhžhhŸh³h Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”h³uh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)”}”(j3NŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”jå Œerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”h³Œ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”•pŒsubstitution_defs”}”(hãh¶j hæj7jjaj:j‹jdjµjŽjßj¸j jâj3j j]j6j‡j`j±jŠjÛj´jjÞj/jjYj2jƒj\j­j†j×j°jjÚj+juŒsubstitution_names”}”(Œssam_controller”h㌠ssam_device”j/Œssam_device_driver”j7Œssam_client_bind”jaŒssam_client_link”j‹Œssam_get_controller”jµŒssam_controller_get”jߌssam_controller_put”j Œssam_device_alloc”j3Œssam_device_add”j]Œssam_device_remove”j‡Œssam_device_driver_register”j±Œssam_device_driver_unregister”jÛŒmodule_ssam_device_driver”jŒssam_notifier_register”jYŒssam_notifier_unregister”jƒŒssam_device_notifier_register”j­Œssam_device_notifier_unregister”j׌ssam_request_do_sync”jŒssam_event_mask”j+uŒrefnames”}”Œrefids”}”Œnameids”}”(j¿ j¼ jjšjÆjÃj»j¸j/ j, j{ jx j· j´ uŒ nametypes”}”(j¿ ‰j‰jƉj»‰j/ ‰j{ ‰j· ‰uh}”(j¼ j0jšjyjÃj j¸jÉj, j¾jx j2 j´ j~ uŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”Œtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nhžhub.