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 32struct callback_info { 33 uint32 token; 34 RemoteHWInterface::CallbackFunction callback; 35 void* cookie; 36}; 37 38 39RemoteHWInterface::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 123RemoteHWInterface::~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 138status_t 139RemoteHWInterface::Initialize() 140{ 141 return fInitStatus; 142} 143 144 145status_t 146RemoteHWInterface::Shutdown() 147{ 148 _Disconnect(); 149 return B_OK; 150} 151 152 153DrawingEngine* 154RemoteHWInterface::CreateDrawingEngine() 155{ 156 return new(std::nothrow) RemoteDrawingEngine(this); 157} 158 159 160EventStream* 161RemoteHWInterface::CreateEventStream() 162{ 163 return fEventStream.Get(); 164} 165 166 167status_t 168RemoteHWInterface::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 189bool 190RemoteHWInterface::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 202callback_info* 203RemoteHWInterface::_FindCallback(uint32 token) 204{ 205 BAutolock lock(fCallbackLocker); 206 return fCallbacks.BinarySearchByKey(token, &_CallbackCompare); 207} 208 209 210int 211RemoteHWInterface::_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 224int32 225RemoteHWInterface::_EventThreadEntry(void* data) 226{ 227 return ((RemoteHWInterface*)data)->_EventThread(); 228} 229 230 231status_t 232RemoteHWInterface::_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 319status_t 320RemoteHWInterface::_NewConnectionCallback(void *cookie, BNetEndpoint &endpoint) 321{ 322 return ((RemoteHWInterface *)cookie)->_NewConnection(endpoint); 323} 324 325 326status_t 327RemoteHWInterface::_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 347void 348RemoteHWInterface::_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 362status_t 363RemoteHWInterface::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 372void 373RemoteHWInterface::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 386status_t 387RemoteHWInterface::GetPreferredMode(display_mode* mode) 388{ 389 *mode = fClientMode; 390 return B_OK; 391} 392 393 394status_t 395RemoteHWInterface::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 412status_t 413RemoteHWInterface::GetFrameBufferConfig(frame_buffer_config& config) 414{ 415 // We don't actually have a frame buffer. 416 return B_UNSUPPORTED; 417} 418 419 420status_t 421RemoteHWInterface::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 438status_t 439RemoteHWInterface::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 447status_t 448RemoteHWInterface::GetTimingConstraints(display_timing_constraints* constraints) 449{ 450 TRACE("get timing constraints unsupported\n"); 451 return B_UNSUPPORTED; 452} 453 454 455status_t 456RemoteHWInterface::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 465status_t 466RemoteHWInterface::SetDPMSMode(uint32 state) 467{ 468 return B_UNSUPPORTED; 469} 470 471 472uint32 473RemoteHWInterface::DPMSMode() 474{ 475 return B_UNSUPPORTED; 476} 477 478 479uint32 480RemoteHWInterface::DPMSCapabilities() 481{ 482 return 0; 483} 484 485 486status_t 487RemoteHWInterface::SetBrightness(float) 488{ 489 return B_UNSUPPORTED; 490} 491 492 493status_t 494RemoteHWInterface::GetBrightness(float*) 495{ 496 return B_UNSUPPORTED; 497} 498 499 500sem_id 501RemoteHWInterface::RetraceSemaphore() 502{ 503 return -1; 504} 505 506 507status_t 508RemoteHWInterface::WaitForRetrace(bigtime_t timeout) 509{ 510 return B_UNSUPPORTED; 511} 512 513 514void 515RemoteHWInterface::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 524void 525RemoteHWInterface::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 534void 535RemoteHWInterface::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 545void 546RemoteHWInterface::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 556RenderingBuffer* 557RemoteHWInterface::FrontBuffer() const 558{ 559 return NULL; 560} 561 562 563RenderingBuffer* 564RemoteHWInterface::BackBuffer() const 565{ 566 return NULL; 567} 568 569 570bool 571RemoteHWInterface::IsDoubleBuffered() const 572{ 573 return false; 574} 575 576 577status_t 578RemoteHWInterface::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 587status_t 588RemoteHWInterface::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 597status_t 598RemoteHWInterface::CopyBackToFront(const BRect& frame) 599{ 600 return B_OK; 601} 602 603 604void 605RemoteHWInterface::_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