€•Œ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ŒPortuguese (Brazilian)”…””}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ8/translations/pt_BR/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Ó)”}”(hjh]”hŒstruct ssam_device”…””}”(hjh²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Ó)”}”(hj*h]”hŒstruct ssam_device_driver”…””}”(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´Khj$ubah}”(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Ó)”}”(hjTh]”hŒssam_client_bind()”…””}”(hjVh²hh³Nh´Nubah}”(h]”h ]”(hÞhߌc-func”eh"]”h$]”h&]”uh1hÒhjRubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hñŒssam_client_bind”uh1hh³hÇh´KhjNubah}”(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Ó)”}”(hj~h]”hŒssam_client_link()”…””}”(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_client_link”uh1hh³hÇh´Khjxubah}”(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Ó)”}”(hj&h]”hŒssam_device_alloc()”…””}”(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_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Ó)”}”(hjPh]”hŒssam_device_add()”…””}”(hjRh²hh³Nh´Nubah}”(h]”h ]”(hÞhߌc-func”eh"]”h$]”h&]”uh1hÒhjNubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hñŒssam_device_add”uh1hh³hÇh´K hjJubah}”(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Ó)”}”(hjzh]”hŒssam_device_remove()”…””}”(hj|h²hh³Nh´Nubah}”(h]”h ]”(hÞhߌc-func”eh"]”h$]”h&]”uh1hÒhjxubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hñŒssam_device_remove”uh1hh³hÇh´K hjtubah}”(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Ó)”}”(hj¤h]”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Ó)”}”(hj"h]”hŒ SSAM_DEVICE()”…””}”(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”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Ó)”}”(hjLh]”hŒssam_notifier_register()”…””}”(hjNh²hh³Nh´Nubah}”(h]”h ]”(hÞhߌc-func”eh"]”h$]”h&]”uh1hÒhjJubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hñŒssam_notifier_register”uh1hh³hÇh´KhjFubah}”(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Ó)”}”(hjvh]”hŒssam_notifier_unregister()”…””}”(hjxh²hh³Nh´Nubah}”(h]”h ]”(hÞhߌc-func”eh"]”h$]”h&]”uh1hÒhjtubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hñŒssam_notifier_unregister”uh1hh³hÇh´Khjpubah}”(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Ó)”}”(hjh]”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”…””}”(hjIh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jGhjDh²hh³hÇh´KubhŒ paragraph”“”)”}”(hŒ$For the API documentation, refer to:”h]”hŒ$For the API documentation, refer to:”…””}”(hjYh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jWh³hÇh´KhjDh²hubhŒcompound”“”)”}”(hhh]”hŒtoctree”“”)”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”hhëŒentries”]”NŒ(driver-api/surface_aggregator/client-api”†”aŒ includefiles”]”jyaŒmaxdepth”KŒcaption”NŒglob”‰Œhidden”‰Œ includehidden”‰Œnumbered”KŒ titlesonly”‰Œ rawentries”]”uh1jlh³hÇh´K hjiubah}”(h]”h ]”Œtoctree-wrapper”ah"]”h$]”h&]”uh1jghjDh²hh³hÇh´NubjC)”}”(hhh]”(jH)”}”(hŒOverview”h]”hŒOverview”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jGhjh²hh³hÇh´K'ubjX)”}”(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&]”uh1jWh³hÇh´K)hjh²hubeh}”(h]”Œoverview”ah ]”h"]”Œoverview”ah$]”h&]”uh1jBhjDh²hh³hÇh´K'ubjC)”}”(hhh]”(jH)”}”(hŒNon-SSAM Client Drivers”h]”hŒNon-SSAM Client Drivers”…””}”(hj·h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jGhj´h²hh³hÇh´K2ubjX)”}”(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)”}”(hj*h]”hÓ)”}”(hj*h]”hŒstruct ssam_device_driver”…””}”(hjðh²hh³Nh´Nubah}”(h]”h ]”(hÞhßj6eh"]”h$]”h&]”uh1hÒh³Nh´Nhjíubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”jCŒ refexplicit”ˆŒrefwarn”‰Œ reftarget”jFuh1hh³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)”}”(hjTh]”hÓ)”}”(hjTh]”hŒssam_client_bind()”…””}”(hjh²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”jmŒ refexplicit”‰Œrefwarn”‰Œ reftarget”jpuh1hh³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)”}”(hj~h]”hÓ)”}”(hj~h]”hŒssam_client_link()”…””}”(hj0h²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²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&]”uh1jWh³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; }”…””}”hjUsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆŒforce”‰Œlanguage”hߌhighlight_args”}”uh1jSh³hÇh´KChj´h²hubjX)”}”(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 ”…””}”(hjgh²hh³Nh´Nubh)”}”(hj¨h]”hÓ)”}”(hj¨h]”hŒssam_get_controller()”…””}”(hjrh²hh³Nh´Nubah}”(h]”h ]”(hÞhßj´eh"]”h$]”h&]”uh1hÒh³Nh´Nhjoubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”jÁŒ refexplicit”‰Œrefwarn”‰Œ reftarget”jÄuh1hh³hÇh´Khjgh²hubhŒ$ and its lifetime be guaranteed via ”…””}”(hjgh²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´Nhjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”jëŒ refexplicit”‰Œrefwarn”‰Œ reftarget”jîuh1hh³hÇh´K hjgh²hubhŒ and ”…””}”(hjgh²hh³Nh´Nubh)”}”(hjüh]”hÓ)”}”(hjüh]”hŒssam_controller_put()”…””}”(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”juh1hh³hÇh´K hjgh²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.”…””}”(hjgh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jWh³hÇh´KRhj´h²hubeh}”(h]”Œnon-ssam-client-drivers”ah ]”h"]”Œnon-ssam client drivers”ah$]”h&]”uh1jBhjDh²hh³hÇh´K2ubjC)”}”(hhh]”(jH)”}”(hŒAdding SSAM Devices”h]”hŒAdding SSAM Devices”…””}”(hjàh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jGhjÝh²hh³hÇh´K[ubjX)”}”(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)”}”(hjh]”hÓ)”}”(hjh]”hŒstruct ssam_device”…””}”(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Œ­ 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)”}”(hj&h]”hÓ)”}”(hj&h]”hŒssam_device_alloc()”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”(hÞhßj2eh"]”h$]”h&]”uh1hÒh³Nh´Nhjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”j?Œ refexplicit”‰Œrefwarn”‰Œ reftarget”jBuh1hh³hÇh´K hjîh²hubhŒ2, subsequently to which they have to be added via ”…””}”(hjîh²hh³Nh´Nubh)”}”(hjPh]”hÓ)”}”(hjPh]”hŒssam_device_add()”…””}”(hj9h²hh³Nh´Nubah}”(h]”h ]”(hÞhßj\eh"]”h$]”h&]”uh1hÒh³Nh´Nhj6ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”jiŒ refexplicit”‰Œrefwarn”‰Œ reftarget”jluh1hh³hÇh´K hjîh²hubhŒ and eventually removed via ”…””}”(hjîh²hh³Nh´Nubh)”}”(hjzh]”hÓ)”}”(hjzh]”hŒssam_device_remove()”…””}”(hjYh²hh³Nh´Nubah}”(h]”h ]”(hÞhßj†eh"]”h$]”h&]”uh1hÒh³Nh´NhjVubah}”(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)”}”(hj~h]”hÓ)”}”(hj~h]”hŒssam_client_link()”…””}”(hjyh²hh³Nh´Nubah}”(h]”h ]”(hÞhßjŠeh"]”h$]”h&]”uh1hÒh³Nh´Nhjvubah}”(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&]”uh1jWh³hÇh´K]hjÝh²hubjX)”}”(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)”}”(hj~h]”hÓ)”}”(hj~h]”hŒssam_client_link()”…””}”(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²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&]”uh1jWh³hÇh´KkhjÝh²hubeh}”(h]”Œadding-ssam-devices”ah ]”h"]”Œadding ssam devices”ah$]”h&]”uh1jBhjDh²hh³hÇh´K[ubjC)”}”(hhh]”(jH)”}”(hŒSSAM Client Drivers”h]”hŒSSAM Client Drivers”…””}”(hjÕh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jGhjÒh²hh³hÇh´KvubjX)”}”(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)”}”(hj*h]”hÓ)”}”(hj*h]”hŒstruct ssam_device_driver”…””}”(hjîh²hh³Nh´Nubah}”(h]”h ]”(hÞhßj6eh"]”h$]”h&]”uh1hÒh³Nh´Nhjëubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”jCŒ refexplicit”ˆŒrefwarn”‰Œ reftarget”jFuh1hh³hÇh´Khjãh²hubhŒ and bind to a ”…””}”(hjãh²hh³Nh´Nubh)”}”(hjh]”hÓ)”}”(hjh]”hŒstruct ssam_device”…””}”(hjh²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Œ via its UID (”…””}”(hjãh²hh³Nh´Nubh)”}”(hŒ.:c:type:`struct ssam_device.uid `”h]”hÓ)”}”(hj-h]”hŒstruct ssam_device.uid”…””}”(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´KxhjãubhŒ) member and the match table (”…””}”(hjãh²hh³Nh´Nubh)”}”(hŒD:c:type:`struct ssam_device_driver.match_table `”h]”hÓ)”}”(hjPh]”hŒ%struct ssam_device_driver.match_table”…””}”(hjRh²hh³Nh´Nubah}”(h]”h ]”(hÞhߌc-type”eh"]”h$]”h&]”uh1hÒhjNubah}”(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)”}”(hj"h]”hÓ)”}”(hj"h]”hŒ SSAM_DEVICE()”…””}”(hjth²hh³Nh´Nubah}”(h]”h ]”(hÞhßj.eh"]”h$]”h&]”uh1hÒh³Nh´Nhjqubah}”(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&]”uh1jWh³hÇh´KxhjÒh²hubjX)”}”(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”…””}”(hj±h²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”…””}”(hjh²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Ó)”}”(hj0h]”hŒSSAM_DOMAIN_VIRTUAL”…””}”(hj2h²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Œ“), 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”…””}”(hjQh²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”…””}”(hjch²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”…””}”(hjuh²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”…””}”(hj‡h²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&]”uh1jWh³hÇh´KhjÒh²hubjX)”}”(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)”}”(hj¤h]”hÓ)”}”(hj¤h]”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ßjeh"]”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&]”uh1jWh³hÇh´KŽhjÒh²hubjX)”}”(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&]”uh1jWh³hÇh´K“hjÒh²hubeh}”(h]”Œssam-client-drivers”ah ]”h"]”Œssam client drivers”ah$]”h&]”uh1jBhjDh²hh³hÇh´KvubjC)”}”(hhh]”(jH)”}”(hŒMaking Synchronous Requests”h]”hŒMaking Synchronous Requests”…””}”(hjI h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jGhjF h²hh³hÇh´KŸubjX)”}”(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.”…””}”(hjW h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jWh³hÇh´K¡hjF h²hubjX)”}”(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.”…””}”(hje h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jWh³hÇh´K©hjF h²hubjT)”}”(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; }”…””}”hjs sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆjc‰jdhßje}”uh1jSh³hÇh´K­hjF h²hubjX)”}”(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 ”…””}”(hj‚ h²hh³Nh´Nubh)”}”(hjôh]”hÓ)”}”(hjôh]”hŒssam_request_do_sync()”…””}”(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”juh1hh³hÇh´Khj‚ 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.”…””}”(hj‚ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jWh³hÇh´KéhjF h²hubjX)”}”(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&]”uh1jWh³hÇh´KíhjF h²hubjT)”}”(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Æjc‰jdhßje}”uh1jSh³hÇh´KðhjF h²hubjX)”}”(hŒThis example defines a function”h]”hŒThis example defines a function”…””}”(hjÍ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jWh³hÇh´KùhjF h²hubjT)”}”(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Æjc‰jdhßje}”uh1jSh³hÇh´KûhjF h²hubjX)”}”(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&]”uh1jWh³hÇh´KÿhjF h²hubjX)”}”(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&]”uh1jWh³hÇh´M hjF 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]”jX)”}”(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&]”uh1jWh³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]”jX)”}”(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Ó)”}”(hj` h]”hŒSSAM_DEFINE_SYNC_REQUEST_R()”…””}”(hjb 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_R”uh1hh³hÇh´M hjZ ubhŒ0 for requests with return value but no argument.”…””}”(hjZ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jWh³hÇh´M hjV 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]”jX)”}”(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&]”uh1jWh³hÇh´Mhj ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj h²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”Œbullet”Œ-”uh1j h³hÇh´M hjF h²hubjX)”}”(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&]”uh1jWh³hÇh´MhjF h²hubj )”}”(hhh]”(j )”}”(hŒ':c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_N`”h]”jX)”}”(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&]”uh1jWh³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]”jX)”}”(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&]”uh1jWh³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]”jX)”}”(hŒ':c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_W`”h]”h)”}”(hjE h]”hÓ)”}”(hjE h]”hŒSSAM_DEFINE_SYNC_REQUEST_MD_W()”…””}”(hjJ h²hh³Nh´Nubah}”(h]”h ]”(hÞhߌc-func”eh"]”h$]”h&]”uh1hÒhjG ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hñŒSSAM_DEFINE_SYNC_REQUEST_MD_W”uh1hh³hÇh´MhjC ubah}”(h]”h ]”h"]”h$]”h&]”uh1jWh³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´MhjF h²hubjX)”}”(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.”…””}”(hjw h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jWh³hÇh´MhjF h²hubjX)”}”(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. ”…””}”(hj… h²hh³Nh´Nubh)”}”(hjh]”hÓ)”}”(hjh]”hŒstruct ssam_device”…””}”(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Œ@, are also provided. These can, for example, be used as follows:”…””}”(hj… h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jWh³hÇh´MhjF h²hubjT)”}”(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Æjc‰jdhßje}”uh1jSh³hÇh´M"hjF h²hubjX)”}”(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&]”uh1jWh³hÇh´M)hjF h²hubjT)”}”(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Æjc‰jdhßje}”uh1jSh³hÇh´M+hjF h²hubjX)”}”(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&]”uh1jWh³hÇh´M/hjF h²hubj )”}”(hhh]”(j )”}”(hŒ':c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_N`”h]”jX)”}”(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&]”uh1jWh³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]”jX)”}”(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&]”uh1jWh³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]”jX)”}”(hŒ':c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_W`”h]”h)”}”(hjX h]”hÓ)”}”(hjX h]”hŒSSAM_DEFINE_SYNC_REQUEST_CL_W()”…””}”(hj] h²hh³Nh´Nubah}”(h]”h ]”(hÞhߌc-func”eh"]”h$]”h&]”uh1hÒhjZ ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰hñŒSSAM_DEFINE_SYNC_REQUEST_CL_W”uh1hh³hÇh´M4hjV ubah}”(h]”h ]”h"]”h$]”h&]”uh1jWh³hÇh´M4hjR ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjí h²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”jÊ jË uh1j h³hÇh´M2hjF h²hubeh}”(h]”Œmaking-synchronous-requests”ah ]”h"]”Œmaking synchronous requests”ah$]”h&]”uh1jBhjDh²hh³hÇh´KŸubjC)”}”(hhh]”(jH)”}”(hŒHandling Events”h]”hŒHandling Events”…””}”(hj• h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jGhj’ h²hh³hÇh´M8ubjX)”}”(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)”}”(hjLh]”hÓ)”}”(hjLh]”hŒssam_notifier_register()”…””}”(hj® h²hh³Nh´Nubah}”(h]”h ]”(hÞhßjXeh"]”h$]”h&]”uh1hÒh³Nh´Nhj« ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”jeŒ refexplicit”‰Œrefwarn”‰Œ reftarget”jhuh1hh³hÇh´Khj£ h²hubhŒ(. The notifier must be unregistered via ”…””}”(hj£ h²hh³Nh´Nubh)”}”(hjvh]”hÓ)”}”(hjvh]”hŒssam_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Œ' once it is not required any more. For ”…””}”(hj£ h²hh³Nh´Nubh)”}”(hjh]”hÓ)”}”(hjh]”hŒstruct ssam_device”…””}”(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Œ 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&]”uh1jWh³hÇh´M:hj’ h²hubjX)”}”(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.”…””}”(hjQ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jWh³hÇh´MAhj’ h²hubjX)”}”(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 ”…””}”(hj_ h²hh³Nh´Nubh)”}”(hjh]”hÓ)”}”(hjh]”hŒenum ssam_event_mask”…””}”(hjj h²hh³Nh´Nubah}”(h]”h ]”(hÞhßj*eh"]”h$]”h&]”uh1hÒh³Nh´Nhjg ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”hëŒ refdomain”hߌreftype”j7Œ refexplicit”ˆŒrefwarn”‰Œ reftarget”j:uh1hh³hÇh´Khj_ h²hubhŒ).”…””}”(hj_ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jWh³hÇh´MKhj’ h²hubjX)”}”(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).”…””}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jWh³hÇh´MRhj’ h²hubjX)”}”(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&]”uh1jWh³hÇh´MWhj’ h²hubjT)”}”(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Æjc‰jdhßje}”uh1jSh³hÇh´MZhj’ h²hubjX)”}”(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&]”uh1jWh³hÇh´M„hj’ h²hubeh}”(h]”Œhandling-events”ah ]”h"]”Œhandling events”ah$]”h&]”uh1jBhjDh²hh³hÇh´M8ubeh}”(h]”Œwriting-client-drivers”ah ]”h"]”Œwriting client drivers”ah$]”h&]”uh1jBhhh²hh³hÇh´Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”hÇuh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)”}”(jGNŒ 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”]”Œsubstitution_defs”}”(h÷hÊj!hújKj$jujNjŸjxjÉj¢jójÌjjöjGj jqjJj›jtjÅjžjïjÈjjòjCjjmjFj—jpjÁjšjëjÄjjîj?juŒsubstitution_names”}”(Œssam_controller”h÷Œ ssam_device”jCŒssam_device_driver”jKŒssam_client_bind”juŒssam_client_link”jŸŒssam_get_controller”jÉŒssam_controller_get”jóŒssam_controller_put”jŒssam_device_alloc”jGŒssam_device_add”jqŒssam_device_remove”j›Œssam_device_driver_register”jÅŒssam_device_driver_unregister”jïŒmodule_ssam_device_driver”jŒssam_notifier_register”jmŒ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Ð j±j®jÚj×jÏjÌjC j@ j jŒ jË jÈ uŒ nametypes”}”(jÓ ‰j±‰jÚ‰jωjC ‰j ‰jË ‰uh}”(jÐ jDj®jj×j´jÌjÝj@ jÒjŒ jF 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.