1 /* SPDX-License-Identifier: GPL-2.0+ */
3 * SSH message builder functions.
5 * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
8 #ifndef _SURFACE_AGGREGATOR_SSH_MSGB_H
9 #define _SURFACE_AGGREGATOR_SSH_MSGB_H
11 #include <linux/unaligned.h>
12 #include <linux/types.h>
14 #include <linux/surface_aggregator/controller.h>
15 #include <linux/surface_aggregator/serial_hub.h>
18 * struct msgbuf - Buffer struct to construct SSH messages.
19 * @begin: Pointer to the beginning of the allocated buffer space.
20 * @end: Pointer to the end (one past last element) of the allocated buffer
22 * @ptr: Pointer to the first free element in the buffer.
31 * msgb_init() - Initialize the given message buffer struct.
32 * @msgb: The buffer struct to initialize
33 * @ptr: Pointer to the underlying memory by which the buffer will be backed.
34 * @cap: Size of the underlying memory.
36 * Initialize the given message buffer struct using the provided memory as
39 static inline void msgb_init(struct msgbuf
*msgb
, u8
*ptr
, size_t cap
)
42 msgb
->end
= ptr
+ cap
;
47 * msgb_bytes_used() - Return the current number of bytes used in the buffer.
48 * @msgb: The message buffer.
50 static inline size_t msgb_bytes_used(const struct msgbuf
*msgb
)
52 return msgb
->ptr
- msgb
->begin
;
55 static inline void __msgb_push_u8(struct msgbuf
*msgb
, u8 value
)
58 msgb
->ptr
+= sizeof(u8
);
61 static inline void __msgb_push_u16(struct msgbuf
*msgb
, u16 value
)
63 put_unaligned_le16(value
, msgb
->ptr
);
64 msgb
->ptr
+= sizeof(u16
);
68 * msgb_push_u16() - Push a u16 value to the buffer.
69 * @msgb: The message buffer.
70 * @value: The value to push to the buffer.
72 static inline void msgb_push_u16(struct msgbuf
*msgb
, u16 value
)
74 if (WARN_ON(msgb
->ptr
+ sizeof(u16
) > msgb
->end
))
77 __msgb_push_u16(msgb
, value
);
81 * msgb_push_syn() - Push SSH SYN bytes to the buffer.
82 * @msgb: The message buffer.
84 static inline void msgb_push_syn(struct msgbuf
*msgb
)
86 msgb_push_u16(msgb
, SSH_MSG_SYN
);
90 * msgb_push_buf() - Push raw data to the buffer.
91 * @msgb: The message buffer.
92 * @buf: The data to push to the buffer.
93 * @len: The length of the data to push to the buffer.
95 static inline void msgb_push_buf(struct msgbuf
*msgb
, const u8
*buf
, size_t len
)
97 msgb
->ptr
= memcpy(msgb
->ptr
, buf
, len
) + len
;
101 * msgb_push_crc() - Compute CRC and push it to the buffer.
102 * @msgb: The message buffer.
103 * @buf: The data for which the CRC should be computed.
104 * @len: The length of the data for which the CRC should be computed.
106 static inline void msgb_push_crc(struct msgbuf
*msgb
, const u8
*buf
, size_t len
)
108 msgb_push_u16(msgb
, ssh_crc(buf
, len
));
112 * msgb_push_frame() - Push a SSH message frame header to the buffer.
113 * @msgb: The message buffer
114 * @ty: The type of the frame.
115 * @len: The length of the payload of the frame.
116 * @seq: The sequence ID of the frame/packet.
118 static inline void msgb_push_frame(struct msgbuf
*msgb
, u8 ty
, u16 len
, u8 seq
)
120 u8
*const begin
= msgb
->ptr
;
122 if (WARN_ON(msgb
->ptr
+ sizeof(struct ssh_frame
) > msgb
->end
))
125 __msgb_push_u8(msgb
, ty
); /* Frame type. */
126 __msgb_push_u16(msgb
, len
); /* Frame payload length. */
127 __msgb_push_u8(msgb
, seq
); /* Frame sequence ID. */
129 msgb_push_crc(msgb
, begin
, msgb
->ptr
- begin
);
133 * msgb_push_ack() - Push a SSH ACK frame to the buffer.
134 * @msgb: The message buffer
135 * @seq: The sequence ID of the frame/packet to be ACKed.
137 static inline void msgb_push_ack(struct msgbuf
*msgb
, u8 seq
)
142 /* ACK-type frame + CRC. */
143 msgb_push_frame(msgb
, SSH_FRAME_TYPE_ACK
, 0x00, seq
);
145 /* Payload CRC (ACK-type frames do not have a payload). */
146 msgb_push_crc(msgb
, msgb
->ptr
, 0);
150 * msgb_push_nak() - Push a SSH NAK frame to the buffer.
151 * @msgb: The message buffer
153 static inline void msgb_push_nak(struct msgbuf
*msgb
)
158 /* NAK-type frame + CRC. */
159 msgb_push_frame(msgb
, SSH_FRAME_TYPE_NAK
, 0x00, 0x00);
161 /* Payload CRC (ACK-type frames do not have a payload). */
162 msgb_push_crc(msgb
, msgb
->ptr
, 0);
166 * msgb_push_cmd() - Push a SSH command frame with payload to the buffer.
167 * @msgb: The message buffer.
168 * @seq: The sequence ID (SEQ) of the frame/packet.
169 * @rqid: The request ID (RQID) of the request contained in the frame.
170 * @rqst: The request to wrap in the frame.
172 static inline void msgb_push_cmd(struct msgbuf
*msgb
, u8 seq
, u16 rqid
,
173 const struct ssam_request
*rqst
)
175 const u8 type
= SSH_FRAME_TYPE_DATA_SEQ
;
181 /* Command frame + CRC. */
182 msgb_push_frame(msgb
, type
, sizeof(struct ssh_command
) + rqst
->length
, seq
);
184 /* Frame payload: Command struct + payload. */
185 if (WARN_ON(msgb
->ptr
+ sizeof(struct ssh_command
) > msgb
->end
))
190 __msgb_push_u8(msgb
, SSH_PLD_TYPE_CMD
); /* Payload type. */
191 __msgb_push_u8(msgb
, rqst
->target_category
); /* Target category. */
192 __msgb_push_u8(msgb
, rqst
->target_id
); /* Target ID. */
193 __msgb_push_u8(msgb
, SSAM_SSH_TID_HOST
); /* Source ID. */
194 __msgb_push_u8(msgb
, rqst
->instance_id
); /* Instance ID. */
195 __msgb_push_u16(msgb
, rqid
); /* Request ID. */
196 __msgb_push_u8(msgb
, rqst
->command_id
); /* Command ID. */
198 /* Command payload. */
199 msgb_push_buf(msgb
, rqst
->payload
, rqst
->length
);
201 /* CRC for command struct + payload. */
202 msgb_push_crc(msgb
, cmd
, msgb
->ptr
- cmd
);
205 #endif /* _SURFACE_AGGREGATOR_SSH_MSGB_H */