xref: /openbmc/libmctp/serial.c (revision 0721f585)
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 
9c7e764a2SJeremy Kerr #ifdef HAVE_CONFIG_H
10c7e764a2SJeremy Kerr #include "config.h"
11c7e764a2SJeremy Kerr #endif
12c7e764a2SJeremy Kerr 
13c7e764a2SJeremy Kerr #ifdef MCTP_HAVE_FILEIO
144cdc200fSJeremy Kerr #include <fcntl.h>
151111c6a5SAndrew Jeffery #include <poll.h>
161111c6a5SAndrew Jeffery #include <unistd.h>
17597b3697SJeremy Kerr #else
18597b3697SJeremy Kerr static const size_t write(int fd, void *buf, size_t len)
19597b3697SJeremy Kerr {
20597b3697SJeremy Kerr 	return -1;
21597b3697SJeremy Kerr }
224cdc200fSJeremy Kerr #endif
234cdc200fSJeremy Kerr 
244cdc200fSJeremy Kerr #define pr_fmt(x) "serial: " x
254cdc200fSJeremy Kerr 
2689a28781SAndrew Jeffery /*
2789a28781SAndrew Jeffery  * @fn: A function that will copy data from the buffer at src into the dst object
2889a28781SAndrew Jeffery  * @dst: An opaque object to pass as state to fn
2989a28781SAndrew Jeffery  * @src: A pointer to the buffer of data to copy to dst
3089a28781SAndrew Jeffery  * @len: The length of the data pointed to by src
3189a28781SAndrew Jeffery  * @return: 0 on succes, negative error code on failure
3289a28781SAndrew Jeffery  *
3389a28781SAndrew Jeffery  * Pre-condition: fn returns a write count or a negative error code
3489a28781SAndrew Jeffery  * Post-condition: All bytes written or an error has occurred
3589a28781SAndrew Jeffery  */
36ad772b97SAndrew Jeffery #define mctp_write_all(fn, dst, src, len)                                      \
37ad772b97SAndrew Jeffery 	({                                                                     \
3889a28781SAndrew Jeffery 		typeof(src) __src = src;                                       \
39ad772b97SAndrew Jeffery 		ssize_t wrote;                                                 \
40ad772b97SAndrew Jeffery 		while (len) {                                                  \
4189a28781SAndrew Jeffery 			wrote = fn(dst, __src, len);                           \
42ad772b97SAndrew Jeffery 			if (wrote < 0)                                         \
43ad772b97SAndrew Jeffery 				break;                                         \
4489a28781SAndrew Jeffery 			__src += wrote;                                        \
45ad772b97SAndrew Jeffery 			len -= wrote;                                          \
46ad772b97SAndrew Jeffery 		}                                                              \
4789a28781SAndrew Jeffery 		len ? wrote : 0;                                               \
48ad772b97SAndrew Jeffery 	})
49ad772b97SAndrew Jeffery 
5089a28781SAndrew Jeffery static ssize_t mctp_serial_write(int fildes, const void *buf, size_t nbyte)
5189a28781SAndrew Jeffery {
5289a28781SAndrew Jeffery 	ssize_t wrote;
5389a28781SAndrew Jeffery 
5489a28781SAndrew Jeffery 	return ((wrote = write(fildes, buf, nbyte)) < 0) ? -errno : wrote;
5589a28781SAndrew Jeffery }
5689a28781SAndrew Jeffery 
574cdc200fSJeremy Kerr #include "libmctp.h"
584cdc200fSJeremy Kerr #include "libmctp-alloc.h"
594cdc200fSJeremy Kerr #include "libmctp-log.h"
604cdc200fSJeremy Kerr #include "libmctp-serial.h"
61ff25d7ebSPrzemyslaw Czarnowski #include "container_of.h"
624cdc200fSJeremy Kerr 
634cdc200fSJeremy Kerr struct mctp_binding_serial {
644cdc200fSJeremy Kerr 	struct mctp_binding binding;
654cdc200fSJeremy Kerr 	int fd;
664cdc200fSJeremy Kerr 	unsigned long bus_id;
674cdc200fSJeremy Kerr 
68597b3697SJeremy Kerr 	mctp_serial_tx_fn	tx_fn;
69597b3697SJeremy Kerr 	void			*tx_fn_data;
70597b3697SJeremy Kerr 
714cdc200fSJeremy Kerr 	/* receive buffer and state */
724cdc200fSJeremy Kerr 	uint8_t			rxbuf[1024];
734cdc200fSJeremy Kerr 	struct mctp_pktbuf	*rx_pkt;
744cdc200fSJeremy Kerr 	uint8_t			rx_exp_len;
754cdc200fSJeremy Kerr 	uint16_t		rx_fcs;
764cdc200fSJeremy Kerr 	enum {
774cdc200fSJeremy Kerr 		STATE_WAIT_SYNC_START,
784cdc200fSJeremy Kerr 		STATE_WAIT_REVISION,
794cdc200fSJeremy Kerr 		STATE_WAIT_LEN,
804cdc200fSJeremy Kerr 		STATE_DATA,
814cdc200fSJeremy Kerr 		STATE_DATA_ESCAPED,
824cdc200fSJeremy Kerr 		STATE_WAIT_FCS1,
834cdc200fSJeremy Kerr 		STATE_WAIT_FCS2,
844cdc200fSJeremy Kerr 		STATE_WAIT_SYNC_END,
854cdc200fSJeremy Kerr 	} rx_state;
86c67605bcSJeremy Kerr 
87c67605bcSJeremy Kerr 	/* temporary transmit buffer */
88c67605bcSJeremy Kerr 	uint8_t			txbuf[256];
894cdc200fSJeremy Kerr };
904cdc200fSJeremy Kerr 
914cdc200fSJeremy Kerr #define binding_to_serial(b) \
924cdc200fSJeremy Kerr 	container_of(b, struct mctp_binding_serial, binding)
934cdc200fSJeremy Kerr 
944cdc200fSJeremy Kerr #define MCTP_SERIAL_REVISION		0x01
954cdc200fSJeremy Kerr #define MCTP_SERIAL_FRAMING_FLAG	0x7e
964cdc200fSJeremy Kerr #define MCTP_SERIAL_ESCAPE		0x7d
974cdc200fSJeremy Kerr 
984cdc200fSJeremy Kerr struct mctp_serial_header {
994cdc200fSJeremy Kerr 	uint8_t	flag;
1004cdc200fSJeremy Kerr 	uint8_t revision;
1014cdc200fSJeremy Kerr 	uint8_t	len;
1024cdc200fSJeremy Kerr };
1034cdc200fSJeremy Kerr 
1044cdc200fSJeremy Kerr struct mctp_serial_trailer {
1054cdc200fSJeremy Kerr 	uint8_t	fcs_msb;
1064cdc200fSJeremy Kerr 	uint8_t fcs_lsb;
1074cdc200fSJeremy Kerr 	uint8_t	flag;
1084cdc200fSJeremy Kerr };
1094cdc200fSJeremy Kerr 
110c67605bcSJeremy Kerr static size_t mctp_serial_pkt_escape(struct mctp_pktbuf *pkt, uint8_t *buf)
1114cdc200fSJeremy Kerr {
1124cdc200fSJeremy Kerr 	uint8_t total_len;
113c67605bcSJeremy Kerr 	uint8_t *p;
1144cdc200fSJeremy Kerr 	int i, j;
1154cdc200fSJeremy Kerr 
1164cdc200fSJeremy Kerr 	total_len = pkt->end - pkt->mctp_hdr_off;
1174cdc200fSJeremy Kerr 
1184cdc200fSJeremy Kerr 	p = (void *)mctp_pktbuf_hdr(pkt);
1194cdc200fSJeremy Kerr 
1204cdc200fSJeremy Kerr 	for (i = 0, j = 0; i < total_len; i++, j++) {
121c67605bcSJeremy Kerr 		uint8_t c = p[i];
1224cdc200fSJeremy Kerr 		if (c == 0x7e || c == 0x7d) {
123c67605bcSJeremy Kerr 			if (buf)
124c67605bcSJeremy Kerr 				buf[j] = 0x7d;
1254cdc200fSJeremy Kerr 			j++;
1264cdc200fSJeremy Kerr 			c ^= 0x20;
1274cdc200fSJeremy Kerr 		}
128c67605bcSJeremy Kerr 		if (buf)
129c67605bcSJeremy Kerr 			buf[j] = c;
1304cdc200fSJeremy Kerr 	}
131c67605bcSJeremy Kerr 
132c67605bcSJeremy Kerr 	return j;
1334cdc200fSJeremy Kerr }
1344cdc200fSJeremy Kerr 
1354cdc200fSJeremy Kerr static int mctp_binding_serial_tx(struct mctp_binding *b,
1364cdc200fSJeremy Kerr 		struct mctp_pktbuf *pkt)
1374cdc200fSJeremy Kerr {
1384cdc200fSJeremy Kerr 	struct mctp_binding_serial *serial = binding_to_serial(b);
1394cdc200fSJeremy Kerr 	struct mctp_serial_header *hdr;
1404cdc200fSJeremy Kerr 	struct mctp_serial_trailer *tlr;
141c67605bcSJeremy Kerr 	uint8_t *buf;
142c67605bcSJeremy Kerr 	size_t len;
1434cdc200fSJeremy Kerr 
1444cdc200fSJeremy Kerr 	/* the length field in the header excludes serial framing
1454cdc200fSJeremy Kerr 	 * and escape sequences */
1464cdc200fSJeremy Kerr 	len = mctp_pktbuf_size(pkt);
1474cdc200fSJeremy Kerr 
148c67605bcSJeremy Kerr 	hdr = (void *)serial->txbuf;
1494cdc200fSJeremy Kerr 	hdr->flag = MCTP_SERIAL_FRAMING_FLAG;
1504cdc200fSJeremy Kerr 	hdr->revision = MCTP_SERIAL_REVISION;
1514cdc200fSJeremy Kerr 	hdr->len = len;
1524cdc200fSJeremy Kerr 
153c67605bcSJeremy Kerr 	buf = (void *)(hdr + 1);
1544cdc200fSJeremy Kerr 
155c67605bcSJeremy Kerr 	len = mctp_serial_pkt_escape(pkt, NULL);
156c67605bcSJeremy Kerr 	if (len + sizeof(*hdr) + sizeof(*tlr) > sizeof(serial->txbuf))
157*0721f585SAndrew Jeffery 		return -EMSGSIZE;
158c67605bcSJeremy Kerr 
159c67605bcSJeremy Kerr 	mctp_serial_pkt_escape(pkt, buf);
160c67605bcSJeremy Kerr 
161c67605bcSJeremy Kerr 	buf += len;
162c67605bcSJeremy Kerr 
163c67605bcSJeremy Kerr 	tlr = (void *)buf;
1644cdc200fSJeremy Kerr 	tlr->flag = MCTP_SERIAL_FRAMING_FLAG;
165c67605bcSJeremy Kerr 	/* todo: trailer FCS */
166c67605bcSJeremy Kerr 	tlr->fcs_msb = 0;
167c67605bcSJeremy Kerr 	tlr->fcs_lsb = 0;
1684cdc200fSJeremy Kerr 
169597b3697SJeremy Kerr 	len += sizeof(*hdr) + sizeof(*tlr);
170597b3697SJeremy Kerr 
171ad772b97SAndrew Jeffery 	if (!serial->tx_fn)
17289a28781SAndrew Jeffery 		return mctp_write_all(mctp_serial_write, serial->fd,
17389a28781SAndrew Jeffery 				      &serial->txbuf[0], len);
1744cdc200fSJeremy Kerr 
17589a28781SAndrew Jeffery 	return mctp_write_all(serial->tx_fn, serial->tx_fn_data, &serial->txbuf[0],
176ad772b97SAndrew Jeffery 			      len);
1774cdc200fSJeremy Kerr }
1784cdc200fSJeremy Kerr 
1794cdc200fSJeremy Kerr static void mctp_serial_finish_packet(struct mctp_binding_serial *serial,
1804cdc200fSJeremy Kerr 		bool valid)
1814cdc200fSJeremy Kerr {
1824cdc200fSJeremy Kerr 	struct mctp_pktbuf *pkt = serial->rx_pkt;
1834cdc200fSJeremy Kerr 	assert(pkt);
1844cdc200fSJeremy Kerr 
1854cdc200fSJeremy Kerr 	if (valid)
1860a00dca2SJeremy Kerr 		mctp_bus_rx(&serial->binding, pkt);
1874cdc200fSJeremy Kerr 
1884cdc200fSJeremy Kerr 	serial->rx_pkt = NULL;
1894cdc200fSJeremy Kerr }
1904cdc200fSJeremy Kerr 
1914cdc200fSJeremy Kerr static void mctp_serial_start_packet(struct mctp_binding_serial *serial,
1924cdc200fSJeremy Kerr 		uint8_t len)
1934cdc200fSJeremy Kerr {
194df15f7e9SJeremy Kerr 	serial->rx_pkt = mctp_pktbuf_alloc(&serial->binding, len);
1954cdc200fSJeremy Kerr }
1964cdc200fSJeremy Kerr 
1974cdc200fSJeremy Kerr static void mctp_rx_consume_one(struct mctp_binding_serial *serial,
1984cdc200fSJeremy Kerr 		uint8_t c)
1994cdc200fSJeremy Kerr {
2004cdc200fSJeremy Kerr 	struct mctp_pktbuf *pkt = serial->rx_pkt;
2014cdc200fSJeremy Kerr 
2024cdc200fSJeremy Kerr 	mctp_prdebug("state: %d, char 0x%02x", serial->rx_state, c);
2034cdc200fSJeremy Kerr 
2044cdc200fSJeremy Kerr 	assert(!pkt == (serial->rx_state == STATE_WAIT_SYNC_START ||
2054cdc200fSJeremy Kerr 			serial->rx_state == STATE_WAIT_REVISION ||
2064cdc200fSJeremy Kerr 			serial->rx_state == STATE_WAIT_LEN));
2074cdc200fSJeremy Kerr 
2084cdc200fSJeremy Kerr 	switch (serial->rx_state) {
2094cdc200fSJeremy Kerr 	case STATE_WAIT_SYNC_START:
2104cdc200fSJeremy Kerr 		if (c != MCTP_SERIAL_FRAMING_FLAG) {
2114cdc200fSJeremy Kerr 			mctp_prdebug("lost sync, dropping packet");
2124cdc200fSJeremy Kerr 			if (pkt)
2134cdc200fSJeremy Kerr 				mctp_serial_finish_packet(serial, false);
2144cdc200fSJeremy Kerr 		} else {
2154cdc200fSJeremy Kerr 			serial->rx_state = STATE_WAIT_REVISION;
2164cdc200fSJeremy Kerr 		}
2174cdc200fSJeremy Kerr 		break;
2184cdc200fSJeremy Kerr 
2194cdc200fSJeremy Kerr 	case STATE_WAIT_REVISION:
2204cdc200fSJeremy Kerr 		if (c == MCTP_SERIAL_REVISION) {
2214cdc200fSJeremy Kerr 			serial->rx_state = STATE_WAIT_LEN;
2224cdc200fSJeremy Kerr 		} else {
2234cdc200fSJeremy Kerr 			mctp_prdebug("invalid revision 0x%02x", c);
2244cdc200fSJeremy Kerr 			serial->rx_state = STATE_WAIT_SYNC_START;
2254cdc200fSJeremy Kerr 		}
2264cdc200fSJeremy Kerr 		break;
2274cdc200fSJeremy Kerr 	case STATE_WAIT_LEN:
228df15f7e9SJeremy Kerr 		if (c > serial->binding.pkt_size ||
229df15f7e9SJeremy Kerr 				c < sizeof(struct mctp_hdr)) {
2304cdc200fSJeremy Kerr 			mctp_prdebug("invalid size %d", c);
2314cdc200fSJeremy Kerr 			serial->rx_state = STATE_WAIT_SYNC_START;
2324cdc200fSJeremy Kerr 		} else {
2334cdc200fSJeremy Kerr 			mctp_serial_start_packet(serial, 0);
2344cdc200fSJeremy Kerr 			pkt = serial->rx_pkt;
2354cdc200fSJeremy Kerr 			serial->rx_exp_len = c;
2364cdc200fSJeremy Kerr 			serial->rx_state = STATE_DATA;
2374cdc200fSJeremy Kerr 		}
2384cdc200fSJeremy Kerr 		break;
2394cdc200fSJeremy Kerr 
2404cdc200fSJeremy Kerr 	case STATE_DATA:
2414cdc200fSJeremy Kerr 		if (c == MCTP_SERIAL_ESCAPE) {
2424cdc200fSJeremy Kerr 			serial->rx_state = STATE_DATA_ESCAPED;
2434cdc200fSJeremy Kerr 		} else {
2444cdc200fSJeremy Kerr 			mctp_pktbuf_push(pkt, &c, 1);
2454cdc200fSJeremy Kerr 			if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len)
2464cdc200fSJeremy Kerr 				serial->rx_state = STATE_WAIT_FCS1;
2474cdc200fSJeremy Kerr 		}
2484cdc200fSJeremy Kerr 		break;
2494cdc200fSJeremy Kerr 
2504cdc200fSJeremy Kerr 	case STATE_DATA_ESCAPED:
2514cdc200fSJeremy Kerr 		c ^= 0x20;
2524cdc200fSJeremy Kerr 		mctp_pktbuf_push(pkt, &c, 1);
2534cdc200fSJeremy Kerr 		if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len)
2544cdc200fSJeremy Kerr 			serial->rx_state = STATE_WAIT_FCS1;
2554cdc200fSJeremy Kerr 		else
2564cdc200fSJeremy Kerr 			serial->rx_state = STATE_DATA;
2574cdc200fSJeremy Kerr 		break;
2584cdc200fSJeremy Kerr 
2594cdc200fSJeremy Kerr 	case STATE_WAIT_FCS1:
2604cdc200fSJeremy Kerr 		serial->rx_fcs = c << 8;
2614cdc200fSJeremy Kerr 		serial->rx_state = STATE_WAIT_FCS2;
2624cdc200fSJeremy Kerr 		break;
2634cdc200fSJeremy Kerr 	case STATE_WAIT_FCS2:
2644cdc200fSJeremy Kerr 		serial->rx_fcs |= c;
2654cdc200fSJeremy Kerr 		/* todo: check fcs */
2664cdc200fSJeremy Kerr 		serial->rx_state = STATE_WAIT_SYNC_END;
2674cdc200fSJeremy Kerr 		break;
2684cdc200fSJeremy Kerr 
2694cdc200fSJeremy Kerr 	case STATE_WAIT_SYNC_END:
2704cdc200fSJeremy Kerr 		if (c == MCTP_SERIAL_FRAMING_FLAG) {
2714cdc200fSJeremy Kerr 			mctp_serial_finish_packet(serial, true);
2724cdc200fSJeremy Kerr 		} else {
2734cdc200fSJeremy Kerr 			mctp_prdebug("missing end frame marker");
2744cdc200fSJeremy Kerr 			mctp_serial_finish_packet(serial, false);
2754cdc200fSJeremy Kerr 		}
2764cdc200fSJeremy Kerr 		serial->rx_state = STATE_WAIT_SYNC_START;
2774cdc200fSJeremy Kerr 		break;
2784cdc200fSJeremy Kerr 	}
2794cdc200fSJeremy Kerr 
2804cdc200fSJeremy Kerr 	mctp_prdebug(" -> state: %d", serial->rx_state);
2814cdc200fSJeremy Kerr }
282597b3697SJeremy Kerr static void mctp_rx_consume(struct mctp_binding_serial *serial,
283597b3697SJeremy Kerr 		const void *buf, size_t len)
2844cdc200fSJeremy Kerr {
2854cdc200fSJeremy Kerr 	size_t i;
2864cdc200fSJeremy Kerr 
2874cdc200fSJeremy Kerr 	for (i = 0; i < len; i++)
2884cdc200fSJeremy Kerr 		mctp_rx_consume_one(serial, *(uint8_t *)(buf + i));
2894cdc200fSJeremy Kerr }
2904cdc200fSJeremy Kerr 
291c7e764a2SJeremy Kerr #ifdef MCTP_HAVE_FILEIO
2924cdc200fSJeremy Kerr int mctp_serial_read(struct mctp_binding_serial *serial)
2934cdc200fSJeremy Kerr {
2944cdc200fSJeremy Kerr 	ssize_t len;
2954cdc200fSJeremy Kerr 
2964cdc200fSJeremy Kerr 	len = read(serial->fd, serial->rxbuf, sizeof(serial->rxbuf));
2974cdc200fSJeremy Kerr 	if (len == 0)
2984cdc200fSJeremy Kerr 		return -1;
2994cdc200fSJeremy Kerr 
3004cdc200fSJeremy Kerr 	if (len < 0) {
3014cdc200fSJeremy Kerr 		mctp_prerr("can't read from serial device: %m");
3024cdc200fSJeremy Kerr 		return -1;
3034cdc200fSJeremy Kerr 	}
3044cdc200fSJeremy Kerr 
3054cdc200fSJeremy Kerr 	mctp_rx_consume(serial, serial->rxbuf, len);
3064cdc200fSJeremy Kerr 
3074cdc200fSJeremy Kerr 	return 0;
3084cdc200fSJeremy Kerr }
3094cdc200fSJeremy Kerr 
3101111c6a5SAndrew Jeffery int mctp_serial_init_pollfd(struct mctp_binding_serial *serial,
3111111c6a5SAndrew Jeffery 			    struct pollfd *pollfd)
3121111c6a5SAndrew Jeffery {
3131111c6a5SAndrew Jeffery 	pollfd->fd = serial->fd;
3141111c6a5SAndrew Jeffery 	pollfd->events = POLLIN;
3151111c6a5SAndrew Jeffery 
3161111c6a5SAndrew Jeffery 	return 0;
3171111c6a5SAndrew Jeffery }
3181111c6a5SAndrew Jeffery 
3194cdc200fSJeremy Kerr int mctp_serial_open_path(struct mctp_binding_serial *serial,
3204cdc200fSJeremy Kerr 		const char *device)
3214cdc200fSJeremy Kerr {
3224cdc200fSJeremy Kerr 	serial->fd = open(device, O_RDWR);
3234cdc200fSJeremy Kerr 	if (serial->fd < 0)
3244cdc200fSJeremy Kerr 		mctp_prerr("can't open device %s: %m", device);
3254cdc200fSJeremy Kerr 
3264cdc200fSJeremy Kerr 	return 0;
3274cdc200fSJeremy Kerr }
3284cdc200fSJeremy Kerr 
3294cdc200fSJeremy Kerr void mctp_serial_open_fd(struct mctp_binding_serial *serial, int fd)
3304cdc200fSJeremy Kerr {
3314cdc200fSJeremy Kerr 	serial->fd = fd;
3324cdc200fSJeremy Kerr }
3334cdc200fSJeremy Kerr #endif
3344cdc200fSJeremy Kerr 
335597b3697SJeremy Kerr void mctp_serial_set_tx_fn(struct mctp_binding_serial *serial,
336597b3697SJeremy Kerr 		mctp_serial_tx_fn fn, void *data)
337597b3697SJeremy Kerr {
338597b3697SJeremy Kerr 	serial->tx_fn = fn;
339597b3697SJeremy Kerr 	serial->tx_fn_data = data;
340597b3697SJeremy Kerr }
341597b3697SJeremy Kerr 
342597b3697SJeremy Kerr int mctp_serial_rx(struct mctp_binding_serial *serial,
343597b3697SJeremy Kerr 		const void *buf, size_t len)
344597b3697SJeremy Kerr {
345597b3697SJeremy Kerr 	mctp_rx_consume(serial, buf, len);
34600e6770bSAndrew Jeffery 	return 0;
347597b3697SJeremy Kerr }
348597b3697SJeremy Kerr 
3493b36d17cSJeremy Kerr static int mctp_serial_core_start(struct mctp_binding *binding)
3504cdc200fSJeremy Kerr {
3513b36d17cSJeremy Kerr 	mctp_binding_set_tx_enabled(binding, true);
3523b36d17cSJeremy Kerr 	return 0;
3533b36d17cSJeremy Kerr }
3543b36d17cSJeremy Kerr 
3553b36d17cSJeremy Kerr struct mctp_binding *mctp_binding_serial_core(struct mctp_binding_serial *b)
3563b36d17cSJeremy Kerr {
3573b36d17cSJeremy Kerr 	return &b->binding;
3584cdc200fSJeremy Kerr }
3594cdc200fSJeremy Kerr 
3604cdc200fSJeremy Kerr struct mctp_binding_serial *mctp_serial_init(void)
3614cdc200fSJeremy Kerr {
3624cdc200fSJeremy Kerr 	struct mctp_binding_serial *serial;
3634cdc200fSJeremy Kerr 
3644cdc200fSJeremy Kerr 	serial = __mctp_alloc(sizeof(*serial));
3650bead57eSJeremy Kerr 	memset(serial, 0, sizeof(*serial));
3664cdc200fSJeremy Kerr 	serial->fd = -1;
3674cdc200fSJeremy Kerr 	serial->rx_state = STATE_WAIT_SYNC_START;
3684cdc200fSJeremy Kerr 	serial->rx_pkt = NULL;
3694cdc200fSJeremy Kerr 	serial->binding.name = "serial";
3704cdc200fSJeremy Kerr 	serial->binding.version = 1;
37173c268e4SAndrew Jeffery 	serial->binding.pkt_size = MCTP_PACKET_SIZE(MCTP_BTU);
37239da3d03SAndrew Jeffery 	serial->binding.pkt_header = 0;
37339da3d03SAndrew Jeffery 	serial->binding.pkt_header = 0;
3744cdc200fSJeremy Kerr 
3753b36d17cSJeremy Kerr 	serial->binding.start = mctp_serial_core_start;
3764cdc200fSJeremy Kerr 	serial->binding.tx = mctp_binding_serial_tx;
3774cdc200fSJeremy Kerr 
3784cdc200fSJeremy Kerr 	return serial;
3794cdc200fSJeremy Kerr }
3804cdc200fSJeremy Kerr 
381f8b4749aSAndrew Jeffery void mctp_serial_destroy(struct mctp_binding_serial *serial)
382f8b4749aSAndrew Jeffery {
383f8b4749aSAndrew Jeffery 	__mctp_free(serial);
384f8b4749aSAndrew Jeffery }
385