xref: /openbmc/libmctp/serial.c (revision b3de343e)
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