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 "sysemu/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 28 AModem android_modem; 29 CharDriverState* android_modem_cs; 30 31 typedef 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 */ 40 static void 41 modem_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 49 static int 50 modem_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 */ 59 static void 60 modem_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 128 static void 129 modem_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 140 void 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