Start work on uevent + Misc Bugfixes
This commit is contained in:
parent
cdd5c9bcf5
commit
d3ad58b8f1
|
@ -2,22 +2,42 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
Modules ms = load_modules("modules", argv + 1, argc - 1);
|
uint64_t modules_mask = 0;
|
||||||
Vec2 (*get_size)() = module_find_func(ms, DISPLAY_GET_SIZE);
|
Modules modules = load_modules("modules", argv + 1, argc - 1, &modules_mask);
|
||||||
void (*flip)() = module_find_func(ms, DISPLAY_FLIP);
|
|
||||||
void (*put_pixel)(Vec2, Color) = module_find_func(ms, DISPLAY_PUT_PIXEL);
|
Vec2 (*get_size)() = module_find_func(modules, DISPLAY_GET_SIZE_V1);
|
||||||
|
void (*flip)() = module_find_func(modules, DISPLAY_FLIP_V1);
|
||||||
|
void (*put_pixel)(Vec2, Color) = module_find_func(modules, DISPLAY_PUT_PIXEL_V1);
|
||||||
|
InputEvent (*poll_event)() = module_find_func(modules, INPUT_POLL_V1);
|
||||||
|
|
||||||
Vec2 display_size = get_size();
|
Vec2 display_size = get_size();
|
||||||
for (int x = 0; x < display_size.x; x++) {
|
for (int x = 0; x < display_size.x; x++) {
|
||||||
for (int y = 0; y < display_size.y; y++) {
|
for (int y = 0; y < display_size.y; y++) {
|
||||||
put_pixel((Vec2){x,y}, (Color){x%256,y%256,0});
|
put_pixel((Vec2) { x, y }, (Color) { x % 256, y % 256, 0 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flip();
|
flip();
|
||||||
|
|
||||||
getchar();
|
int mouseX;
|
||||||
|
int mouseY;
|
||||||
|
|
||||||
unload_modules(ms);
|
while (1) {
|
||||||
|
InputEvent e = poll_event();
|
||||||
|
if (e.type == EVENT_KEY_DOWN)
|
||||||
|
break;
|
||||||
|
if (e.type == EVENT_MOUSE_MOVE_X) {
|
||||||
|
mouseX += e.data;
|
||||||
|
// printf("Mouse: (%d,%d)", mouseX, mouseY);
|
||||||
|
}
|
||||||
|
if (e.type == EVENT_MOUSE_MOVE_Y) {
|
||||||
|
mouseY += e.data;
|
||||||
|
// printf("Mouse: (%d,%d)", mouseX, mouseY);
|
||||||
|
}
|
||||||
|
put_pixel((Vec2) { mouseX, mouseY }, (Color) { 255, 255, 255 });
|
||||||
|
flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
unload_modules(modules);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
#include "../twm.h"
|
#include "../twm.h"
|
||||||
#include <stdio.h>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
int bitcount(uint64_t v) {
|
int bitcount(uint64_t v) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while (v > 0) {
|
while (v > 0) {
|
||||||
v &= v - 1;
|
v &= v - 1;
|
||||||
count ++;
|
count++;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ void unload_modules(Modules ms) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Modules load_modules(char *module_dir, char *modules[], size_t num_modules) {
|
Modules load_modules(char* module_dir, char* modules[], size_t num_modules, uint64_t* features) {
|
||||||
Modules ms = { 0 };
|
Modules ms = { 0 };
|
||||||
uint64_t needed = BIT(FEATURE_MAX) - 1;
|
uint64_t needed = BIT(FEATURE_MAX) - 1;
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ Modules load_modules(char *module_dir, char *modules[], size_t num_modules) {
|
||||||
LOG_WARNING("Failed to load library %s (%s)", dll_name, dlerror());
|
LOG_WARNING("Failed to load library %s (%s)", dll_name, dlerror());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uint64_t *feature_lists = (uint64_t*)dlsym(m.dll, "FEATURE_LISTS");
|
uint64_t* feature_lists = (uint64_t*)dlsym(m.dll, "FEATURE_LISTS");
|
||||||
|
|
||||||
size_t best_feature = 0;
|
size_t best_feature = 0;
|
||||||
int best_feature_value = 0;
|
int best_feature_value = 0;
|
||||||
|
@ -54,17 +54,20 @@ Modules load_modules(char *module_dir, char *modules[], size_t num_modules) {
|
||||||
dlclose(m.dll);
|
dlclose(m.dll);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
m.init = (ModuleInit)dlsym(m.dll, "module_init");
|
m.init = (ModuleInit)dlsym(m.dll, "module_init");
|
||||||
twm_assert(m.init, "Module doesn't have module_init");
|
twm_assert(m.init, "Module doesn't have module_init");
|
||||||
m.close = (ModuleClose)dlsym(m.dll, "module_close");
|
m.close = (ModuleClose)dlsym(m.dll, "module_close");
|
||||||
twm_assert(m.close, "Module doesn't have module_close");
|
twm_assert(m.close, "Module doesn't have module_close");
|
||||||
|
|
||||||
if ((m.funcs = (void*)m.init(best_feature)) == NULL) {
|
if ((m.funcs = (void*)m.init(best_feature)) == NULL) {
|
||||||
|
LOG_WARNING("Module %s couldn't load", dll_name);
|
||||||
dlclose(m.dll);
|
dlclose(m.dll);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_INFO("Loaded module %s", dll_name);
|
||||||
|
|
||||||
ms.modules = realloc(ms.modules, sizeof(Module) * ++ms.count);
|
ms.modules = realloc(ms.modules, sizeof(Module) * ++ms.count);
|
||||||
twm_assert(ms.modules, "Get more ram");
|
twm_assert(ms.modules, "Get more ram");
|
||||||
memcpy(&ms.modules[ms.count - 1], &m, sizeof(Module));
|
memcpy(&ms.modules[ms.count - 1], &m, sizeof(Module));
|
||||||
|
@ -73,6 +76,7 @@ Modules load_modules(char *module_dir, char *modules[], size_t num_modules) {
|
||||||
if (needed != 0) {
|
if (needed != 0) {
|
||||||
LOG_WARNING("Failed to find all needed modules: %lu", needed);
|
LOG_WARNING("Failed to find all needed modules: %lu", needed);
|
||||||
}
|
}
|
||||||
|
*features = (BIT(FEATURE_MAX) - 1) ^ needed;
|
||||||
return ms;
|
return ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
#define MODULE_NAME "drm"
|
#define MODULE_NAME "drm"
|
||||||
#include "../twm.h"
|
#include "../twm.h"
|
||||||
#include <stdlib.h>
|
#include <drm_fourcc.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <xf86drm.h>
|
#include <xf86drm.h>
|
||||||
#include <xf86drmMode.h>
|
#include <xf86drmMode.h>
|
||||||
#include <drm_fourcc.h>
|
|
||||||
|
|
||||||
#define max(a,b) (((a)>(b))?(a):(b))
|
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t id; // Unknown use
|
uint32_t id; // Unknown use
|
||||||
|
@ -17,7 +17,7 @@ typedef struct {
|
||||||
uint32_t pitch;
|
uint32_t pitch;
|
||||||
uint32_t handle;
|
uint32_t handle;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
uint8_t *data;
|
uint8_t* data;
|
||||||
} DRMFb;
|
} DRMFb;
|
||||||
|
|
||||||
typedef struct _DRMConnector {
|
typedef struct _DRMConnector {
|
||||||
|
@ -32,24 +32,27 @@ typedef struct _DRMConnector {
|
||||||
Vec2 size;
|
Vec2 size;
|
||||||
DRMFb frame;
|
DRMFb frame;
|
||||||
|
|
||||||
struct _DRMConnector *next;
|
struct _DRMConnector* next;
|
||||||
} DRMConnector;
|
} DRMConnector;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int drm_fd;
|
int drm_fd;
|
||||||
DRMFb frameBuffer;
|
DRMFb frameBuffer;
|
||||||
DRMConnector *connectors;
|
DRMConnector* connectors;
|
||||||
} DRMState;
|
} DRMState;
|
||||||
|
|
||||||
static DRMState *data;
|
static DRMState* data;
|
||||||
|
|
||||||
uint32_t find_crtc(int fd, drmModeResPtr resources, drmModeConnectorPtr connector, uint32_t *taken) {
|
uint32_t find_crtc(int fd, drmModeResPtr resources, drmModeConnectorPtr connector, uint32_t* taken) {
|
||||||
for (int i = 0; i < connector->count_encoders; i++) {
|
for (int i = 0; i < connector->count_encoders; i++) {
|
||||||
drmModeEncoderPtr encoder = drmModeGetEncoder(fd, connector->encoders[i]);
|
drmModeEncoderPtr encoder = drmModeGetEncoder(fd, connector->encoders[i]);
|
||||||
if (!encoder) continue;
|
if (!encoder)
|
||||||
|
continue;
|
||||||
for (int j = 0; j < resources->count_crtcs; j++) {
|
for (int j = 0; j < resources->count_crtcs; j++) {
|
||||||
if ((encoder->possible_crtcs & BIT(j)) == 0) continue; // Not compatible
|
if ((encoder->possible_crtcs & BIT(j)) == 0)
|
||||||
if ((*taken & BIT(j)) != 0) continue; // Already taken
|
continue; // Not compatible
|
||||||
|
if ((*taken & BIT(j)) != 0)
|
||||||
|
continue; // Already taken
|
||||||
drmModeFreeEncoder(encoder);
|
drmModeFreeEncoder(encoder);
|
||||||
*taken |= BIT(j);
|
*taken |= BIT(j);
|
||||||
return resources->crtcs[j];
|
return resources->crtcs[j];
|
||||||
|
@ -60,20 +63,24 @@ uint32_t find_crtc(int fd, drmModeResPtr resources, drmModeConnectorPtr connecto
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool create_fb(int fd, DRMFb *out, Vec2 size) {
|
bool create_fb(int fd, DRMFb* out, Vec2 size) {
|
||||||
if(drmModeCreateDumbBuffer(fd, size.x, size.y, 32, 0, &out->handle, &out->pitch, &out->size) < 0) return false;
|
if (drmModeCreateDumbBuffer(fd, size.x, size.y, 32, 0, &out->handle, &out->pitch, &out->size) < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
uint32_t handles[4] = { out->handle };
|
uint32_t handles[4] = { out->handle };
|
||||||
uint32_t pitches[4] = { out->pitch };
|
uint32_t pitches[4] = { out->pitch };
|
||||||
uint32_t offsets[4] = { 0 };
|
uint32_t offsets[4] = { 0 };
|
||||||
|
|
||||||
if (drmModeAddFB2(fd, size.x, size.y, DRM_FORMAT_XRGB8888, handles, pitches, offsets, &out->id, 0) < 0) goto err_dumb;
|
if (drmModeAddFB2(fd, size.x, size.y, DRM_FORMAT_XRGB8888, handles, pitches, offsets, &out->id, 0) < 0)
|
||||||
|
goto err_dumb;
|
||||||
|
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
if(drmModeMapDumbBuffer(fd,out->handle, &offset) < 0) goto err_dumb;
|
if (drmModeMapDumbBuffer(fd, out->handle, &offset) < 0)
|
||||||
|
goto err_dumb;
|
||||||
|
|
||||||
out->data = mmap(0, out->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
|
out->data = mmap(0, out->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
|
||||||
if (out->data == MAP_FAILED) goto err_fb;
|
if (out->data == MAP_FAILED)
|
||||||
|
goto err_fb;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
err_fb:
|
err_fb:
|
||||||
|
@ -83,18 +90,19 @@ err_dumb:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_fb(int fd, DRMFb *fb) {
|
void destroy_fb(int fd, DRMFb* fb) {
|
||||||
munmap(fb->data, fb->size);
|
munmap(fb->data, fb->size);
|
||||||
drmModeRmFB(fd, fb->id);
|
drmModeRmFB(fd, fb->id);
|
||||||
drmModeDestroyDumbBuffer(fd, fb->handle);
|
drmModeDestroyDumbBuffer(fd, fb->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_put_pixel(Vec2 position, Color col) {
|
void display_put_pixel(Vec2 position, Color col) {
|
||||||
DRMConnector *conn = data->connectors;
|
DRMConnector* conn = data->connectors;
|
||||||
while (conn) {
|
while (conn) {
|
||||||
if (conn->enabled) {
|
if (conn->enabled) {
|
||||||
if (position.x < 0 || position.x >= conn->size.x || position.y < 0 || position.y >= conn->size.y) continue;
|
if (position.x < 0 || position.x >= conn->size.x || position.y < 0 || position.y >= conn->size.y)
|
||||||
uint8_t *row = conn->frame.data + position.y*conn->frame.pitch;
|
continue;
|
||||||
|
uint8_t* row = conn->frame.data + position.y * conn->frame.pitch;
|
||||||
row[position.x * 4 + 0] = col.blue;
|
row[position.x * 4 + 0] = col.blue;
|
||||||
row[position.x * 4 + 1] = col.green;
|
row[position.x * 4 + 1] = col.green;
|
||||||
row[position.x * 4 + 2] = col.red;
|
row[position.x * 4 + 2] = col.red;
|
||||||
|
@ -107,16 +115,16 @@ void display_put_pixel(Vec2 position, Color col) {
|
||||||
void display_blit(Vec2 pos, Image image) {
|
void display_blit(Vec2 pos, Image image) {
|
||||||
for (int x = 0; x < image.size.x; x++) {
|
for (int x = 0; x < image.size.x; x++) {
|
||||||
for (int y = 0; y < image.size.y; y++) {
|
for (int y = 0; y < image.size.y; y++) {
|
||||||
display_put_pixel((Vec2){x+pos.x,y+pos.y}, image.data[y][x]);
|
display_put_pixel((Vec2) { x + pos.x, y + pos.y }, image.data[y][x]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_flip() {
|
void display_flip() {
|
||||||
DRMConnector *conn = data->connectors;
|
DRMConnector* conn = data->connectors;
|
||||||
while (conn) {
|
while (conn) {
|
||||||
if (conn->enabled) {
|
if (conn->enabled) {
|
||||||
drmModeClip clip = (drmModeClip){.x1 = 0, .y1 = 0, .x2 = conn->frame.width, .y2 = conn->frame.height};
|
drmModeClip clip = (drmModeClip) { .x1 = 0, .y1 = 0, .x2 = conn->frame.width, .y2 = conn->frame.height };
|
||||||
drmModeDirtyFB(data->drm_fd, conn->frame.id, &clip, 1);
|
drmModeDirtyFB(data->drm_fd, conn->frame.id, &clip, 1);
|
||||||
}
|
}
|
||||||
conn = conn->next;
|
conn = conn->next;
|
||||||
|
@ -126,7 +134,7 @@ void display_flip() {
|
||||||
Vec2 display_get_size() {
|
Vec2 display_get_size() {
|
||||||
int maxX = 0;
|
int maxX = 0;
|
||||||
int maxY = 0;
|
int maxY = 0;
|
||||||
DRMConnector *conn = data->connectors;
|
DRMConnector* conn = data->connectors;
|
||||||
while (conn) {
|
while (conn) {
|
||||||
if (conn->enabled) {
|
if (conn->enabled) {
|
||||||
maxX = max(maxX, conn->size.x);
|
maxX = max(maxX, conn->size.x);
|
||||||
|
@ -134,27 +142,28 @@ Vec2 display_get_size() {
|
||||||
}
|
}
|
||||||
conn = conn->next;
|
conn = conn->next;
|
||||||
}
|
}
|
||||||
return (Vec2){maxX, maxY};
|
return (Vec2) { maxX, maxY };
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------
|
//--------------------------------------------------------
|
||||||
|
|
||||||
const uint64_t FEATURE_LISTS[] = {
|
const uint64_t FEATURE_LISTS[] = {
|
||||||
BIT(BASIC_RENDERING) | BIT(ADVANCED_RENDERING),
|
BIT(BASIC_RENDERING),
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
const FeatureFunc FUNCTIONS[] = {
|
const FeatureFunc FUNCTIONS[] = {
|
||||||
(FeatureFunc){ DISPLAY_PUT_PIXEL, display_put_pixel },
|
(FeatureFunc) { DISPLAY_PUT_PIXEL_V1, display_put_pixel },
|
||||||
(FeatureFunc){ DISPLAY_BLIT, display_blit },
|
(FeatureFunc) { DISPLAY_BLIT_V1, display_blit },
|
||||||
(FeatureFunc){ DISPLAY_GET_SIZE, display_get_size },
|
(FeatureFunc) { DISPLAY_GET_SIZE_V1, display_get_size },
|
||||||
(FeatureFunc){ DISPLAY_FLIP, display_flip },
|
(FeatureFunc) { DISPLAY_FLIP_V1, display_flip },
|
||||||
(FeatureFunc){ FUNC_END, NULL }
|
(FeatureFunc) { FUNC_END, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
FeatureFunc* module_init(size_t features_selected) {
|
FeatureFunc* module_init(size_t features_selected) {
|
||||||
data = malloc(sizeof(DRMState));
|
data = malloc(sizeof(DRMState));
|
||||||
if (data == NULL) return NULL;
|
if (data == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
data->drm_fd = open("/dev/dri/card0", O_RDWR);
|
data->drm_fd = open("/dev/dri/card0", O_RDWR);
|
||||||
|
|
||||||
|
@ -167,8 +176,8 @@ FeatureFunc* module_init(size_t features_selected) {
|
||||||
for (int i = 0; i < resources->count_connectors; i++) {
|
for (int i = 0; i < resources->count_connectors; i++) {
|
||||||
drmModeConnectorPtr drm_connector = drmModeGetConnector(data->drm_fd, resources->connectors[i]);
|
drmModeConnectorPtr drm_connector = drmModeGetConnector(data->drm_fd, resources->connectors[i]);
|
||||||
twm_assert_custom(drm_connector != NULL, "Failed to open connector", continue);
|
twm_assert_custom(drm_connector != NULL, "Failed to open connector", continue);
|
||||||
|
|
||||||
DRMConnector *connector = malloc(sizeof(DRMConnector));
|
DRMConnector* connector = malloc(sizeof(DRMConnector));
|
||||||
twm_assert_custom(connector != NULL, "Failed to allocate connector data", goto cleanup);
|
twm_assert_custom(connector != NULL, "Failed to allocate connector data", goto cleanup);
|
||||||
connector->next = data->connectors;
|
connector->next = data->connectors;
|
||||||
data->connectors = connector;
|
data->connectors = connector;
|
||||||
|
@ -176,24 +185,22 @@ FeatureFunc* module_init(size_t features_selected) {
|
||||||
connector->id = drm_connector->connector_id;
|
connector->id = drm_connector->connector_id;
|
||||||
connector->enabled = drm_connector->connection == DRM_MODE_CONNECTED;
|
connector->enabled = drm_connector->connection == DRM_MODE_CONNECTED;
|
||||||
|
|
||||||
LOG_INFO("Found connector %d (%s)", connector->id, connector->enabled?"Enabled":"Disabled");
|
LOG_INFO("Found connector %d (%s)", connector->id, connector->enabled ? "Enabled" : "Disabled");
|
||||||
|
|
||||||
if (!connector->enabled) goto cleanup;
|
if (!connector->enabled)
|
||||||
|
goto cleanup;
|
||||||
twm_assert_custom(drm_connector->modes != NULL, "Connector has no modes", connector->enabled = false; goto cleanup);
|
twm_assert_custom(drm_connector->modes != NULL, "Connector has no modes", connector->enabled = false; goto cleanup);
|
||||||
|
|
||||||
connector->crtc_id = find_crtc(data->drm_fd, resources, drm_connector, &taken_crtcs);
|
connector->crtc_id = find_crtc(data->drm_fd, resources, drm_connector, &taken_crtcs);
|
||||||
twm_assert_custom(connector->crtc_id != 0, "Failed to find crtc", connector->enabled = false; goto cleanup);
|
twm_assert_custom(connector->crtc_id != 0, "Failed to find crtc", connector->enabled = false; goto cleanup);
|
||||||
|
|
||||||
LOG_INFO("\tFound CRTC %d", connector->crtc_id);
|
LOG_INFO("\tFound CRTC %d", connector->crtc_id);
|
||||||
|
|
||||||
connector->mode = drm_connector->modes[0];
|
connector->mode = drm_connector->modes[0];
|
||||||
connector->size = (Vec2){connector->mode.hdisplay, connector->mode.vdisplay};
|
connector->size = (Vec2) { connector->mode.hdisplay, connector->mode.vdisplay };
|
||||||
|
|
||||||
LOG_INFO("\tUsing Mode %dx%d", connector->size.x, connector->size.y);
|
LOG_INFO("\tUsing Mode %dx%d", connector->size.x, connector->size.y);
|
||||||
|
|
||||||
twm_assert_custom(create_fb(data->drm_fd, &connector->frame, connector->size), "Failed to make framebuffer", connector->enabled = false; goto cleanup);
|
twm_assert_custom(create_fb(data->drm_fd, &connector->frame, connector->size), "Failed to make framebuffer", connector->enabled = false; goto cleanup);
|
||||||
LOG_INFO("\tMade framebuffer with id %d", connector->frame.id);
|
LOG_INFO("\tMade framebuffer with id %d", connector->frame.id);
|
||||||
|
|
||||||
connector->old_mode = drmModeGetCrtc(data->drm_fd, connector->crtc_id);
|
connector->old_mode = drmModeGetCrtc(data->drm_fd, connector->crtc_id);
|
||||||
|
|
||||||
twm_assert_custom(drmModeSetCrtc(data->drm_fd, connector->crtc_id, connector->frame.id, 0, 0, &connector->id, 1, &connector->mode) >= 0, "Failed to set CRTC mode", connector->enabled = false; goto cleanup);
|
twm_assert_custom(drmModeSetCrtc(data->drm_fd, connector->crtc_id, connector->frame.id, 0, 0, &connector->id, 1, &connector->mode) >= 0, "Failed to set CRTC mode", connector->enabled = false; goto cleanup);
|
||||||
|
@ -207,7 +214,6 @@ FeatureFunc* module_init(size_t features_selected) {
|
||||||
return (FeatureFunc*)FUNCTIONS;
|
return (FeatureFunc*)FUNCTIONS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void module_close() {
|
void module_close() {
|
||||||
while (data->connectors) {
|
while (data->connectors) {
|
||||||
if (data->connectors->enabled) {
|
if (data->connectors->enabled) {
|
||||||
|
@ -219,7 +225,7 @@ void module_close() {
|
||||||
drmModeFreeCrtc(crtc);
|
drmModeFreeCrtc(crtc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DRMConnector *tmp = data->connectors->next;
|
DRMConnector* tmp = data->connectors->next;
|
||||||
free(data->connectors);
|
free(data->connectors);
|
||||||
data->connectors = tmp;
|
data->connectors = tmp;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#define MODULE_NAME "drm"
|
#define MODULE_NAME "fb"
|
||||||
#include "../twm.h"
|
#include "../twm.h"
|
||||||
#include <linux/fb.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <linux/fb.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -11,17 +11,17 @@ typedef struct {
|
||||||
long screen_size;
|
long screen_size;
|
||||||
struct fb_fix_screeninfo fscrinfo;
|
struct fb_fix_screeninfo fscrinfo;
|
||||||
struct fb_var_screeninfo vscrinfo;
|
struct fb_var_screeninfo vscrinfo;
|
||||||
uint8_t *frame_buffer;
|
uint8_t* frame_buffer;
|
||||||
} FBData;
|
} FBData;
|
||||||
|
|
||||||
static FBData *data;
|
static FBData* data;
|
||||||
|
|
||||||
Vec2 display_get_size() {
|
Vec2 display_get_size() {
|
||||||
return (Vec2){data->vscrinfo.xres, data->vscrinfo.yres};
|
return (Vec2) { data->vscrinfo.xres, data->vscrinfo.yres };
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t get_pixel_color(Color col) {
|
uint32_t get_pixel_color(Color col) {
|
||||||
return (col.red<<data->vscrinfo.red.offset) | (col.green<<data->vscrinfo.green.offset) | (col.blue<<data->vscrinfo.blue.offset);
|
return (col.red << data->vscrinfo.red.offset) | (col.green << data->vscrinfo.green.offset) | (col.blue << data->vscrinfo.blue.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_put_pixel(Vec2 pos, Color col) {
|
void display_put_pixel(Vec2 pos, Color col) {
|
||||||
|
@ -29,11 +29,10 @@ void display_put_pixel(Vec2 pos, Color col) {
|
||||||
*((uint32_t*)(data->frame_buffer + pixel_offset)) = get_pixel_color(col);
|
*((uint32_t*)(data->frame_buffer + pixel_offset)) = get_pixel_color(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void display_blit(Vec2 pos, Image image) {
|
void display_blit(Vec2 pos, Image image) {
|
||||||
for (int x = 0; x < image.size.x; x++) {
|
for (int x = 0; x < image.size.x; x++) {
|
||||||
for (int y = 0; y < image.size.y; y++) {
|
for (int y = 0; y < image.size.y; y++) {
|
||||||
display_put_pixel((Vec2){x+pos.x,y+pos.y}, image.data[y][x]);
|
display_put_pixel((Vec2) { x + pos.x, y + pos.y }, image.data[y][x]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,18 +48,19 @@ const uint64_t FEATURE_LISTS[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const FeatureFunc FUNCTIONS[] = {
|
const FeatureFunc FUNCTIONS[] = {
|
||||||
(FeatureFunc){ DISPLAY_PUT_PIXEL, display_put_pixel },
|
(FeatureFunc) { DISPLAY_PUT_PIXEL_V1, display_put_pixel },
|
||||||
(FeatureFunc){ DISPLAY_BLIT, display_blit },
|
(FeatureFunc) { DISPLAY_BLIT_V1, display_blit },
|
||||||
(FeatureFunc){ DISPLAY_GET_SIZE, display_get_size },
|
(FeatureFunc) { DISPLAY_GET_SIZE_V1, display_get_size },
|
||||||
(FeatureFunc){ DISPLAY_FLIP, display_flip },
|
(FeatureFunc) { DISPLAY_FLIP_V1, display_flip },
|
||||||
(FeatureFunc){ FUNC_END, NULL },
|
(FeatureFunc) { FUNC_END, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
FeatureFunc *module_init(size_t feature_selected) {
|
FeatureFunc* module_init(size_t feature_selected) {
|
||||||
data = malloc(sizeof(FBData));
|
data = malloc(sizeof(FBData));
|
||||||
if (data == NULL) return NULL;
|
if (data == NULL)
|
||||||
|
return NULL;
|
||||||
data->fb_fd = open("/dev/fb0", O_RDWR);
|
data->fb_fd = open("/dev/fb0", O_RDWR);
|
||||||
|
|
||||||
ioctl(data->fb_fd, FBIOGET_FSCREENINFO, &data->fscrinfo);
|
ioctl(data->fb_fd, FBIOGET_FSCREENINFO, &data->fscrinfo);
|
||||||
ioctl(data->fb_fd, FBIOGET_VSCREENINFO, &data->vscrinfo);
|
ioctl(data->fb_fd, FBIOGET_VSCREENINFO, &data->vscrinfo);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
#include <errno.h>
|
||||||
|
#include <linux/input-event-codes.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#define MODULE_NAME "uevent"
|
||||||
|
#include "../twm.h"
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define GRAB 1
|
||||||
|
#define UNGRAB 0
|
||||||
|
|
||||||
|
typedef enum { OTHER = 0,
|
||||||
|
KBD,
|
||||||
|
MOUSE } DevType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct timeval time;
|
||||||
|
unsigned short type;
|
||||||
|
unsigned short code;
|
||||||
|
unsigned int value;
|
||||||
|
} ev_event;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
DevType type;
|
||||||
|
int fd;
|
||||||
|
ev_event event_buffer[2];
|
||||||
|
int event_buffer_ptr;
|
||||||
|
} EVDev;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t devnum;
|
||||||
|
EVDev* devices;
|
||||||
|
} EVData;
|
||||||
|
|
||||||
|
static EVData* data;
|
||||||
|
|
||||||
|
void module_close();
|
||||||
|
|
||||||
|
EventKey key_to_event(unsigned int key) {
|
||||||
|
switch (key) {
|
||||||
|
case BTN_TOUCH:
|
||||||
|
return EKEY_TOUCH;
|
||||||
|
case BTN_LEFT:
|
||||||
|
return EKEY_BTN_LEFT;
|
||||||
|
case BTN_RIGHT:
|
||||||
|
return EKEY_BTN_RIGHT;
|
||||||
|
default:
|
||||||
|
return EKEY_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InputEvent convert_event(ev_event e, DevType t) {
|
||||||
|
if (e.type == EV_ABS && e.code == ABS_X && t == MOUSE) {
|
||||||
|
return (InputEvent) { EVENT_MOUSE_SET_X, e.value };
|
||||||
|
}
|
||||||
|
if (e.type == EV_ABS && e.code == ABS_Y && t == MOUSE) {
|
||||||
|
return (InputEvent) { EVENT_MOUSE_SET_Y, e.value };
|
||||||
|
}
|
||||||
|
if (e.type == EV_REL && e.code == REL_X && t == MOUSE) {
|
||||||
|
return (InputEvent) { EVENT_MOUSE_MOVE_X, e.value };
|
||||||
|
}
|
||||||
|
if (e.type == EV_REL && e.code == REL_Y && t == MOUSE) {
|
||||||
|
return (InputEvent) { EVENT_MOUSE_MOVE_Y, e.value };
|
||||||
|
}
|
||||||
|
if (e.type == EV_KEY) {
|
||||||
|
if (e.value == 1)
|
||||||
|
return (InputEvent) { t == MOUSE ? EVENT_MOUSE_BUTTON_DOWN : EVENT_KEY_DOWN, key_to_event(e.code) };
|
||||||
|
else
|
||||||
|
return (InputEvent) { t == MOUSE ? EVENT_MOUSE_BUTTON_UP : EVENT_KEY_UP, key_to_event(e.code) };
|
||||||
|
}
|
||||||
|
return (InputEvent) { .type = EVENT_EMPTY, 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
InputEvent input_poll() {
|
||||||
|
for (int i = 0; i < data->devnum; i++) {
|
||||||
|
ssize_t num = read(data->devices[i].fd,
|
||||||
|
((uint8_t*)data->devices[i].event_buffer) + data->devices[i].event_buffer_ptr,
|
||||||
|
2 * sizeof(ev_event) - data->devices[i].event_buffer_ptr);
|
||||||
|
if (num != -1) {
|
||||||
|
data->devices[i].event_buffer_ptr += num;
|
||||||
|
if (data->devices[i].event_buffer_ptr >= sizeof(ev_event)) {
|
||||||
|
ev_event event = data->devices[i].event_buffer[0];
|
||||||
|
data->devices[i].event_buffer_ptr -= sizeof(ev_event);
|
||||||
|
memmove(data->devices[i].event_buffer,
|
||||||
|
((uint8_t*)data->devices[i].event_buffer) + sizeof(ev_event),
|
||||||
|
data->devices[i].event_buffer_ptr);
|
||||||
|
return convert_event(event, data->devices[i].type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
twm_assert(errno == EAGAIN, "Reading event device failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (InputEvent) { EVENT_EMPTY, 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------
|
||||||
|
|
||||||
|
const uint64_t FEATURE_LISTS[] = {
|
||||||
|
BIT(BASIC_INPUT),
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
const FeatureFunc FUNCTIONS[] = {
|
||||||
|
(FeatureFunc) { INPUT_POLL_V1, input_poll },
|
||||||
|
(FeatureFunc) { FUNC_END, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
FeatureFunc* module_init(size_t feature_selected) {
|
||||||
|
data = malloc(sizeof(EVData));
|
||||||
|
if (data == NULL)
|
||||||
|
return NULL;
|
||||||
|
usleep(100); // Make sure all pending events have been processed before we look at them
|
||||||
|
// Otherwise you get weird stuff where the enter key is always down
|
||||||
|
FILE* f = fopen("/proc/bus/input/devices", "r");
|
||||||
|
char c;
|
||||||
|
char k[1024], v[1024];
|
||||||
|
|
||||||
|
data->devnum = 0;
|
||||||
|
data->devices = NULL;
|
||||||
|
|
||||||
|
while (!feof(f)) {
|
||||||
|
c = fgetc(f);
|
||||||
|
if (c == '\n')
|
||||||
|
continue;
|
||||||
|
if (c == 'I') {
|
||||||
|
data->devices = realloc(data->devices, ++data->devnum * sizeof(EVDev));
|
||||||
|
memset(&data->devices[data->devnum - 1], 0, sizeof(data->devices[data->devnum - 1]));
|
||||||
|
data->devices[data->devnum - 1].type = OTHER;
|
||||||
|
data->devices[data->devnum - 1].fd = -1;
|
||||||
|
}
|
||||||
|
fscanf(f, ": %[^=]=%[^\n]\n", k, v);
|
||||||
|
if (c == 'H') {
|
||||||
|
char* pch = strtok(v, " ");
|
||||||
|
while (pch != NULL) {
|
||||||
|
if (data->devices == NULL)
|
||||||
|
break;
|
||||||
|
if (strcmp(pch, "kbd") == 0) {
|
||||||
|
LOG_INFO("Found keyboard at device %zu", data->devnum - 1);
|
||||||
|
data->devices[data->devnum - 1].type = KBD;
|
||||||
|
}
|
||||||
|
if (strncmp(pch, "mouse", 5) == 0) {
|
||||||
|
LOG_INFO("Found mouse at device %zu", data->devnum - 1);
|
||||||
|
data->devices[data->devnum - 1].type = MOUSE;
|
||||||
|
}
|
||||||
|
if (strncmp(pch, "event", 5) == 0) {
|
||||||
|
char devpath[64] = "/dev/input/";
|
||||||
|
strcat(devpath, pch);
|
||||||
|
data->devices[data->devnum - 1].fd = open(devpath, O_RDONLY | O_NONBLOCK);
|
||||||
|
ioctl(data->devices[data->devnum - 1].fd, EVIOCGRAB, UNGRAB);
|
||||||
|
ioctl(data->devices[data->devnum - 1].fd, EVIOCGRAB, GRAB);
|
||||||
|
}
|
||||||
|
pch = strtok(NULL, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return (FeatureFunc*)FUNCTIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void module_close() {
|
||||||
|
for (int i = 0; i < data->devnum; i++) {
|
||||||
|
ioctl(data->devices[data->devnum - 1].fd, EVIOCGRAB, UNGRAB);
|
||||||
|
close(data->devices[i].fd);
|
||||||
|
}
|
||||||
|
free(data);
|
||||||
|
}
|
114
src/twm.h
114
src/twm.h
|
@ -1,47 +1,121 @@
|
||||||
#ifndef _TWM_H
|
#ifndef _TWM_H
|
||||||
#define _TWM_H
|
#define _TWM_H
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BASIC_RENDERING = 0,
|
BASIC_RENDERING = 0, // DISPLAY_*_V1
|
||||||
ADVANCED_RENDERING = 1,
|
BASIC_INPUT = 1, // INPUT_*_V1
|
||||||
FEATURE_MAX
|
FEATURE_MAX
|
||||||
} ModuleFeatures;
|
} ModuleFeatures;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FUNC_END = 0,
|
FUNC_END = 0,
|
||||||
DISPLAY_PUT_PIXEL,
|
DISPLAY_PUT_PIXEL_V1, // (Vec2 position, Color col) -> void
|
||||||
DISPLAY_BLIT,
|
DISPLAY_BLIT_V1, // (Vec2 position, Image image) -> void
|
||||||
DISPLAY_FLIP,
|
DISPLAY_FLIP_V1, // () -> void
|
||||||
DISPLAY_GET_SIZE,
|
DISPLAY_GET_SIZE_V1, // () -> Vec2
|
||||||
|
INPUT_POLL_V1, // () -> InputEvent
|
||||||
MODULE_FUNC_MAX
|
MODULE_FUNC_MAX
|
||||||
} ModuleFunc;
|
} ModuleFunc;
|
||||||
|
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
|
||||||
#define BIT(n) ((uint64_t)1<<(n))
|
#define BIT(n) ((uint64_t)1 << (n))
|
||||||
|
|
||||||
#ifdef MODULE_NAME
|
#ifdef MODULE_NAME
|
||||||
#define LOG_WARNING(f, ...) do {printf("\033[33;1m[ WARNING ]\033[0m Module " MODULE_NAME ": " f "\n", __VA_ARGS__); fflush(stdout); } while (0)
|
#define LOG_WARNING(f, ...) \
|
||||||
#define LOG_INFO(f, ...) do {printf("\033[34;1m[ INFO ]\033[0m Module " MODULE_NAME ": " f "\n", __VA_ARGS__); fflush(stdout); } while (0)
|
do { \
|
||||||
#define LOG_ERROR(f, ...) do {printf("\033[31;1m[ ERROR ]\033[0m Module " MODULE_NAME ": " f "\n", __VA_ARGS__); fflush(stdout); } while (0)
|
printf("\033[33;1m[ WARNING ]\033[0m Module " MODULE_NAME ": " f "\n", __VA_ARGS__); \
|
||||||
|
fflush(stdout); \
|
||||||
|
} while (0)
|
||||||
|
#define LOG_INFO(f, ...) \
|
||||||
|
do { \
|
||||||
|
printf("\033[34;1m[ INFO ]\033[0m Module " MODULE_NAME ": " f "\n", __VA_ARGS__); \
|
||||||
|
fflush(stdout); \
|
||||||
|
} while (0)
|
||||||
|
#define LOG_ERROR(f, ...) \
|
||||||
|
do { \
|
||||||
|
printf("\033[31;1m[ ERROR ]\033[0m Module " MODULE_NAME ": " f "\n", __VA_ARGS__); \
|
||||||
|
fflush(stdout); \
|
||||||
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#define LOG_WARNING(f, ...) do {printf("\033[33;1m[ WARNING ]\033[0m " f "\n", __VA_ARGS__); fflush(stdout); } while (0)
|
#define LOG_WARNING(f, ...) \
|
||||||
#define LOG_INFO(f, ...) do {printf("\033[34;1m[ INFO ]\033[0m " f "\n", __VA_ARGS__); fflush(stdout); } while (0)
|
do { \
|
||||||
#define LOG_ERROR(f, ...) do {printf("\033[31;1m[ ERROR ]\033[0m " f "\n", __VA_ARGS__); fflush(stdout); } while (0)
|
printf("\033[33;1m[ WARNING ]\033[0m " f "\n", __VA_ARGS__); \
|
||||||
|
fflush(stdout); \
|
||||||
|
} while (0)
|
||||||
|
#define LOG_INFO(f, ...) \
|
||||||
|
do { \
|
||||||
|
printf("\033[34;1m[ INFO ]\033[0m " f "\n", __VA_ARGS__); \
|
||||||
|
fflush(stdout); \
|
||||||
|
} while (0)
|
||||||
|
#define LOG_ERROR(f, ...) \
|
||||||
|
do { \
|
||||||
|
printf("\033[31;1m[ ERROR ]\033[0m " f "\n", __VA_ARGS__); \
|
||||||
|
fflush(stdout); \
|
||||||
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define twm_assert(e, m) do { if (!e) { LOG_ERROR("Assertion Failed: %s (%s:%d %s)", m, __FILE__, __LINE__, #e); abort(); } } while (0)
|
#define twm_assert(e, m) \
|
||||||
#define twm_assert_custom(e, m, c) do { if (!(e)) { LOG_ERROR("Assertion Failed: %s (%s:%d %s)", m, __FILE__, __LINE__, #e); c; } } while (0)
|
do { \
|
||||||
|
if (!(e)) { \
|
||||||
|
LOG_ERROR("Assertion Failed: %s (%s:%d %s)", m, __FILE__, __LINE__, #e); \
|
||||||
|
abort(); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define twm_assert_custom(e, m, c) \
|
||||||
|
do { \
|
||||||
|
if (!(e)) { \
|
||||||
|
LOG_ERROR("Assertion Failed: %s (%s:%d %s)", m, __FILE__, __LINE__, #e); \
|
||||||
|
c; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
Modules load_modules(char*, char*[], size_t);
|
Modules load_modules(char*, char*[], size_t, uint64_t*);
|
||||||
void unload_modules(Modules);
|
void unload_modules(Modules);
|
||||||
void* module_find_func(Modules ms, ModuleFunc type);
|
void* module_find_func(Modules ms, ModuleFunc type);
|
||||||
|
|
||||||
typedef struct { int x; int y; } Vec2;
|
typedef struct {
|
||||||
typedef struct { uint8_t red; uint8_t green; uint8_t blue; } Color;
|
int x;
|
||||||
typedef struct { Vec2 size; Color** data; } Image;
|
int y;
|
||||||
|
} Vec2;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t red;
|
||||||
|
uint8_t green;
|
||||||
|
uint8_t blue;
|
||||||
|
} Color;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Vec2 size;
|
||||||
|
Color** data;
|
||||||
|
} Image;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EVENT_EMPTY = 0,
|
||||||
|
EVENT_SYNC,
|
||||||
|
EVENT_KEY_DOWN,
|
||||||
|
EVENT_KEY_UP,
|
||||||
|
EVENT_MOUSE_MOVE_X,
|
||||||
|
EVENT_MOUSE_MOVE_Y,
|
||||||
|
EVENT_MOUSE_SET_X,
|
||||||
|
EVENT_MOUSE_SET_Y,
|
||||||
|
EVENT_MOUSE_BUTTON_DOWN,
|
||||||
|
EVENT_MOUSE_BUTTON_UP
|
||||||
|
} EventType;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EKEY_UNKNOWN = 0,
|
||||||
|
EKEY_TOUCH,
|
||||||
|
EKEY_BTN_LEFT,
|
||||||
|
EKEY_BTN_RIGHT,
|
||||||
|
} EventKey;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EventType type;
|
||||||
|
int data;
|
||||||
|
} InputEvent;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue