aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/surface/aggregator/ssh_msgb.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/surface/aggregator/ssh_msgb.h')
-rw-r--r--drivers/platform/surface/aggregator/ssh_msgb.h205
1 files changed, 205 insertions, 0 deletions
diff --git a/drivers/platform/surface/aggregator/ssh_msgb.h b/drivers/platform/surface/aggregator/ssh_msgb.h
new file mode 100644
index 000000000000..1221f642dda1
--- /dev/null
+++ b/drivers/platform/surface/aggregator/ssh_msgb.h
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * SSH message builder functions.
+ *
+ * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
+ */
+
+#ifndef _SURFACE_AGGREGATOR_SSH_MSGB_H
+#define _SURFACE_AGGREGATOR_SSH_MSGB_H
+
+#include <asm/unaligned.h>
+#include <linux/types.h>
+
+#include <linux/surface_aggregator/controller.h>
+#include <linux/surface_aggregator/serial_hub.h>
+
+/**
+ * struct msgbuf - Buffer struct to construct SSH messages.
+ * @begin: Pointer to the beginning of the allocated buffer space.
+ * @end: Pointer to the end (one past last element) of the allocated buffer
+ * space.
+ * @ptr: Pointer to the first free element in the buffer.
+ */
+struct msgbuf {
+ u8 *begin;
+ u8 *end;
+ u8 *ptr;
+};
+
+/**
+ * msgb_init() - Initialize the given message buffer struct.
+ * @msgb: The buffer struct to initialize
+ * @ptr: Pointer to the underlying memory by which the buffer will be backed.
+ * @cap: Size of the underlying memory.
+ *
+ * Initialize the given message buffer struct using the provided memory as
+ * backing.
+ */
+static inline void msgb_init(struct msgbuf *msgb, u8 *ptr, size_t cap)
+{
+ msgb->begin = ptr;
+ msgb->end = ptr + cap;
+ msgb->ptr = ptr;
+}
+
+/**
+ * msgb_bytes_used() - Return the current number of bytes used in the buffer.
+ * @msgb: The message buffer.
+ */
+static inline size_t msgb_bytes_used(const struct msgbuf *msgb)
+{
+ return msgb->ptr - msgb->begin;
+}
+
+static inline void __msgb_push_u8(struct msgbuf *msgb, u8 value)
+{
+ *msgb->ptr = value;
+ msgb->ptr += sizeof(u8);
+}
+
+static inline void __msgb_push_u16(struct msgbuf *msgb, u16 value)
+{
+ put_unaligned_le16(value, msgb->ptr);
+ msgb->ptr += sizeof(u16);
+}
+
+/**
+ * msgb_push_u16() - Push a u16 value to the buffer.
+ * @msgb: The message buffer.
+ * @value: The value to push to the buffer.
+ */
+static inline void msgb_push_u16(struct msgbuf *msgb, u16 value)
+{
+ if (WARN_ON(msgb->ptr + sizeof(u16) > msgb->end))
+ return;
+
+ __msgb_push_u16(msgb, value);
+}
+
+/**
+ * msgb_push_syn() - Push SSH SYN bytes to the buffer.
+ * @msgb: The message buffer.
+ */
+static inline void msgb_push_syn(struct msgbuf *msgb)
+{
+ msgb_push_u16(msgb, SSH_MSG_SYN);
+}
+
+/**
+ * msgb_push_buf() - Push raw data to the buffer.
+ * @msgb: The message buffer.
+ * @buf: The data to push to the buffer.
+ * @len: The length of the data to push to the buffer.
+ */
+static inline void msgb_push_buf(struct msgbuf *msgb, const u8 *buf, size_t len)
+{
+ msgb->ptr = memcpy(msgb->ptr, buf, len) + len;
+}
+
+/**
+ * msgb_push_crc() - Compute CRC and push it to the buffer.
+ * @msgb: The message buffer.
+ * @buf: The data for which the CRC should be computed.
+ * @len: The length of the data for which the CRC should be computed.
+ */
+static inline void msgb_push_crc(struct msgbuf *msgb, const u8 *buf, size_t len)
+{
+ msgb_push_u16(msgb, ssh_crc(buf, len));
+}
+
+/**
+ * msgb_push_frame() - Push a SSH message frame header to the buffer.
+ * @msgb: The message buffer
+ * @ty: The type of the frame.
+ * @len: The length of the payload of the frame.
+ * @seq: The sequence ID of the frame/packet.
+ */
+static inline void msgb_push_frame(struct msgbuf *msgb, u8 ty, u16 len, u8 seq)
+{
+ u8 *const begin = msgb->ptr;
+
+ if (WARN_ON(msgb->ptr + sizeof(struct ssh_frame) > msgb->end))
+ return;
+
+ __msgb_push_u8(msgb, ty); /* Frame type. */
+ __msgb_push_u16(msgb, len); /* Frame payload length. */
+ __msgb_push_u8(msgb, seq); /* Frame sequence ID. */
+
+ msgb_push_crc(msgb, begin, msgb->ptr - begin);
+}
+
+/**
+ * msgb_push_ack() - Push a SSH ACK frame to the buffer.
+ * @msgb: The message buffer
+ * @seq: The sequence ID of the frame/packet to be ACKed.
+ */
+static inline void msgb_push_ack(struct msgbuf *msgb, u8 seq)
+{
+ /* SYN. */
+ msgb_push_syn(msgb);
+
+ /* ACK-type frame + CRC. */
+ msgb_push_frame(msgb, SSH_FRAME_TYPE_ACK, 0x00, seq);
+
+ /* Payload CRC (ACK-type frames do not have a payload). */
+ msgb_push_crc(msgb, msgb->ptr, 0);
+}
+
+/**
+ * msgb_push_nak() - Push a SSH NAK frame to the buffer.
+ * @msgb: The message buffer
+ */
+static inline void msgb_push_nak(struct msgbuf *msgb)
+{
+ /* SYN. */
+ msgb_push_syn(msgb);
+
+ /* NAK-type frame + CRC. */
+ msgb_push_frame(msgb, SSH_FRAME_TYPE_NAK, 0x00, 0x00);
+
+ /* Payload CRC (ACK-type frames do not have a payload). */
+ msgb_push_crc(msgb, msgb->ptr, 0);
+}
+
+/**
+ * msgb_push_cmd() - Push a SSH command frame with payload to the buffer.
+ * @msgb: The message buffer.
+ * @seq: The sequence ID (SEQ) of the frame/packet.
+ * @rqid: The request ID (RQID) of the request contained in the frame.
+ * @rqst: The request to wrap in the frame.
+ */
+static inline void msgb_push_cmd(struct msgbuf *msgb, u8 seq, u16 rqid,
+ const struct ssam_request *rqst)
+{
+ const u8 type = SSH_FRAME_TYPE_DATA_SEQ;
+ u8 *cmd;
+
+ /* SYN. */
+ msgb_push_syn(msgb);
+
+ /* Command frame + CRC. */
+ msgb_push_frame(msgb, type, sizeof(struct ssh_command) + rqst->length, seq);
+
+ /* Frame payload: Command struct + payload. */
+ if (WARN_ON(msgb->ptr + sizeof(struct ssh_command) > msgb->end))
+ return;
+
+ cmd = msgb->ptr;
+
+ __msgb_push_u8(msgb, SSH_PLD_TYPE_CMD); /* Payload type. */
+ __msgb_push_u8(msgb, rqst->target_category); /* Target category. */
+ __msgb_push_u8(msgb, rqst->target_id); /* Target ID (out). */
+ __msgb_push_u8(msgb, 0x00); /* Target ID (in). */
+ __msgb_push_u8(msgb, rqst->instance_id); /* Instance ID. */
+ __msgb_push_u16(msgb, rqid); /* Request ID. */
+ __msgb_push_u8(msgb, rqst->command_id); /* Command ID. */
+
+ /* Command payload. */
+ msgb_push_buf(msgb, rqst->payload, rqst->length);
+
+ /* CRC for command struct + payload. */
+ msgb_push_crc(msgb, cmd, msgb->ptr - cmd);
+}
+
+#endif /* _SURFACE_AGGREGATOR_SSH_MSGB_H */