xref: /openbmc/libmctp/serial.c (revision a3830d259a53269f7b9c8b46129e863ebed1b188)
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 
9b3de343eSJohn Chung #include "crc-16-ccitt.h"
10b3de343eSJohn 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,const void * buf,size_t len)206e0c5d6dSMatt Johnston static const size_t write(int fd, const 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 
284a09e1dcSMatt Johnston #define SERIAL_BTU MCTP_BTU
294a09e1dcSMatt Johnston 
304cdc200fSJeremy Kerr #include "libmctp.h"
314cdc200fSJeremy Kerr #include "libmctp-alloc.h"
324cdc200fSJeremy Kerr #include "libmctp-log.h"
334cdc200fSJeremy Kerr #include "libmctp-serial.h"
34ff25d7ebSPrzemyslaw Czarnowski #include "container_of.h"
354cdc200fSJeremy Kerr 
364cdc200fSJeremy Kerr struct mctp_binding_serial {
374cdc200fSJeremy Kerr 	struct mctp_binding binding;
384cdc200fSJeremy Kerr 	int fd;
394cdc200fSJeremy Kerr 	unsigned long bus_id;
404cdc200fSJeremy Kerr 
41597b3697SJeremy Kerr 	mctp_serial_tx_fn tx_fn;
42597b3697SJeremy Kerr 	void *tx_fn_data;
43597b3697SJeremy Kerr 
444cdc200fSJeremy Kerr 	/* receive buffer and state */
454cdc200fSJeremy Kerr 	uint8_t rxbuf[1024];
464cdc200fSJeremy Kerr 	struct mctp_pktbuf *rx_pkt;
47*a3830d25SMatt Johnston 	uint8_t rx_storage[MCTP_PKTBUF_SIZE(SERIAL_BTU)] PKTBUF_STORAGE_ALIGN;
484cdc200fSJeremy Kerr 	uint8_t rx_exp_len;
494cdc200fSJeremy Kerr 	uint16_t rx_fcs;
50b3de343eSJohn Chung 	uint16_t rx_fcs_calc;
514cdc200fSJeremy Kerr 	enum {
524cdc200fSJeremy Kerr 		STATE_WAIT_SYNC_START,
534cdc200fSJeremy Kerr 		STATE_WAIT_REVISION,
544cdc200fSJeremy Kerr 		STATE_WAIT_LEN,
554cdc200fSJeremy Kerr 		STATE_DATA,
564cdc200fSJeremy Kerr 		STATE_DATA_ESCAPED,
574cdc200fSJeremy Kerr 		STATE_WAIT_FCS1,
584cdc200fSJeremy Kerr 		STATE_WAIT_FCS2,
594cdc200fSJeremy Kerr 		STATE_WAIT_SYNC_END,
604cdc200fSJeremy Kerr 	} rx_state;
61c67605bcSJeremy Kerr 
62c67605bcSJeremy Kerr 	/* temporary transmit buffer */
63c67605bcSJeremy Kerr 	uint8_t txbuf[256];
644a09e1dcSMatt Johnston 	/* used by the MCTP stack */
65*a3830d25SMatt Johnston 	uint8_t tx_storage[MCTP_PKTBUF_SIZE(SERIAL_BTU)] PKTBUF_STORAGE_ALIGN;
664cdc200fSJeremy Kerr };
674cdc200fSJeremy Kerr 
684cdc200fSJeremy Kerr #define binding_to_serial(b)                                                   \
694cdc200fSJeremy Kerr 	container_of(b, struct mctp_binding_serial, binding)
704cdc200fSJeremy Kerr 
714cdc200fSJeremy Kerr #define MCTP_SERIAL_REVISION	 0x01
724cdc200fSJeremy Kerr #define MCTP_SERIAL_FRAMING_FLAG 0x7e
734cdc200fSJeremy Kerr #define MCTP_SERIAL_ESCAPE	 0x7d
744cdc200fSJeremy Kerr 
754cdc200fSJeremy Kerr struct mctp_serial_header {
764cdc200fSJeremy Kerr 	uint8_t flag;
774cdc200fSJeremy Kerr 	uint8_t revision;
784cdc200fSJeremy Kerr 	uint8_t len;
794cdc200fSJeremy Kerr };
804cdc200fSJeremy Kerr 
814cdc200fSJeremy Kerr struct mctp_serial_trailer {
824cdc200fSJeremy Kerr 	uint8_t fcs_msb;
834cdc200fSJeremy Kerr 	uint8_t fcs_lsb;
844cdc200fSJeremy Kerr 	uint8_t flag;
854cdc200fSJeremy Kerr };
864cdc200fSJeremy Kerr 
87e79ac010SMatt Johnston /*
88e79ac010SMatt Johnston  * @fn: A function that will copy data from the buffer at src into the dst object
89e79ac010SMatt Johnston  * @dst: An opaque object to pass as state to fn
90e79ac010SMatt Johnston  * @src: A pointer to the buffer of data to copy to dst
91e79ac010SMatt Johnston  * @len: The length of the data pointed to by src
92e79ac010SMatt Johnston  * @return: 0 on succes, negative error code on failure
93e79ac010SMatt Johnston  *
94e79ac010SMatt Johnston  * Pre-condition: fn returns a write count or a negative error code
95e79ac010SMatt Johnston  * Post-condition: All bytes written or an error has occurred
96e79ac010SMatt Johnston  */
mctp_write_all(mctp_serial_tx_fn fn,void * dst,uint8_t * src,size_t len)97e79ac010SMatt Johnston static ssize_t mctp_write_all(mctp_serial_tx_fn fn, void *dst, uint8_t *src,
98e79ac010SMatt Johnston 			      size_t len)
99e79ac010SMatt Johnston {
100e79ac010SMatt Johnston 	uint8_t *__src = src;
101e79ac010SMatt Johnston 	ssize_t wrote;
102e79ac010SMatt Johnston 	while (len) {
103e79ac010SMatt Johnston 		wrote = fn(dst, __src, len);
104e79ac010SMatt Johnston 		if (wrote < 0) {
105e79ac010SMatt Johnston 			break;
106e79ac010SMatt Johnston 		}
107e79ac010SMatt Johnston 		__src += wrote;
108e79ac010SMatt Johnston 		len -= wrote;
109e79ac010SMatt Johnston 	}
110e79ac010SMatt Johnston 	return len ? wrote : 0;
111e79ac010SMatt Johnston }
112e79ac010SMatt Johnston 
mctp_serial_write(void * fildesp,void * buf,size_t nbyte)113e79ac010SMatt Johnston static int mctp_serial_write(void *fildesp, void *buf, size_t nbyte)
114e79ac010SMatt Johnston {
115e79ac010SMatt Johnston 	ssize_t wrote;
116e79ac010SMatt Johnston 	int fildes = *((int *)fildesp);
117e79ac010SMatt Johnston 
118e79ac010SMatt Johnston 	return ((wrote = write(fildes, buf, nbyte)) < 0) ? -errno : wrote;
119e79ac010SMatt Johnston }
120e79ac010SMatt Johnston 
mctp_serial_pkt_escape(struct mctp_pktbuf * pkt,uint8_t * buf)121c67605bcSJeremy Kerr static size_t mctp_serial_pkt_escape(struct mctp_pktbuf *pkt, uint8_t *buf)
1224cdc200fSJeremy Kerr {
1234cdc200fSJeremy Kerr 	uint8_t total_len;
124c67605bcSJeremy Kerr 	uint8_t *p;
1254cdc200fSJeremy Kerr 	int i, j;
1264cdc200fSJeremy Kerr 
1274cdc200fSJeremy Kerr 	total_len = pkt->end - pkt->mctp_hdr_off;
1284cdc200fSJeremy Kerr 
1294cdc200fSJeremy Kerr 	p = (void *)mctp_pktbuf_hdr(pkt);
1304cdc200fSJeremy Kerr 
1314cdc200fSJeremy Kerr 	for (i = 0, j = 0; i < total_len; i++, j++) {
132c67605bcSJeremy Kerr 		uint8_t c = p[i];
1334cdc200fSJeremy Kerr 		if (c == 0x7e || c == 0x7d) {
134c67605bcSJeremy Kerr 			if (buf)
135c67605bcSJeremy Kerr 				buf[j] = 0x7d;
1364cdc200fSJeremy Kerr 			j++;
1374cdc200fSJeremy Kerr 			c ^= 0x20;
1384cdc200fSJeremy Kerr 		}
139c67605bcSJeremy Kerr 		if (buf)
140c67605bcSJeremy Kerr 			buf[j] = c;
1414cdc200fSJeremy Kerr 	}
142c67605bcSJeremy Kerr 
143c67605bcSJeremy Kerr 	return j;
1444cdc200fSJeremy Kerr }
1454cdc200fSJeremy Kerr 
mctp_binding_serial_tx(struct mctp_binding * b,struct mctp_pktbuf * pkt)1464cdc200fSJeremy Kerr static int mctp_binding_serial_tx(struct mctp_binding *b,
1474cdc200fSJeremy Kerr 				  struct mctp_pktbuf *pkt)
1484cdc200fSJeremy Kerr {
1494cdc200fSJeremy Kerr 	struct mctp_binding_serial *serial = binding_to_serial(b);
1504cdc200fSJeremy Kerr 	struct mctp_serial_header *hdr;
1514cdc200fSJeremy Kerr 	struct mctp_serial_trailer *tlr;
152c67605bcSJeremy Kerr 	uint8_t *buf;
153c67605bcSJeremy Kerr 	size_t len;
154b3de343eSJohn Chung 	uint16_t fcs;
1554cdc200fSJeremy Kerr 
1564cdc200fSJeremy Kerr 	/* the length field in the header excludes serial framing
1574cdc200fSJeremy Kerr 	 * and escape sequences */
1584cdc200fSJeremy Kerr 	len = mctp_pktbuf_size(pkt);
1594cdc200fSJeremy Kerr 
160c67605bcSJeremy Kerr 	hdr = (void *)serial->txbuf;
1614cdc200fSJeremy Kerr 	hdr->flag = MCTP_SERIAL_FRAMING_FLAG;
1624cdc200fSJeremy Kerr 	hdr->revision = MCTP_SERIAL_REVISION;
1634cdc200fSJeremy Kerr 	hdr->len = len;
1644cdc200fSJeremy Kerr 
165b3de343eSJohn Chung 	// Calculate fcs
166b3de343eSJohn Chung 	fcs = crc_16_ccitt(FCS_INIT_16, (const uint8_t *)hdr + 1, 2);
167b3de343eSJohn Chung 	fcs = crc_16_ccitt(fcs, (const uint8_t *)mctp_pktbuf_hdr(pkt), len);
168b3de343eSJohn Chung 
169c67605bcSJeremy Kerr 	buf = (void *)(hdr + 1);
1704cdc200fSJeremy Kerr 
171c67605bcSJeremy Kerr 	len = mctp_serial_pkt_escape(pkt, NULL);
172c67605bcSJeremy Kerr 	if (len + sizeof(*hdr) + sizeof(*tlr) > sizeof(serial->txbuf))
1730721f585SAndrew Jeffery 		return -EMSGSIZE;
174c67605bcSJeremy Kerr 
175c67605bcSJeremy Kerr 	mctp_serial_pkt_escape(pkt, buf);
176c67605bcSJeremy Kerr 
177c67605bcSJeremy Kerr 	buf += len;
178c67605bcSJeremy Kerr 
179c67605bcSJeremy Kerr 	tlr = (void *)buf;
1804cdc200fSJeremy Kerr 	tlr->flag = MCTP_SERIAL_FRAMING_FLAG;
181b3de343eSJohn Chung 	tlr->fcs_msb = fcs >> 8;
182b3de343eSJohn Chung 	tlr->fcs_lsb = fcs & 0xff;
1834cdc200fSJeremy Kerr 
184597b3697SJeremy Kerr 	len += sizeof(*hdr) + sizeof(*tlr);
185597b3697SJeremy Kerr 
186ad772b97SAndrew Jeffery 	if (!serial->tx_fn)
187e79ac010SMatt Johnston 		return mctp_write_all(mctp_serial_write, &serial->fd,
18889a28781SAndrew Jeffery 				      &serial->txbuf[0], len);
1894cdc200fSJeremy Kerr 
190a721c2d8SPatrick Williams 	return mctp_write_all(serial->tx_fn, serial->tx_fn_data,
191a721c2d8SPatrick Williams 			      &serial->txbuf[0], len);
1924cdc200fSJeremy Kerr }
1934cdc200fSJeremy Kerr 
mctp_serial_finish_packet(struct mctp_binding_serial * serial,bool valid)1944cdc200fSJeremy Kerr static void mctp_serial_finish_packet(struct mctp_binding_serial *serial,
1954cdc200fSJeremy Kerr 				      bool valid)
1964cdc200fSJeremy Kerr {
1974cdc200fSJeremy Kerr 	struct mctp_pktbuf *pkt = serial->rx_pkt;
1984cdc200fSJeremy Kerr 	assert(pkt);
1994cdc200fSJeremy Kerr 
2004cdc200fSJeremy Kerr 	if (valid)
2010a00dca2SJeremy Kerr 		mctp_bus_rx(&serial->binding, pkt);
2024cdc200fSJeremy Kerr 
2034cdc200fSJeremy Kerr 	serial->rx_pkt = NULL;
2044cdc200fSJeremy Kerr }
2054cdc200fSJeremy Kerr 
mctp_serial_start_packet(struct mctp_binding_serial * serial)2064a09e1dcSMatt Johnston static void mctp_serial_start_packet(struct mctp_binding_serial *serial)
2074cdc200fSJeremy Kerr {
2084a09e1dcSMatt Johnston 	serial->rx_pkt = mctp_pktbuf_init(&serial->binding, serial->rx_storage);
2094cdc200fSJeremy Kerr }
2104cdc200fSJeremy Kerr 
mctp_rx_consume_one(struct mctp_binding_serial * serial,uint8_t c)211a721c2d8SPatrick Williams static void mctp_rx_consume_one(struct mctp_binding_serial *serial, uint8_t c)
2124cdc200fSJeremy Kerr {
2134cdc200fSJeremy Kerr 	struct mctp_pktbuf *pkt = serial->rx_pkt;
214b3de343eSJohn Chung 	bool valid = false;
2154cdc200fSJeremy Kerr 
2164cdc200fSJeremy Kerr 	mctp_prdebug("state: %d, char 0x%02x", serial->rx_state, c);
2174cdc200fSJeremy Kerr 
2184cdc200fSJeremy Kerr 	assert(!pkt == (serial->rx_state == STATE_WAIT_SYNC_START ||
2194cdc200fSJeremy Kerr 			serial->rx_state == STATE_WAIT_REVISION ||
2204cdc200fSJeremy Kerr 			serial->rx_state == STATE_WAIT_LEN));
2214cdc200fSJeremy Kerr 
2224cdc200fSJeremy Kerr 	switch (serial->rx_state) {
2234cdc200fSJeremy Kerr 	case STATE_WAIT_SYNC_START:
2244cdc200fSJeremy Kerr 		if (c != MCTP_SERIAL_FRAMING_FLAG) {
2254cdc200fSJeremy Kerr 			mctp_prdebug("lost sync, dropping packet");
2264cdc200fSJeremy Kerr 			if (pkt)
2274cdc200fSJeremy Kerr 				mctp_serial_finish_packet(serial, false);
2284cdc200fSJeremy Kerr 		} else {
2294cdc200fSJeremy Kerr 			serial->rx_state = STATE_WAIT_REVISION;
2304cdc200fSJeremy Kerr 		}
2314cdc200fSJeremy Kerr 		break;
2324cdc200fSJeremy Kerr 
2334cdc200fSJeremy Kerr 	case STATE_WAIT_REVISION:
2344cdc200fSJeremy Kerr 		if (c == MCTP_SERIAL_REVISION) {
2354cdc200fSJeremy Kerr 			serial->rx_state = STATE_WAIT_LEN;
236b3de343eSJohn Chung 			serial->rx_fcs_calc = crc_16_ccitt_byte(FCS_INIT_16, c);
2371fe5899eSNikhil Namjoshi 		} else if (c == MCTP_SERIAL_FRAMING_FLAG) {
2381fe5899eSNikhil Namjoshi 			/* Handle the case where there are bytes dropped in request,
2391fe5899eSNikhil Namjoshi 			 * and the state machine is out of sync. The failed request's
2401fe5899eSNikhil Namjoshi 			 * trailing footer i.e. 0x7e would be interpreted as next
2411fe5899eSNikhil Namjoshi 			 * request's framing footer. So if we are in STATE_WAIT_REVISION
2421fe5899eSNikhil Namjoshi 			 * and receive 0x7e byte, then contine to stay in
2431fe5899eSNikhil Namjoshi 			 * STATE_WAIT_REVISION
2441fe5899eSNikhil Namjoshi 			 */
2451fe5899eSNikhil Namjoshi 			mctp_prdebug(
2461fe5899eSNikhil Namjoshi 				"Received serial framing flag 0x%02x while waiting"
2471fe5899eSNikhil Namjoshi 				" for serial revision 0x%02x.",
2481fe5899eSNikhil Namjoshi 				c, MCTP_SERIAL_REVISION);
2494cdc200fSJeremy Kerr 		} else {
2504cdc200fSJeremy Kerr 			mctp_prdebug("invalid revision 0x%02x", c);
2514cdc200fSJeremy Kerr 			serial->rx_state = STATE_WAIT_SYNC_START;
2524cdc200fSJeremy Kerr 		}
2534cdc200fSJeremy Kerr 		break;
2544cdc200fSJeremy Kerr 	case STATE_WAIT_LEN:
255df15f7e9SJeremy Kerr 		if (c > serial->binding.pkt_size ||
256df15f7e9SJeremy Kerr 		    c < sizeof(struct mctp_hdr)) {
2574cdc200fSJeremy Kerr 			mctp_prdebug("invalid size %d", c);
2584cdc200fSJeremy Kerr 			serial->rx_state = STATE_WAIT_SYNC_START;
2594cdc200fSJeremy Kerr 		} else {
2604a09e1dcSMatt Johnston 			mctp_serial_start_packet(serial);
2614cdc200fSJeremy Kerr 			pkt = serial->rx_pkt;
2624cdc200fSJeremy Kerr 			serial->rx_exp_len = c;
2634cdc200fSJeremy Kerr 			serial->rx_state = STATE_DATA;
264b3de343eSJohn Chung 			serial->rx_fcs_calc =
265b3de343eSJohn Chung 				crc_16_ccitt_byte(serial->rx_fcs_calc, c);
2664cdc200fSJeremy Kerr 		}
2674cdc200fSJeremy Kerr 		break;
2684cdc200fSJeremy Kerr 
2694cdc200fSJeremy Kerr 	case STATE_DATA:
2704cdc200fSJeremy Kerr 		if (c == MCTP_SERIAL_ESCAPE) {
2714cdc200fSJeremy Kerr 			serial->rx_state = STATE_DATA_ESCAPED;
2724cdc200fSJeremy Kerr 		} else {
2734cdc200fSJeremy Kerr 			mctp_pktbuf_push(pkt, &c, 1);
274b3de343eSJohn Chung 			serial->rx_fcs_calc =
275b3de343eSJohn Chung 				crc_16_ccitt_byte(serial->rx_fcs_calc, c);
2764cdc200fSJeremy Kerr 			if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len)
2774cdc200fSJeremy Kerr 				serial->rx_state = STATE_WAIT_FCS1;
2784cdc200fSJeremy Kerr 		}
2794cdc200fSJeremy Kerr 		break;
2804cdc200fSJeremy Kerr 
2814cdc200fSJeremy Kerr 	case STATE_DATA_ESCAPED:
2824cdc200fSJeremy Kerr 		c ^= 0x20;
2834cdc200fSJeremy Kerr 		mctp_pktbuf_push(pkt, &c, 1);
284b3de343eSJohn Chung 		serial->rx_fcs_calc = crc_16_ccitt_byte(serial->rx_fcs_calc, c);
2854cdc200fSJeremy Kerr 		if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len)
2864cdc200fSJeremy Kerr 			serial->rx_state = STATE_WAIT_FCS1;
2874cdc200fSJeremy Kerr 		else
2884cdc200fSJeremy Kerr 			serial->rx_state = STATE_DATA;
2894cdc200fSJeremy Kerr 		break;
2904cdc200fSJeremy Kerr 
2914cdc200fSJeremy Kerr 	case STATE_WAIT_FCS1:
2924cdc200fSJeremy Kerr 		serial->rx_fcs = c << 8;
2934cdc200fSJeremy Kerr 		serial->rx_state = STATE_WAIT_FCS2;
2944cdc200fSJeremy Kerr 		break;
2954cdc200fSJeremy Kerr 	case STATE_WAIT_FCS2:
2964cdc200fSJeremy Kerr 		serial->rx_fcs |= c;
2974cdc200fSJeremy Kerr 		serial->rx_state = STATE_WAIT_SYNC_END;
2984cdc200fSJeremy Kerr 		break;
2994cdc200fSJeremy Kerr 
3004cdc200fSJeremy Kerr 	case STATE_WAIT_SYNC_END:
301b3de343eSJohn Chung 		if (serial->rx_fcs == serial->rx_fcs_calc) {
3024cdc200fSJeremy Kerr 			if (c == MCTP_SERIAL_FRAMING_FLAG) {
303b3de343eSJohn Chung 				valid = true;
3044cdc200fSJeremy Kerr 			} else {
305b3de343eSJohn Chung 				valid = false;
3064cdc200fSJeremy Kerr 				mctp_prdebug("missing end frame marker");
3074cdc200fSJeremy Kerr 			}
308b3de343eSJohn Chung 		} else {
309b3de343eSJohn Chung 			valid = false;
310b3de343eSJohn Chung 			mctp_prdebug("invalid fcs : 0x%04x, expect 0x%04x",
311b3de343eSJohn Chung 				     serial->rx_fcs, serial->rx_fcs_calc);
312b3de343eSJohn Chung 		}
313b3de343eSJohn Chung 
314b3de343eSJohn Chung 		mctp_serial_finish_packet(serial, valid);
3154cdc200fSJeremy Kerr 		serial->rx_state = STATE_WAIT_SYNC_START;
3164cdc200fSJeremy Kerr 		break;
3174cdc200fSJeremy Kerr 	}
3184cdc200fSJeremy Kerr 
3194cdc200fSJeremy Kerr 	mctp_prdebug(" -> state: %d", serial->rx_state);
3204cdc200fSJeremy Kerr }
mctp_rx_consume(struct mctp_binding_serial * serial,const void * buf,size_t len)321a721c2d8SPatrick Williams static void mctp_rx_consume(struct mctp_binding_serial *serial, const void *buf,
322a721c2d8SPatrick Williams 			    size_t len)
3234cdc200fSJeremy Kerr {
3244cdc200fSJeremy Kerr 	size_t i;
3254cdc200fSJeremy Kerr 
3264cdc200fSJeremy Kerr 	for (i = 0; i < len; i++)
3273ef47785SMatt Johnston 		mctp_rx_consume_one(serial, ((const uint8_t *)buf)[i]);
3284cdc200fSJeremy Kerr }
3294cdc200fSJeremy Kerr 
330c7e764a2SJeremy Kerr #ifdef MCTP_HAVE_FILEIO
mctp_serial_read(struct mctp_binding_serial * serial)3314cdc200fSJeremy Kerr int mctp_serial_read(struct mctp_binding_serial *serial)
3324cdc200fSJeremy Kerr {
3334cdc200fSJeremy Kerr 	ssize_t len;
3344cdc200fSJeremy Kerr 
3354cdc200fSJeremy Kerr 	len = read(serial->fd, serial->rxbuf, sizeof(serial->rxbuf));
3364cdc200fSJeremy Kerr 	if (len == 0)
3374cdc200fSJeremy Kerr 		return -1;
3384cdc200fSJeremy Kerr 
3394cdc200fSJeremy Kerr 	if (len < 0) {
3403ef47785SMatt Johnston 		mctp_prerr("can't read from serial device: %s",
3413ef47785SMatt Johnston 			   strerror(errno));
3424cdc200fSJeremy Kerr 		return -1;
3434cdc200fSJeremy Kerr 	}
3444cdc200fSJeremy Kerr 
3454cdc200fSJeremy Kerr 	mctp_rx_consume(serial, serial->rxbuf, len);
3464cdc200fSJeremy Kerr 
3474cdc200fSJeremy Kerr 	return 0;
3484cdc200fSJeremy Kerr }
3494cdc200fSJeremy Kerr 
mctp_serial_init_pollfd(struct mctp_binding_serial * serial,struct pollfd * pollfd)3501111c6a5SAndrew Jeffery int mctp_serial_init_pollfd(struct mctp_binding_serial *serial,
3511111c6a5SAndrew Jeffery 			    struct pollfd *pollfd)
3521111c6a5SAndrew Jeffery {
3531111c6a5SAndrew Jeffery 	pollfd->fd = serial->fd;
3541111c6a5SAndrew Jeffery 	pollfd->events = POLLIN;
3551111c6a5SAndrew Jeffery 
3561111c6a5SAndrew Jeffery 	return 0;
3571111c6a5SAndrew Jeffery }
3581111c6a5SAndrew Jeffery 
mctp_serial_open_path(struct mctp_binding_serial * serial,const char * device)3594cdc200fSJeremy Kerr int mctp_serial_open_path(struct mctp_binding_serial *serial,
3604cdc200fSJeremy Kerr 			  const char *device)
3614cdc200fSJeremy Kerr {
3624cdc200fSJeremy Kerr 	serial->fd = open(device, O_RDWR);
3634cdc200fSJeremy Kerr 	if (serial->fd < 0)
3643ef47785SMatt Johnston 		mctp_prerr("can't open device %s: %s", device, strerror(errno));
3654cdc200fSJeremy Kerr 
3664cdc200fSJeremy Kerr 	return 0;
3674cdc200fSJeremy Kerr }
3684cdc200fSJeremy Kerr 
mctp_serial_open_fd(struct mctp_binding_serial * serial,int fd)3694cdc200fSJeremy Kerr void mctp_serial_open_fd(struct mctp_binding_serial *serial, int fd)
3704cdc200fSJeremy Kerr {
3714cdc200fSJeremy Kerr 	serial->fd = fd;
3724cdc200fSJeremy Kerr }
3734cdc200fSJeremy Kerr #endif
3744cdc200fSJeremy Kerr 
mctp_serial_set_tx_fn(struct mctp_binding_serial * serial,mctp_serial_tx_fn fn,void * data)375597b3697SJeremy Kerr void mctp_serial_set_tx_fn(struct mctp_binding_serial *serial,
376597b3697SJeremy Kerr 			   mctp_serial_tx_fn fn, void *data)
377597b3697SJeremy Kerr {
378597b3697SJeremy Kerr 	serial->tx_fn = fn;
379597b3697SJeremy Kerr 	serial->tx_fn_data = data;
380597b3697SJeremy Kerr }
381597b3697SJeremy Kerr 
mctp_serial_rx(struct mctp_binding_serial * serial,const void * buf,size_t len)382a721c2d8SPatrick Williams int mctp_serial_rx(struct mctp_binding_serial *serial, const void *buf,
383a721c2d8SPatrick Williams 		   size_t len)
384597b3697SJeremy Kerr {
385597b3697SJeremy Kerr 	mctp_rx_consume(serial, buf, len);
38600e6770bSAndrew Jeffery 	return 0;
387597b3697SJeremy Kerr }
388597b3697SJeremy Kerr 
mctp_serial_core_start(struct mctp_binding * binding)3893b36d17cSJeremy Kerr static int mctp_serial_core_start(struct mctp_binding *binding)
3904cdc200fSJeremy Kerr {
3913b36d17cSJeremy Kerr 	mctp_binding_set_tx_enabled(binding, true);
3923b36d17cSJeremy Kerr 	return 0;
3933b36d17cSJeremy Kerr }
3943b36d17cSJeremy Kerr 
mctp_binding_serial_core(struct mctp_binding_serial * b)3953b36d17cSJeremy Kerr struct mctp_binding *mctp_binding_serial_core(struct mctp_binding_serial *b)
3963b36d17cSJeremy Kerr {
3973b36d17cSJeremy Kerr 	return &b->binding;
3984cdc200fSJeremy Kerr }
3994cdc200fSJeremy Kerr 
mctp_serial_init(void)4004cdc200fSJeremy Kerr struct mctp_binding_serial *mctp_serial_init(void)
4014cdc200fSJeremy Kerr {
4024cdc200fSJeremy Kerr 	struct mctp_binding_serial *serial;
4034cdc200fSJeremy Kerr 
4044cdc200fSJeremy Kerr 	serial = __mctp_alloc(sizeof(*serial));
4050bead57eSJeremy Kerr 	memset(serial, 0, sizeof(*serial));
4064cdc200fSJeremy Kerr 	serial->fd = -1;
4074cdc200fSJeremy Kerr 	serial->rx_state = STATE_WAIT_SYNC_START;
4084cdc200fSJeremy Kerr 	serial->rx_pkt = NULL;
4094cdc200fSJeremy Kerr 	serial->binding.name = "serial";
4104cdc200fSJeremy Kerr 	serial->binding.version = 1;
4114a09e1dcSMatt Johnston 	serial->binding.pkt_size = MCTP_PACKET_SIZE(SERIAL_BTU);
41239da3d03SAndrew Jeffery 	serial->binding.pkt_header = 0;
4132a2a0f6fSKonstantin Aladyshev 	serial->binding.pkt_trailer = 0;
4144a09e1dcSMatt Johnston 	serial->binding.tx_storage = serial->tx_storage;
4154cdc200fSJeremy Kerr 
4163b36d17cSJeremy Kerr 	serial->binding.start = mctp_serial_core_start;
4174cdc200fSJeremy Kerr 	serial->binding.tx = mctp_binding_serial_tx;
4184cdc200fSJeremy Kerr 
4194cdc200fSJeremy Kerr 	return serial;
4204cdc200fSJeremy Kerr }
4214cdc200fSJeremy Kerr 
mctp_serial_destroy(struct mctp_binding_serial * serial)422f8b4749aSAndrew Jeffery void mctp_serial_destroy(struct mctp_binding_serial *serial)
423f8b4749aSAndrew Jeffery {
424f8b4749aSAndrew Jeffery 	__mctp_free(serial);
425f8b4749aSAndrew Jeffery }
426