582 lines · plain
1=================================2Intel Integrated Sensor Hub (ISH)3=================================4 5A sensor hub enables the ability to offload sensor polling and algorithm6processing to a dedicated low power co-processor. This allows the core7processor to go into low power modes more often, resulting in increased8battery life.9 10There are many vendors providing external sensor hubs conforming to HID11Sensor usage tables. These may be found in tablets, 2-in-1 convertible laptops12and embedded products. Linux has had this support since Linux 3.9.13 14Intel® introduced integrated sensor hubs as a part of the SoC starting from15Cherry Trail and now supported on multiple generations of CPU packages. There16are many commercial devices already shipped with Integrated Sensor Hubs (ISH).17These ISH also comply to HID sensor specification, but the difference is the18transport protocol used for communication. The current external sensor hubs19mainly use HID over I2C or USB. But ISH doesn't use either I2C or USB.20 21Overview22========23 24Using a analogy with a usbhid implementation, the ISH follows a similar model25for a very high speed communication::26 27 ----------------- ----------------------28 | USB HID | --> | ISH HID |29 ----------------- ----------------------30 ----------------- ----------------------31 | USB protocol | --> | ISH Transport |32 ----------------- ----------------------33 ----------------- ----------------------34 | EHCI/XHCI | --> | ISH IPC |35 ----------------- ----------------------36 PCI PCI37 ----------------- ----------------------38 |Host controller| --> | ISH processor |39 ----------------- ----------------------40 USB Link41 ----------------- ----------------------42 | USB End points| --> | ISH Clients |43 ----------------- ----------------------44 45Like USB protocol provides a method for device enumeration, link management46and user data encapsulation, the ISH also provides similar services. But it is47very light weight tailored to manage and communicate with ISH client48applications implemented in the firmware.49 50The ISH allows multiple sensor management applications executing in the51firmware. Like USB endpoints the messaging can be to/from a client. As part of52enumeration process, these clients are identified. These clients can be simple53HID sensor applications, sensor calibration applications or sensor firmware54update applications.55 56The implementation model is similar, like USB bus, ISH transport is also57implemented as a bus. Each client application executing in the ISH processor58is registered as a device on this bus. The driver, which binds each device59(ISH HID driver) identifies the device type and registers with the HID core.60 61ISH Implementation: Block Diagram62=================================63 64::65 66 ---------------------------67 | User Space Applications |68 ---------------------------69 70 ----------------IIO ABI----------------71 --------------------------72 | IIO Sensor Drivers |73 --------------------------74 --------------------------75 | IIO core |76 --------------------------77 --------------------------78 | HID Sensor Hub MFD |79 --------------------------80 --------------------------81 | HID Core |82 --------------------------83 --------------------------84 | HID over ISH Client |85 --------------------------86 --------------------------87 | ISH Transport (ISHTP) |88 --------------------------89 --------------------------90 | IPC Drivers |91 --------------------------92 OS93 ---------------- PCI -----------------94 Hardware + Firmware95 ----------------------------96 | ISH Hardware/Firmware(FW) |97 ----------------------------98 99High level processing in above blocks100=====================================101 102Hardware Interface103------------------104 105The ISH is exposed as "Non-VGA unclassified PCI device" to the host. The PCI106product and vendor IDs are changed from different generations of processors. So107the source code which enumerates drivers needs to update from generation to108generation.109 110Inter Processor Communication (IPC) driver111------------------------------------------112 113Location: drivers/hid/intel-ish-hid/ipc114 115The IPC message uses memory mapped I/O. The registers are defined in116hw-ish-regs.h.117 118IPC/FW message types119^^^^^^^^^^^^^^^^^^^^120 121There are two types of messages, one for management of link and another for122messages to and from transport layers.123 124TX and RX of Transport messages125...............................126 127A set of memory mapped register offers support of multi-byte messages TX and128RX (e.g. IPC_REG_ISH2HOST_MSG, IPC_REG_HOST2ISH_MSG). The IPC layer maintains129internal queues to sequence messages and send them in order to the firmware.130Optionally the caller can register handler to get notification of completion.131A doorbell mechanism is used in messaging to trigger processing in host and132client firmware side. When ISH interrupt handler is called, the ISH2HOST133doorbell register is used by host drivers to determine that the interrupt134is for ISH.135 136Each side has 32 32-bit message registers and a 32-bit doorbell. Doorbell137register has the following format::138 139 Bits 0..6: fragment length (7 bits are used)140 Bits 10..13: encapsulated protocol141 Bits 16..19: management command (for IPC management protocol)142 Bit 31: doorbell trigger (signal H/W interrupt to the other side)143 Other bits are reserved, should be 0.144 145Transport layer interface146^^^^^^^^^^^^^^^^^^^^^^^^^147 148To abstract HW level IPC communication, a set of callbacks is registered.149The transport layer uses them to send and receive messages.150Refer to struct ishtp_hw_ops for callbacks.151 152ISH Transport layer153-------------------154 155Location: drivers/hid/intel-ish-hid/ishtp/156 157A Generic Transport Layer158^^^^^^^^^^^^^^^^^^^^^^^^^159 160The transport layer is a bi-directional protocol, which defines:161- Set of commands to start, stop, connect, disconnect and flow control162(see ishtp/hbm.h for details)163- A flow control mechanism to avoid buffer overflows164 165This protocol resembles bus messages described in the following document:166http://www.intel.com/content/dam/www/public/us/en/documents/technical-\167specifications/dcmi-hi-1-0-spec.pdf "Chapter 7: Bus Message Layer"168 169Connection and Flow Control Mechanism170^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^171 172Each FW client and a protocol is identified by a UUID. In order to communicate173to a FW client, a connection must be established using connect request and174response bus messages. If successful, a pair (host_client_id and fw_client_id)175will identify the connection.176 177Once connection is established, peers send each other flow control bus messages178independently. Every peer may send a message only if it has received a179flow-control credit before. Once it has sent a message, it may not send another one180before receiving the next flow control credit.181Either side can send disconnect request bus message to end communication. Also182the link will be dropped if major FW reset occurs.183 184Peer to Peer data transfer185^^^^^^^^^^^^^^^^^^^^^^^^^^186 187Peer to Peer data transfer can happen with or without using DMA. Depending on188the sensor bandwidth requirement DMA can be enabled by using module parameter189ishtp_use_dma under intel_ishtp.190 191Each side (host and FW) manages its DMA transfer memory independently. When an192ISHTP client from either host or FW side wants to send something, it decides193whether to send over IPC or over DMA; for each transfer the decision is194independent. The sending side sends DMA_XFER message when the message is in195the respective host buffer (TX when host client sends, RX when FW client196sends). The recipient of DMA message responds with DMA_XFER_ACK, indicating197the sender that the memory region for that message may be reused.198 199DMA initialization is started with host sending DMA_ALLOC_NOTIFY bus message200(that includes RX buffer) and FW responds with DMA_ALLOC_NOTIFY_ACK.201Additionally to DMA address communication, this sequence checks capabilities:202if the host doesn't support DMA, then it won't send DMA allocation, so FW can't203send DMA; if FW doesn't support DMA then it won't respond with204DMA_ALLOC_NOTIFY_ACK, in which case host will not use DMA transfers.205Here ISH acts as busmaster DMA controller. Hence when host sends DMA_XFER,206it's request to do host->ISH DMA transfer; when FW sends DMA_XFER, it means207that it already did DMA and the message resides at host. Thus, DMA_XFER208and DMA_XFER_ACK act as ownership indicators.209 210At initial state all outgoing memory belongs to the sender (TX to host, RX to211FW), DMA_XFER transfers ownership on the region that contains ISHTP message to212the receiving side, DMA_XFER_ACK returns ownership to the sender. A sender213need not wait for previous DMA_XFER to be ack'ed, and may send another message214as long as remaining continuous memory in its ownership is enough.215In principle, multiple DMA_XFER and DMA_XFER_ACK messages may be sent at once216(up to IPC MTU), thus allowing for interrupt throttling.217Currently, ISH FW decides to send over DMA if ISHTP message is more than 3 IPC218fragments and via IPC otherwise.219 220Ring Buffers221^^^^^^^^^^^^222 223When a client initiates a connection, a ring of RX and TX buffers is allocated.224The size of ring can be specified by the client. HID client sets 16 and 32 for225TX and RX buffers respectively. On send request from client, the data to be226sent is copied to one of the send ring buffer and scheduled to be sent using227bus message protocol. These buffers are required because the FW may have not228have processed the last message and may not have enough flow control credits229to send. Same thing holds true on receive side and flow control is required.230 231Host Enumeration232^^^^^^^^^^^^^^^^233 234The host enumeration bus command allows discovery of clients present in the FW.235There can be multiple sensor clients and clients for calibration function.236 237To ease implementation and allow independent drivers to handle each client,238this transport layer takes advantage of Linux Bus driver model. Each239client is registered as device on the transport bus (ishtp bus).240 241Enumeration sequence of messages:242 243- Host sends HOST_START_REQ_CMD, indicating that host ISHTP layer is up.244- FW responds with HOST_START_RES_CMD245- Host sends HOST_ENUM_REQ_CMD (enumerate FW clients)246- FW responds with HOST_ENUM_RES_CMD that includes bitmap of available FW247 client IDs248- For each FW ID found in that bitmap host sends249 HOST_CLIENT_PROPERTIES_REQ_CMD250- FW responds with HOST_CLIENT_PROPERTIES_RES_CMD. Properties include UUID,251 max ISHTP message size, etc.252- Once host received properties for that last discovered client, it considers253 ISHTP device fully functional (and allocates DMA buffers)254 255HID over ISH Client256-------------------257 258Location: drivers/hid/intel-ish-hid259 260The ISHTP client driver is responsible for:261 262- enumerate HID devices under FW ISH client263- Get Report descriptor264- Register with HID core as a LL driver265- Process Get/Set feature request266- Get input reports267 268HID Sensor Hub MFD and IIO sensor drivers269-----------------------------------------270 271The functionality in these drivers is the same as an external sensor hub.272Refer to273Documentation/hid/hid-sensor.rst for HID sensor274Documentation/ABI/testing/sysfs-bus-iio for IIO ABIs to user space.275 276End to End HID transport Sequence Diagram277-----------------------------------------278 279::280 281 HID-ISH-CLN ISHTP IPC HW282 | | | |283 | | |-----WAKE UP------------------>|284 | | | |285 | | |-----HOST READY--------------->|286 | | | |287 | | |<----MNG_RESET_NOTIFY_ACK----- |288 | | | |289 | |<----ISHTP_START------ | |290 | | | |291 | |<-----------------HOST_START_RES_CMD-------------------|292 | | | |293 | |------------------QUERY_SUBSCRIBER-------------------->|294 | | | |295 | |------------------HOST_ENUM_REQ_CMD------------------->|296 | | | |297 | |<-----------------HOST_ENUM_RES_CMD--------------------|298 | | | |299 | |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|300 | | | |301 | |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|302 | Create new device on in ishtp bus | |303 | | | |304 | |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|305 | | | |306 | |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|307 | Create new device on in ishtp bus | |308 | | | |309 | |--Repeat HOST_CLIENT_PROPERTIES_REQ_CMD-till last one--|310 | | | |311 probed()312 |----ishtp_cl_connect--->|----------------- CLIENT_CONNECT_REQ_CMD-------------->|313 | | | |314 | |<----------------CLIENT_CONNECT_RES_CMD----------------|315 | | | |316 |register event callback | | |317 | | | |318 |ishtp_cl_send(319 HOSTIF_DM_ENUM_DEVICES) |----------fill ishtp_msg_hdr struct write to HW----- >|320 | | | |321 | | |<-----IRQ(IPC_PROTOCOL_ISHTP---|322 | | | |323 |<--ENUM_DEVICE RSP------| | |324 | | | |325 for each enumerated device326 |ishtp_cl_send(327 HOSTIF_GET_HID_DESCRIPTOR|----------fill ishtp_msg_hdr struct write to HW----- >|328 | | | |329 ...Response330 | | | |331 for each enumerated device332 |ishtp_cl_send(333 HOSTIF_GET_REPORT_DESCRIPTOR|--------------fill ishtp_msg_hdr struct write to HW-- >|334 | | | |335 | | | |336 hid_allocate_device337 | | | |338 hid_add_device | | |339 | | | |340 341 342ISH Firmware Loading from Host Flow343-----------------------------------344 345Starting from the Lunar Lake generation, the ISH firmware has been divided into two components for better space optimization and increased flexibility. These components include a bootloader that is integrated into the BIOS, and a main firmware that is stored within the operating system's file system.346 347The process works as follows:348 349- Initially, the ISHTP driver sends a command, HOST_START_REQ_CMD, to the ISH bootloader. In response, the bootloader sends back a HOST_START_RES_CMD. This response includes the ISHTP_SUPPORT_CAP_LOADER bit. Subsequently, the ISHTP driver checks if this bit is set. If it is, the firmware loading process from the host begins.350 351- During this process, the ISHTP driver first invokes the request_firmware() function, followed by sending a LOADER_CMD_XFER_QUERY command. Upon receiving a response from the bootloader, the ISHTP driver sends a LOADER_CMD_XFER_FRAGMENT command. After receiving another response, the ISHTP driver sends a LOADER_CMD_START command. The bootloader responds and then proceeds to the Main Firmware.352 353- After the process concludes, the ISHTP driver calls the release_firmware() function.354 355For more detailed information, please refer to the flow descriptions provided below:356 357::358 359 +---------------+ +-----------------+360 | ISHTP Driver | | ISH Bootloader |361 +---------------+ +-----------------+362 | |363 |~~~Send HOST_START_REQ_CMD~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|364 | |365 |<--Send HOST_START_RES_CMD(Includes ISHTP_SUPPORT_CAP_LOADER bit)----|366 | |367 ****************************************************************************************368 * if ISHTP_SUPPORT_CAP_LOADER bit is set *369 ****************************************************************************************370 | |371 |~~~start loading firmware from host process~~~+ |372 | | |373 |<---------------------------------------------+ |374 | |375 --------------------------- |376 | Call request_firmware() | |377 --------------------------- |378 | |379 |~~~Send LOADER_CMD_XFER_QUERY~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|380 | |381 |<--Send response-----------------------------------------------------|382 | |383 |~~~Send LOADER_CMD_XFER_FRAGMENT~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|384 | |385 |<--Send response-----------------------------------------------------|386 | |387 |~~~Send LOADER_CMD_START~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|388 | |389 |<--Send response-----------------------------------------------------|390 | |391 | |~~~Jump to Main Firmware~~~+392 | | |393 | |<--------------------------+394 | |395 --------------------------- |396 | Call release_firmware() | |397 --------------------------- |398 | |399 ****************************************************************************************400 * end if *401 ****************************************************************************************402 | |403 +---------------+ +-----------------+404 | ISHTP Driver | | ISH Bootloader |405 +---------------+ +-----------------+406 407Vendor Custom Firmware Loading408^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^409 410The firmware running inside ISH can be provided by Intel or developed by vendors using the Firmware Development Kit (FDK) provided by Intel.411Intel will upstream the Intel-built firmware to the ``linux-firmware.git`` repository, located under the path ``intel/ish/``. For the Lunar Lake platform, the Intel-built ISH firmware will be named ``ish_lnlm.bin``.412Vendors who wish to upstream their custom firmware should follow these guidelines for naming their firmware files:413 414- The firmware filename should use one of the following patterns:415 416 - ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin``417 - ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin``418 - ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.bin``419 - ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.bin``420 421- ``${intel_plat_gen}`` indicates the Intel platform generation (e.g., ``lnlm`` for Lunar Lake) and must not exceed 8 characters in length.422- ``${SYS_VENDOR_CRC32}`` is the CRC32 checksum of the ``sys_vendor`` value from the DMI field ``DMI_SYS_VENDOR``.423- ``${PRODUCT_NAME_CRC32}`` is the CRC32 checksum of the ``product_name`` value from the DMI field ``DMI_PRODUCT_NAME``.424- ``${PRODUCT_SKU_CRC32}`` is the CRC32 checksum of the ``product_sku`` value from the DMI field ``DMI_PRODUCT_SKU``.425 426During system boot, the ISH Linux driver will attempt to load the firmware in the following order, prioritizing custom firmware with more precise matching patterns:427 4281. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin``4292. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin``4303. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.bin``4314. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.bin``4325. ``intel/ish/ish_${intel_plat_gen}.bin``433 434The driver will load the first matching firmware and skip the rest. If no matching firmware is found, it will proceed to the next pattern in the specified order. If all searches fail, the default Intel firmware, listed last in the order above, will be loaded.435 436ISH Debugging437-------------438 439To debug ISH, event tracing mechanism is used. To enable debug logs::440 441 echo 1 > /sys/kernel/tracing/events/intel_ish/enable442 cat /sys/kernel/tracing/trace443 444ISH IIO sysfs Example on Lenovo thinkpad Yoga 260445-------------------------------------------------446 447::448 449 root@otcpl-ThinkPad-Yoga-260:~# tree -l /sys/bus/iio/devices/450 /sys/bus/iio/devices/451 ├── iio:device0 -> ../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0452 │ ├── buffer453 │ │ ├── enable454 │ │ ├── length455 │ │ └── watermark456 ...457 │ ├── in_accel_hysteresis458 │ ├── in_accel_offset459 │ ├── in_accel_sampling_frequency460 │ ├── in_accel_scale461 │ ├── in_accel_x_raw462 │ ├── in_accel_y_raw463 │ ├── in_accel_z_raw464 │ ├── name465 │ ├── scan_elements466 │ │ ├── in_accel_x_en467 │ │ ├── in_accel_x_index468 │ │ ├── in_accel_x_type469 │ │ ├── in_accel_y_en470 │ │ ├── in_accel_y_index471 │ │ ├── in_accel_y_type472 │ │ ├── in_accel_z_en473 │ │ ├── in_accel_z_index474 │ │ └── in_accel_z_type475 ...476 │ │ ├── devices477 │ │ │ │ ├── buffer478 │ │ │ │ │ ├── enable479 │ │ │ │ │ ├── length480 │ │ │ │ │ └── watermark481 │ │ │ │ ├── dev482 │ │ │ │ ├── in_intensity_both_raw483 │ │ │ │ ├── in_intensity_hysteresis484 │ │ │ │ ├── in_intensity_offset485 │ │ │ │ ├── in_intensity_sampling_frequency486 │ │ │ │ ├── in_intensity_scale487 │ │ │ │ ├── name488 │ │ │ │ ├── scan_elements489 │ │ │ │ │ ├── in_intensity_both_en490 │ │ │ │ │ ├── in_intensity_both_index491 │ │ │ │ │ └── in_intensity_both_type492 │ │ │ │ ├── trigger493 │ │ │ │ │ └── current_trigger494 ...495 │ │ │ │ ├── buffer496 │ │ │ │ │ ├── enable497 │ │ │ │ │ ├── length498 │ │ │ │ │ └── watermark499 │ │ │ │ ├── dev500 │ │ │ │ ├── in_magn_hysteresis501 │ │ │ │ ├── in_magn_offset502 │ │ │ │ ├── in_magn_sampling_frequency503 │ │ │ │ ├── in_magn_scale504 │ │ │ │ ├── in_magn_x_raw505 │ │ │ │ ├── in_magn_y_raw506 │ │ │ │ ├── in_magn_z_raw507 │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_raw508 │ │ │ │ ├── in_rot_hysteresis509 │ │ │ │ ├── in_rot_offset510 │ │ │ │ ├── in_rot_sampling_frequency511 │ │ │ │ ├── in_rot_scale512 │ │ │ │ ├── name513 ...514 │ │ │ │ ├── scan_elements515 │ │ │ │ │ ├── in_magn_x_en516 │ │ │ │ │ ├── in_magn_x_index517 │ │ │ │ │ ├── in_magn_x_type518 │ │ │ │ │ ├── in_magn_y_en519 │ │ │ │ │ ├── in_magn_y_index520 │ │ │ │ │ ├── in_magn_y_type521 │ │ │ │ │ ├── in_magn_z_en522 │ │ │ │ │ ├── in_magn_z_index523 │ │ │ │ │ ├── in_magn_z_type524 │ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_en525 │ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_index526 │ │ │ │ │ └── in_rot_from_north_magnetic_tilt_comp_type527 │ │ │ │ ├── trigger528 │ │ │ │ │ └── current_trigger529 ...530 │ │ │ │ ├── buffer531 │ │ │ │ │ ├── enable532 │ │ │ │ │ ├── length533 │ │ │ │ │ └── watermark534 │ │ │ │ ├── dev535 │ │ │ │ ├── in_anglvel_hysteresis536 │ │ │ │ ├── in_anglvel_offset537 │ │ │ │ ├── in_anglvel_sampling_frequency538 │ │ │ │ ├── in_anglvel_scale539 │ │ │ │ ├── in_anglvel_x_raw540 │ │ │ │ ├── in_anglvel_y_raw541 │ │ │ │ ├── in_anglvel_z_raw542 │ │ │ │ ├── name543 │ │ │ │ ├── scan_elements544 │ │ │ │ │ ├── in_anglvel_x_en545 │ │ │ │ │ ├── in_anglvel_x_index546 │ │ │ │ │ ├── in_anglvel_x_type547 │ │ │ │ │ ├── in_anglvel_y_en548 │ │ │ │ │ ├── in_anglvel_y_index549 │ │ │ │ │ ├── in_anglvel_y_type550 │ │ │ │ │ ├── in_anglvel_z_en551 │ │ │ │ │ ├── in_anglvel_z_index552 │ │ │ │ │ └── in_anglvel_z_type553 │ │ │ │ ├── trigger554 │ │ │ │ │ └── current_trigger555 ...556 │ │ │ │ ├── buffer557 │ │ │ │ │ ├── enable558 │ │ │ │ │ ├── length559 │ │ │ │ │ └── watermark560 │ │ │ │ ├── dev561 │ │ │ │ ├── in_anglvel_hysteresis562 │ │ │ │ ├── in_anglvel_offset563 │ │ │ │ ├── in_anglvel_sampling_frequency564 │ │ │ │ ├── in_anglvel_scale565 │ │ │ │ ├── in_anglvel_x_raw566 │ │ │ │ ├── in_anglvel_y_raw567 │ │ │ │ ├── in_anglvel_z_raw568 │ │ │ │ ├── name569 │ │ │ │ ├── scan_elements570 │ │ │ │ │ ├── in_anglvel_x_en571 │ │ │ │ │ ├── in_anglvel_x_index572 │ │ │ │ │ ├── in_anglvel_x_type573 │ │ │ │ │ ├── in_anglvel_y_en574 │ │ │ │ │ ├── in_anglvel_y_index575 │ │ │ │ │ ├── in_anglvel_y_type576 │ │ │ │ │ ├── in_anglvel_z_en577 │ │ │ │ │ ├── in_anglvel_z_index578 │ │ │ │ │ └── in_anglvel_z_type579 │ │ │ │ ├── trigger580 │ │ │ │ │ └── current_trigger581 ...582