2012-05-01 20:43:55 -04:00
|
|
|
/*******************************************************************************
|
|
|
|
|
2015-03-19 09:27:28 -04:00
|
|
|
Copyright(C) Jonas 'Sortie' Termansen 2012, 2014, 2015.
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2013-07-10 09:26:01 -04:00
|
|
|
This file is part of Sortix.
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2013-07-10 09:26:01 -04:00
|
|
|
Sortix is free software: you can redistribute it and/or modify it under the
|
|
|
|
terms of the GNU General Public License as published by the Free Software
|
|
|
|
Foundation, either version 3 of the License, or (at your option) any later
|
|
|
|
version.
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2013-07-10 09:26:01 -04:00
|
|
|
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
details.
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2013-07-10 09:26:01 -04:00
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
|
|
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2013-07-10 09:26:01 -04:00
|
|
|
video.cpp
|
|
|
|
Framework for Sortix video drivers.
|
2012-05-01 20:43:55 -04:00
|
|
|
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
2012-09-22 10:44:50 -04:00
|
|
|
#include <errno.h>
|
2012-09-22 14:38:34 -04:00
|
|
|
#include <string.h>
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
#include <sortix/kernel/copy.h>
|
2013-10-26 20:42:10 -04:00
|
|
|
#include <sortix/kernel/kernel.h>
|
|
|
|
#include <sortix/kernel/kthread.h>
|
2015-03-19 19:08:08 -04:00
|
|
|
#include <sortix/kernel/log.h>
|
2013-10-26 20:42:10 -04:00
|
|
|
#include <sortix/kernel/string.h>
|
2014-03-25 15:28:51 -04:00
|
|
|
#include <sortix/kernel/syscall.h>
|
2013-10-26 20:42:10 -04:00
|
|
|
#include <sortix/kernel/textbuffer.h>
|
|
|
|
#include <sortix/kernel/video.h>
|
|
|
|
|
2012-05-01 20:43:55 -04:00
|
|
|
namespace Sortix {
|
|
|
|
namespace Video {
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
const uint64_t ONE_AND_ONLY_DEVICE = 0;
|
|
|
|
const uint64_t ONE_AND_ONLY_CONNECTOR = 0;
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
kthread_mutex_t video_lock = KTHREAD_MUTEX_INITIALIZER;
|
|
|
|
|
|
|
|
struct DeviceEntry
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
|
|
|
char* name;
|
2014-03-25 15:28:51 -04:00
|
|
|
VideoDevice* device;
|
2012-05-01 20:43:55 -04:00
|
|
|
};
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
size_t num_devices = 0;
|
|
|
|
size_t devices_length = 0;
|
|
|
|
DeviceEntry* devices = NULL;
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
bool RegisterDevice(const char* name, VideoDevice* device)
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
ScopedLock lock(&video_lock);
|
|
|
|
if ( num_devices == devices_length )
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
size_t newdevices_length = devices_length ? 2 * devices_length : 8UL;
|
|
|
|
DeviceEntry* newdevices = new DeviceEntry[newdevices_length];
|
|
|
|
if ( !newdevices )
|
|
|
|
return false;
|
2015-11-21 18:40:12 -05:00
|
|
|
if ( devices )
|
|
|
|
{
|
|
|
|
memcpy(newdevices, devices, sizeof(*devices) * num_devices);
|
|
|
|
delete[] devices;
|
|
|
|
}
|
|
|
|
devices = newdevices;
|
2014-03-25 15:28:51 -04:00
|
|
|
devices_length = devices_length;
|
2012-05-01 20:43:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
char* drivername = String::Clone(name);
|
2014-03-25 15:28:51 -04:00
|
|
|
if ( !drivername )
|
|
|
|
return false;
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
size_t index = num_devices++;
|
|
|
|
devices[index].name = drivername;
|
|
|
|
devices[index].device = device;
|
2012-05-01 20:43:55 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
__attribute__((unused))
|
|
|
|
static bool TransmitString(struct dispmsg_string* dest, const char* str)
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
size_t size = strlen(str) + 1;
|
|
|
|
size_t dest_size = dest->byte_size;
|
|
|
|
dest->byte_size = size;
|
|
|
|
if ( dest_size < size )
|
|
|
|
return errno = ERANGE, false;
|
|
|
|
return CopyToUser(dest->str, str, size);
|
2012-05-01 20:43:55 -04:00
|
|
|
}
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
__attribute__((unused))
|
|
|
|
static char* ReceiveString(struct dispmsg_string* src)
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
if ( !src->byte_size )
|
|
|
|
return errno = EINVAL, (char*) NULL;
|
|
|
|
char* ret = new char[src->byte_size];
|
|
|
|
if ( !ret )
|
|
|
|
return NULL;
|
|
|
|
if ( !CopyFromUser(ret, src->str, src->byte_size) )
|
|
|
|
return NULL;
|
|
|
|
if ( ret[src->byte_size-1] != '\0' )
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
delete[] ret;
|
|
|
|
return errno = EINVAL, (char*) NULL;
|
2012-05-01 20:43:55 -04:00
|
|
|
}
|
2014-03-25 15:28:51 -04:00
|
|
|
return ret;
|
2012-05-01 20:43:55 -04:00
|
|
|
}
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
static int EnumerateDevices(void* ptr, size_t size)
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
struct dispmsg_enumerate_devices msg;
|
|
|
|
if ( size != sizeof(msg) )
|
|
|
|
return errno = EINVAL, -1;
|
|
|
|
if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
|
|
|
|
return -1;
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
ScopedLock lock(&video_lock);
|
|
|
|
|
|
|
|
size_t requested_num_devices = msg.devices_length;
|
|
|
|
msg.devices_length = num_devices;
|
|
|
|
|
|
|
|
if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if ( requested_num_devices < num_devices )
|
|
|
|
return errno = ERANGE, -1;
|
|
|
|
|
|
|
|
for ( uint64_t i = 0; i < num_devices; i++ )
|
|
|
|
if ( !CopyToUser(&msg.devices[i], &i, sizeof(i)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
2012-05-01 20:43:55 -04:00
|
|
|
}
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
static int GetDriverCount(void* ptr, size_t size)
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
struct dispmsg_get_driver_count msg;
|
|
|
|
if ( size != sizeof(msg) )
|
|
|
|
return errno = EINVAL, -1;
|
|
|
|
if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ScopedLock lock(&video_lock);
|
|
|
|
|
|
|
|
if ( num_devices <= msg.device )
|
|
|
|
return errno = ENODEV, -1;
|
|
|
|
|
|
|
|
msg.driver_count = 1;
|
|
|
|
|
|
|
|
if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
2012-05-01 20:43:55 -04:00
|
|
|
}
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
static int GetDriverName(void* ptr, size_t size)
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
struct dispmsg_get_driver_name msg;
|
|
|
|
if ( size != sizeof(msg) )
|
|
|
|
return errno = EINVAL, -1;
|
|
|
|
if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
|
|
|
|
return -1;
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
ScopedLock lock(&video_lock);
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
if ( num_devices <= msg.device )
|
|
|
|
return errno = ENODEV, -1;
|
|
|
|
|
|
|
|
DeviceEntry* device_entry = &devices[msg.device];
|
|
|
|
if ( !TransmitString(&msg.name, device_entry->name) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
2012-05-01 20:43:55 -04:00
|
|
|
}
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
static int GetDriver(void* ptr, size_t size)
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
struct dispmsg_get_driver msg;
|
|
|
|
if ( size != sizeof(msg) )
|
|
|
|
return errno = EINVAL, -1;
|
|
|
|
if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
|
|
|
|
return -1;
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
ScopedLock lock(&video_lock);
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
if ( num_devices <= msg.device )
|
|
|
|
return errno = ENODEV, -1;
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
msg.driver_index = 0;
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
|
|
|
|
return -1;
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
return 0;
|
|
|
|
}
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
static int SetDriver(void* ptr, size_t size)
|
|
|
|
{
|
|
|
|
struct dispmsg_set_driver msg;
|
|
|
|
if ( size != sizeof(msg) )
|
|
|
|
return errno = EINVAL, -1;
|
|
|
|
if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
|
|
|
|
return -1;
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
ScopedLock lock(&video_lock);
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
if ( num_devices <= msg.device )
|
|
|
|
return errno = ENODEV, -1;
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
if ( msg.driver_index != 0 )
|
|
|
|
return errno = EINVAL, -1;
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
|
|
|
|
return -1;
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
return 0;
|
|
|
|
}
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2015-03-19 19:08:08 -04:00
|
|
|
static struct dispmsg_crtc_mode GetLogFallbackMode()
|
|
|
|
{
|
|
|
|
struct dispmsg_crtc_mode mode;
|
|
|
|
memset(&mode, 0, sizeof(mode));
|
|
|
|
mode.control = DISPMSG_CONTROL_VALID;
|
|
|
|
mode.fb_format = Log::fallback_framebuffer_bpp;
|
|
|
|
mode.view_xres = (uint32_t) Log::fallback_framebuffer_width;
|
|
|
|
mode.view_yres = (uint32_t) Log::fallback_framebuffer_height;
|
|
|
|
mode.fb_location = 0;
|
|
|
|
mode.pitch = Log::fallback_framebuffer_width *
|
|
|
|
Log::fallback_framebuffer_bpp / 8;
|
|
|
|
return mode;
|
|
|
|
}
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
static int SetCrtcMode(void* ptr, size_t size)
|
|
|
|
{
|
|
|
|
struct dispmsg_set_crtc_mode msg;
|
|
|
|
if ( size != sizeof(msg) )
|
|
|
|
return errno = EINVAL, -1;
|
|
|
|
if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
|
|
|
|
return -1;
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
ScopedLock lock(&video_lock);
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2015-03-19 19:08:08 -04:00
|
|
|
if ( msg.device < num_devices )
|
|
|
|
{
|
|
|
|
DeviceEntry* device_entry = &devices[msg.device];
|
|
|
|
VideoDevice* device = device_entry->device;
|
|
|
|
if ( !device->SwitchMode(msg.connector, msg.mode) )
|
|
|
|
return -1;
|
|
|
|
// TODO: This could potentially fail.
|
|
|
|
if ( msg.device == ONE_AND_ONLY_DEVICE &&
|
|
|
|
msg.connector == ONE_AND_ONLY_CONNECTOR )
|
|
|
|
{
|
|
|
|
Log::fallback_framebuffer = NULL;
|
|
|
|
Log::device_textbufhandle->Replace(device->CreateTextBuffer(msg.connector));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( Log::fallback_framebuffer &&
|
|
|
|
msg.device == ONE_AND_ONLY_DEVICE &&
|
|
|
|
msg.connector == ONE_AND_ONLY_CONNECTOR )
|
|
|
|
{
|
|
|
|
struct dispmsg_crtc_mode fallback_mode = GetLogFallbackMode();
|
|
|
|
if ( memcmp(&msg.mode, &fallback_mode, sizeof(msg.mode)) != 0 )
|
|
|
|
return errno = EINVAL, -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
return errno = ENODEV, -1;
|
2015-03-19 19:08:08 -04:00
|
|
|
}
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
// No need to respond.
|
2012-05-01 20:43:55 -04:00
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
return 0;
|
2012-05-01 20:43:55 -04:00
|
|
|
}
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
static int GetCrtcMode(void* ptr, size_t size)
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
struct dispmsg_get_crtc_mode msg;
|
|
|
|
if ( size != sizeof(msg) )
|
|
|
|
return errno = EINVAL, -1;
|
|
|
|
if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ScopedLock lock(&video_lock);
|
|
|
|
|
2015-03-19 19:08:08 -04:00
|
|
|
struct dispmsg_crtc_mode mode;
|
|
|
|
if ( Log::fallback_framebuffer &&
|
|
|
|
msg.device == ONE_AND_ONLY_DEVICE &&
|
|
|
|
msg.connector == ONE_AND_ONLY_CONNECTOR )
|
|
|
|
{
|
|
|
|
mode = GetLogFallbackMode();
|
|
|
|
}
|
|
|
|
else if ( msg.device < num_devices )
|
|
|
|
{
|
|
|
|
DeviceEntry* device_entry = &devices[msg.device];
|
|
|
|
VideoDevice* device = device_entry->device;
|
|
|
|
// TODO: There is no real way to detect failure here.
|
|
|
|
errno = 0;
|
|
|
|
mode = device->GetCurrentMode(msg.connector);
|
|
|
|
if ( !(mode.control & DISPMSG_CONTROL_VALID) && errno != 0 )
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
return errno = ENODEV, -1;
|
2015-03-19 19:08:08 -04:00
|
|
|
}
|
2014-03-25 15:28:51 -04:00
|
|
|
|
|
|
|
msg.mode = mode;
|
|
|
|
|
|
|
|
if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
2012-05-01 20:43:55 -04:00
|
|
|
}
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
static int GetCrtcModes(void* ptr, size_t size)
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
struct dispmsg_get_crtc_modes msg;
|
|
|
|
if ( size != sizeof(msg) )
|
|
|
|
return errno = EINVAL, -1;
|
|
|
|
if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ScopedLock lock(&video_lock);
|
|
|
|
|
2015-03-19 19:08:08 -04:00
|
|
|
size_t nummodes = 0;
|
|
|
|
struct dispmsg_crtc_mode* modes = NULL;
|
|
|
|
if ( msg.device < num_devices )
|
|
|
|
{
|
|
|
|
DeviceEntry* device_entry = &devices[msg.device];
|
|
|
|
VideoDevice* device = device_entry->device;
|
|
|
|
modes = device->GetModes(msg.connector, &nummodes);
|
|
|
|
if ( !modes )
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else if ( Log::fallback_framebuffer &&
|
|
|
|
msg.device == ONE_AND_ONLY_DEVICE &&
|
|
|
|
msg.connector == ONE_AND_ONLY_CONNECTOR )
|
|
|
|
{
|
|
|
|
if ( !(modes = new struct dispmsg_crtc_mode[1]) )
|
|
|
|
return -1;
|
|
|
|
modes[nummodes++] = GetLogFallbackMode();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
return errno = ENODEV, -1;
|
2015-03-19 19:08:08 -04:00
|
|
|
}
|
2014-03-25 15:28:51 -04:00
|
|
|
|
|
|
|
size_t requested_modes = msg.modes_length;
|
|
|
|
msg.modes_length = nummodes;
|
|
|
|
|
|
|
|
if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if ( requested_modes < nummodes )
|
|
|
|
{
|
|
|
|
delete[] modes;
|
|
|
|
return errno = ERANGE, -1;
|
|
|
|
}
|
|
|
|
|
2012-05-01 20:43:55 -04:00
|
|
|
for ( size_t i = 0; i < nummodes; i++ )
|
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
if ( !CopyToUser(&msg.modes[i], &modes[i], sizeof(modes[i])) )
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
delete[] modes;
|
|
|
|
return -1;
|
2012-05-01 20:43:55 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
delete[] modes;
|
|
|
|
|
|
|
|
return 0;
|
2012-05-01 20:43:55 -04:00
|
|
|
}
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
static int GetMemorySize(void* ptr, size_t size)
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
struct dispmsg_get_memory_size msg;
|
|
|
|
if ( size != sizeof(msg) )
|
|
|
|
return errno = EINVAL, -1;
|
|
|
|
if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ScopedLock lock(&video_lock);
|
|
|
|
|
2015-03-19 19:08:08 -04:00
|
|
|
if ( Log::fallback_framebuffer &&
|
|
|
|
msg.device == ONE_AND_ONLY_DEVICE )
|
|
|
|
{
|
|
|
|
msg.memory_size = Log::fallback_framebuffer_width *
|
|
|
|
Log::fallback_framebuffer_height *
|
|
|
|
Log::fallback_framebuffer_bpp / 8;
|
|
|
|
}
|
|
|
|
else if ( msg.device < num_devices )
|
|
|
|
{
|
|
|
|
DeviceEntry* device_entry = &devices[msg.device];
|
|
|
|
VideoDevice* device = device_entry->device;
|
|
|
|
msg.memory_size = device->FrameSize();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
return errno = ENODEV, -1;
|
2015-03-19 19:08:08 -04:00
|
|
|
}
|
2014-03-25 15:28:51 -04:00
|
|
|
|
|
|
|
DeviceEntry* device_entry = &devices[msg.device];
|
|
|
|
VideoDevice* device = device_entry->device;
|
|
|
|
|
|
|
|
msg.memory_size = device->FrameSize();
|
|
|
|
|
|
|
|
if ( !CopyToUser(ptr, &msg, sizeof(msg)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
2012-05-01 20:43:55 -04:00
|
|
|
}
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
static int WriteMemory(void* ptr, size_t size)
|
2012-12-15 20:06:29 -05:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
struct dispmsg_write_memory msg;
|
|
|
|
if ( size != sizeof(msg) )
|
|
|
|
return errno = EINVAL, -1;
|
|
|
|
if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ScopedLock lock(&video_lock);
|
|
|
|
|
2015-03-19 19:08:08 -04:00
|
|
|
if ( Log::fallback_framebuffer &&
|
|
|
|
msg.device == ONE_AND_ONLY_DEVICE )
|
|
|
|
{
|
|
|
|
size_t ideal_pitch = Log::fallback_framebuffer_width *
|
|
|
|
Log::fallback_framebuffer_bpp / 8;
|
|
|
|
if ( ideal_pitch == Log::fallback_framebuffer_pitch )
|
|
|
|
{
|
|
|
|
size_t framesize = Log::fallback_framebuffer_height *
|
|
|
|
Log::fallback_framebuffer_pitch;
|
|
|
|
if ( framesize < msg.offset )
|
|
|
|
return 0;
|
|
|
|
size_t count = msg.size;
|
|
|
|
size_t left = framesize - msg.offset;
|
|
|
|
if ( left < count )
|
|
|
|
count = left;
|
|
|
|
const uint8_t* src = msg.src;
|
|
|
|
uint8_t* dst = Log::fallback_framebuffer + msg.offset;
|
|
|
|
if ( !CopyFromUser(dst, src, count) )
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const uint8_t* src = msg.src;
|
|
|
|
size_t src_size = msg.size;
|
|
|
|
uint64_t y = msg.offset / ideal_pitch;
|
|
|
|
uint64_t x = msg.offset % ideal_pitch;
|
|
|
|
while ( src_size && y < Log::fallback_framebuffer_height )
|
|
|
|
{
|
|
|
|
size_t count = src_size;
|
|
|
|
if ( ideal_pitch -x < count )
|
|
|
|
count = ideal_pitch - x;
|
|
|
|
uint8_t* dst = Log::fallback_framebuffer +
|
|
|
|
Log::fallback_framebuffer_pitch * y + x;
|
|
|
|
if ( !CopyFromUser(dst, src, count) )
|
|
|
|
return -1;
|
|
|
|
src += count;
|
|
|
|
src_size -= count;
|
|
|
|
x = 0;
|
|
|
|
y++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( msg.device < num_devices )
|
|
|
|
{
|
|
|
|
DeviceEntry* device_entry = &devices[msg.device];
|
|
|
|
VideoDevice* device = device_entry->device;
|
|
|
|
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
|
|
|
if ( device->WriteAt(&ctx, msg.offset, msg.src, msg.size) < 0 )
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
return errno = ENODEV, -1;
|
2015-03-19 19:08:08 -04:00
|
|
|
}
|
2014-03-25 15:28:51 -04:00
|
|
|
|
2015-05-10 14:28:33 -04:00
|
|
|
Log::Invalidate();
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
return 0;
|
2012-12-15 20:06:29 -05:00
|
|
|
}
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
static int ReadMemory(void* ptr, size_t size)
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
struct dispmsg_read_memory msg;
|
|
|
|
if ( size != sizeof(msg) )
|
|
|
|
return errno = EINVAL, -1;
|
|
|
|
if ( !CopyFromUser(&msg, ptr, sizeof(msg)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ScopedLock lock(&video_lock);
|
|
|
|
|
2015-03-19 19:08:08 -04:00
|
|
|
if ( Log::fallback_framebuffer &&
|
|
|
|
msg.device == ONE_AND_ONLY_DEVICE )
|
|
|
|
{
|
|
|
|
size_t ideal_pitch = Log::fallback_framebuffer_width *
|
|
|
|
Log::fallback_framebuffer_bpp / 8;
|
|
|
|
if ( ideal_pitch == Log::fallback_framebuffer_pitch )
|
|
|
|
{
|
|
|
|
size_t framesize = Log::fallback_framebuffer_height *
|
|
|
|
Log::fallback_framebuffer_pitch;
|
|
|
|
if ( framesize < msg.offset )
|
|
|
|
return 0;
|
|
|
|
size_t count = msg.size;
|
|
|
|
size_t left = framesize - msg.offset;
|
|
|
|
if ( left < count )
|
|
|
|
count = left;
|
|
|
|
const uint8_t* src = Log::fallback_framebuffer + msg.offset;
|
|
|
|
uint8_t* dst = msg.dst;
|
|
|
|
if ( !CopyToUser(dst, src, count) )
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint8_t* dst = msg.dst;
|
|
|
|
size_t dst_size = msg.size;
|
|
|
|
uint64_t y = msg.offset / ideal_pitch;
|
|
|
|
uint64_t x = msg.offset % ideal_pitch;
|
|
|
|
while ( dst_size && y < Log::fallback_framebuffer_height )
|
|
|
|
{
|
|
|
|
size_t count = dst_size;
|
|
|
|
if ( ideal_pitch -x < count )
|
|
|
|
count = ideal_pitch - x;
|
|
|
|
const uint8_t* src = Log::fallback_framebuffer +
|
|
|
|
Log::fallback_framebuffer_pitch * y + x;
|
|
|
|
if ( !CopyToUser(dst, src, count) )
|
|
|
|
return -1;
|
|
|
|
dst += count;
|
|
|
|
dst_size -= count;
|
|
|
|
x = 0;
|
|
|
|
y++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( msg.device < num_devices )
|
|
|
|
{
|
|
|
|
DeviceEntry* device_entry = &devices[msg.device];
|
|
|
|
VideoDevice* device = device_entry->device;
|
|
|
|
ioctx_t ctx; SetupUserIOCtx(&ctx);
|
|
|
|
if ( device->ReadAt(&ctx, msg.offset, msg.dst, msg.size) < 0 )
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-03-25 15:28:51 -04:00
|
|
|
return errno = ENODEV, -1;
|
2015-03-19 19:08:08 -04:00
|
|
|
}
|
2014-03-25 15:28:51 -04:00
|
|
|
|
|
|
|
return 0;
|
2012-05-01 20:43:55 -04:00
|
|
|
}
|
|
|
|
|
2014-10-16 18:04:47 -04:00
|
|
|
} // namespace Video
|
|
|
|
} // namespace Sortix
|
|
|
|
|
|
|
|
namespace Sortix {
|
|
|
|
|
|
|
|
int sys_dispmsg_issue(void* ptr, size_t size)
|
2012-05-01 20:43:55 -04:00
|
|
|
{
|
2014-10-16 18:04:47 -04:00
|
|
|
using namespace Video;
|
|
|
|
|
2014-03-25 15:28:51 -04:00
|
|
|
struct dispmsg_header hdr;
|
|
|
|
if ( size < sizeof(hdr) )
|
|
|
|
return errno = EINVAL, -1;
|
|
|
|
if ( !CopyFromUser(&hdr, ptr, sizeof(hdr)) )
|
|
|
|
return -1;
|
|
|
|
switch ( hdr.msgid )
|
|
|
|
{
|
|
|
|
case DISPMSG_ENUMERATE_DEVICES: return EnumerateDevices(ptr, size);
|
|
|
|
case DISPMSG_GET_DRIVER_COUNT: return GetDriverCount(ptr, size);
|
|
|
|
case DISPMSG_GET_DRIVER_NAME: return GetDriverName(ptr, size);
|
|
|
|
case DISPMSG_GET_DRIVER: return GetDriver(ptr, size);
|
|
|
|
case DISPMSG_SET_DRIVER: return SetDriver(ptr, size);
|
|
|
|
case DISPMSG_SET_CRTC_MODE: return SetCrtcMode(ptr, size);
|
|
|
|
case DISPMSG_GET_CRTC_MODE: return GetCrtcMode(ptr, size);
|
|
|
|
case DISPMSG_GET_CRTC_MODES: return GetCrtcModes(ptr, size);
|
|
|
|
case DISPMSG_GET_MEMORY_SIZE: return GetMemorySize(ptr, size);
|
|
|
|
case DISPMSG_WRITE_MEMORY: return WriteMemory(ptr, size);
|
|
|
|
case DISPMSG_READ_MEMORY: return ReadMemory(ptr, size);
|
|
|
|
default:
|
|
|
|
return errno = ENOSYS, -1;
|
|
|
|
}
|
2012-05-01 20:43:55 -04:00
|
|
|
}
|
|
|
|
|
2014-10-16 18:04:47 -04:00
|
|
|
} // namespace Sortix
|