blob: 0402df0cc4871dc64fef4e8477ec996ac1375caf [file] [log] [blame]
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -08001/* Copyright (C) 2010 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
13/*
14 * Contains UI-side framebuffer client that receives framebuffer updates
15 * from the core.
16 */
17
18#include "android/framebuffer-common.h"
19#include "android/framebuffer-ui.h"
20#include "android/utils/system.h"
21#include "android/utils/debug.h"
22
23#define PANIC(...) do { fprintf(stderr, __VA_ARGS__); \
24 exit(1); \
25 } while (0)
26
27/*
28 * Enumerates states for the client framebuffer update reader.
29 */
30typedef enum ClientFBState {
31 /* The reader is waiting on update header. */
32 WAIT_HEADER,
33
34 /* The reader is waiting on pixels. */
35 WAIT_PIXELS,
36} ClientFBState;
37
38/*
39 * Descriptor for the framebuffer client.
40 */
41struct ClientFramebuffer {
42 /* Core connection instance for the framebuffer client. */
43 CoreConnection* core_connection;
44
45 /* Current update header. */
46 FBUpdateMessage update_header;
47
48 /* Reader's buffer. */
49 uint8_t* reader_buffer;
50
51 /* Offset in the reader's buffer where to read next chunk of data. */
52 size_t reader_offset;
53
54 /* Total number of bytes the reader expects to read. */
55 size_t reader_bytes;
56
57 /* Current state of the update reader. */
58 ClientFBState fb_state;
59
60 /* Socket descriptor for the framebuffer client. */
61 int sock;
62};
63
64/* The only instance of framebuffer client. */
65static ClientFramebuffer _client_fb;
66
67/*
68 * Updates a desplay rectangle.
69 * Param
70 * x, y, w, and h define rectangle to update.
71 * bits_per_pixel define number of bits used to encode a single pixel.
72 * pixels contains pixels for the rectangle. Buffer addressed by this parameter
73 * must be eventually freed with free()
74 */
75void
76update_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h,
77 uint8_t bits_per_pixel, uint8_t* pixels)
78{
79 // TODO: Do the actual update!
80 printf("Update rectangle (%d bytes): %d:%d %d:%d\n",
81 w * h * (bits_per_pixel / 8), x, y, w, h);
82 free(pixels);
83}
84
85/*
86 * Asynchronous I/O callback launched when framebuffer notifications are ready
87 * to be read.
88 * Param:
89 * opaque - ClientFramebuffer instance.
90 */
91static void
92_clientfb_read_cb(void* opaque)
93{
94 ClientFramebuffer* fb_client = opaque;
95 int ret;
96
97 // Read updates while they are immediately available.
98 for (;;) {
99 // Read next chunk of data.
100 ret = read(fb_client->sock, fb_client->reader_buffer + fb_client->reader_offset,
101 fb_client->reader_bytes - fb_client->reader_offset);
102 if (ret == 0) {
103 /* disconnection ! */
104 clientfb_destroy(fb_client);
105 return;
106 }
107 if (ret < 0) {
108 if (errno == EINTR) {
109 /* loop on EINTR */
110 continue;
111 } else if (errno == EWOULDBLOCK || errno == EAGAIN) {
112 // Chunk is not avalable at this point. Come back later.
113 return;
114 }
115 }
116
117 fb_client->reader_offset += ret;
118 if (fb_client->reader_offset != fb_client->reader_bytes) {
119 // There are still some data left in the pipe.
120 continue;
121 }
122
123 // All expected data has been read. Time to change the state.
124 if (fb_client->fb_state == WAIT_HEADER) {
125 // Update header has been read. Prepare for the pixels.
126 fb_client->fb_state = WAIT_PIXELS;
127 fb_client->reader_offset = 0;
128 fb_client->reader_bytes = fb_client->update_header.w *
129 fb_client->update_header.h *
130 (fb_client->update_header.bits_per_pixel / 8);
131 fb_client->reader_buffer = malloc(fb_client->reader_bytes);
132 if (fb_client->reader_buffer == NULL) {
133 PANIC("Unable to allocate memory for framebuffer update\n");
134 }
135 } else {
136 // Pixels have been read. Prepare for the header.
137 uint8_t* pixels = fb_client->reader_buffer;
138
139 fb_client->fb_state = WAIT_HEADER;
140 fb_client->reader_offset = 0;
141 fb_client->reader_bytes = sizeof(FBUpdateMessage);
142 fb_client->reader_buffer = (uint8_t*)&fb_client->update_header;
143
144 // Perform the update. Note that pixels buffer must be freed there.
145 update_rect(fb_client->update_header.x, fb_client->update_header.y,
146 fb_client->update_header.w, fb_client->update_header.h,
147 fb_client->update_header.bits_per_pixel, pixels);
148 }
149 }
150}
151
152ClientFramebuffer*
153clientfb_create(SockAddress* console_socket, const char* protocol)
154{
155 char* connect_message = NULL;
156 char switch_cmd[256];
157
158 // Connect to the framebuffer service.
159 _client_fb.core_connection = core_connection_create(console_socket);
160 if (_client_fb.core_connection == NULL) {
161 derror("Framebuffer client is unable to connect to the console: %s\n",
162 errno_str);
163 return NULL;
164 }
165 if (core_connection_open(_client_fb.core_connection)) {
166 core_connection_free(_client_fb.core_connection);
167 _client_fb.core_connection = NULL;
168 derror("Framebuffer client is unable to ioen the console: %s\n",
169 errno_str);
170 return NULL;
171 }
172 snprintf(switch_cmd, sizeof(switch_cmd), "framebuffer %s", protocol);
173 if (core_connection_switch_stream(_client_fb.core_connection, switch_cmd,
174 &connect_message)) {
175 derror("Unable to attach to the framebuffer %s: %s\n",
176 switch_cmd, connect_message ? connect_message : "");
177 if (connect_message != NULL) {
178 free(connect_message);
179 }
180 core_connection_close(_client_fb.core_connection);
181 core_connection_free(_client_fb.core_connection);
182 _client_fb.core_connection = NULL;
183 return NULL;
184 }
185 if (connect_message != NULL) {
186 free(connect_message);
187 }
188
189 // Now that we're connected lets initialize the descriptor.
190 _client_fb.sock = core_connection_get_socket(_client_fb.core_connection);
191 _client_fb.fb_state = WAIT_HEADER;
192 _client_fb.reader_buffer = (uint8_t*)&_client_fb.update_header;
193 _client_fb.reader_offset = 0;
194 _client_fb.reader_bytes = sizeof(FBUpdateMessage);
195
196 // At last setup read callback, and start receiving the updates.
197 if (qemu_set_fd_handler(_client_fb.sock, _clientfb_read_cb, NULL, &_client_fb)) {
198 derror("Unable to set up framebuffer read callback\n");
199 core_connection_close(_client_fb.core_connection);
200 core_connection_free(_client_fb.core_connection);
201 _client_fb.core_connection = NULL;
202 return NULL;
203 }
204
205 fprintf(stdout, "Framebuffer %s is now attached to the core %s\n",
206 protocol, sock_address_to_string(console_socket));
207
208 return &_client_fb;
209}
210
211void
212clientfb_destroy(ClientFramebuffer* client_fb)
213{
214 if (client_fb != NULL && client_fb->core_connection != NULL) {
215 // Disable the reader callback.
216 qemu_set_fd_handler(client_fb->sock, NULL, NULL, NULL);
217
218 // Close framebuffer connection.
219 core_connection_close(client_fb->core_connection);
220 core_connection_free(client_fb->core_connection);
221 client_fb->core_connection = NULL;
222 }
223}