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