1
2
3
4
5
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
19
20
21
22
23
24struct msgbuf {
25 u8 *begin;
26 u8 *end;
27 u8 *ptr;
28};
29
30
31
32
33
34
35
36
37
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
48
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
69
70
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
82
83
84static inline void msgb_push_syn(struct msgbuf *msgb)
85{
86 msgb_push_u16(msgb, SSH_MSG_SYN);
87}
88
89
90
91
92
93
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
102
103
104
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
113
114
115
116
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);
126 __msgb_push_u16(msgb, len);
127 __msgb_push_u8(msgb, seq);
128
129 msgb_push_crc(msgb, begin, msgb->ptr - begin);
130}
131
132
133
134
135
136
137static inline void msgb_push_ack(struct msgbuf *msgb, u8 seq)
138{
139
140 msgb_push_syn(msgb);
141
142
143 msgb_push_frame(msgb, SSH_FRAME_TYPE_ACK, 0x00, seq);
144
145
146 msgb_push_crc(msgb, msgb->ptr, 0);
147}
148
149
150
151
152
153static inline void msgb_push_nak(struct msgbuf *msgb)
154{
155
156 msgb_push_syn(msgb);
157
158
159 msgb_push_frame(msgb, SSH_FRAME_TYPE_NAK, 0x00, 0x00);
160
161
162 msgb_push_crc(msgb, msgb->ptr, 0);
163}
164
165
166
167
168
169
170
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
179 msgb_push_syn(msgb);
180
181
182 msgb_push_frame(msgb, type, sizeof(struct ssh_command) + rqst->length, seq);
183
184
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);
191 __msgb_push_u8(msgb, rqst->target_category);
192 __msgb_push_u8(msgb, rqst->target_id);
193 __msgb_push_u8(msgb, 0x00);
194 __msgb_push_u8(msgb, rqst->instance_id);
195 __msgb_push_u16(msgb, rqid);
196 __msgb_push_u8(msgb, rqst->command_id);
197
198
199 msgb_push_buf(msgb, rqst->payload, rqst->length);
200
201
202 msgb_push_crc(msgb, cmd, msgb->ptr - cmd);
203}
204
205#endif
206