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