1 /*
2 * Copyright 2009, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Michael Lotz <mmlr@mlotz.ch>
7 */
8
9 #include "RemoteHWInterface.h"
10 #include "RemoteDrawingEngine.h"
11 #include "RemoteEventStream.h"
12 #include "RemoteMessage.h"
13
14 #include "NetReceiver.h"
15 #include "NetSender.h"
16 #include "StreamingRingBuffer.h"
17
18 #include "SystemPalette.h"
19
20 #include <Autolock.h>
21 #include <NetEndpoint.h>
22
23 #include <new>
24 #include <string.h>
25
26
27 #define TRACE(x...) /*debug_printf("RemoteHWInterface: " x)*/
28 #define TRACE_ALWAYS(x...) debug_printf("RemoteHWInterface: " x)
29 #define TRACE_ERROR(x...) debug_printf("RemoteHWInterface: " x)
30
31
32 struct callback_info {
33 uint32 token;
34 RemoteHWInterface::CallbackFunction callback;
35 void* cookie;
36 };
37
38
RemoteHWInterface(const char * target)39 RemoteHWInterface::RemoteHWInterface(const char* target)
40 :
41 HWInterface(),
42 fTarget(target),
43 fIsConnected(false),
44 fProtocolVersion(100),
45 fConnectionSpeed(0),
46 fListenPort(10901),
47 fListenEndpoint(NULL),
48 fSendBuffer(NULL),
49 fReceiveBuffer(NULL),
50 fSender(NULL),
51 fReceiver(NULL),
52 fEventThread(-1),
53 fEventStream(NULL),
54 fCallbackLocker("callback locker")
55 {
56 memset(&fFallbackMode, 0, sizeof(fFallbackMode));
57 fFallbackMode.virtual_width = 640;
58 fFallbackMode.virtual_height = 480;
59 fFallbackMode.space = B_RGB32;
60 _FillDisplayModeTiming(fFallbackMode);
61
62 fCurrentMode = fClientMode = fFallbackMode;
63
64 if (sscanf(fTarget, "%" B_SCNu16, &fListenPort) != 1) {
65 fInitStatus = B_BAD_VALUE;
66 return;
67 }
68
69 fListenEndpoint.SetTo(new(std::nothrow) BNetEndpoint());
70 if (!fListenEndpoint.IsSet()) {
71 fInitStatus = B_NO_MEMORY;
72 return;
73 }
74
75 fInitStatus = fListenEndpoint->Bind(fListenPort);
76 if (fInitStatus != B_OK)
77 return;
78
79 fSendBuffer.SetTo(new(std::nothrow) StreamingRingBuffer(16 * 1024));
80 if (!fSendBuffer.IsSet()) {
81 fInitStatus = B_NO_MEMORY;
82 return;
83 }
84
85 fInitStatus = fSendBuffer->InitCheck();
86 if (fInitStatus != B_OK)
87 return;
88
89 fReceiveBuffer.SetTo(new(std::nothrow) StreamingRingBuffer(16 * 1024));
90 if (!fReceiveBuffer.IsSet()) {
91 fInitStatus = B_NO_MEMORY;
92 return;
93 }
94
95 fInitStatus = fReceiveBuffer->InitCheck();
96 if (fInitStatus != B_OK)
97 return;
98
99 fReceiver.SetTo(new(std::nothrow) NetReceiver(fListenEndpoint.Get(), fReceiveBuffer.Get(),
100 _NewConnectionCallback, this));
101 if (!fReceiver.IsSet()) {
102 fInitStatus = B_NO_MEMORY;
103 return;
104 }
105
106 fEventStream.SetTo(new(std::nothrow) RemoteEventStream());
107 if (!fEventStream.IsSet()) {
108 fInitStatus = B_NO_MEMORY;
109 return;
110 }
111
112 fEventThread = spawn_thread(_EventThreadEntry, "remote event thread",
113 B_NORMAL_PRIORITY, this);
114 if (fEventThread < 0) {
115 fInitStatus = fEventThread;
116 return;
117 }
118
119 resume_thread(fEventThread);
120 }
121
122
~RemoteHWInterface()123 RemoteHWInterface::~RemoteHWInterface()
124 {
125 //TODO: check order
126 fReceiver.Unset();
127 fReceiveBuffer.Unset();
128
129 fSendBuffer.Unset();
130 fSender.Unset();
131
132 fListenEndpoint.Unset();
133
134 fEventStream.Unset();
135 }
136
137
138 status_t
Initialize()139 RemoteHWInterface::Initialize()
140 {
141 return fInitStatus;
142 }
143
144
145 status_t
Shutdown()146 RemoteHWInterface::Shutdown()
147 {
148 _Disconnect();
149 return B_OK;
150 }
151
152
153 DrawingEngine*
CreateDrawingEngine()154 RemoteHWInterface::CreateDrawingEngine()
155 {
156 return new(std::nothrow) RemoteDrawingEngine(this);
157 }
158
159
160 EventStream*
CreateEventStream()161 RemoteHWInterface::CreateEventStream()
162 {
163 return fEventStream.Get();
164 }
165
166
167 status_t
AddCallback(uint32 token,CallbackFunction callback,void * cookie)168 RemoteHWInterface::AddCallback(uint32 token, CallbackFunction callback,
169 void* cookie)
170 {
171 BAutolock lock(fCallbackLocker);
172 int32 index = fCallbacks.BinarySearchIndexByKey(token, &_CallbackCompare);
173 if (index >= 0)
174 return B_NAME_IN_USE;
175
176 callback_info* info = new(std::nothrow) callback_info;
177 if (info == NULL)
178 return B_NO_MEMORY;
179
180 info->token = token;
181 info->callback = callback;
182 info->cookie = cookie;
183
184 fCallbacks.AddItem(info, -index - 1);
185 return B_OK;
186 }
187
188
189 bool
RemoveCallback(uint32 token)190 RemoteHWInterface::RemoveCallback(uint32 token)
191 {
192 BAutolock lock(fCallbackLocker);
193 int32 index = fCallbacks.BinarySearchIndexByKey(token, &_CallbackCompare);
194 if (index < 0)
195 return false;
196
197 delete fCallbacks.RemoveItemAt(index);
198 return true;
199 }
200
201
202 callback_info*
_FindCallback(uint32 token)203 RemoteHWInterface::_FindCallback(uint32 token)
204 {
205 BAutolock lock(fCallbackLocker);
206 return fCallbacks.BinarySearchByKey(token, &_CallbackCompare);
207 }
208
209
210 int
_CallbackCompare(const uint32 * key,const callback_info * info)211 RemoteHWInterface::_CallbackCompare(const uint32* key,
212 const callback_info* info)
213 {
214 if (info->token == *key)
215 return 0;
216
217 if (info->token < *key)
218 return -1;
219
220 return 1;
221 }
222
223
224 int32
_EventThreadEntry(void * data)225 RemoteHWInterface::_EventThreadEntry(void* data)
226 {
227 return ((RemoteHWInterface*)data)->_EventThread();
228 }
229
230
231 status_t
_EventThread()232 RemoteHWInterface::_EventThread()
233 {
234 RemoteMessage message(fReceiveBuffer.Get(), NULL);
235 while (true) {
236 uint16 code;
237 status_t result = message.NextMessage(code);
238 if (result != B_OK) {
239 TRACE_ERROR("failed to read message from receiver: %s\n",
240 strerror(result));
241 return result;
242 }
243
244 TRACE("got message code %" B_PRIu16 " with %" B_PRIu32 " bytes\n", code,
245 message.DataLeft());
246
247 if (code >= RP_MOUSE_MOVED && code <= RP_MODIFIERS_CHANGED) {
248 // an input event, dispatch to the event stream
249 if (fEventStream->EventReceived(message))
250 continue;
251 }
252
253 switch (code) {
254 case RP_INIT_CONNECTION:
255 {
256 RemoteMessage reply(NULL, fSendBuffer.Get());
257 reply.Start(RP_INIT_CONNECTION);
258 status_t result = reply.Flush();
259 (void)result;
260 TRACE("init connection result: %s\n", strerror(result));
261 break;
262 }
263
264 case RP_UPDATE_DISPLAY_MODE:
265 {
266 int32 width, height;
267 message.Read(width);
268 result = message.Read(height);
269 if (result != B_OK) {
270 TRACE_ERROR("failed to read display mode\n");
271 break;
272 }
273
274 fIsConnected = true;
275 fClientMode.virtual_width = width;
276 fClientMode.virtual_height = height;
277 _FillDisplayModeTiming(fClientMode);
278 _NotifyScreenChanged();
279 break;
280 }
281
282 case RP_GET_SYSTEM_PALETTE:
283 {
284 RemoteMessage reply(NULL, fSendBuffer.Get());
285 reply.Start(RP_GET_SYSTEM_PALETTE_RESULT);
286
287 const color_map *map = SystemColorMap();
288 uint32 count = (uint32)B_COUNT_OF(map->color_list);
289
290 reply.Add(count);
291 for (size_t i = 0; i < count; i++) {
292 const rgb_color &color = map->color_list[i];
293 reply.Add(color.red);
294 reply.Add(color.green);
295 reply.Add(color.blue);
296 reply.Add(color.alpha);
297 }
298
299 break;
300 }
301
302 default:
303 {
304 uint32 token;
305 if (message.Read(token) == B_OK) {
306 callback_info* info = _FindCallback(token);
307 if (info != NULL && info->callback(info->cookie, message))
308 break;
309 }
310
311 TRACE_ERROR("unhandled remote event code %u\n", code);
312 break;
313 }
314 }
315 }
316 }
317
318
319 status_t
_NewConnectionCallback(void * cookie,BNetEndpoint & endpoint)320 RemoteHWInterface::_NewConnectionCallback(void *cookie, BNetEndpoint &endpoint)
321 {
322 return ((RemoteHWInterface *)cookie)->_NewConnection(endpoint);
323 }
324
325
326 status_t
_NewConnection(BNetEndpoint & endpoint)327 RemoteHWInterface::_NewConnection(BNetEndpoint &endpoint)
328 {
329 fSender.Unset();
330
331 fSendBuffer->MakeEmpty();
332
333 BNetEndpoint *sendEndpoint = new(std::nothrow) BNetEndpoint(endpoint);
334 if (sendEndpoint == NULL)
335 return B_NO_MEMORY;
336
337 fSender.SetTo(new(std::nothrow) NetSender(sendEndpoint, fSendBuffer.Get()));
338 if (!fSender.IsSet()) {
339 delete sendEndpoint;
340 return B_NO_MEMORY;
341 }
342
343 return B_OK;
344 }
345
346
347 void
_Disconnect()348 RemoteHWInterface::_Disconnect()
349 {
350 if (fIsConnected) {
351 RemoteMessage message(NULL, fSendBuffer.Get());
352 message.Start(RP_CLOSE_CONNECTION);
353 message.Flush();
354 fIsConnected = false;
355 }
356
357 if (fListenEndpoint.IsSet())
358 fListenEndpoint->Close();
359 }
360
361
362 status_t
SetMode(const display_mode & mode)363 RemoteHWInterface::SetMode(const display_mode& mode)
364 {
365 TRACE("set mode: %" B_PRIu16 " %" B_PRIu16 "\n", mode.virtual_width,
366 mode.virtual_height);
367 fCurrentMode = mode;
368 return B_OK;
369 }
370
371
372 void
GetMode(display_mode * mode)373 RemoteHWInterface::GetMode(display_mode* mode)
374 {
375 if (mode == NULL || !ReadLock())
376 return;
377
378 *mode = fCurrentMode;
379 ReadUnlock();
380
381 TRACE("get mode: %" B_PRIu16 " %" B_PRIu16 "\n", mode->virtual_width,
382 mode->virtual_height);
383 }
384
385
386 status_t
GetPreferredMode(display_mode * mode)387 RemoteHWInterface::GetPreferredMode(display_mode* mode)
388 {
389 *mode = fClientMode;
390 return B_OK;
391 }
392
393
394 status_t
GetDeviceInfo(accelerant_device_info * info)395 RemoteHWInterface::GetDeviceInfo(accelerant_device_info* info)
396 {
397 if (!ReadLock())
398 return B_ERROR;
399
400 info->version = fProtocolVersion;
401 info->dac_speed = fConnectionSpeed;
402 info->memory = 33554432; // 32MB
403 strlcpy(info->name, "Haiku, Inc. RemoteHWInterface", sizeof(info->name));
404 strlcpy(info->chipset, "Haiku, Inc. Chipset", sizeof(info->chipset));
405 strlcpy(info->serial_no, fTarget, sizeof(info->serial_no));
406
407 ReadUnlock();
408 return B_OK;
409 }
410
411
412 status_t
GetFrameBufferConfig(frame_buffer_config & config)413 RemoteHWInterface::GetFrameBufferConfig(frame_buffer_config& config)
414 {
415 // We don't actually have a frame buffer.
416 return B_UNSUPPORTED;
417 }
418
419
420 status_t
GetModeList(display_mode ** _modes,uint32 * _count)421 RemoteHWInterface::GetModeList(display_mode** _modes, uint32* _count)
422 {
423 AutoReadLocker _(this);
424
425 display_mode* modes = new(std::nothrow) display_mode[2];
426 if (modes == NULL)
427 return B_NO_MEMORY;
428
429 modes[0] = fFallbackMode;
430 modes[1] = fClientMode;
431 *_modes = modes;
432 *_count = 2;
433
434 return B_OK;
435 }
436
437
438 status_t
GetPixelClockLimits(display_mode * mode,uint32 * low,uint32 * high)439 RemoteHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low,
440 uint32* high)
441 {
442 TRACE("get pixel clock limits unsupported\n");
443 return B_UNSUPPORTED;
444 }
445
446
447 status_t
GetTimingConstraints(display_timing_constraints * constraints)448 RemoteHWInterface::GetTimingConstraints(display_timing_constraints* constraints)
449 {
450 TRACE("get timing constraints unsupported\n");
451 return B_UNSUPPORTED;
452 }
453
454
455 status_t
ProposeMode(display_mode * candidate,const display_mode * low,const display_mode * high)456 RemoteHWInterface::ProposeMode(display_mode* candidate, const display_mode* low,
457 const display_mode* high)
458 {
459 TRACE("propose mode: %" B_PRIu16 " %" B_PRIu16 "\n",
460 candidate->virtual_width, candidate->virtual_height);
461 return B_OK;
462 }
463
464
465 status_t
SetDPMSMode(uint32 state)466 RemoteHWInterface::SetDPMSMode(uint32 state)
467 {
468 return B_UNSUPPORTED;
469 }
470
471
472 uint32
DPMSMode()473 RemoteHWInterface::DPMSMode()
474 {
475 return B_UNSUPPORTED;
476 }
477
478
479 uint32
DPMSCapabilities()480 RemoteHWInterface::DPMSCapabilities()
481 {
482 return 0;
483 }
484
485
486 status_t
SetBrightness(float)487 RemoteHWInterface::SetBrightness(float)
488 {
489 return B_UNSUPPORTED;
490 }
491
492
493 status_t
GetBrightness(float *)494 RemoteHWInterface::GetBrightness(float*)
495 {
496 return B_UNSUPPORTED;
497 }
498
499
500 sem_id
RetraceSemaphore()501 RemoteHWInterface::RetraceSemaphore()
502 {
503 return -1;
504 }
505
506
507 status_t
WaitForRetrace(bigtime_t timeout)508 RemoteHWInterface::WaitForRetrace(bigtime_t timeout)
509 {
510 return B_UNSUPPORTED;
511 }
512
513
514 void
SetCursor(ServerCursor * cursor)515 RemoteHWInterface::SetCursor(ServerCursor* cursor)
516 {
517 HWInterface::SetCursor(cursor);
518 RemoteMessage message(NULL, fSendBuffer.Get());
519 message.Start(RP_SET_CURSOR);
520 message.AddCursor(CursorAndDragBitmap().Get());
521 }
522
523
524 void
SetCursorVisible(bool visible)525 RemoteHWInterface::SetCursorVisible(bool visible)
526 {
527 HWInterface::SetCursorVisible(visible);
528 RemoteMessage message(NULL, fSendBuffer.Get());
529 message.Start(RP_SET_CURSOR_VISIBLE);
530 message.Add(visible);
531 }
532
533
534 void
MoveCursorTo(float x,float y)535 RemoteHWInterface::MoveCursorTo(float x, float y)
536 {
537 HWInterface::MoveCursorTo(x, y);
538 RemoteMessage message(NULL, fSendBuffer.Get());
539 message.Start(RP_MOVE_CURSOR_TO);
540 message.Add(x);
541 message.Add(y);
542 }
543
544
545 void
SetDragBitmap(const ServerBitmap * bitmap,const BPoint & offsetFromCursor)546 RemoteHWInterface::SetDragBitmap(const ServerBitmap* bitmap,
547 const BPoint& offsetFromCursor)
548 {
549 HWInterface::SetDragBitmap(bitmap, offsetFromCursor);
550 RemoteMessage message(NULL, fSendBuffer.Get());
551 message.Start(RP_SET_CURSOR);
552 message.AddCursor(CursorAndDragBitmap().Get());
553 }
554
555
556 RenderingBuffer*
FrontBuffer() const557 RemoteHWInterface::FrontBuffer() const
558 {
559 return NULL;
560 }
561
562
563 RenderingBuffer*
BackBuffer() const564 RemoteHWInterface::BackBuffer() const
565 {
566 return NULL;
567 }
568
569
570 bool
IsDoubleBuffered() const571 RemoteHWInterface::IsDoubleBuffered() const
572 {
573 return false;
574 }
575
576
577 status_t
InvalidateRegion(const BRegion & region)578 RemoteHWInterface::InvalidateRegion(const BRegion& region)
579 {
580 RemoteMessage message(NULL, fSendBuffer.Get());
581 message.Start(RP_INVALIDATE_REGION);
582 message.AddRegion(region);
583 return B_OK;
584 }
585
586
587 status_t
Invalidate(const BRect & frame)588 RemoteHWInterface::Invalidate(const BRect& frame)
589 {
590 RemoteMessage message(NULL, fSendBuffer.Get());
591 message.Start(RP_INVALIDATE_RECT);
592 message.Add(frame);
593 return B_OK;
594 }
595
596
597 status_t
CopyBackToFront(const BRect & frame)598 RemoteHWInterface::CopyBackToFront(const BRect& frame)
599 {
600 return B_OK;
601 }
602
603
604 void
_FillDisplayModeTiming(display_mode & mode)605 RemoteHWInterface::_FillDisplayModeTiming(display_mode &mode)
606 {
607 mode.timing.pixel_clock
608 = (uint64_t)mode.virtual_width * mode.virtual_height * 60 / 1000;
609 mode.timing.h_display = mode.timing.h_sync_start = mode.timing.h_sync_end
610 = mode.timing.h_total = mode.virtual_width;
611 mode.timing.v_display = mode.timing.v_sync_start = mode.timing.v_sync_end
612 = mode.timing.v_total = mode.virtual_height;
613 }
614