1/* Copyright (C) 2007-2008 The Android Open Source Project 2** 3** This software is licensed under the terms of the GNU General Public 4** License version 2, as published by the Free Software Foundation, and 5** may be copied, distributed, and modified under those terms. 6** 7** This program is distributed in the hope that it will be useful, 8** but WITHOUT ANY WARRANTY; without even the implied warranty of 9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10** GNU General Public License for more details. 11*/ 12/* implement the modem character device for Android within the QEMU event loop. 13 * it communicates through a serial port with "rild" (Radio Interface Layer Daemon) 14 * on the emulated device. 15 */ 16#include "modem_driver.h" 17#include "qemu-char.h" 18 19#define xxDEBUG 20 21#ifdef DEBUG 22# include <stdio.h> 23# define D(...) ( fprintf( stderr, __VA_ARGS__ ) ) 24#else 25# define D(...) ((void)0) 26#endif 27 28AModem android_modem; 29CharDriverState* android_modem_cs; 30 31typedef struct { 32 CharDriverState* cs; 33 AModem modem; 34 char in_buff[ 1024 ]; 35 int in_pos; 36 int in_sms; 37} ModemDriver; 38 39/* send unsollicited messages to the device */ 40static void 41modem_driver_unsol( void* _md, const char* message) 42{ 43 ModemDriver* md = _md; 44 int len = strlen(message); 45 46 qemu_chr_write(md->cs, (const uint8_t*)message, len); 47} 48 49static int 50modem_driver_can_read( void* _md ) 51{ 52 ModemDriver* md = _md; 53 int ret = sizeof(md->in_buff) - md->in_pos; 54 55 return ret; 56} 57 58/* despite its name, this function is called when the device writes to the modem */ 59static void 60modem_driver_read( void* _md, const uint8_t* src, int len ) 61{ 62 ModemDriver* md = _md; 63 const uint8_t* end = src + len; 64 int nn; 65 66 D( "%s: reading %d from %p bytes:", __FUNCTION__, len, src ); 67 for (nn = 0; nn < len; nn++) { 68 int c = src[nn]; 69 if (c >= 32 && c < 127) 70 D( "%c", c ); 71 else if (c == '\n') 72 D( "<LF>" ); 73 else if (c == '\r') 74 D( "<CR>" ); 75 else 76 D( "\\x%02x", c ); 77 } 78 D( "\n" ); 79 80 for ( ; src < end; src++ ) { 81 char c = src[0]; 82 83 if (md->in_sms) { 84 if (c != 26) 85 goto AppendChar; 86 87 md->in_buff[ md->in_pos ] = c; 88 md->in_pos++; 89 md->in_sms = 0; 90 c = '\n'; 91 } 92 93 if (c == '\n' || c == '\r') { 94 const char* answer; 95 96 if (md->in_pos == 0) /* skip empty lines */ 97 continue; 98 99 md->in_buff[ md->in_pos ] = 0; 100 md->in_pos = 0; 101 102 D( "%s: << %s\n", __FUNCTION__, md->in_buff ); 103 answer = amodem_send(android_modem, md->in_buff); 104 if (answer != NULL) { 105 D( "%s: >> %s\n", __FUNCTION__, answer ); 106 len = strlen(answer); 107 if (len == 2 && answer[0] == '>' && answer[1] == ' ') 108 md->in_sms = 1; 109 110 qemu_chr_write(md->cs, (const uint8_t*)answer, len); 111 qemu_chr_write(md->cs, (const uint8_t*)"\r", 1); 112 } else 113 D( "%s: -- NO ANSWER\n", __FUNCTION__ ); 114 115 continue; 116 } 117 AppendChar: 118 md->in_buff[ md->in_pos++ ] = c; 119 if (md->in_pos == sizeof(md->in_buff)) { 120 /* input is too long !! */ 121 md->in_pos = 0; 122 } 123 } 124 D( "%s: done\n", __FUNCTION__ ); 125} 126 127 128static void 129modem_driver_init( int base_port, ModemDriver* dm, CharDriverState* cs ) 130{ 131 dm->cs = cs; 132 dm->in_pos = 0; 133 dm->in_sms = 0; 134 dm->modem = amodem_create( base_port, modem_driver_unsol, dm ); 135 136 qemu_chr_add_handlers( cs, modem_driver_can_read, modem_driver_read, NULL, dm ); 137} 138 139 140void android_modem_init( int base_port ) 141{ 142 static ModemDriver modem_driver[1]; 143 144 if (android_modem_cs != NULL) { 145 modem_driver_init( base_port, modem_driver, android_modem_cs ); 146 android_modem = modem_driver->modem; 147 } 148} 149