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