18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Copyright (C) 2007-2008 The Android Open Source Project
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project**
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This software is licensed under the terms of the GNU General Public
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** License version 2, as published by the Free Software Foundation, and
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** may be copied, distributed, and modified under those terms.
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project**
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This program is distributed in the hope that it will be useful,
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** but WITHOUT ANY WARRANTY; without even the implied warranty of
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** GNU General Public License for more details.
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project*/
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu-char.h"
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "cbuffer.h"
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu_debug.h"
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  xxDEBUG
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#  include <stdio.h>
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#  define  D(...)   ( fprintf( stderr, __VA_ARGS__ ), fprintf(stderr, "\n") )
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#  define  D(...)   ((void)0)
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* we want to implement a bi-directionnal communication channel
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * between two QEMU character drivers that merge well into the
278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * QEMU event loop.
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * each half of the channel has its own object and buffer, and
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * we implement communication through charpipe_poll() which
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * must be called by the main event loop after its call to select()
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  BIP_BUFFER_SIZE  512
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct BipBuffer {
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct BipBuffer*  next;
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CBuffer            cb[1];
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char               buff[ BIP_BUFFER_SIZE ];
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} BipBuffer;
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic BipBuffer*  _free_bip_buffers;
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic BipBuffer*
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectbip_buffer_alloc( void )
478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BipBuffer*  bip = _free_bip_buffers;
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (bip != NULL) {
508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        _free_bip_buffers = bip->next;
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        bip = malloc( sizeof(*bip) );
538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (bip == NULL) {
548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            derror( "%s: not enough memory", __FUNCTION__ );
558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            exit(1);
568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bip->next = NULL;
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    cbuffer_reset( bip->cb, bip->buff, sizeof(bip->buff) );
608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return bip;
618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectbip_buffer_free( BipBuffer*  bip )
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bip->next         = _free_bip_buffers;
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    _free_bip_buffers = bip;
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* this models each half of the charpipe */
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct CharPipeHalf {
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CharDriverState       cs[1];
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BipBuffer*            bip_first;
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BipBuffer*            bip_last;
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct CharPipeHalf*  peer;         /* NULL if closed */
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} CharPipeHalf;
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectcharpipehalf_close( CharDriverState*  cs )
828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CharPipeHalf*  ph = cs->opaque;
848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (ph->bip_first) {
868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        BipBuffer*  bip = ph->bip_first;
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ph->bip_first = bip->next;
888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        bip_buffer_free(bip);
898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ph->bip_last    = NULL;
918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ph->peer        = NULL;
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectcharpipehalf_write( CharDriverState*  cs, const uint8_t*  buf, int  len )
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CharPipeHalf*  ph   = cs->opaque;
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CharPipeHalf*  peer = ph->peer;
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BipBuffer*     bip  = ph->bip_last;
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int            ret  = 0;
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    D("%s: writing %d bytes to %p: '%s'", __FUNCTION__,
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project      len, ph, quote_bytes( buf, len ));
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (bip == NULL && peer != NULL && peer->cs->chr_read != NULL) {
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* no buffered data, try to write directly to the peer */
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        while (len > 0) {
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            int  size;
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (peer->cs->chr_can_read) {
1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                size = qemu_chr_can_read( peer->cs );
1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (size == 0)
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    break;
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (size > len)
1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    size = len;
1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            } else
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                size = len;
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            qemu_chr_read( peer->cs, (uint8_t*)buf, size );
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            buf += size;
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            len -= size;
1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ret += size;
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (len == 0)
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return ret;
1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* buffer the remaining data */
1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (bip == NULL) {
1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        bip = bip_buffer_alloc();
1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ph->bip_first = ph->bip_last = bip;
1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (len > 0) {
1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int  len2 = cbuffer_write( bip->cb, buf, len );
1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        buf += len2;
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ret += len2;
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        len -= len2;
1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (len == 0)
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* ok, we need another buffer */
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ph->bip_last = bip_buffer_alloc();
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        bip->next = ph->bip_last;
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        bip       = ph->bip_last;
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return  ret;
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectcharpipehalf_poll( CharPipeHalf*  ph )
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CharPipeHalf*   peer = ph->peer;
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int             size;
1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (peer == NULL || peer->cs->chr_read == NULL)
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (1) {
1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        BipBuffer*  bip = ph->bip_first;
1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint8_t*    base;
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int         avail;
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (bip == NULL)
1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        size = cbuffer_read_avail(bip->cb);
1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (size == 0) {
1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ph->bip_first = bip->next;
1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (ph->bip_first == NULL)
1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                ph->bip_last = NULL;
1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            bip_buffer_free(bip);
1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            continue;
1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (ph->cs->chr_can_read) {
1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            int  size2 = qemu_chr_can_read(peer->cs);
1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (size2 == 0)
1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (size > size2)
1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                size = size2;
1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        avail = cbuffer_read_peek( bip->cb, &base );
1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (avail > size)
1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            avail = size;
1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        D("%s: sending %d bytes from %p: '%s'", __FUNCTION__,
1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            avail, ph, quote_bytes( base, avail ));
1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_chr_read( peer->cs, base, avail );
1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cbuffer_read_step( bip->cb, avail );
1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
2048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectcharpipehalf_init( CharPipeHalf*  ph, CharPipeHalf*  peer )
2058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CharDriverState*  cs = ph->cs;
2078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ph->bip_first   = NULL;
2098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ph->bip_last    = NULL;
2108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ph->peer        = peer;
2118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    cs->chr_write            = charpipehalf_write;
2138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    cs->chr_ioctl            = NULL;
2148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    cs->chr_send_event       = NULL;
2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    cs->chr_close            = charpipehalf_close;
2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    cs->opaque               = ph;
2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct CharPipeState {
2218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CharPipeHalf  a[1];
2228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CharPipeHalf  b[1];
2238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} CharPipeState;
2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define   MAX_CHAR_PIPES   8
2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic CharPipeState  _s_charpipes[ MAX_CHAR_PIPES ];
2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint
2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectqemu_chr_open_charpipe( CharDriverState*  *pfirst, CharDriverState*  *psecond )
2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CharPipeState*  cp     = _s_charpipes;
2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CharPipeState*  cp_end = cp + MAX_CHAR_PIPES;
2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for ( ; cp < cp_end; cp++ ) {
2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if ( cp->a->peer == NULL && cp->b->peer == NULL )
2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (cp == cp_end) {  /* can't allocate one */
2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *pfirst  = NULL;
2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *psecond = NULL;
2458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return -1;
2468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    charpipehalf_init( cp->a, cp->b );
2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    charpipehalf_init( cp->b, cp->a );
2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    *pfirst  = cp->a->cs;
2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    *psecond = cp->b->cs;
2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2564735694ff99078f961876525ebbd55317956083fDavid Turner/** This models a charbuffer, an object used to buffer
2574735694ff99078f961876525ebbd55317956083fDavid Turner ** the data that is sent to a given endpoint CharDriverState
2584735694ff99078f961876525ebbd55317956083fDavid Turner ** object.
2594735694ff99078f961876525ebbd55317956083fDavid Turner **
2604735694ff99078f961876525ebbd55317956083fDavid Turner ** On the other hand, any can_read() / read() request performed
2614735694ff99078f961876525ebbd55317956083fDavid Turner ** by the endpoint will be passed to the CharBuffer's corresponding
2624735694ff99078f961876525ebbd55317956083fDavid Turner ** handlers.
2634735694ff99078f961876525ebbd55317956083fDavid Turner **/
2644735694ff99078f961876525ebbd55317956083fDavid Turner
2654735694ff99078f961876525ebbd55317956083fDavid Turnertypedef struct CharBuffer {
2664735694ff99078f961876525ebbd55317956083fDavid Turner    CharDriverState  cs[1];
2674735694ff99078f961876525ebbd55317956083fDavid Turner    BipBuffer*       bip_first;
2684735694ff99078f961876525ebbd55317956083fDavid Turner    BipBuffer*       bip_last;
2694735694ff99078f961876525ebbd55317956083fDavid Turner    CharDriverState* endpoint;  /* NULL if closed */
2704735694ff99078f961876525ebbd55317956083fDavid Turner    char             closing;
2714735694ff99078f961876525ebbd55317956083fDavid Turner} CharBuffer;
2724735694ff99078f961876525ebbd55317956083fDavid Turner
2734735694ff99078f961876525ebbd55317956083fDavid Turner
2744735694ff99078f961876525ebbd55317956083fDavid Turnerstatic void
2754735694ff99078f961876525ebbd55317956083fDavid Turnercharbuffer_close( CharDriverState*  cs )
2764735694ff99078f961876525ebbd55317956083fDavid Turner{
2774735694ff99078f961876525ebbd55317956083fDavid Turner    CharBuffer*  cbuf = cs->opaque;
2784735694ff99078f961876525ebbd55317956083fDavid Turner
2794735694ff99078f961876525ebbd55317956083fDavid Turner    while (cbuf->bip_first) {
2804735694ff99078f961876525ebbd55317956083fDavid Turner        BipBuffer*  bip = cbuf->bip_first;
2814735694ff99078f961876525ebbd55317956083fDavid Turner        cbuf->bip_first = bip->next;
2824735694ff99078f961876525ebbd55317956083fDavid Turner        bip_buffer_free(bip);
2834735694ff99078f961876525ebbd55317956083fDavid Turner    }
2844735694ff99078f961876525ebbd55317956083fDavid Turner    cbuf->bip_last = NULL;
2854735694ff99078f961876525ebbd55317956083fDavid Turner    cbuf->endpoint = NULL;
2864735694ff99078f961876525ebbd55317956083fDavid Turner
2874735694ff99078f961876525ebbd55317956083fDavid Turner    if (cbuf->endpoint != NULL) {
2884735694ff99078f961876525ebbd55317956083fDavid Turner        qemu_chr_close(cbuf->endpoint);
2894735694ff99078f961876525ebbd55317956083fDavid Turner        cbuf->endpoint = NULL;
2904735694ff99078f961876525ebbd55317956083fDavid Turner    }
2914735694ff99078f961876525ebbd55317956083fDavid Turner}
2924735694ff99078f961876525ebbd55317956083fDavid Turner
2934735694ff99078f961876525ebbd55317956083fDavid Turnerstatic int
2944735694ff99078f961876525ebbd55317956083fDavid Turnercharbuffer_write( CharDriverState*  cs, const uint8_t*  buf, int  len )
2954735694ff99078f961876525ebbd55317956083fDavid Turner{
2964735694ff99078f961876525ebbd55317956083fDavid Turner    CharBuffer*       cbuf = cs->opaque;
2974735694ff99078f961876525ebbd55317956083fDavid Turner    CharDriverState*  peer = cbuf->endpoint;
2984735694ff99078f961876525ebbd55317956083fDavid Turner    BipBuffer*        bip  = cbuf->bip_last;
2994735694ff99078f961876525ebbd55317956083fDavid Turner    int               ret  = 0;
3004735694ff99078f961876525ebbd55317956083fDavid Turner
3014735694ff99078f961876525ebbd55317956083fDavid Turner    D("%s: writing %d bytes to %p: '%s'", __FUNCTION__,
3024735694ff99078f961876525ebbd55317956083fDavid Turner      len, cbuf, quote_bytes( buf, len ));
3034735694ff99078f961876525ebbd55317956083fDavid Turner
3044735694ff99078f961876525ebbd55317956083fDavid Turner    if (bip == NULL && peer != NULL) {
3054735694ff99078f961876525ebbd55317956083fDavid Turner        /* no buffered data, try to write directly to the peer */
3064735694ff99078f961876525ebbd55317956083fDavid Turner        int  size = qemu_chr_write(peer, buf, len);
3074735694ff99078f961876525ebbd55317956083fDavid Turner
3084735694ff99078f961876525ebbd55317956083fDavid Turner        if (size < 0)  /* just to be safe */
3094735694ff99078f961876525ebbd55317956083fDavid Turner            size = 0;
3104735694ff99078f961876525ebbd55317956083fDavid Turner        else if (size > len)
3114735694ff99078f961876525ebbd55317956083fDavid Turner            size = len;
3124735694ff99078f961876525ebbd55317956083fDavid Turner
3134735694ff99078f961876525ebbd55317956083fDavid Turner        buf += size;
3144735694ff99078f961876525ebbd55317956083fDavid Turner        ret += size;
3154735694ff99078f961876525ebbd55317956083fDavid Turner        len -= size;
3164735694ff99078f961876525ebbd55317956083fDavid Turner    }
3174735694ff99078f961876525ebbd55317956083fDavid Turner
3184735694ff99078f961876525ebbd55317956083fDavid Turner    if (len == 0)
3194735694ff99078f961876525ebbd55317956083fDavid Turner        return ret;
3204735694ff99078f961876525ebbd55317956083fDavid Turner
3214735694ff99078f961876525ebbd55317956083fDavid Turner    /* buffer the remaining data */
3224735694ff99078f961876525ebbd55317956083fDavid Turner    if (bip == NULL) {
3234735694ff99078f961876525ebbd55317956083fDavid Turner        bip = bip_buffer_alloc();
3244735694ff99078f961876525ebbd55317956083fDavid Turner        cbuf->bip_first = cbuf->bip_last = bip;
3254735694ff99078f961876525ebbd55317956083fDavid Turner    }
3264735694ff99078f961876525ebbd55317956083fDavid Turner
3274735694ff99078f961876525ebbd55317956083fDavid Turner    while (len > 0) {
3284735694ff99078f961876525ebbd55317956083fDavid Turner        int  len2 = cbuffer_write( bip->cb, buf, len );
3294735694ff99078f961876525ebbd55317956083fDavid Turner
3304735694ff99078f961876525ebbd55317956083fDavid Turner        buf += len2;
3314735694ff99078f961876525ebbd55317956083fDavid Turner        ret += len2;
3324735694ff99078f961876525ebbd55317956083fDavid Turner        len -= len2;
3334735694ff99078f961876525ebbd55317956083fDavid Turner        if (len == 0)
3344735694ff99078f961876525ebbd55317956083fDavid Turner            break;
3354735694ff99078f961876525ebbd55317956083fDavid Turner
3364735694ff99078f961876525ebbd55317956083fDavid Turner        /* ok, we need another buffer */
3374735694ff99078f961876525ebbd55317956083fDavid Turner        cbuf->bip_last = bip_buffer_alloc();
3384735694ff99078f961876525ebbd55317956083fDavid Turner        bip->next = cbuf->bip_last;
3394735694ff99078f961876525ebbd55317956083fDavid Turner        bip       = cbuf->bip_last;
3404735694ff99078f961876525ebbd55317956083fDavid Turner    }
3414735694ff99078f961876525ebbd55317956083fDavid Turner    return  ret;
3424735694ff99078f961876525ebbd55317956083fDavid Turner}
3434735694ff99078f961876525ebbd55317956083fDavid Turner
3444735694ff99078f961876525ebbd55317956083fDavid Turner
3454735694ff99078f961876525ebbd55317956083fDavid Turnerstatic void
3464735694ff99078f961876525ebbd55317956083fDavid Turnercharbuffer_poll( CharBuffer*  cbuf )
3474735694ff99078f961876525ebbd55317956083fDavid Turner{
3484735694ff99078f961876525ebbd55317956083fDavid Turner    CharDriverState*  peer = cbuf->endpoint;
3494735694ff99078f961876525ebbd55317956083fDavid Turner
3504735694ff99078f961876525ebbd55317956083fDavid Turner    if (peer == NULL)
3514735694ff99078f961876525ebbd55317956083fDavid Turner        return;
3524735694ff99078f961876525ebbd55317956083fDavid Turner
3534735694ff99078f961876525ebbd55317956083fDavid Turner    while (1) {
3544735694ff99078f961876525ebbd55317956083fDavid Turner        BipBuffer*  bip = cbuf->bip_first;
3554735694ff99078f961876525ebbd55317956083fDavid Turner        uint8_t*    base;
3564735694ff99078f961876525ebbd55317956083fDavid Turner        int         avail;
3574735694ff99078f961876525ebbd55317956083fDavid Turner        int         size;
3584735694ff99078f961876525ebbd55317956083fDavid Turner
3594735694ff99078f961876525ebbd55317956083fDavid Turner        if (bip == NULL)
3604735694ff99078f961876525ebbd55317956083fDavid Turner            break;
3614735694ff99078f961876525ebbd55317956083fDavid Turner
3624735694ff99078f961876525ebbd55317956083fDavid Turner        avail = cbuffer_read_peek( bip->cb, &base );
3634735694ff99078f961876525ebbd55317956083fDavid Turner        if (avail == 0) {
3644735694ff99078f961876525ebbd55317956083fDavid Turner            cbuf->bip_first = bip->next;
3654735694ff99078f961876525ebbd55317956083fDavid Turner            if (cbuf->bip_first == NULL)
3664735694ff99078f961876525ebbd55317956083fDavid Turner                cbuf->bip_last = NULL;
3674735694ff99078f961876525ebbd55317956083fDavid Turner            bip_buffer_free(bip);
3684735694ff99078f961876525ebbd55317956083fDavid Turner            continue;
3694735694ff99078f961876525ebbd55317956083fDavid Turner        }
3704735694ff99078f961876525ebbd55317956083fDavid Turner
3714735694ff99078f961876525ebbd55317956083fDavid Turner        size = qemu_chr_write( peer, base, avail );
3724735694ff99078f961876525ebbd55317956083fDavid Turner
3734735694ff99078f961876525ebbd55317956083fDavid Turner        if (size < 0)  /* just to be safe */
3744735694ff99078f961876525ebbd55317956083fDavid Turner            size = 0;
3754735694ff99078f961876525ebbd55317956083fDavid Turner        else if (size > avail)
3764735694ff99078f961876525ebbd55317956083fDavid Turner            size = avail;
3774735694ff99078f961876525ebbd55317956083fDavid Turner
3784735694ff99078f961876525ebbd55317956083fDavid Turner        cbuffer_read_step( bip->cb, size );
3794735694ff99078f961876525ebbd55317956083fDavid Turner
3804735694ff99078f961876525ebbd55317956083fDavid Turner        if (size < avail)
3814735694ff99078f961876525ebbd55317956083fDavid Turner            break;
3824735694ff99078f961876525ebbd55317956083fDavid Turner    }
3834735694ff99078f961876525ebbd55317956083fDavid Turner}
3844735694ff99078f961876525ebbd55317956083fDavid Turner
3854735694ff99078f961876525ebbd55317956083fDavid Turner
3864735694ff99078f961876525ebbd55317956083fDavid Turnerstatic void
3874735694ff99078f961876525ebbd55317956083fDavid Turnercharbuffer_update_handlers( CharDriverState*  cs )
3884735694ff99078f961876525ebbd55317956083fDavid Turner{
3894735694ff99078f961876525ebbd55317956083fDavid Turner    CharBuffer*  cbuf = cs->opaque;
3904735694ff99078f961876525ebbd55317956083fDavid Turner
3914735694ff99078f961876525ebbd55317956083fDavid Turner    qemu_chr_add_handlers( cbuf->endpoint,
3924735694ff99078f961876525ebbd55317956083fDavid Turner                           cs->chr_can_read,
3934735694ff99078f961876525ebbd55317956083fDavid Turner                           cs->chr_read,
3944735694ff99078f961876525ebbd55317956083fDavid Turner                           cs->chr_event,
3954735694ff99078f961876525ebbd55317956083fDavid Turner                           cs->handler_opaque );
3964735694ff99078f961876525ebbd55317956083fDavid Turner}
3974735694ff99078f961876525ebbd55317956083fDavid Turner
3984735694ff99078f961876525ebbd55317956083fDavid Turner
3994735694ff99078f961876525ebbd55317956083fDavid Turnerstatic void
4004735694ff99078f961876525ebbd55317956083fDavid Turnercharbuffer_init( CharBuffer*  cbuf, CharDriverState*  endpoint )
4014735694ff99078f961876525ebbd55317956083fDavid Turner{
4024735694ff99078f961876525ebbd55317956083fDavid Turner    CharDriverState*  cs = cbuf->cs;
4034735694ff99078f961876525ebbd55317956083fDavid Turner
4044735694ff99078f961876525ebbd55317956083fDavid Turner    cbuf->bip_first   = NULL;
4054735694ff99078f961876525ebbd55317956083fDavid Turner    cbuf->bip_last    = NULL;
4064735694ff99078f961876525ebbd55317956083fDavid Turner    cbuf->endpoint    = endpoint;
4074735694ff99078f961876525ebbd55317956083fDavid Turner
4084735694ff99078f961876525ebbd55317956083fDavid Turner    cs->chr_write               = charbuffer_write;
4094735694ff99078f961876525ebbd55317956083fDavid Turner    cs->chr_ioctl               = NULL;
4104735694ff99078f961876525ebbd55317956083fDavid Turner    cs->chr_send_event          = NULL;
4114735694ff99078f961876525ebbd55317956083fDavid Turner    cs->chr_close               = charbuffer_close;
4124735694ff99078f961876525ebbd55317956083fDavid Turner    cs->chr_update_read_handler = charbuffer_update_handlers;
4134735694ff99078f961876525ebbd55317956083fDavid Turner    cs->opaque                  = cbuf;
4144735694ff99078f961876525ebbd55317956083fDavid Turner}
4154735694ff99078f961876525ebbd55317956083fDavid Turner
4164735694ff99078f961876525ebbd55317956083fDavid Turner#define MAX_CHAR_BUFFERS  8
4174735694ff99078f961876525ebbd55317956083fDavid Turner
4184735694ff99078f961876525ebbd55317956083fDavid Turnerstatic CharBuffer  _s_charbuffers[ MAX_CHAR_BUFFERS ];
4194735694ff99078f961876525ebbd55317956083fDavid Turner
4204735694ff99078f961876525ebbd55317956083fDavid TurnerCharDriverState*
4214735694ff99078f961876525ebbd55317956083fDavid Turnerqemu_chr_open_buffer( CharDriverState*  endpoint )
4224735694ff99078f961876525ebbd55317956083fDavid Turner{
4234735694ff99078f961876525ebbd55317956083fDavid Turner    CharBuffer*  cbuf     = _s_charbuffers;
4244735694ff99078f961876525ebbd55317956083fDavid Turner    CharBuffer*  cbuf_end = cbuf + MAX_CHAR_BUFFERS;
4254735694ff99078f961876525ebbd55317956083fDavid Turner
4264735694ff99078f961876525ebbd55317956083fDavid Turner    if (endpoint == NULL)
4274735694ff99078f961876525ebbd55317956083fDavid Turner        return NULL;
4284735694ff99078f961876525ebbd55317956083fDavid Turner
4294735694ff99078f961876525ebbd55317956083fDavid Turner    for ( ; cbuf < cbuf_end; cbuf++ ) {
4304735694ff99078f961876525ebbd55317956083fDavid Turner        if (cbuf->endpoint == NULL)
4314735694ff99078f961876525ebbd55317956083fDavid Turner            break;
4324735694ff99078f961876525ebbd55317956083fDavid Turner    }
4334735694ff99078f961876525ebbd55317956083fDavid Turner
4344735694ff99078f961876525ebbd55317956083fDavid Turner    if (cbuf == cbuf_end)
4354735694ff99078f961876525ebbd55317956083fDavid Turner        return NULL;
4364735694ff99078f961876525ebbd55317956083fDavid Turner
4374735694ff99078f961876525ebbd55317956083fDavid Turner    charbuffer_init(cbuf, endpoint);
4384735694ff99078f961876525ebbd55317956083fDavid Turner    return cbuf->cs;
4394735694ff99078f961876525ebbd55317956083fDavid Turner}
4404735694ff99078f961876525ebbd55317956083fDavid Turner
4414735694ff99078f961876525ebbd55317956083fDavid Turner
4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectcharpipe_poll( void )
4448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CharPipeState*  cp     = _s_charpipes;
4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    CharPipeState*  cp_end = cp + MAX_CHAR_PIPES;
4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4484735694ff99078f961876525ebbd55317956083fDavid Turner    CharBuffer*     cb     = _s_charbuffers;
4494735694ff99078f961876525ebbd55317956083fDavid Turner    CharBuffer*     cb_end = cb + MAX_CHAR_BUFFERS;
4504735694ff99078f961876525ebbd55317956083fDavid Turner
4514735694ff99078f961876525ebbd55317956083fDavid Turner    /* poll the charpipes */
4528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for ( ; cp < cp_end; cp++ ) {
4538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        CharPipeHalf*  half;
4548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        half = cp->a;
4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (half->peer != NULL)
4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            charpipehalf_poll(half);
4588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        half = cp->b;
4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (half->peer != NULL)
4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            charpipehalf_poll(half);
4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4634735694ff99078f961876525ebbd55317956083fDavid Turner
4644735694ff99078f961876525ebbd55317956083fDavid Turner    /* poll the charbuffers */
4654735694ff99078f961876525ebbd55317956083fDavid Turner    for ( ; cb < cb_end; cb++ ) {
4664735694ff99078f961876525ebbd55317956083fDavid Turner        if (cb->endpoint != NULL)
4674735694ff99078f961876525ebbd55317956083fDavid Turner            charbuffer_poll(cb);
4684735694ff99078f961876525ebbd55317956083fDavid Turner    }
4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
470