1*8d779282SMaximilian Luz.. SPDX-License-Identifier: GPL-2.0+ 2*8d779282SMaximilian Luz 3*8d779282SMaximilian Luz.. |u8| replace:: :c:type:`u8 <u8>` 4*8d779282SMaximilian Luz.. |u16| replace:: :c:type:`u16 <u16>` 5*8d779282SMaximilian Luz.. |TYPE| replace:: ``TYPE`` 6*8d779282SMaximilian Luz.. |LEN| replace:: ``LEN`` 7*8d779282SMaximilian Luz.. |SEQ| replace:: ``SEQ`` 8*8d779282SMaximilian Luz.. |SYN| replace:: ``SYN`` 9*8d779282SMaximilian Luz.. |NAK| replace:: ``NAK`` 10*8d779282SMaximilian Luz.. |ACK| replace:: ``ACK`` 11*8d779282SMaximilian Luz.. |DATA| replace:: ``DATA`` 12*8d779282SMaximilian Luz.. |DATA_SEQ| replace:: ``DATA_SEQ`` 13*8d779282SMaximilian Luz.. |DATA_NSQ| replace:: ``DATA_NSQ`` 14*8d779282SMaximilian Luz.. |TC| replace:: ``TC`` 15*8d779282SMaximilian Luz.. |TID| replace:: ``TID`` 16*8d779282SMaximilian Luz.. |IID| replace:: ``IID`` 17*8d779282SMaximilian Luz.. |RQID| replace:: ``RQID`` 18*8d779282SMaximilian Luz.. |CID| replace:: ``CID`` 19*8d779282SMaximilian Luz 20*8d779282SMaximilian Luz=========================== 21*8d779282SMaximilian LuzSurface Serial Hub Protocol 22*8d779282SMaximilian Luz=========================== 23*8d779282SMaximilian Luz 24*8d779282SMaximilian LuzThe Surface Serial Hub (SSH) is the central communication interface for the 25*8d779282SMaximilian Luzembedded Surface Aggregator Module controller (SAM or EC), found on newer 26*8d779282SMaximilian LuzSurface generations. We will refer to this protocol and interface as 27*8d779282SMaximilian LuzSAM-over-SSH, as opposed to SAM-over-HID for the older generations. 28*8d779282SMaximilian Luz 29*8d779282SMaximilian LuzOn Surface devices with SAM-over-SSH, SAM is connected to the host via UART 30*8d779282SMaximilian Luzand defined in ACPI as device with ID ``MSHW0084``. On these devices, 31*8d779282SMaximilian Luzsignificant functionality is provided via SAM, including access to battery 32*8d779282SMaximilian Luzand power information and events, thermal read-outs and events, and many 33*8d779282SMaximilian Luzmore. For Surface Laptops, keyboard input is handled via HID directed 34*8d779282SMaximilian Luzthrough SAM, on the Surface Laptop 3 and Surface Book 3 this also includes 35*8d779282SMaximilian Luztouchpad input. 36*8d779282SMaximilian Luz 37*8d779282SMaximilian LuzNote that the standard disclaimer for this subsystem also applies to this 38*8d779282SMaximilian Luzdocument: All of this has been reverse-engineered and may thus be erroneous 39*8d779282SMaximilian Luzand/or incomplete. 40*8d779282SMaximilian Luz 41*8d779282SMaximilian LuzAll CRCs used in the following are two-byte ``crc_ccitt_false(0xffff, ...)``. 42*8d779282SMaximilian LuzAll multi-byte values are little-endian, there is no implicit padding between 43*8d779282SMaximilian Luzvalues. 44*8d779282SMaximilian Luz 45*8d779282SMaximilian Luz 46*8d779282SMaximilian LuzSSH Packet Protocol: Definitions 47*8d779282SMaximilian Luz================================ 48*8d779282SMaximilian Luz 49*8d779282SMaximilian LuzThe fundamental communication unit of the SSH protocol is a frame 50*8d779282SMaximilian Luz(:c:type:`struct ssh_frame <ssh_frame>`). A frame consists of the following 51*8d779282SMaximilian Luzfields, packed together and in order: 52*8d779282SMaximilian Luz 53*8d779282SMaximilian Luz.. flat-table:: SSH Frame 54*8d779282SMaximilian Luz :widths: 1 1 4 55*8d779282SMaximilian Luz :header-rows: 1 56*8d779282SMaximilian Luz 57*8d779282SMaximilian Luz * - Field 58*8d779282SMaximilian Luz - Type 59*8d779282SMaximilian Luz - Description 60*8d779282SMaximilian Luz 61*8d779282SMaximilian Luz * - |TYPE| 62*8d779282SMaximilian Luz - |u8| 63*8d779282SMaximilian Luz - Type identifier of the frame. 64*8d779282SMaximilian Luz 65*8d779282SMaximilian Luz * - |LEN| 66*8d779282SMaximilian Luz - |u16| 67*8d779282SMaximilian Luz - Length of the payload associated with the frame. 68*8d779282SMaximilian Luz 69*8d779282SMaximilian Luz * - |SEQ| 70*8d779282SMaximilian Luz - |u8| 71*8d779282SMaximilian Luz - Sequence ID (see explanation below). 72*8d779282SMaximilian Luz 73*8d779282SMaximilian LuzEach frame structure is followed by a CRC over this structure. The CRC over 74*8d779282SMaximilian Luzthe frame structure (|TYPE|, |LEN|, and |SEQ| fields) is placed directly 75*8d779282SMaximilian Luzafter the frame structure and before the payload. The payload is followed by 76*8d779282SMaximilian Luzits own CRC (over all payload bytes). If the payload is not present (i.e. 77*8d779282SMaximilian Luzthe frame has ``LEN=0``), the CRC of the payload is still present and will 78*8d779282SMaximilian Luzevaluate to ``0xffff``. The |LEN| field does not include any of the CRCs, it 79*8d779282SMaximilian Luzequals the number of bytes inbetween the CRC of the frame and the CRC of the 80*8d779282SMaximilian Luzpayload. 81*8d779282SMaximilian Luz 82*8d779282SMaximilian LuzAdditionally, the following fixed two-byte sequences are used: 83*8d779282SMaximilian Luz 84*8d779282SMaximilian Luz.. flat-table:: SSH Byte Sequences 85*8d779282SMaximilian Luz :widths: 1 1 4 86*8d779282SMaximilian Luz :header-rows: 1 87*8d779282SMaximilian Luz 88*8d779282SMaximilian Luz * - Name 89*8d779282SMaximilian Luz - Value 90*8d779282SMaximilian Luz - Description 91*8d779282SMaximilian Luz 92*8d779282SMaximilian Luz * - |SYN| 93*8d779282SMaximilian Luz - ``[0xAA, 0x55]`` 94*8d779282SMaximilian Luz - Synchronization bytes. 95*8d779282SMaximilian Luz 96*8d779282SMaximilian LuzA message consists of |SYN|, followed by the frame (|TYPE|, |LEN|, |SEQ| and 97*8d779282SMaximilian LuzCRC) and, if specified in the frame (i.e. ``LEN > 0``), payload bytes, 98*8d779282SMaximilian Luzfollowed finally, regardless if the payload is present, the payload CRC. The 99*8d779282SMaximilian Luzmessages corresponding to an exchange are, in part, identified by having the 100*8d779282SMaximilian Luzsame sequence ID (|SEQ|), stored inside the frame (more on this in the next 101*8d779282SMaximilian Luzsection). The sequence ID is a wrapping counter. 102*8d779282SMaximilian Luz 103*8d779282SMaximilian LuzA frame can have the following types 104*8d779282SMaximilian Luz(:c:type:`enum ssh_frame_type <ssh_frame_type>`): 105*8d779282SMaximilian Luz 106*8d779282SMaximilian Luz.. flat-table:: SSH Frame Types 107*8d779282SMaximilian Luz :widths: 1 1 4 108*8d779282SMaximilian Luz :header-rows: 1 109*8d779282SMaximilian Luz 110*8d779282SMaximilian Luz * - Name 111*8d779282SMaximilian Luz - Value 112*8d779282SMaximilian Luz - Short Description 113*8d779282SMaximilian Luz 114*8d779282SMaximilian Luz * - |NAK| 115*8d779282SMaximilian Luz - ``0x04`` 116*8d779282SMaximilian Luz - Sent on error in previously received message. 117*8d779282SMaximilian Luz 118*8d779282SMaximilian Luz * - |ACK| 119*8d779282SMaximilian Luz - ``0x40`` 120*8d779282SMaximilian Luz - Sent to acknowledge receival of |DATA| frame. 121*8d779282SMaximilian Luz 122*8d779282SMaximilian Luz * - |DATA_SEQ| 123*8d779282SMaximilian Luz - ``0x80`` 124*8d779282SMaximilian Luz - Sent to transfer data. Sequenced. 125*8d779282SMaximilian Luz 126*8d779282SMaximilian Luz * - |DATA_NSQ| 127*8d779282SMaximilian Luz - ``0x00`` 128*8d779282SMaximilian Luz - Same as |DATA_SEQ|, but does not need to be ACKed. 129*8d779282SMaximilian Luz 130*8d779282SMaximilian LuzBoth |NAK|- and |ACK|-type frames are used to control flow of messages and 131*8d779282SMaximilian Luzthus do not carry a payload. |DATA_SEQ|- and |DATA_NSQ|-type frames on the 132*8d779282SMaximilian Luzother hand must carry a payload. The flow sequence and interaction of 133*8d779282SMaximilian Luzdifferent frame types will be described in more depth in the next section. 134*8d779282SMaximilian Luz 135*8d779282SMaximilian Luz 136*8d779282SMaximilian LuzSSH Packet Protocol: Flow Sequence 137*8d779282SMaximilian Luz================================== 138*8d779282SMaximilian Luz 139*8d779282SMaximilian LuzEach exchange begins with |SYN|, followed by a |DATA_SEQ|- or 140*8d779282SMaximilian Luz|DATA_NSQ|-type frame, followed by its CRC, payload, and payload CRC. In 141*8d779282SMaximilian Luzcase of a |DATA_NSQ|-type frame, the exchange is then finished. In case of a 142*8d779282SMaximilian Luz|DATA_SEQ|-type frame, the receiving party has to acknowledge receival of 143*8d779282SMaximilian Luzthe frame by responding with a message containing an |ACK|-type frame with 144*8d779282SMaximilian Luzthe same sequence ID of the |DATA| frame. In other words, the sequence ID of 145*8d779282SMaximilian Luzthe |ACK| frame specifies the |DATA| frame to be acknowledged. In case of an 146*8d779282SMaximilian Luzerror, e.g. an invalid CRC, the receiving party responds with a message 147*8d779282SMaximilian Luzcontaining an |NAK|-type frame. As the sequence ID of the previous data 148*8d779282SMaximilian Luzframe, for which an error is indicated via the |NAK| frame, cannot be relied 149*8d779282SMaximilian Luzupon, the sequence ID of the |NAK| frame should not be used and is set to 150*8d779282SMaximilian Luzzero. After receival of an |NAK| frame, the sending party should re-send all 151*8d779282SMaximilian Luzoutstanding (non-ACKed) messages. 152*8d779282SMaximilian Luz 153*8d779282SMaximilian LuzSequence IDs are not synchronized between the two parties, meaning that they 154*8d779282SMaximilian Luzare managed independently for each party. Identifying the messages 155*8d779282SMaximilian Luzcorresponding to a single exchange thus relies on the sequence ID as well as 156*8d779282SMaximilian Luzthe type of the message, and the context. Specifically, the sequence ID is 157*8d779282SMaximilian Luzused to associate an ``ACK`` with its ``DATA_SEQ``-type frame, but not 158*8d779282SMaximilian Luz``DATA_SEQ``- or ``DATA_NSQ``-type frames with other ``DATA``- type frames. 159*8d779282SMaximilian Luz 160*8d779282SMaximilian LuzAn example exchange might look like this: 161*8d779282SMaximilian Luz 162*8d779282SMaximilian Luz:: 163*8d779282SMaximilian Luz 164*8d779282SMaximilian Luz tx: -- SYN FRAME(D) CRC(F) PAYLOAD CRC(P) ----------------------------- 165*8d779282SMaximilian Luz rx: ------------------------------------- SYN FRAME(A) CRC(F) CRC(P) -- 166*8d779282SMaximilian Luz 167*8d779282SMaximilian Luzwhere both frames have the same sequence ID (``SEQ``). Here, ``FRAME(D)`` 168*8d779282SMaximilian Luzindicates a |DATA_SEQ|-type frame, ``FRAME(A)`` an ``ACK``-type frame, 169*8d779282SMaximilian Luz``CRC(F)`` the CRC over the previous frame, ``CRC(P)`` the CRC over the 170*8d779282SMaximilian Luzprevious payload. In case of an error, the exchange would look like this: 171*8d779282SMaximilian Luz 172*8d779282SMaximilian Luz:: 173*8d779282SMaximilian Luz 174*8d779282SMaximilian Luz tx: -- SYN FRAME(D) CRC(F) PAYLOAD CRC(P) ----------------------------- 175*8d779282SMaximilian Luz rx: ------------------------------------- SYN FRAME(N) CRC(F) CRC(P) -- 176*8d779282SMaximilian Luz 177*8d779282SMaximilian Luzupon which the sender should re-send the message. ``FRAME(N)`` indicates an 178*8d779282SMaximilian Luz|NAK|-type frame. Note that the sequence ID of the |NAK|-type frame is fixed 179*8d779282SMaximilian Luzto zero. For |DATA_NSQ|-type frames, both exchanges are the same: 180*8d779282SMaximilian Luz 181*8d779282SMaximilian Luz:: 182*8d779282SMaximilian Luz 183*8d779282SMaximilian Luz tx: -- SYN FRAME(DATA_NSQ) CRC(F) PAYLOAD CRC(P) ---------------------- 184*8d779282SMaximilian Luz rx: ------------------------------------------------------------------- 185*8d779282SMaximilian Luz 186*8d779282SMaximilian LuzHere, an error can be detected, but not corrected or indicated to the 187*8d779282SMaximilian Luzsending party. These exchanges are symmetric, i.e. switching ``rx`` and 188*8d779282SMaximilian Luz``tx`` results again in a valid exchange. Currently, no longer exchanges are 189*8d779282SMaximilian Luzknown. 190*8d779282SMaximilian Luz 191*8d779282SMaximilian Luz 192*8d779282SMaximilian LuzCommands: Requests, Responses, and Events 193*8d779282SMaximilian Luz========================================= 194*8d779282SMaximilian Luz 195*8d779282SMaximilian LuzCommands are sent as payload inside a data frame. Currently, this is the 196*8d779282SMaximilian Luzonly known payload type of |DATA| frames, with a payload-type value of 197*8d779282SMaximilian Luz``0x80`` (:c:type:`SSH_PLD_TYPE_CMD <ssh_payload_type>`). 198*8d779282SMaximilian Luz 199*8d779282SMaximilian LuzThe command-type payload (:c:type:`struct ssh_command <ssh_command>`) 200*8d779282SMaximilian Luzconsists of an eight-byte command structure, followed by optional and 201*8d779282SMaximilian Luzvariable length command data. The length of this optional data is derived 202*8d779282SMaximilian Luzfrom the frame payload length given in the corresponding frame, i.e. it is 203*8d779282SMaximilian Luz``frame.len - sizeof(struct ssh_command)``. The command struct contains the 204*8d779282SMaximilian Luzfollowing fields, packed together and in order: 205*8d779282SMaximilian Luz 206*8d779282SMaximilian Luz.. flat-table:: SSH Command 207*8d779282SMaximilian Luz :widths: 1 1 4 208*8d779282SMaximilian Luz :header-rows: 1 209*8d779282SMaximilian Luz 210*8d779282SMaximilian Luz * - Field 211*8d779282SMaximilian Luz - Type 212*8d779282SMaximilian Luz - Description 213*8d779282SMaximilian Luz 214*8d779282SMaximilian Luz * - |TYPE| 215*8d779282SMaximilian Luz - |u8| 216*8d779282SMaximilian Luz - Type of the payload. For commands always ``0x80``. 217*8d779282SMaximilian Luz 218*8d779282SMaximilian Luz * - |TC| 219*8d779282SMaximilian Luz - |u8| 220*8d779282SMaximilian Luz - Target category. 221*8d779282SMaximilian Luz 222*8d779282SMaximilian Luz * - |TID| (out) 223*8d779282SMaximilian Luz - |u8| 224*8d779282SMaximilian Luz - Target ID for outgoing (host to EC) commands. 225*8d779282SMaximilian Luz 226*8d779282SMaximilian Luz * - |TID| (in) 227*8d779282SMaximilian Luz - |u8| 228*8d779282SMaximilian Luz - Target ID for incoming (EC to host) commands. 229*8d779282SMaximilian Luz 230*8d779282SMaximilian Luz * - |IID| 231*8d779282SMaximilian Luz - |u8| 232*8d779282SMaximilian Luz - Instance ID. 233*8d779282SMaximilian Luz 234*8d779282SMaximilian Luz * - |RQID| 235*8d779282SMaximilian Luz - |u16| 236*8d779282SMaximilian Luz - Request ID. 237*8d779282SMaximilian Luz 238*8d779282SMaximilian Luz * - |CID| 239*8d779282SMaximilian Luz - |u8| 240*8d779282SMaximilian Luz - Command ID. 241*8d779282SMaximilian Luz 242*8d779282SMaximilian LuzThe command struct and data, in general, does not contain any failure 243*8d779282SMaximilian Luzdetection mechanism (e.g. CRCs), this is solely done on the frame level. 244*8d779282SMaximilian Luz 245*8d779282SMaximilian LuzCommand-type payloads are used by the host to send commands and requests to 246*8d779282SMaximilian Luzthe EC as well as by the EC to send responses and events back to the host. 247*8d779282SMaximilian LuzWe differentiate between requests (sent by the host), responses (sent by the 248*8d779282SMaximilian LuzEC in response to a request), and events (sent by the EC without a preceding 249*8d779282SMaximilian Luzrequest). 250*8d779282SMaximilian Luz 251*8d779282SMaximilian LuzCommands and events are uniquely identified by their target category 252*8d779282SMaximilian Luz(``TC``) and command ID (``CID``). The target category specifies a general 253*8d779282SMaximilian Luzcategory for the command (e.g. system in general, vs. battery and AC, vs. 254*8d779282SMaximilian Luztemperature, and so on), while the command ID specifies the command inside 255*8d779282SMaximilian Luzthat category. Only the combination of |TC| + |CID| is unique. Additionally, 256*8d779282SMaximilian Luzcommands have an instance ID (``IID``), which is used to differentiate 257*8d779282SMaximilian Luzbetween different sub-devices. For example ``TC=3`` ``CID=1`` is a 258*8d779282SMaximilian Luzrequest to get the temperature on a thermal sensor, where |IID| specifies 259*8d779282SMaximilian Luzthe respective sensor. If the instance ID is not used, it should be set to 260*8d779282SMaximilian Luzzero. If instance IDs are used, they, in general, start with a value of one, 261*8d779282SMaximilian Luzwhereas zero may be used for instance independent queries, if applicable. A 262*8d779282SMaximilian Luzresponse to a request should have the same target category, command ID, and 263*8d779282SMaximilian Luzinstance ID as the corresponding request. 264*8d779282SMaximilian Luz 265*8d779282SMaximilian LuzResponses are matched to their corresponding request via the request ID 266*8d779282SMaximilian Luz(``RQID``) field. This is a 16 bit wrapping counter similar to the sequence 267*8d779282SMaximilian LuzID on the frames. Note that the sequence ID of the frames for a 268*8d779282SMaximilian Luzrequest-response pair does not match. Only the request ID has to match. 269*8d779282SMaximilian LuzFrame-protocol wise these are two separate exchanges, and may even be 270*8d779282SMaximilian Luzseparated, e.g. by an event being sent after the request but before the 271*8d779282SMaximilian Luzresponse. Not all commands produce a response, and this is not detectable by 272*8d779282SMaximilian Luz|TC| + |CID|. It is the responsibility of the issuing party to wait for a 273*8d779282SMaximilian Luzresponse (or signal this to the communication framework, as is done in 274*8d779282SMaximilian LuzSAN/ACPI via the ``SNC`` flag). 275*8d779282SMaximilian Luz 276*8d779282SMaximilian LuzEvents are identified by unique and reserved request IDs. These IDs should 277*8d779282SMaximilian Luznot be used by the host when sending a new request. They are used on the 278*8d779282SMaximilian Luzhost to, first, detect events and, second, match them with a registered 279*8d779282SMaximilian Luzevent handler. Request IDs for events are chosen by the host and directed to 280*8d779282SMaximilian Luzthe EC when setting up and enabling an event source (via the 281*8d779282SMaximilian Luzenable-event-source request). The EC then uses the specified request ID for 282*8d779282SMaximilian Luzevents sent from the respective source. Note that an event should still be 283*8d779282SMaximilian Luzidentified by its target category, command ID, and, if applicable, instance 284*8d779282SMaximilian LuzID, as a single event source can send multiple different event types. In 285*8d779282SMaximilian Luzgeneral, however, a single target category should map to a single reserved 286*8d779282SMaximilian Luzevent request ID. 287*8d779282SMaximilian Luz 288*8d779282SMaximilian LuzFurthermore, requests, responses, and events have an associated target ID 289*8d779282SMaximilian Luz(``TID``). This target ID is split into output (host to EC) and input (EC to 290*8d779282SMaximilian Luzhost) fields, with the respecting other field (e.g. output field on incoming 291*8d779282SMaximilian Luzmessages) set to zero. Two ``TID`` values are known: Primary (``0x01``) and 292*8d779282SMaximilian Luzsecondary (``0x02``). In general, the response to a request should have the 293*8d779282SMaximilian Luzsame ``TID`` value, however, the field (output vs. input) should be used in 294*8d779282SMaximilian Luzaccordance to the direction in which the response is sent (i.e. on the input 295*8d779282SMaximilian Luzfield, as responses are generally sent from the EC to the host). 296*8d779282SMaximilian Luz 297*8d779282SMaximilian LuzNote that, even though requests and events should be uniquely identifiable 298*8d779282SMaximilian Luzby target category and command ID alone, the EC may require specific 299*8d779282SMaximilian Luztarget ID and instance ID values to accept a command. A command that is 300*8d779282SMaximilian Luzaccepted for ``TID=1``, for example, may not be accepted for ``TID=2`` 301*8d779282SMaximilian Luzand vice versa. 302*8d779282SMaximilian Luz 303*8d779282SMaximilian Luz 304*8d779282SMaximilian LuzLimitations and Observations 305*8d779282SMaximilian Luz============================ 306*8d779282SMaximilian Luz 307*8d779282SMaximilian LuzThe protocol can, in theory, handle up to ``U8_MAX`` frames in parallel, 308*8d779282SMaximilian Luzwith up to ``U16_MAX`` pending requests (neglecting request IDs reserved for 309*8d779282SMaximilian Luzevents). In practice, however, this is more limited. From our testing 310*8d779282SMaximilian Luz(although via a python and thus a user-space program), it seems that the EC 311*8d779282SMaximilian Luzcan handle up to four requests (mostly) reliably in parallel at a certain 312*8d779282SMaximilian Luztime. With five or more requests in parallel, consistent discarding of 313*8d779282SMaximilian Luzcommands (ACKed frame but no command response) has been observed. For five 314*8d779282SMaximilian Luzsimultaneous commands, this reproducibly resulted in one command being 315*8d779282SMaximilian Luzdropped and four commands being handled. 316*8d779282SMaximilian Luz 317*8d779282SMaximilian LuzHowever, it has also been noted that, even with three requests in parallel, 318*8d779282SMaximilian Luzoccasional frame drops happen. Apart from this, with a limit of three 319*8d779282SMaximilian Luzpending requests, no dropped commands (i.e. command being dropped but frame 320*8d779282SMaximilian Luzcarrying command being ACKed) have been observed. In any case, frames (and 321*8d779282SMaximilian Luzpossibly also commands) should be re-sent by the host if a certain timeout 322*8d779282SMaximilian Luzis exceeded. This is done by the EC for frames with a timeout of one second, 323*8d779282SMaximilian Luzup to two re-tries (i.e. three transmissions in total). The limit of 324*8d779282SMaximilian Luzre-tries also applies to received NAKs, and, in a worst case scenario, can 325*8d779282SMaximilian Luzlead to entire messages being dropped. 326*8d779282SMaximilian Luz 327*8d779282SMaximilian LuzWhile this also seems to work fine for pending data frames as long as no 328*8d779282SMaximilian Luztransmission failures occur, implementation and handling of these seems to 329*8d779282SMaximilian Luzdepend on the assumption that there is only one non-acknowledged data frame. 330*8d779282SMaximilian LuzIn particular, the detection of repeated frames relies on the last sequence 331*8d779282SMaximilian Luznumber. This means that, if a frame that has been successfully received by 332*8d779282SMaximilian Luzthe EC is sent again, e.g. due to the host not receiving an |ACK|, the EC 333*8d779282SMaximilian Luzwill only detect this if it has the sequence ID of the last frame received 334*8d779282SMaximilian Luzby the EC. As an example: Sending two frames with ``SEQ=0`` and ``SEQ=1`` 335*8d779282SMaximilian Luzfollowed by a repetition of ``SEQ=0`` will not detect the second ``SEQ=0`` 336*8d779282SMaximilian Luzframe as such, and thus execute the command in this frame each time it has 337*8d779282SMaximilian Luzbeen received, i.e. twice in this example. Sending ``SEQ=0``, ``SEQ=1`` and 338*8d779282SMaximilian Luzthen repeating ``SEQ=1`` will detect the second ``SEQ=1`` as repetition of 339*8d779282SMaximilian Luzthe first one and ignore it, thus executing the contained command only once. 340*8d779282SMaximilian Luz 341*8d779282SMaximilian LuzIn conclusion, this suggests a limit of at most one pending un-ACKed frame 342*8d779282SMaximilian Luz(per party, effectively leading to synchronous communication regarding 343*8d779282SMaximilian Luzframes) and at most three pending commands. The limit to synchronous frame 344*8d779282SMaximilian Luztransfers seems to be consistent with behavior observed on Windows. 345