0001
0002
0003
0004
0005
0006
0007
0008 #ifndef _SURFACE_AGGREGATOR_SSH_MSGB_H
0009 #define _SURFACE_AGGREGATOR_SSH_MSGB_H
0010
0011 #include <asm/unaligned.h>
0012 #include <linux/types.h>
0013
0014 #include <linux/surface_aggregator/controller.h>
0015 #include <linux/surface_aggregator/serial_hub.h>
0016
0017
0018
0019
0020
0021
0022
0023
0024 struct msgbuf {
0025 u8 *begin;
0026 u8 *end;
0027 u8 *ptr;
0028 };
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039 static inline void msgb_init(struct msgbuf *msgb, u8 *ptr, size_t cap)
0040 {
0041 msgb->begin = ptr;
0042 msgb->end = ptr + cap;
0043 msgb->ptr = ptr;
0044 }
0045
0046
0047
0048
0049
0050 static inline size_t msgb_bytes_used(const struct msgbuf *msgb)
0051 {
0052 return msgb->ptr - msgb->begin;
0053 }
0054
0055 static inline void __msgb_push_u8(struct msgbuf *msgb, u8 value)
0056 {
0057 *msgb->ptr = value;
0058 msgb->ptr += sizeof(u8);
0059 }
0060
0061 static inline void __msgb_push_u16(struct msgbuf *msgb, u16 value)
0062 {
0063 put_unaligned_le16(value, msgb->ptr);
0064 msgb->ptr += sizeof(u16);
0065 }
0066
0067
0068
0069
0070
0071
0072 static inline void msgb_push_u16(struct msgbuf *msgb, u16 value)
0073 {
0074 if (WARN_ON(msgb->ptr + sizeof(u16) > msgb->end))
0075 return;
0076
0077 __msgb_push_u16(msgb, value);
0078 }
0079
0080
0081
0082
0083
0084 static inline void msgb_push_syn(struct msgbuf *msgb)
0085 {
0086 msgb_push_u16(msgb, SSH_MSG_SYN);
0087 }
0088
0089
0090
0091
0092
0093
0094
0095 static inline void msgb_push_buf(struct msgbuf *msgb, const u8 *buf, size_t len)
0096 {
0097 msgb->ptr = memcpy(msgb->ptr, buf, len) + len;
0098 }
0099
0100
0101
0102
0103
0104
0105
0106 static inline void msgb_push_crc(struct msgbuf *msgb, const u8 *buf, size_t len)
0107 {
0108 msgb_push_u16(msgb, ssh_crc(buf, len));
0109 }
0110
0111
0112
0113
0114
0115
0116
0117
0118 static inline void msgb_push_frame(struct msgbuf *msgb, u8 ty, u16 len, u8 seq)
0119 {
0120 u8 *const begin = msgb->ptr;
0121
0122 if (WARN_ON(msgb->ptr + sizeof(struct ssh_frame) > msgb->end))
0123 return;
0124
0125 __msgb_push_u8(msgb, ty);
0126 __msgb_push_u16(msgb, len);
0127 __msgb_push_u8(msgb, seq);
0128
0129 msgb_push_crc(msgb, begin, msgb->ptr - begin);
0130 }
0131
0132
0133
0134
0135
0136
0137 static inline void msgb_push_ack(struct msgbuf *msgb, u8 seq)
0138 {
0139
0140 msgb_push_syn(msgb);
0141
0142
0143 msgb_push_frame(msgb, SSH_FRAME_TYPE_ACK, 0x00, seq);
0144
0145
0146 msgb_push_crc(msgb, msgb->ptr, 0);
0147 }
0148
0149
0150
0151
0152
0153 static inline void msgb_push_nak(struct msgbuf *msgb)
0154 {
0155
0156 msgb_push_syn(msgb);
0157
0158
0159 msgb_push_frame(msgb, SSH_FRAME_TYPE_NAK, 0x00, 0x00);
0160
0161
0162 msgb_push_crc(msgb, msgb->ptr, 0);
0163 }
0164
0165
0166
0167
0168
0169
0170
0171
0172 static inline void msgb_push_cmd(struct msgbuf *msgb, u8 seq, u16 rqid,
0173 const struct ssam_request *rqst)
0174 {
0175 const u8 type = SSH_FRAME_TYPE_DATA_SEQ;
0176 u8 *cmd;
0177
0178
0179 msgb_push_syn(msgb);
0180
0181
0182 msgb_push_frame(msgb, type, sizeof(struct ssh_command) + rqst->length, seq);
0183
0184
0185 if (WARN_ON(msgb->ptr + sizeof(struct ssh_command) > msgb->end))
0186 return;
0187
0188 cmd = msgb->ptr;
0189
0190 __msgb_push_u8(msgb, SSH_PLD_TYPE_CMD);
0191 __msgb_push_u8(msgb, rqst->target_category);
0192 __msgb_push_u8(msgb, rqst->target_id);
0193 __msgb_push_u8(msgb, 0x00);
0194 __msgb_push_u8(msgb, rqst->instance_id);
0195 __msgb_push_u16(msgb, rqid);
0196 __msgb_push_u8(msgb, rqst->command_id);
0197
0198
0199 msgb_push_buf(msgb, rqst->payload, rqst->length);
0200
0201
0202 msgb_push_crc(msgb, cmd, msgb->ptr - cmd);
0203 }
0204
0205 #endif