diff --git a/configure.ac b/configure.ac index 688ef9b8..53907f2d 100644 --- a/configure.ac +++ b/configure.ac @@ -902,6 +902,8 @@ CheckDRM() VIDEO_DRIVERS="$VIDEO_DRIVERS drm/libvideo_drm.la" DEP_LIBS="$DEP_LIBS -ldrm" need_udev="yes" + DRM_INC_DIR="`$PKG_CONFIG --variable includedir libdrm`/drm" + AC_SUBST(DRM_INC_DIR) else AC_MSG_WARN([$video_drm]) fi diff --git a/include/exstubs.h b/include/exstubs.h index 13bc0133..028cd94a 100644 --- a/include/exstubs.h +++ b/include/exstubs.h @@ -84,6 +84,49 @@ struct commlcd_info { extern "C" { #endif /* __cplusplus */ +#ifdef _MGGAL_DRM + +#include + +/* + * this struct should be defined by the driver + */ +struct _DrmDriver; +typedef struct _DrmDriver DrmDriver; + +typedef struct _DrmDriverOps { + DrmDriver* (*create_driver) (int device_fd); + void (*destroy_driver) (DrmDriver *driver); + + uint32_t (* create_buffer) (DrmDriver *driver, + unsigned int width, unsigned int height, + unsigned int *pitch); + + BOOL (* fetch_buffer) (DrmDriver *driver, + uint32_t buffer_id, + unsigned int *width, unsigned int *height, + unsigned int *pitch); + + BOOL (* map_buffer) (DrmDriver *driver, + uint32_t buffer_id); + void (* unmap_buffer) (DrmDriver *driver, + uint32_t buffer_id); + + char * (* begin_flush) (DrmDriver *driver, + uint32_t buffer_id); + + void (* end_flush) (DrmDriver *driver, + uint32_t buffer_id); + + void (* destroy_buffer) (DrmDriver *driver, + uint32_t buffer_id); +} DrmDriverOps; + +/* implement this stub to return the DRM driver operators */ +DrmDriverOps* __drm_ex_driver_get (const char* driver_name); + +#endif /* _MGGAL_DRM */ + /* external stubs for COMMLCD NEWGAL engine */ #ifdef _MGGAL_COMMLCD diff --git a/src/newgal/drm/Makefile.am b/src/newgal/drm/Makefile.am index baf59845..d4d5c44c 100644 --- a/src/newgal/drm/Makefile.am +++ b/src/newgal/drm/Makefile.am @@ -1,6 +1,6 @@ ## Makefile.am for the drm video driver -AM_CPPFLAGS = -I$(abs_top_srcdir)/src/include -I$(abs_top_srcdir)/include -I$(abs_top_srcdir)/src/newgal/ +AM_CPPFLAGS = -I$(abs_top_srcdir)/src/include -I$(abs_top_srcdir)/include -I$(abs_top_srcdir)/src/newgal/ -I$(DRM_INC_DIR) noinst_LTLIBRARIES = libvideo_drm.la diff --git a/src/newgal/drm/drmvideo.c b/src/newgal/drm/drmvideo.c index 1e8a9d60..30894cbf 100644 --- a/src/newgal/drm/drmvideo.c +++ b/src/newgal/drm/drmvideo.c @@ -35,16 +35,27 @@ #include #include +#define _DEBUG #include "common.h" -#include "newgal.h" -#include "sysvideo.h" -#include "pixels_c.h" #ifdef _MGGAL_DRM +#include +#include +#include +#include +#include +#include +#include + +#include "minigui.h" +#include "newgal.h" +#include "exstubs.h" + +#include "pixels_c.h" #include "drmvideo.h" -#define DRMVID_DRIVER_NAME "drm" +#define DRM_DRIVER_NAME "drm" /* Initialization/Query functions */ static int DRM_VideoInit(_THIS, GAL_PixelFormat *vformat); @@ -61,15 +72,104 @@ static void DRM_FreeHWSurface(_THIS, GAL_Surface *surface); static int DRM_Available(void) { - return(1); + return drmAvailable(); } static void DRM_DeleteDevice(GAL_VideoDevice *device) { + if (device->hidden->driver && device->hidden->driver_ops) { + device->hidden->driver_ops->destroy_driver(device->hidden->driver); + } + free(device->hidden); free(device); } +static char* find_driver_for_device (const char *dev_name) +{ + char *driver; + int major_number, minor_number; + struct stat file_attrs; + char *device_path; + char device_link_path[PATH_MAX + 1] = ""; + int ret; + + if (stat (dev_name, &file_attrs) < 0) { + _ERR_PRINTF("NEWGAL>DRM: failed to call stat on %s\n", dev_name); + return NULL; + } + + if (!S_ISCHR (file_attrs.st_mode)) { + _ERR_PRINTF("NEWGAL>DRM: %s is not a character device\n", dev_name); + return NULL; + } + + major_number = major (file_attrs.st_rdev); + minor_number = minor (file_attrs.st_rdev); + + ret = asprintf (&device_path, "/sys/dev/char/%d:%d/device/driver", + major_number, minor_number); + if (ret < 0) { + _ERR_PRINTF("NEWGAL>DRM: failed to call asprintf to build device path\n"); + return NULL; + } + + if (readlink (device_path, device_link_path, + sizeof (device_link_path) - 1) < 0) { + free (device_path); + return NULL; + } + + _DBG_PRINTF("NEWGAL>DRM: device link path: %s\n", device_link_path); + + free (device_path); + driver = strrchr (device_link_path, '/'); + if (driver == NULL) + return NULL; + + return strdup (driver + strlen ("/")); +} + +static int open_drm_device(GAL_VideoDevice *device) +{ + char *driver_name; + int device_fd; + + driver_name = find_driver_for_device(device->hidden->dev_name); + _DBG_PRINTF("NEWGAL>DRM: Trye to load DRM driver: %s\n", driver_name); + device_fd = drmOpen(driver_name, NULL); + + if (device_fd < 0) { + _ERR_PRINTF("drmOpen failed"); + free(driver_name); + return -1; + } + + if (strcmp(driver_name, "i915") == 0) { + _DBG_PRINTF("NEWGAL>DRM: found driver: i915\n"); + } + else { +#ifdef __TARGET_EXTERNAL__ + device->hidden->driver_ops = __drm_ex_driver_get(driver_name); +#endif + } + + free (driver_name); + if (device->hidden->driver_ops == NULL) { + close (device_fd); + return -1; + } + + device->hidden->driver = device->hidden->driver_ops->create_driver(device_fd); + if (device->hidden->driver == NULL) { + close(device_fd); + return -1; + } + + device->hidden->dev_fd = device_fd; + return 0; +} + static GAL_VideoDevice *DRM_CreateDevice(int devindex) { GAL_VideoDevice *device; @@ -77,18 +177,30 @@ static GAL_VideoDevice *DRM_CreateDevice(int devindex) /* Initialize all variables that we clean on shutdown */ device = (GAL_VideoDevice *)malloc(sizeof(GAL_VideoDevice)); if ( device ) { - memset(device, 0, (sizeof *device)); + memset(device, 0, (sizeof (*device))); device->hidden = (struct GAL_PrivateVideoData *) - malloc((sizeof *device->hidden)); + malloc((sizeof (*device->hidden))); } - if ( (device == NULL) || (device->hidden == NULL) ) { + if ((device == NULL) || (device->hidden == NULL)) { GAL_OutOfMemory(); - if ( device ) { + if (device) { free(device); } - return(0); + return NULL; + } + + memset(device->hidden, 0, (sizeof (*device->hidden))); + if (GetMgEtcValue ("drm", "device", + device->hidden->dev_name, LEN_DEVICE_NAME) < 0) { + strcpy(device->hidden->dev_name, "/dev/dri/card0"); + _WRN_PRINTF("No drm.device defined, use the default '/dev/dri/card0'"); + } + + device->hidden->dev_fd = -1; + open_drm_device(device); + if (device->hidden->dev_fd < 0) { + return NULL; } - memset(device->hidden, 0, (sizeof *device->hidden)); /* Set the function pointers */ device->VideoInit = DRM_VideoInit; @@ -112,14 +224,14 @@ static GAL_VideoDevice *DRM_CreateDevice(int devindex) } VideoBootStrap DRM_bootstrap = { - DRMVID_DRIVER_NAME, "Linux DRM video driver", + DRM_DRIVER_NAME, "Linux DRM video driver", DRM_Available, DRM_CreateDevice }; static int DRM_VideoInit(_THIS, GAL_PixelFormat *vformat) { - _MG_PRINTF("NEWGAL>DRM: Calling init method!\n"); + _DBG_PRINTF("NEWGAL>DRM: Calling init method!\n"); /* Determine the screen depth (use default 8-bit depth) */ /* we change this during the GAL_SetVideoMode implementation... */ diff --git a/src/newgal/drm/drmvideo.h b/src/newgal/drm/drmvideo.h index 0056ad04..22af5321 100644 --- a/src/newgal/drm/drmvideo.h +++ b/src/newgal/drm/drmvideo.h @@ -41,7 +41,15 @@ /* Private display data */ +#define LEN_DEVICE_NAME 31 + struct GAL_PrivateVideoData { + char dev_name[LEN_DEVICE_NAME + 1]; + int dev_fd; + + DrmDriverOps* driver_ops; + DrmDriver* driver; + int w, h; void *buffer; };