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 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 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 139 RemoteHWInterface::Initialize() 140 { 141 return fInitStatus; 142 } 143 144 145 status_t 146 RemoteHWInterface::Shutdown() 147 { 148 _Disconnect(); 149 return B_OK; 150 } 151 152 153 DrawingEngine* 154 RemoteHWInterface::CreateDrawingEngine() 155 { 156 return new(std::nothrow) RemoteDrawingEngine(this); 157 } 158 159 160 EventStream* 161 RemoteHWInterface::CreateEventStream() 162 { 163 return fEventStream.Get(); 164 } 165 166 167 status_t 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 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* 203 RemoteHWInterface::_FindCallback(uint32 token) 204 { 205 BAutolock lock(fCallbackLocker); 206 return fCallbacks.BinarySearchByKey(token, &_CallbackCompare); 207 } 208 209 210 int 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 225 RemoteHWInterface::_EventThreadEntry(void* data) 226 { 227 return ((RemoteHWInterface*)data)->_EventThread(); 228 } 229 230 231 status_t 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 320 RemoteHWInterface::_NewConnectionCallback(void *cookie, BNetEndpoint &endpoint) 321 { 322 return ((RemoteHWInterface *)cookie)->_NewConnection(endpoint); 323 } 324 325 326 status_t 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 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 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 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 387 RemoteHWInterface::GetPreferredMode(display_mode* mode) 388 { 389 *mode = fClientMode; 390 return B_OK; 391 } 392 393 394 status_t 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 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 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 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 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 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 466 RemoteHWInterface::SetDPMSMode(uint32 state) 467 { 468 return B_UNSUPPORTED; 469 } 470 471 472 uint32 473 RemoteHWInterface::DPMSMode() 474 { 475 return B_UNSUPPORTED; 476 } 477 478 479 uint32 480 RemoteHWInterface::DPMSCapabilities() 481 { 482 return 0; 483 } 484 485 486 status_t 487 RemoteHWInterface::SetBrightness(float) 488 { 489 return B_UNSUPPORTED; 490 } 491 492 493 status_t 494 RemoteHWInterface::GetBrightness(float*) 495 { 496 return B_UNSUPPORTED; 497 } 498 499 500 sem_id 501 RemoteHWInterface::RetraceSemaphore() 502 { 503 return -1; 504 } 505 506 507 status_t 508 RemoteHWInterface::WaitForRetrace(bigtime_t timeout) 509 { 510 return B_UNSUPPORTED; 511 } 512 513 514 void 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 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 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 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* 557 RemoteHWInterface::FrontBuffer() const 558 { 559 return NULL; 560 } 561 562 563 RenderingBuffer* 564 RemoteHWInterface::BackBuffer() const 565 { 566 return NULL; 567 } 568 569 570 bool 571 RemoteHWInterface::IsDoubleBuffered() const 572 { 573 return false; 574 } 575 576 577 status_t 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 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 598 RemoteHWInterface::CopyBackToFront(const BRect& frame) 599 { 600 return B_OK; 601 } 602 603 604 void 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