Re:

Michael Tirado
2018-10-22T02:46:51Z

[-- Attachment #1: Type: text/plain, Size: 837 bytes --]

On Mon, Oct 22, 2018 at 1:50 AM Dave Airlie <airlied@gmail.com> wrote:
>
> On Mon, 22 Oct 2018 at 10:49, Michael Tirado <mtirado418@gmail.com> wrote:
> >
> > On Mon, Oct 22, 2018 at 12:26 AM Dave Airlie <airlied@gmail.com> wrote:
> > >
> > > This shouldn't be necessary, did someone misbackport the mmap changes without:
> If you have custom userspace software, make sure it's using
> AC_SYS_LARGEFILE or whatever the equivalant is in your build system.
>
> 64-bit file offsets are important.
>

That fixed it! -D_FILE_OFFSET_BITS=64 is the pre-processor define
needed. It's a bit more than unintuitive but I'm glad I don't need
this stupid patch anymore, Thanks.

In case anyone is further interested I have attached test program
since I spent the last hour or so chopping it up anyway :S [ gcc -o
kms -D_FILE_OFFSET_BITS=64 main.c ]

[-- Attachment #2: main.c --]
[-- Type: application/octet-stream, Size: 17153 bytes --]

/* Copyright (C) 2017 Michael R. Tirado <mtirado418@gmail.com> -- GPLv3+
*
* This program is libre 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.
*
* This program 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. You should have
* received a copy of the GNU General Public License version 3
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <malloc.h>
#include <signal.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <drm/drm.h>
#include <drm/drm_mode.h>

#define STRERR strerror(errno)

#ifndef PTRBITCOUNT
#define PTRBITCOUNT 32
#endif
/* kernel structs use __u64 for pointer types */
#if (PTRBITCOUNT == 32)
#define ptr_from_krn(ptr) ((void *)(uint32_t)(ptr))
#define ptr_to_krn(ptr) ((uint32_t)(ptr))
#elif (PTRBITCOUNT == 64)
#define ptr_from_krn(ptr) ((void *)(uint64_t)(ptr))
#define ptr_to_krn(ptr) ((uint64_t)(ptr))
#else
#error "PTRBITCOUNT is undefined"
#endif
#ifndef MAX_FBS
#define MAX_FBS 12
#endif
#ifndef MAX_CRTCS
#define MAX_CRTCS 12
#endif
#ifndef MAX_CONNECTORS
#define MAX_CONNECTORS 12
#endif
#ifndef MAX_ENCODERS
#define MAX_ENCODERS 12
#endif
#ifndef MAX_PROPS
#define MAX_PROPS 256
#endif
#ifndef MAX_MODES
#define MAX_MODES 256
#endif
#if (PTRBITCOUNT == 32)
#define drm_to_ptr(ptr) ((void *)(uint32_t)(ptr))
#define drm_from_ptr(ptr) ((uint32_t)(ptr))
#elif (PTRBITCOUNT == 64)
#define drm_to_ptr(ptr) ((void *)(uint64_t)(ptr))
#define drm_from_ptr(ptr) ((uint64_t)(ptr))
#else
#error "PTRBITCOUNT is undefined"
#endif
#define drm_alloc(size) (drm_from_ptr(calloc(1,size)))

struct drm_buffer
{
uint32_t drm_id;
uint32_t fb_id;
uint32_t pitch;
uint32_t width;
uint32_t height;
uint32_t depth;
uint32_t bpp;
char *addr;
size_t size;
};
struct drm_display
{
struct drm_mode_get_encoder encoder;
struct drm_mode_crtc crtc;
struct drm_mode_get_connector *conn; /* do we need array for multi-screen? */
struct drm_mode_modeinfo *modes; /* these both point to conn's mode array */
struct drm_mode_modeinfo *cur_mode;
uint32_t cur_mode_idx;
uint32_t mode_count;
uint32_t conn_id;
};
struct drm_kms
{
struct drm_display display;
struct drm_buffer *sfb;
struct drm_mode_card_res *res;
int card_fd;
};

/* get id out of drm_id_ptr */
static uint32_t drm_get_id(uint64_t addr, uint32_t idx)
{
return ((uint32_t *)drm_to_ptr(addr))[idx];
}

static int free_mode_card_res(struct drm_mode_card_res *res)
{
if (!res)
return -1;
if (res->fb_id_ptr)
free(drm_to_ptr(res->fb_id_ptr));
if (res->crtc_id_ptr)
free(drm_to_ptr(res->crtc_id_ptr));
if (res->encoder_id_ptr)
free(drm_to_ptr(res->encoder_id_ptr));
if (res->connector_id_ptr)
free(drm_to_ptr(res->connector_id_ptr));
free(res);
return 0;
}

static struct drm_mode_card_res *alloc_mode_card_res(int fd)
{
struct drm_mode_card_res res;
struct drm_mode_card_res *ret;
uint32_t count_fbs, count_crtcs, count_connectors, count_encoders;

memset(&res, 0, sizeof(struct drm_mode_card_res));
if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) {
printf("ioctl(DRM_IOCTL_MODE_GETRESOURCES, &res): %s\n", STRERR);
return NULL;
}
if (res.count_fbs > MAX_FBS
|| res.count_crtcs > MAX_CRTCS
|| res.count_encoders > MAX_ENCODERS
|| res.count_connectors > MAX_CONNECTORS) {
printf("resource limit reached, see defines.h\n");
return NULL;
}
if (res.count_fbs) {
res.fb_id_ptr = drm_alloc(sizeof(uint32_t)*res.count_fbs);
if (!res.fb_id_ptr)
goto alloc_err;
}
if (res.count_crtcs) {
res.crtc_id_ptr = drm_alloc(sizeof(uint32_t)*res.count_crtcs);
if (!res.crtc_id_ptr)
goto alloc_err;
}
if (res.count_encoders) {
res.encoder_id_ptr = drm_alloc(sizeof(uint32_t)*res.count_encoders);
if (!res.encoder_id_ptr)
goto alloc_err;
}
if (res.count_connectors) {
res.connector_id_ptr = drm_alloc(sizeof(uint32_t)*res.count_connectors);
if (!res.connector_id_ptr)
goto alloc_err;
}
count_fbs = res.count_fbs;
count_crtcs = res.count_crtcs;
count_encoders = res.count_encoders;
count_connectors = res.count_connectors;

if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res) == -1) {
printf("ioctl(DRM_IOCTL_MODE_GETRESOURCES, &res): %s\n", STRERR);
goto free_err;
}

if (count_fbs != res.count_fbs
|| count_crtcs != res.count_crtcs
|| count_encoders != res.count_encoders
|| count_connectors != res.count_connectors) {
errno = EAGAIN;
goto free_err;
}

ret = calloc(1, sizeof(struct drm_mode_card_res));
if (!ret)
goto alloc_err;

memcpy(ret, &res, sizeof(struct drm_mode_card_res));
return ret;

alloc_err:
errno = ENOMEM;
free_err:
free(drm_to_ptr(res.fb_id_ptr));
free(drm_to_ptr(res.crtc_id_ptr));
free(drm_to_ptr(res.connector_id_ptr));
free(drm_to_ptr(res.encoder_id_ptr));
return NULL;
}

static struct drm_mode_get_connector *alloc_connector(int fd, uint32_t conn_id)
{
struct drm_mode_get_connector conn;
struct drm_mode_get_connector *ret;
uint32_t count_modes, count_props, count_encoders;

memset(&conn, 0, sizeof(struct drm_mode_get_connector));
conn.connector_id = conn_id;

if (ioctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn) == -1) {
printf("ioctl(DRM_IOCTL_MODE_GETCONNECTOR, &conn): %s\n", STRERR);
return NULL;
}
if (conn.count_modes > MAX_MODES
|| conn.count_props > MAX_PROPS
|| conn.count_encoders > MAX_ENCODERS) {
printf("resource limit reached, see defines.h\n");
return NULL;
}
if (conn.count_modes) {
conn.modes_ptr = drm_alloc(sizeof(struct drm_mode_modeinfo)
* conn.count_modes);
if (!conn.modes_ptr)
goto alloc_err;
}
if (conn.count_props) {
conn.props_ptr = drm_alloc(sizeof(uint32_t)*conn.count_props);
if (!conn.props_ptr)
goto alloc_err;
conn.prop_values_ptr = drm_alloc(sizeof(uint64_t)*conn.count_props);
if (!conn.prop_values_ptr)
goto alloc_err;
}
if (conn.count_encoders) {
conn.encoders_ptr = drm_alloc(sizeof(uint32_t)*conn.count_encoders);
if (!conn.encoders_ptr)
goto alloc_err;
}
count_modes = conn.count_modes;
count_props = conn.count_props;
count_encoders = conn.count_encoders;

if (ioctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn) == -1) {
printf("ioctl(DRM_IOCTL_MODE_GETCONNECTOR, &conn): %s\n", STRERR);
goto free_err;
}

if (count_modes != conn.count_modes
|| count_props != conn.count_props
|| count_encoders != conn.count_encoders) {
errno = EAGAIN;
goto free_err;
}

ret = calloc(1, sizeof(struct drm_mode_get_connector));
if (!ret)
goto alloc_err;

memcpy(ret, &conn, sizeof(struct drm_mode_get_connector));
return ret;

alloc_err:
errno = ENOMEM;
free_err:
free(drm_to_ptr(conn.modes_ptr));
free(drm_to_ptr(conn.props_ptr));
free(drm_to_ptr(conn.encoders_ptr));
free(drm_to_ptr(conn.prop_values_ptr));
return NULL;
}

static struct drm_mode_modeinfo *get_connector_modeinfo(struct drm_mode_get_connector *conn, uint32_t *count)
{
if (!conn || !count)
return NULL;
*count = conn->count_modes;
return drm_to_ptr(conn->modes_ptr);

}

static int free_connector(struct drm_mode_get_connector *conn)
{
if (!conn)
return -1;
if (conn->modes_ptr)
free(drm_to_ptr(conn->modes_ptr));
if (conn->props_ptr)
free(drm_to_ptr(conn->props_ptr));
if (conn->encoders_ptr)
free(drm_to_ptr(conn->encoders_ptr));
if (conn->prop_values_ptr)
free(drm_to_ptr(conn->prop_values_ptr));
free(conn);
return 0;
}

static int drm_kms_connect_sfb(struct drm_kms *self)
{
struct drm_display *display = &self->display;
struct drm_mode_get_connector *conn;
struct drm_mode_modeinfo *cur_mode;
struct drm_mode_get_encoder *encoder;
struct drm_mode_crtc *crtc;
if (!display || !display->conn || !display->cur_mode || !self->sfb)
return -1;

conn = display->conn;
cur_mode = display->cur_mode;
encoder = &self->display.encoder;
crtc = &self->display.crtc;
memset(crtc, 0, sizeof(struct drm_mode_crtc));
memset(encoder, 0, sizeof(struct drm_mode_get_encoder));

/* XXX: there can be multiple encoders, have not investigated this much */
if (conn->encoder_id == 0) {
printf("conn->encoder_id was 0, defaulting to encoder[0]\n");
conn->encoder_id = ((uint32_t *)drm_to_ptr(conn->encoders_ptr))[0];
}
encoder->encoder_id = conn->encoder_id;

if (ioctl(self->card_fd, DRM_IOCTL_MODE_GETENCODER, encoder) == -1) {
printf("ioctl(DRM_IOCTL_MODE_GETENCODER): %s\n", STRERR);
return -1;
}

if (encoder->crtc_id == 0) {
printf("encoder->crtc_id was 0, defaulting to crtc[0]\n");
encoder->crtc_id = ((uint32_t *)drm_to_ptr(self->res->crtc_id_ptr))[0];
}
crtc->crtc_id = encoder->crtc_id;

if (ioctl(self->card_fd, DRM_IOCTL_MODE_GETCRTC, crtc) == -1) {
printf("ioctl(DRM_IOCTL_MODE_GETCRTC): %s\n", STRERR);
return -1;
}

/* set crtc mode */
crtc->fb_id = self->sfb->fb_id;
crtc->set_connectors_ptr = drm_from_ptr((void *)&conn->connector_id);
crtc->count_connectors = 1;
crtc->mode = *cur_mode;
/*printf("\nsetting mode:\n\n");
print_mode_modeinfo(cur_mode);*/
crtc->mode_valid = 1;
if (ioctl(self->card_fd, DRM_IOCTL_MODE_SETCRTC, crtc) == -1) {
printf("ioctl(DRM_IOCTL_MODE_SETCRTC): %s\n", STRERR);
return -1;
}
return 0;
}

/* stupid frame buffer */
static struct drm_buffer *alloc_sfb(int card_fd,
uint32_t width,
uint32_t height,
uint32_t depth,
uint32_t bpp)
{
struct drm_mode_create_dumb cdumb;
struct drm_mode_map_dumb moff;
struct drm_mode_fb_cmd cmd;
struct drm_buffer *ret;
void *fbmap;

memset(&cdumb, 0, sizeof(cdumb));
memset(&moff, 0, sizeof(moff));
memset(&cmd, 0, sizeof(cmd));

/* create dumb buffer */
cdumb.width = width;
cdumb.height = height;
cdumb.bpp = bpp;
cdumb.flags = 0;
cdumb.pitch = 0;
cdumb.size = 0;
cdumb.handle = 0;
if (ioctl(card_fd, DRM_IOCTL_MODE_CREATE_DUMB, &cdumb) == -1) {
printf("ioctl(DRM_IOCTL_MODE_CREATE_DUMB): %s\n", STRERR);
return NULL;
}
/* add framebuffer object */
cmd.width = cdumb.width;
cmd.height = cdumb.height;
cmd.bpp = cdumb.bpp;
cmd.pitch = cdumb.pitch;
cmd.depth = depth;
cmd.handle = cdumb.handle;
if (ioctl(card_fd, DRM_IOCTL_MODE_ADDFB, &cmd) == -1) {
printf("ioctl(DRM_IOCTL_MODE_ADDFB): %s\n", STRERR);
ioctl(card_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &cdumb.handle);
return NULL;
}
/* get mmap offset */
moff.handle = cdumb.handle;
if (ioctl(card_fd, DRM_IOCTL_MODE_MAP_DUMB, &moff) == -1) {
printf("ioctl(DRM_IOCTL_MODE_MAP_DUMB): %s\n", STRERR);
ioctl(card_fd, DRM_IOCTL_MODE_RMFB, &cmd.fb_id);
ioctl(card_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &cdumb.handle);
return NULL;
}
/* XXX this is probably better off as MAP_PRIVATE, we can't prime
* the main framebuffer if it's "dumb", AFAIK */
fbmap = mmap(0, (size_t)cdumb.size, PROT_READ|PROT_WRITE,
MAP_SHARED, card_fd, (off_t)moff.offset);
if (fbmap == MAP_FAILED) {
printf("framebuffer mmap failed: %s\n", STRERR);
ioctl(card_fd, DRM_IOCTL_MODE_RMFB, &cmd.fb_id);
ioctl(card_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &cdumb.handle);
return NULL;
}

ret = calloc(1, sizeof(struct drm_buffer));
if (!ret) {
printf("-ENOMEM\n");
munmap(fbmap, cdumb.size);
ioctl(card_fd, DRM_IOCTL_MODE_RMFB, &cmd.fb_id);
ioctl(card_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &cdumb.handle);
return NULL;
}
ret->addr = fbmap;
ret->size = cdumb.size;
ret->pitch = cdumb.pitch;
ret->width = cdumb.width;
ret->height = cdumb.height;
ret->bpp = cdumb.bpp;
ret->depth = cmd.depth;
ret->fb_id = cmd.fb_id;
ret->drm_id = cdumb.handle;
memset(fbmap, 0x27, cdumb.size);
return ret;
}

static int destroy_sfb(int card_fd, struct drm_buffer *sfb)
{
if (!sfb)
return -1;

if (munmap(sfb->addr, sfb->size) == -1)
printf("munmap: %s\n", STRERR);
if (ioctl(card_fd, DRM_IOCTL_MODE_RMFB, &sfb->fb_id))
printf("ioctl(DRM_IOCTL_MODE_RMFB): %s\n", STRERR);
if (ioctl(card_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &sfb->drm_id))
printf("ioctl(DRM_IOCTL_MODE_DESTROY_DUMB): %s\n", STRERR);
free(sfb);
return 0;
}
static int card_set_master(int card_fd)
{
if (ioctl(card_fd, DRM_IOCTL_SET_MASTER, 0)) {
printf("ioctl(DRM_IOCTL_SET_MASTER, 0): %s\n", STRERR);
return -1;
}
return 0;
}
static int card_drop_master(int card_fd)
{
if (ioctl(card_fd, DRM_IOCTL_DROP_MASTER, 0)) {
printf("ioctl(DRM_IOCTL_DROP_MASTER, 0): %s\n", STRERR);
return -1;
}
return 0;
}
static int drm_display_destroy(struct drm_display *display)
{
if (display->conn)
free_connector(display->conn);
memset(display, 0, sizeof(struct drm_display));
return 0;
}
int drm_kms_destroy(struct drm_kms *self)
{
if (self->sfb)
destroy_sfb(self->card_fd, self->sfb);
if (self->res)
free_mode_card_res(self->res);
drm_display_destroy(&self->display);

close(self->card_fd);
memset(self, 0, sizeof(struct drm_kms));
free(self);
return 0;
}
static int get_mode_idx(struct drm_mode_modeinfo *modes,
uint16_t count,
uint16_t width,
uint16_t height,
uint16_t refresh)
{
int i;
int pick = -1;
if (width == 0)
width = 0xffff;
if (height == 0)
height = 0xffff;
for (i = 0; i < count; ++i)
{
if (modes[i].hdisplay > width || modes[i].vdisplay > height)
continue;
/* pretend these radical modes don't exist for now */
if (modes[i].hdisplay % 16 == 0) {
if (pick < 0) {
pick = i;
continue;
}
if (modes[i].hdisplay > modes[pick].hdisplay)
pick = i;
else if (modes[i].vdisplay > modes[pick].vdisplay)
pick = i;
else if (modes[i].hdisplay == modes[pick].hdisplay
&& modes[i].vdisplay == modes[pick].vdisplay) {
if (abs(refresh - modes[i].vrefresh)
< abs(refresh - modes[pick].vrefresh)) {
pick = i;
}
}
}
}
if (pick < 0) {
printf("could not find any usable modes for (%dx%d@%dhz)\n",
width, height, refresh);
return -1;
}
return pick;
}
/* TODO handle hotplugging */
static int drm_display_load(struct drm_kms *self,
uint16_t req_width,
uint16_t req_height,
uint16_t req_refresh,
struct drm_display *out)
{
uint32_t conn_id;
int idx = -1;

/* FIXME uses primary connector? "0" */
conn_id = drm_get_id(self->res->connector_id_ptr, 0);
out->conn = alloc_connector(self->card_fd, conn_id);
if (!out->conn) {
printf("unable to create drm connector structure\n");
return -1;
}

out->conn_id = conn_id;
out->modes = get_connector_modeinfo(out->conn, &out->mode_count);
idx = get_mode_idx(out->modes, out->mode_count,
req_width, req_height, req_refresh);
if (idx < 0)
goto free_err;

out->cur_mode_idx = (uint32_t)idx;
out->cur_mode = &out->modes[out->cur_mode_idx];
return 0;
free_err:
drm_display_destroy(out);
return -1;
}
struct drm_kms *drm_mode_create(char *devname,
int no_connect,
uint16_t req_width,
uint16_t req_height,
uint16_t req_refresh)
{
char devpath[128];
struct drm_kms *self;
struct drm_mode_modeinfo *cur_mode;
int card_fd;

snprintf(devpath, sizeof(devpath), "/dev/dri/%s", devname);
card_fd = open(devpath, O_RDWR|O_CLOEXEC);
if (card_fd == -1) {
printf("open(%s): %s\n", devpath, STRERR);
return NULL;
}
if (card_set_master(card_fd)) {
printf("card_set_master failed\n");
return NULL;
}

self = calloc(1, sizeof(struct drm_kms));
if (!self)
return NULL;

self->card_fd = card_fd;
self->res = alloc_mode_card_res(card_fd);
if (!self->res) {
printf("unable to create drm structure\n");
goto free_err;
}

if (drm_display_load(self, req_width, req_height, req_refresh, &self->display)) {
printf("drm_display_load failed\n");
goto free_err;
}
cur_mode = self->display.cur_mode;
printf("connector(%d) using mode[%d] (%dx%d@%dhz)\n",
self->display.conn_id,
self->display.cur_mode_idx,
cur_mode->hdisplay,
cur_mode->vdisplay,
cur_mode->vrefresh);

/* buffer pitch must divide evenly by 16,
* TODO check against bpp here when that is variable instead of 32 */
self->sfb = alloc_sfb(card_fd, cur_mode->hdisplay, cur_mode->vdisplay, 24, 32);
if (!self->sfb) {
printf("alloc_sfb failed\n");
goto free_err;
}

if (!no_connect && drm_kms_connect_sfb(self)) {
printf("drm_kms_connect_sfb failed\n");
goto free_err;
}
return self;

free_err:
drm_kms_destroy(self);
return NULL;
}

int main(int argc, char *argv[])
{
int ret = -1;
struct drm_kms *card0;
/*card0 = drm_mode_create("card0", g_srv_opts.inactive_vt,
g_srv_opts.request_width,
g_srv_opts.request_height,
g_srv_opts.request_refresh);*/
/* do not connect to vt */
card0 = drm_mode_create("card0", 1, 640, 480, 60);
if (card0 == NULL) {
printf("drm_mode_create failed\n");
return -1;
}

drm_kms_destroy(card0);

printf("looks ok, returning 0\n");
return 0;
}