linux/drivers/platform/surface/aggregator/ssh_msgb.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0+ */
   2/*
   3 * SSH message builder functions.
   4 *
   5 * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
   6 */
   7
   8#ifndef _SURFACE_AGGREGATOR_SSH_MSGB_H
   9#define _SURFACE_AGGREGATOR_SSH_MSGB_H
  10
  11#include <asm/unaligned.h>
  12#include <linux/types.h>
  13
  14#include <linux/surface_aggregator/controller.h>
  15#include <linux/surface_aggregator/serial_hub.h>
  16
  17/**
  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
  21 *         space.
  22 * @ptr:   Pointer to the first free element in the buffer.
  23 */
  24struct msgbuf {
  25        u8 *begin;
  26        u8 *end;
  27        u8 *ptr;
  28};
  29
  30/**
  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.
  35 *
  36 * Initialize the given message buffer struct using the provided memory as
  37 * backing.
  38 */
  39static inline void msgb_init(struct msgbuf *msgb, u8 *ptr, size_t cap)
  40{
  41        msgb->begin = ptr;
  42        msgb->end = ptr + cap;
  43        msgb->ptr = ptr;
  44}
  45
  46/**
  47 * msgb_bytes_used() - Return the current number of bytes used in the buffer.
  48 * @msgb: The message buffer.
  49 */
  50static inline size_t msgb_bytes_used(const struct msgbuf *msgb)
  51{
  52        return msgb->ptr - msgb->begin;
  53}
  54
  55static inline void __msgb_push_u8(struct msgbuf *msgb, u8 value)
  56{
  57        *msgb->ptr = value;
  58        msgb->ptr += sizeof(u8);
  59}
  60
  61static inline void __msgb_push_u16(struct msgbuf *msgb, u16 value)
  62{
  63        put_unaligned_le16(value, msgb->ptr);
  64        msgb->ptr += sizeof(u16);
  65}
  66
  67/**
  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.
  71 */
  72static inline void msgb_push_u16(struct msgbuf *msgb, u16 value)
  73{
  74        if (WARN_ON(msgb->ptr + sizeof(u16) > msgb->end))
  75                return;
  76
  77        __msgb_push_u16(msgb, value);
  78}
  79
  80/**
  81 * msgb_push_syn() - Push SSH SYN bytes to the buffer.
  82 * @msgb: The message buffer.
  83 */
  84static inline void msgb_push_syn(struct msgbuf *msgb)
  85{
  86        msgb_push_u16(msgb, SSH_MSG_SYN);
  87}
  88
  89/**
  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.
  94 */
  95static inline void msgb_push_buf(struct msgbuf *msgb, const u8 *buf, size_t len)
  96{
  97        msgb->ptr = memcpy(msgb->ptr, buf, len) + len;
  98}
  99
 100/**
 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.
 105 */
 106static inline void msgb_push_crc(struct msgbuf *msgb, const u8 *buf, size_t len)
 107{
 108        msgb_push_u16(msgb, ssh_crc(buf, len));
 109}
 110
 111/**
 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.
 117 */
 118static inline void msgb_push_frame(struct msgbuf *msgb, u8 ty, u16 len, u8 seq)
 119{
 120        u8 *const begin = msgb->ptr;
 121
 122        if (WARN_ON(msgb->ptr + sizeof(struct ssh_frame) > msgb->end))
 123                return;
 124
 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. */
 128
 129        msgb_push_crc(msgb, begin, msgb->ptr - begin);
 130}
 131
 132/**
 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.
 136 */
 137static inline void msgb_push_ack(struct msgbuf *msgb, u8 seq)
 138{
 139        /* SYN. */
 140        msgb_push_syn(msgb);
 141
 142        /* ACK-type frame + CRC. */
 143        msgb_push_frame(msgb, SSH_FRAME_TYPE_ACK, 0x00, seq);
 144
 145        /* Payload CRC (ACK-type frames do not have a payload). */
 146        msgb_push_crc(msgb, msgb->ptr, 0);
 147}
 148
 149/**
 150 * msgb_push_nak() - Push a SSH NAK frame to the buffer.
 151 * @msgb: The message buffer
 152 */
 153static inline void msgb_push_nak(struct msgbuf *msgb)
 154{
 155        /* SYN. */
 156        msgb_push_syn(msgb);
 157
 158        /* NAK-type frame + CRC. */
 159        msgb_push_frame(msgb, SSH_FRAME_TYPE_NAK, 0x00, 0x00);
 160
 161        /* Payload CRC (ACK-type frames do not have a payload). */
 162        msgb_push_crc(msgb, msgb->ptr, 0);
 163}
 164
 165/**
 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.
 171 */
 172static inline void msgb_push_cmd(struct msgbuf *msgb, u8 seq, u16 rqid,
 173                                 const struct ssam_request *rqst)
 174{
 175        const u8 type = SSH_FRAME_TYPE_DATA_SEQ;
 176        u8 *cmd;
 177
 178        /* SYN. */
 179        msgb_push_syn(msgb);
 180
 181        /* Command frame + CRC. */
 182        msgb_push_frame(msgb, type, sizeof(struct ssh_command) + rqst->length, seq);
 183
 184        /* Frame payload: Command struct + payload. */
 185        if (WARN_ON(msgb->ptr + sizeof(struct ssh_command) > msgb->end))
 186                return;
 187
 188        cmd = msgb->ptr;
 189
 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 (out). */
 193        __msgb_push_u8(msgb, 0x00);                     /* Target ID (in). */
 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. */
 197
 198        /* Command payload. */
 199        msgb_push_buf(msgb, rqst->payload, rqst->length);
 200
 201        /* CRC for command struct + payload. */
 202        msgb_push_crc(msgb, cmd, msgb->ptr - cmd);
 203}
 204
 205#endif /* _SURFACE_AGGREGATOR_SSH_MSGB_H */
 206