13d36ee2eSJeremy Kerr /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
24cdc200fSJeremy Kerr
34cdc200fSJeremy Kerr #include <assert.h>
489a28781SAndrew Jeffery #include <errno.h>
54cdc200fSJeremy Kerr #include <stdbool.h>
64cdc200fSJeremy Kerr #include <stdlib.h>
74cdc200fSJeremy Kerr #include <string.h>
84cdc200fSJeremy Kerr
9*b3de343eSJohn Chung #include "crc-16-ccitt.h"
10*b3de343eSJohn Chung
11c7e764a2SJeremy Kerr #ifdef HAVE_CONFIG_H
12c7e764a2SJeremy Kerr #include "config.h"
13c7e764a2SJeremy Kerr #endif
14c7e764a2SJeremy Kerr
15c7e764a2SJeremy Kerr #ifdef MCTP_HAVE_FILEIO
164cdc200fSJeremy Kerr #include <fcntl.h>
171111c6a5SAndrew Jeffery #include <poll.h>
181111c6a5SAndrew Jeffery #include <unistd.h>
19597b3697SJeremy Kerr #else
write(int fd,void * buf,size_t len)20597b3697SJeremy Kerr static const size_t write(int fd, void *buf, size_t len)
21597b3697SJeremy Kerr {
22597b3697SJeremy Kerr return -1;
23597b3697SJeremy Kerr }
244cdc200fSJeremy Kerr #endif
254cdc200fSJeremy Kerr
264cdc200fSJeremy Kerr #define pr_fmt(x) "serial: " x
274cdc200fSJeremy Kerr
2889a28781SAndrew Jeffery /*
2989a28781SAndrew Jeffery * @fn: A function that will copy data from the buffer at src into the dst object
3089a28781SAndrew Jeffery * @dst: An opaque object to pass as state to fn
3189a28781SAndrew Jeffery * @src: A pointer to the buffer of data to copy to dst
3289a28781SAndrew Jeffery * @len: The length of the data pointed to by src
3389a28781SAndrew Jeffery * @return: 0 on succes, negative error code on failure
3489a28781SAndrew Jeffery *
3589a28781SAndrew Jeffery * Pre-condition: fn returns a write count or a negative error code
3689a28781SAndrew Jeffery * Post-condition: All bytes written or an error has occurred
3789a28781SAndrew Jeffery */
38ad772b97SAndrew Jeffery #define mctp_write_all(fn, dst, src, len) \
39ad772b97SAndrew Jeffery ({ \
4089a28781SAndrew Jeffery typeof(src) __src = src; \
41ad772b97SAndrew Jeffery ssize_t wrote; \
42ad772b97SAndrew Jeffery while (len) { \
4389a28781SAndrew Jeffery wrote = fn(dst, __src, len); \
44ad772b97SAndrew Jeffery if (wrote < 0) \
45ad772b97SAndrew Jeffery break; \
4689a28781SAndrew Jeffery __src += wrote; \
47ad772b97SAndrew Jeffery len -= wrote; \
48ad772b97SAndrew Jeffery } \
4989a28781SAndrew Jeffery len ? wrote : 0; \
50ad772b97SAndrew Jeffery })
51ad772b97SAndrew Jeffery
mctp_serial_write(int fildes,const void * buf,size_t nbyte)5289a28781SAndrew Jeffery static ssize_t mctp_serial_write(int fildes, const void *buf, size_t nbyte)
5389a28781SAndrew Jeffery {
5489a28781SAndrew Jeffery ssize_t wrote;
5589a28781SAndrew Jeffery
5689a28781SAndrew Jeffery return ((wrote = write(fildes, buf, nbyte)) < 0) ? -errno : wrote;
5789a28781SAndrew Jeffery }
5889a28781SAndrew Jeffery
594cdc200fSJeremy Kerr #include "libmctp.h"
604cdc200fSJeremy Kerr #include "libmctp-alloc.h"
614cdc200fSJeremy Kerr #include "libmctp-log.h"
624cdc200fSJeremy Kerr #include "libmctp-serial.h"
63ff25d7ebSPrzemyslaw Czarnowski #include "container_of.h"
644cdc200fSJeremy Kerr
654cdc200fSJeremy Kerr struct mctp_binding_serial {
664cdc200fSJeremy Kerr struct mctp_binding binding;
674cdc200fSJeremy Kerr int fd;
684cdc200fSJeremy Kerr unsigned long bus_id;
694cdc200fSJeremy Kerr
70597b3697SJeremy Kerr mctp_serial_tx_fn tx_fn;
71597b3697SJeremy Kerr void *tx_fn_data;
72597b3697SJeremy Kerr
734cdc200fSJeremy Kerr /* receive buffer and state */
744cdc200fSJeremy Kerr uint8_t rxbuf[1024];
754cdc200fSJeremy Kerr struct mctp_pktbuf *rx_pkt;
764cdc200fSJeremy Kerr uint8_t rx_exp_len;
774cdc200fSJeremy Kerr uint16_t rx_fcs;
78*b3de343eSJohn Chung uint16_t rx_fcs_calc;
794cdc200fSJeremy Kerr enum {
804cdc200fSJeremy Kerr STATE_WAIT_SYNC_START,
814cdc200fSJeremy Kerr STATE_WAIT_REVISION,
824cdc200fSJeremy Kerr STATE_WAIT_LEN,
834cdc200fSJeremy Kerr STATE_DATA,
844cdc200fSJeremy Kerr STATE_DATA_ESCAPED,
854cdc200fSJeremy Kerr STATE_WAIT_FCS1,
864cdc200fSJeremy Kerr STATE_WAIT_FCS2,
874cdc200fSJeremy Kerr STATE_WAIT_SYNC_END,
884cdc200fSJeremy Kerr } rx_state;
89c67605bcSJeremy Kerr
90c67605bcSJeremy Kerr /* temporary transmit buffer */
91c67605bcSJeremy Kerr uint8_t txbuf[256];
924cdc200fSJeremy Kerr };
934cdc200fSJeremy Kerr
944cdc200fSJeremy Kerr #define binding_to_serial(b) \
954cdc200fSJeremy Kerr container_of(b, struct mctp_binding_serial, binding)
964cdc200fSJeremy Kerr
974cdc200fSJeremy Kerr #define MCTP_SERIAL_REVISION 0x01
984cdc200fSJeremy Kerr #define MCTP_SERIAL_FRAMING_FLAG 0x7e
994cdc200fSJeremy Kerr #define MCTP_SERIAL_ESCAPE 0x7d
1004cdc200fSJeremy Kerr
1014cdc200fSJeremy Kerr struct mctp_serial_header {
1024cdc200fSJeremy Kerr uint8_t flag;
1034cdc200fSJeremy Kerr uint8_t revision;
1044cdc200fSJeremy Kerr uint8_t len;
1054cdc200fSJeremy Kerr };
1064cdc200fSJeremy Kerr
1074cdc200fSJeremy Kerr struct mctp_serial_trailer {
1084cdc200fSJeremy Kerr uint8_t fcs_msb;
1094cdc200fSJeremy Kerr uint8_t fcs_lsb;
1104cdc200fSJeremy Kerr uint8_t flag;
1114cdc200fSJeremy Kerr };
1124cdc200fSJeremy Kerr
mctp_serial_pkt_escape(struct mctp_pktbuf * pkt,uint8_t * buf)113c67605bcSJeremy Kerr static size_t mctp_serial_pkt_escape(struct mctp_pktbuf *pkt, uint8_t *buf)
1144cdc200fSJeremy Kerr {
1154cdc200fSJeremy Kerr uint8_t total_len;
116c67605bcSJeremy Kerr uint8_t *p;
1174cdc200fSJeremy Kerr int i, j;
1184cdc200fSJeremy Kerr
1194cdc200fSJeremy Kerr total_len = pkt->end - pkt->mctp_hdr_off;
1204cdc200fSJeremy Kerr
1214cdc200fSJeremy Kerr p = (void *)mctp_pktbuf_hdr(pkt);
1224cdc200fSJeremy Kerr
1234cdc200fSJeremy Kerr for (i = 0, j = 0; i < total_len; i++, j++) {
124c67605bcSJeremy Kerr uint8_t c = p[i];
1254cdc200fSJeremy Kerr if (c == 0x7e || c == 0x7d) {
126c67605bcSJeremy Kerr if (buf)
127c67605bcSJeremy Kerr buf[j] = 0x7d;
1284cdc200fSJeremy Kerr j++;
1294cdc200fSJeremy Kerr c ^= 0x20;
1304cdc200fSJeremy Kerr }
131c67605bcSJeremy Kerr if (buf)
132c67605bcSJeremy Kerr buf[j] = c;
1334cdc200fSJeremy Kerr }
134c67605bcSJeremy Kerr
135c67605bcSJeremy Kerr return j;
1364cdc200fSJeremy Kerr }
1374cdc200fSJeremy Kerr
mctp_binding_serial_tx(struct mctp_binding * b,struct mctp_pktbuf * pkt)1384cdc200fSJeremy Kerr static int mctp_binding_serial_tx(struct mctp_binding *b,
1394cdc200fSJeremy Kerr struct mctp_pktbuf *pkt)
1404cdc200fSJeremy Kerr {
1414cdc200fSJeremy Kerr struct mctp_binding_serial *serial = binding_to_serial(b);
1424cdc200fSJeremy Kerr struct mctp_serial_header *hdr;
1434cdc200fSJeremy Kerr struct mctp_serial_trailer *tlr;
144c67605bcSJeremy Kerr uint8_t *buf;
145c67605bcSJeremy Kerr size_t len;
146*b3de343eSJohn Chung uint16_t fcs;
1474cdc200fSJeremy Kerr
1484cdc200fSJeremy Kerr /* the length field in the header excludes serial framing
1494cdc200fSJeremy Kerr * and escape sequences */
1504cdc200fSJeremy Kerr len = mctp_pktbuf_size(pkt);
1514cdc200fSJeremy Kerr
152c67605bcSJeremy Kerr hdr = (void *)serial->txbuf;
1534cdc200fSJeremy Kerr hdr->flag = MCTP_SERIAL_FRAMING_FLAG;
1544cdc200fSJeremy Kerr hdr->revision = MCTP_SERIAL_REVISION;
1554cdc200fSJeremy Kerr hdr->len = len;
1564cdc200fSJeremy Kerr
157*b3de343eSJohn Chung // Calculate fcs
158*b3de343eSJohn Chung fcs = crc_16_ccitt(FCS_INIT_16, (const uint8_t *)hdr + 1, 2);
159*b3de343eSJohn Chung fcs = crc_16_ccitt(fcs, (const uint8_t *)mctp_pktbuf_hdr(pkt), len);
160*b3de343eSJohn Chung
161c67605bcSJeremy Kerr buf = (void *)(hdr + 1);
1624cdc200fSJeremy Kerr
163c67605bcSJeremy Kerr len = mctp_serial_pkt_escape(pkt, NULL);
164c67605bcSJeremy Kerr if (len + sizeof(*hdr) + sizeof(*tlr) > sizeof(serial->txbuf))
1650721f585SAndrew Jeffery return -EMSGSIZE;
166c67605bcSJeremy Kerr
167c67605bcSJeremy Kerr mctp_serial_pkt_escape(pkt, buf);
168c67605bcSJeremy Kerr
169c67605bcSJeremy Kerr buf += len;
170c67605bcSJeremy Kerr
171c67605bcSJeremy Kerr tlr = (void *)buf;
1724cdc200fSJeremy Kerr tlr->flag = MCTP_SERIAL_FRAMING_FLAG;
173*b3de343eSJohn Chung tlr->fcs_msb = fcs >> 8;
174*b3de343eSJohn Chung tlr->fcs_lsb = fcs & 0xff;
1754cdc200fSJeremy Kerr
176597b3697SJeremy Kerr len += sizeof(*hdr) + sizeof(*tlr);
177597b3697SJeremy Kerr
178ad772b97SAndrew Jeffery if (!serial->tx_fn)
17989a28781SAndrew Jeffery return mctp_write_all(mctp_serial_write, serial->fd,
18089a28781SAndrew Jeffery &serial->txbuf[0], len);
1814cdc200fSJeremy Kerr
182a721c2d8SPatrick Williams return mctp_write_all(serial->tx_fn, serial->tx_fn_data,
183a721c2d8SPatrick Williams &serial->txbuf[0], len);
1844cdc200fSJeremy Kerr }
1854cdc200fSJeremy Kerr
mctp_serial_finish_packet(struct mctp_binding_serial * serial,bool valid)1864cdc200fSJeremy Kerr static void mctp_serial_finish_packet(struct mctp_binding_serial *serial,
1874cdc200fSJeremy Kerr bool valid)
1884cdc200fSJeremy Kerr {
1894cdc200fSJeremy Kerr struct mctp_pktbuf *pkt = serial->rx_pkt;
1904cdc200fSJeremy Kerr assert(pkt);
1914cdc200fSJeremy Kerr
1924cdc200fSJeremy Kerr if (valid)
1930a00dca2SJeremy Kerr mctp_bus_rx(&serial->binding, pkt);
1944cdc200fSJeremy Kerr
1954cdc200fSJeremy Kerr serial->rx_pkt = NULL;
1964cdc200fSJeremy Kerr }
1974cdc200fSJeremy Kerr
mctp_serial_start_packet(struct mctp_binding_serial * serial,uint8_t len)1984cdc200fSJeremy Kerr static void mctp_serial_start_packet(struct mctp_binding_serial *serial,
1994cdc200fSJeremy Kerr uint8_t len)
2004cdc200fSJeremy Kerr {
201df15f7e9SJeremy Kerr serial->rx_pkt = mctp_pktbuf_alloc(&serial->binding, len);
2024cdc200fSJeremy Kerr }
2034cdc200fSJeremy Kerr
mctp_rx_consume_one(struct mctp_binding_serial * serial,uint8_t c)204a721c2d8SPatrick Williams static void mctp_rx_consume_one(struct mctp_binding_serial *serial, uint8_t c)
2054cdc200fSJeremy Kerr {
2064cdc200fSJeremy Kerr struct mctp_pktbuf *pkt = serial->rx_pkt;
207*b3de343eSJohn Chung bool valid = false;
2084cdc200fSJeremy Kerr
2094cdc200fSJeremy Kerr mctp_prdebug("state: %d, char 0x%02x", serial->rx_state, c);
2104cdc200fSJeremy Kerr
2114cdc200fSJeremy Kerr assert(!pkt == (serial->rx_state == STATE_WAIT_SYNC_START ||
2124cdc200fSJeremy Kerr serial->rx_state == STATE_WAIT_REVISION ||
2134cdc200fSJeremy Kerr serial->rx_state == STATE_WAIT_LEN));
2144cdc200fSJeremy Kerr
2154cdc200fSJeremy Kerr switch (serial->rx_state) {
2164cdc200fSJeremy Kerr case STATE_WAIT_SYNC_START:
2174cdc200fSJeremy Kerr if (c != MCTP_SERIAL_FRAMING_FLAG) {
2184cdc200fSJeremy Kerr mctp_prdebug("lost sync, dropping packet");
2194cdc200fSJeremy Kerr if (pkt)
2204cdc200fSJeremy Kerr mctp_serial_finish_packet(serial, false);
2214cdc200fSJeremy Kerr } else {
2224cdc200fSJeremy Kerr serial->rx_state = STATE_WAIT_REVISION;
2234cdc200fSJeremy Kerr }
2244cdc200fSJeremy Kerr break;
2254cdc200fSJeremy Kerr
2264cdc200fSJeremy Kerr case STATE_WAIT_REVISION:
2274cdc200fSJeremy Kerr if (c == MCTP_SERIAL_REVISION) {
2284cdc200fSJeremy Kerr serial->rx_state = STATE_WAIT_LEN;
229*b3de343eSJohn Chung serial->rx_fcs_calc = crc_16_ccitt_byte(FCS_INIT_16, c);
2301fe5899eSNikhil Namjoshi } else if (c == MCTP_SERIAL_FRAMING_FLAG) {
2311fe5899eSNikhil Namjoshi /* Handle the case where there are bytes dropped in request,
2321fe5899eSNikhil Namjoshi * and the state machine is out of sync. The failed request's
2331fe5899eSNikhil Namjoshi * trailing footer i.e. 0x7e would be interpreted as next
2341fe5899eSNikhil Namjoshi * request's framing footer. So if we are in STATE_WAIT_REVISION
2351fe5899eSNikhil Namjoshi * and receive 0x7e byte, then contine to stay in
2361fe5899eSNikhil Namjoshi * STATE_WAIT_REVISION
2371fe5899eSNikhil Namjoshi */
2381fe5899eSNikhil Namjoshi mctp_prdebug(
2391fe5899eSNikhil Namjoshi "Received serial framing flag 0x%02x while waiting"
2401fe5899eSNikhil Namjoshi " for serial revision 0x%02x.",
2411fe5899eSNikhil Namjoshi c, MCTP_SERIAL_REVISION);
2424cdc200fSJeremy Kerr } else {
2434cdc200fSJeremy Kerr mctp_prdebug("invalid revision 0x%02x", c);
2444cdc200fSJeremy Kerr serial->rx_state = STATE_WAIT_SYNC_START;
2454cdc200fSJeremy Kerr }
2464cdc200fSJeremy Kerr break;
2474cdc200fSJeremy Kerr case STATE_WAIT_LEN:
248df15f7e9SJeremy Kerr if (c > serial->binding.pkt_size ||
249df15f7e9SJeremy Kerr c < sizeof(struct mctp_hdr)) {
2504cdc200fSJeremy Kerr mctp_prdebug("invalid size %d", c);
2514cdc200fSJeremy Kerr serial->rx_state = STATE_WAIT_SYNC_START;
2524cdc200fSJeremy Kerr } else {
2534cdc200fSJeremy Kerr mctp_serial_start_packet(serial, 0);
2544cdc200fSJeremy Kerr pkt = serial->rx_pkt;
2554cdc200fSJeremy Kerr serial->rx_exp_len = c;
2564cdc200fSJeremy Kerr serial->rx_state = STATE_DATA;
257*b3de343eSJohn Chung serial->rx_fcs_calc =
258*b3de343eSJohn Chung crc_16_ccitt_byte(serial->rx_fcs_calc, c);
2594cdc200fSJeremy Kerr }
2604cdc200fSJeremy Kerr break;
2614cdc200fSJeremy Kerr
2624cdc200fSJeremy Kerr case STATE_DATA:
2634cdc200fSJeremy Kerr if (c == MCTP_SERIAL_ESCAPE) {
2644cdc200fSJeremy Kerr serial->rx_state = STATE_DATA_ESCAPED;
2654cdc200fSJeremy Kerr } else {
2664cdc200fSJeremy Kerr mctp_pktbuf_push(pkt, &c, 1);
267*b3de343eSJohn Chung serial->rx_fcs_calc =
268*b3de343eSJohn Chung crc_16_ccitt_byte(serial->rx_fcs_calc, c);
2694cdc200fSJeremy Kerr if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len)
2704cdc200fSJeremy Kerr serial->rx_state = STATE_WAIT_FCS1;
2714cdc200fSJeremy Kerr }
2724cdc200fSJeremy Kerr break;
2734cdc200fSJeremy Kerr
2744cdc200fSJeremy Kerr case STATE_DATA_ESCAPED:
2754cdc200fSJeremy Kerr c ^= 0x20;
2764cdc200fSJeremy Kerr mctp_pktbuf_push(pkt, &c, 1);
277*b3de343eSJohn Chung serial->rx_fcs_calc = crc_16_ccitt_byte(serial->rx_fcs_calc, c);
2784cdc200fSJeremy Kerr if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len)
2794cdc200fSJeremy Kerr serial->rx_state = STATE_WAIT_FCS1;
2804cdc200fSJeremy Kerr else
2814cdc200fSJeremy Kerr serial->rx_state = STATE_DATA;
2824cdc200fSJeremy Kerr break;
2834cdc200fSJeremy Kerr
2844cdc200fSJeremy Kerr case STATE_WAIT_FCS1:
2854cdc200fSJeremy Kerr serial->rx_fcs = c << 8;
2864cdc200fSJeremy Kerr serial->rx_state = STATE_WAIT_FCS2;
2874cdc200fSJeremy Kerr break;
2884cdc200fSJeremy Kerr case STATE_WAIT_FCS2:
2894cdc200fSJeremy Kerr serial->rx_fcs |= c;
2904cdc200fSJeremy Kerr serial->rx_state = STATE_WAIT_SYNC_END;
2914cdc200fSJeremy Kerr break;
2924cdc200fSJeremy Kerr
2934cdc200fSJeremy Kerr case STATE_WAIT_SYNC_END:
294*b3de343eSJohn Chung if (serial->rx_fcs == serial->rx_fcs_calc) {
2954cdc200fSJeremy Kerr if (c == MCTP_SERIAL_FRAMING_FLAG) {
296*b3de343eSJohn Chung valid = true;
2974cdc200fSJeremy Kerr } else {
298*b3de343eSJohn Chung valid = false;
2994cdc200fSJeremy Kerr mctp_prdebug("missing end frame marker");
3004cdc200fSJeremy Kerr }
301*b3de343eSJohn Chung } else {
302*b3de343eSJohn Chung valid = false;
303*b3de343eSJohn Chung mctp_prdebug("invalid fcs : 0x%04x, expect 0x%04x",
304*b3de343eSJohn Chung serial->rx_fcs, serial->rx_fcs_calc);
305*b3de343eSJohn Chung }
306*b3de343eSJohn Chung
307*b3de343eSJohn Chung mctp_serial_finish_packet(serial, valid);
3084cdc200fSJeremy Kerr serial->rx_state = STATE_WAIT_SYNC_START;
3094cdc200fSJeremy Kerr break;
3104cdc200fSJeremy Kerr }
3114cdc200fSJeremy Kerr
3124cdc200fSJeremy Kerr mctp_prdebug(" -> state: %d", serial->rx_state);
3134cdc200fSJeremy Kerr }
mctp_rx_consume(struct mctp_binding_serial * serial,const void * buf,size_t len)314a721c2d8SPatrick Williams static void mctp_rx_consume(struct mctp_binding_serial *serial, const void *buf,
315a721c2d8SPatrick Williams size_t len)
3164cdc200fSJeremy Kerr {
3174cdc200fSJeremy Kerr size_t i;
3184cdc200fSJeremy Kerr
3194cdc200fSJeremy Kerr for (i = 0; i < len; i++)
3204cdc200fSJeremy Kerr mctp_rx_consume_one(serial, *(uint8_t *)(buf + i));
3214cdc200fSJeremy Kerr }
3224cdc200fSJeremy Kerr
323c7e764a2SJeremy Kerr #ifdef MCTP_HAVE_FILEIO
mctp_serial_read(struct mctp_binding_serial * serial)3244cdc200fSJeremy Kerr int mctp_serial_read(struct mctp_binding_serial *serial)
3254cdc200fSJeremy Kerr {
3264cdc200fSJeremy Kerr ssize_t len;
3274cdc200fSJeremy Kerr
3284cdc200fSJeremy Kerr len = read(serial->fd, serial->rxbuf, sizeof(serial->rxbuf));
3294cdc200fSJeremy Kerr if (len == 0)
3304cdc200fSJeremy Kerr return -1;
3314cdc200fSJeremy Kerr
3324cdc200fSJeremy Kerr if (len < 0) {
3334cdc200fSJeremy Kerr mctp_prerr("can't read from serial device: %m");
3344cdc200fSJeremy Kerr return -1;
3354cdc200fSJeremy Kerr }
3364cdc200fSJeremy Kerr
3374cdc200fSJeremy Kerr mctp_rx_consume(serial, serial->rxbuf, len);
3384cdc200fSJeremy Kerr
3394cdc200fSJeremy Kerr return 0;
3404cdc200fSJeremy Kerr }
3414cdc200fSJeremy Kerr
mctp_serial_init_pollfd(struct mctp_binding_serial * serial,struct pollfd * pollfd)3421111c6a5SAndrew Jeffery int mctp_serial_init_pollfd(struct mctp_binding_serial *serial,
3431111c6a5SAndrew Jeffery struct pollfd *pollfd)
3441111c6a5SAndrew Jeffery {
3451111c6a5SAndrew Jeffery pollfd->fd = serial->fd;
3461111c6a5SAndrew Jeffery pollfd->events = POLLIN;
3471111c6a5SAndrew Jeffery
3481111c6a5SAndrew Jeffery return 0;
3491111c6a5SAndrew Jeffery }
3501111c6a5SAndrew Jeffery
mctp_serial_open_path(struct mctp_binding_serial * serial,const char * device)3514cdc200fSJeremy Kerr int mctp_serial_open_path(struct mctp_binding_serial *serial,
3524cdc200fSJeremy Kerr const char *device)
3534cdc200fSJeremy Kerr {
3544cdc200fSJeremy Kerr serial->fd = open(device, O_RDWR);
3554cdc200fSJeremy Kerr if (serial->fd < 0)
3564cdc200fSJeremy Kerr mctp_prerr("can't open device %s: %m", device);
3574cdc200fSJeremy Kerr
3584cdc200fSJeremy Kerr return 0;
3594cdc200fSJeremy Kerr }
3604cdc200fSJeremy Kerr
mctp_serial_open_fd(struct mctp_binding_serial * serial,int fd)3614cdc200fSJeremy Kerr void mctp_serial_open_fd(struct mctp_binding_serial *serial, int fd)
3624cdc200fSJeremy Kerr {
3634cdc200fSJeremy Kerr serial->fd = fd;
3644cdc200fSJeremy Kerr }
3654cdc200fSJeremy Kerr #endif
3664cdc200fSJeremy Kerr
mctp_serial_set_tx_fn(struct mctp_binding_serial * serial,mctp_serial_tx_fn fn,void * data)367597b3697SJeremy Kerr void mctp_serial_set_tx_fn(struct mctp_binding_serial *serial,
368597b3697SJeremy Kerr mctp_serial_tx_fn fn, void *data)
369597b3697SJeremy Kerr {
370597b3697SJeremy Kerr serial->tx_fn = fn;
371597b3697SJeremy Kerr serial->tx_fn_data = data;
372597b3697SJeremy Kerr }
373597b3697SJeremy Kerr
mctp_serial_rx(struct mctp_binding_serial * serial,const void * buf,size_t len)374a721c2d8SPatrick Williams int mctp_serial_rx(struct mctp_binding_serial *serial, const void *buf,
375a721c2d8SPatrick Williams size_t len)
376597b3697SJeremy Kerr {
377597b3697SJeremy Kerr mctp_rx_consume(serial, buf, len);
37800e6770bSAndrew Jeffery return 0;
379597b3697SJeremy Kerr }
380597b3697SJeremy Kerr
mctp_serial_core_start(struct mctp_binding * binding)3813b36d17cSJeremy Kerr static int mctp_serial_core_start(struct mctp_binding *binding)
3824cdc200fSJeremy Kerr {
3833b36d17cSJeremy Kerr mctp_binding_set_tx_enabled(binding, true);
3843b36d17cSJeremy Kerr return 0;
3853b36d17cSJeremy Kerr }
3863b36d17cSJeremy Kerr
mctp_binding_serial_core(struct mctp_binding_serial * b)3873b36d17cSJeremy Kerr struct mctp_binding *mctp_binding_serial_core(struct mctp_binding_serial *b)
3883b36d17cSJeremy Kerr {
3893b36d17cSJeremy Kerr return &b->binding;
3904cdc200fSJeremy Kerr }
3914cdc200fSJeremy Kerr
mctp_serial_init(void)3924cdc200fSJeremy Kerr struct mctp_binding_serial *mctp_serial_init(void)
3934cdc200fSJeremy Kerr {
3944cdc200fSJeremy Kerr struct mctp_binding_serial *serial;
3954cdc200fSJeremy Kerr
3964cdc200fSJeremy Kerr serial = __mctp_alloc(sizeof(*serial));
3970bead57eSJeremy Kerr memset(serial, 0, sizeof(*serial));
3984cdc200fSJeremy Kerr serial->fd = -1;
3994cdc200fSJeremy Kerr serial->rx_state = STATE_WAIT_SYNC_START;
4004cdc200fSJeremy Kerr serial->rx_pkt = NULL;
4014cdc200fSJeremy Kerr serial->binding.name = "serial";
4024cdc200fSJeremy Kerr serial->binding.version = 1;
40373c268e4SAndrew Jeffery serial->binding.pkt_size = MCTP_PACKET_SIZE(MCTP_BTU);
40439da3d03SAndrew Jeffery serial->binding.pkt_header = 0;
4052a2a0f6fSKonstantin Aladyshev serial->binding.pkt_trailer = 0;
4064cdc200fSJeremy Kerr
4073b36d17cSJeremy Kerr serial->binding.start = mctp_serial_core_start;
4084cdc200fSJeremy Kerr serial->binding.tx = mctp_binding_serial_tx;
4094cdc200fSJeremy Kerr
4104cdc200fSJeremy Kerr return serial;
4114cdc200fSJeremy Kerr }
4124cdc200fSJeremy Kerr
mctp_serial_destroy(struct mctp_binding_serial * serial)413f8b4749aSAndrew Jeffery void mctp_serial_destroy(struct mctp_binding_serial *serial)
414f8b4749aSAndrew Jeffery {
415f8b4749aSAndrew Jeffery __mctp_free(serial);
416f8b4749aSAndrew Jeffery }
417