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