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