diff --git a/src/Makefile.am b/src/Makefile.am index a3faea2..0e6b2f5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -52,7 +52,11 @@ fbturbo_drv_la_SOURCES = \ sunxi_video.c \ sunxi_video.h \ sunxi_disp_ioctl.h \ - g2d_driver.h + g2d_driver.h \ + raspi_hwcursor.c \ + raspi_hwcursor.h \ + raspi_mailbox.c \ + raspi_mailbox.h if HAVE_LIBUMP fbturbo_drv_la_SOURCES += \ diff --git a/src/fbdev.c b/src/fbdev.c index 90d9f39..7390690 100644 --- a/src/fbdev.c +++ b/src/fbdev.c @@ -55,6 +55,8 @@ #include "backing_store_tuner.h" #include "sunxi_video.h" +#include "raspi_hwcursor.h" + #ifdef HAVE_LIBUMP #include "sunxi_mali_ump_dri2.h" #endif @@ -282,12 +284,12 @@ static Bool FBDevPciProbe(DriverPtr drv, int entity_num, pScrn = xf86ConfigPciEntity(NULL, 0, entity_num, NULL, NULL, NULL, NULL, NULL, NULL); if (pScrn) { - char *device; + const char *device; GDevPtr devSection = xf86GetDevFromEntity(pScrn->entityList[0], pScrn->entityInstanceList[0]); device = xf86FindOptionValue(devSection->options, "fbdev"); - if (fbdevHWProbe(NULL, device, NULL)) { + if (fbdevHWProbe(NULL, (char*)device, NULL)) { pScrn->driverVersion = FBDEV_VERSION; pScrn->driverName = FBDEV_DRIVER_NAME; pScrn->name = FBDEV_NAME; @@ -326,7 +328,7 @@ FBDevProbe(DriverPtr drv, int flags) #ifndef XSERVER_LIBPCIACCESS int bus,device,func; #endif - char *dev; + const char *dev; Bool foundScreen = FALSE; TRACE("probe start"); @@ -363,7 +365,7 @@ FBDevProbe(DriverPtr drv, int flags) 0; } - if (fbdevHWProbe(NULL,dev,NULL)) { + if (fbdevHWProbe(NULL,(char*)dev,NULL)) { pScrn = NULL; if (isPci) { #ifndef XSERVER_LIBPCIACCESS @@ -464,7 +466,7 @@ FBDevPreInit(ScrnInfoPtr pScrn, int flags) } #endif /* open device */ - if (!fbdevHWInit(pScrn,NULL,xf86FindOptionValue(fPtr->pEnt->device->options,"fbdev"))) + if (!fbdevHWInit(pScrn, NULL, (char*)xf86FindOptionValue(fPtr->pEnt->device->options,"fbdev"))) return FALSE; default_depth = fbdevHWGetDepth(pScrn,&fbbpp); if (!xf86SetDepthBpp(pScrn, default_depth, default_depth, fbbpp, @@ -1066,8 +1068,18 @@ FBDevScreenInit(SCREEN_INIT_ARGS_DECL) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "using hardware cursor\n"); else - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "failed to enable hardware cursor\n"); + { + // Try the raspi cursor code + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Detecting Raspi HW cursor...\n"); + + fPtr->SunxiDispHardwareCursor_private = raspberry_cursor_init(pScreen); + + if (fPtr->SunxiDispHardwareCursor_private) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "using Raspi hardware cursor\n"); + else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "failed to enable hardware cursor\n"); + } } #ifdef HAVE_LIBUMP diff --git a/src/fbdev_priv.h b/src/fbdev_priv.h index 6a6e4ce..a98f39f 100644 --- a/src/fbdev_priv.h +++ b/src/fbdev_priv.h @@ -83,3 +83,5 @@ typedef struct { #define SUNXI_VIDEO(p) ((SunxiVideo *) \ (FBDEVPTR(p)->SunxiVideo_private)) + +#define RASPI_DISP_HWC(p) ((raspberry_cursor_state_s *) (FBDEVPTR(p)->SunxiDispHardwareCursor_private)) diff --git a/src/raspi_hwcursor.c b/src/raspi_hwcursor.c new file mode 100644 index 0000000..6282842 --- /dev/null +++ b/src/raspi_hwcursor.c @@ -0,0 +1,354 @@ +/* + * Copyright © 2014 James Hughes jnahughes@googlemail.com + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + + +#include "xf86.h" +#include "xf86Cursor.h" +#include "cursorstr.h" +#include "servermd.h" + +#include "sunxi_disp.h" +#include "fbdev_priv.h" +#include "raspi_hwcursor.h" +#include "raspi_mailbox.h" + + +#define MIN_RASPI_VERSION_NUMBER 1390809622 + +/* Show/Enable the cursor + * + */ +static void ShowCursor(ScrnInfoPtr pScrn) +{ + raspberry_cursor_state_s *state = RASPI_DISP_HWC(pScrn); + + state->enabled = 1; + + mailbox_set_cursor_position(state->mailbox_fd, state->enabled, state->x, state->y, 1); +} + +/* Hide/Disable the cursor + * + */ +static void HideCursor(ScrnInfoPtr pScrn) +{ + raspberry_cursor_state_s *state = RASPI_DISP_HWC(pScrn); + + state->enabled = 0; + + mailbox_set_cursor_position(state->mailbox_fd, state->enabled, state->x, state->y, 1); +} + +/* Set cursor position on display + * + */ +static void SetCursorPosition(ScrnInfoPtr pScrn, int x, int y) +{ + raspberry_cursor_state_s *state = RASPI_DISP_HWC(pScrn); + + state->x = x; + state->y = y; + + mailbox_set_cursor_position(state->mailbox_fd, state->enabled, state->x, state->y, 1); +} + +/* Set the cursor colours. + */ +static void SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) +{ + raspberry_cursor_state_s *state = RASPI_DISP_HWC(pScrn); + + state->background_colour = bg; + state->foreground_colour = fg; + + // Ought to regenerate the ARGB cursor here using the new colours...but current version + // doesn't support this. Something for another day... +} + +/* Load a cursor image. + * Loads the supplied cursor bits to VC4 + */ +static void LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *bits) +{ + raspberry_cursor_state_s *state = RASPI_DISP_HWC(pScrn); + int size = state->realised_width * state->realised_height * 4; + + memcpy(state->transfer_buffer.user, bits, size); + + // Our cursor needs a minimum width/height of 16 each + mailbox_set_cursor_info(state->mailbox_fd, state->realised_width, state->realised_height, 0, state->transfer_buffer.buffer, state->hotspotx, state->hotspotx); +} + +/* Called to generate a ARGB cursor from the X definition passed in + * + * Incoming data is 1bpp, with the rows padded to BITMAP_SCANLINE_PAD bits. + * + */ +static unsigned char* RealiseCursor(xf86CursorInfoPtr info, CursorPtr pCurs) +{ + raspberry_cursor_state_s *state = RASPI_DISP_HWC(info->pScrn); + char *mem; + // Round up our width/height to 16 as minimum requirements for VC cursor + int dest_width = pCurs->bits->width < 16 ? 16 : pCurs->bits->width; + int dest_height = pCurs->bits->height < 16 ? 16 : pCurs->bits->height; + int dest_size = dest_width * dest_height * 4; // 4 bpp; + int dest_pitch = dest_width; // this is in uint32_t's so no need pump up by bpp + + mem = calloc(1, dest_size); + + // Passed in colours are 16 bit device independent values. We want 8 bit components in one uint32_t + state->foreground_colour = (pCurs->foreRed & 0xFF00) << 8 | (pCurs->foreGreen & 0xFF00) | (pCurs->foreBlue & 0xff00) >> 8; + state->background_colour = (pCurs->backRed & 0xFF00) << 8 | (pCurs->backGreen & 0xFF00) | (pCurs->backBlue & 0xff00) >> 8; + + if (mem) + { + if (pCurs->bits->argb) + { + memcpy(mem, pCurs->bits->argb, dest_size); + } + else + { + int x,y,bit; + typedef uint8_t PIX_TYPE; + #define PIX_TYPE_SIZE (sizeof(PIX_TYPE) * 8) + + PIX_TYPE *src = (PIX_TYPE *)pCurs->bits->source; + PIX_TYPE *mask = (PIX_TYPE *)pCurs->bits->mask; + PIX_TYPE *current_src, *current_mask; + + uint32_t *dst, pixel; + + // Pitch may not be the width. + // Pad up to the BITMAP_SCANLINE_PAD to give pixels, then work out the number of PIX types in the width + // at 1bpp + int src_pitch = ( (pCurs->bits->width +(BITMAP_SCANLINE_PAD - 1)) & ~(BITMAP_SCANLINE_PAD - 1)) / PIX_TYPE_SIZE; + + dst = (uint32_t*)mem; + + // For every scanline in source + for (y=0;ybits->height;y++) + { + uint32_t *dst_p = dst; + current_src = src; + current_mask = mask; + + // For each PIX in scanline + for (x=0;xbits->width;x+=PIX_TYPE_SIZE) + { + // For each bit in the incoming PIX, @ 1bits per pixel + for (bit=0;bit> bit) & 0x01) ? state->foreground_colour : state->background_colour; + + pixel |= ((*current_mask >> bit) & 0x01) ? 0xff000000 : 0; + + *dst_p++ = pixel; + } + + current_src++; + current_mask++; + } + + src += src_pitch; + mask += src_pitch; + dst += dest_pitch; + } + } + + state->realised_height = dest_height; + state->realised_width = dest_width; + state->hotspotx = 0; + state->hotspoty = 0; // pCurs->bits->height; + + } + + return mem; +} + +/* Called to turn on the ARGB HW cursor + * + */ +static Bool UseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + raspberry_cursor_state_s *state = RASPI_DISP_HWC(pScrn); + + /* VC4 supports ARGB cursors up to 64x64 */ + + if (pCurs->bits->height <= MAX_ARGB_CURSOR_HEIGHT && pCurs->bits->width <= MAX_ARGB_CURSOR_WIDTH) + { + state->enabled = 1; + } + else + { + state->enabled = 0; + } + + mailbox_set_cursor_position(state->mailbox_fd, state->enabled, state->x, state->y, 1); + + return state->enabled ? TRUE : FALSE; +} + +/* Load an ARGB8888 bitmap to the VC4 for use as cursor + * + */ +static void LoadCursorARGB(ScrnInfoPtr pScrn, CursorPtr pCurs) +{ + raspberry_cursor_state_s *state = RASPI_DISP_HWC(pScrn); + int copy_size; + + state->width = pCurs->bits->width; + state->height = pCurs->bits->height; + state->format = 0; + + // It appears that the hotspot is already compensated for by X, so we dont need to pass it on to VC4. + state->hotspotx = 0; + state->hotspoty = 0; + + // Clear our transfer buffer up front + memset(state->transfer_buffer.user, 0, state->transfer_buffer_size); + + // Copy cursor pixels to our VC memory + copy_size = min(state->width * state->height * 4, state->transfer_buffer_size) ; // 4 bytes/pixel + + memcpy(state->transfer_buffer.user, pCurs->bits->argb, copy_size); + + mailbox_set_cursor_info(state->mailbox_fd, state->width, state->height, state->format, state->transfer_buffer.buffer, state->hotspotx, state->hotspoty); +} + + +/* Initialise the Raspberry Pi HW cursor system + * + */ +raspberry_cursor_state_s *raspberry_cursor_init(ScreenPtr pScreen) +{ + xf86CursorInfoPtr InfoPtr; + raspberry_cursor_state_s *state; + int fd; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + unsigned int version; + VIDEOCORE_MEMORY_H mem; + int alloc_size, dummy; + + fd = mailbox_init(); + + if (fd == 0) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "raspberry_cursor_init: Failed to initialise mailbox\n"); + return NULL; + } + + // Get the firmware number to ensure we have cursor support. + version = mailbox_get_version(fd); + + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "raspberry_cursor_init: Detected firmware version %d)\n", version); + + if ( version < MIN_RASPI_VERSION_NUMBER) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "raspberry_cursor_init: No cursor support present in this firmware\n"); + return NULL; + } + + if (!(InfoPtr = xf86CreateCursorInfoRec())) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "raspberry_cursor_init: xf86CreateCursorInfoRec() failed\n"); + return NULL; + } + + InfoPtr->ShowCursor = ShowCursor; + InfoPtr->HideCursor = HideCursor; + InfoPtr->SetCursorPosition = SetCursorPosition; + InfoPtr->SetCursorColors = SetCursorColors; + InfoPtr->LoadCursorImage = LoadCursorImage; + InfoPtr->RealizeCursor = RealiseCursor; + + InfoPtr->MaxWidth = MAX_ARGB_CURSOR_WIDTH; + InfoPtr->MaxHeight = MAX_ARGB_CURSOR_HEIGHT; + InfoPtr->Flags = HARDWARE_CURSOR_ARGB | HARDWARE_CURSOR_UPDATE_UNHIDDEN ; + + InfoPtr->UseHWCursorARGB = UseHWCursorARGB; + InfoPtr->LoadCursorARGB = LoadCursorARGB; + + if (!xf86InitCursor(pScreen, InfoPtr)) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "raspberry_cursor_init: xf86InitCursor(pScreen, InfoPtr) failed\n"); + xf86DestroyCursorInfoRec(InfoPtr); + return NULL; + } + + state = calloc(1, sizeof(raspberry_cursor_state_s)); + if (!state) + { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "raspberry_cursor_init: calloc failed\n"); + xf86DestroyCursorInfoRec(InfoPtr); + return NULL; + } + + // Get some videocore memory for pixel buffer when transferring cursor image to GPU + // Allocate the max size we will need. Its not a huge amount anyway. + state->transfer_buffer_size = MAX_ARGB_CURSOR_HEIGHT * MAX_ARGB_CURSOR_WIDTH * 4;// 4 bytes/pixel + state->transfer_buffer = mailbox_videocore_alloc(fd, state->transfer_buffer_size); + + state->InfoPtr = InfoPtr; + state->mailbox_fd = fd; + + state->hotspotx = 0; + state->hotspoty = 0; + + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "raspberry_cursor_init: Complete\n"); + + return state; +} + +/* Close down the Raspberry Pi cursor system and release any resources + * + */ +void raspberry_cursor_close(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + raspberry_cursor_state_s *state = RASPI_DISP_HWC(pScrn); + + if (state) + { + // Get rid of cursor from display + mailbox_set_cursor_position(state->mailbox_fd, 0, state->x, state->y, 1); + + mailbox_videocore_free(state->mailbox_fd, state->transfer_buffer); + xf86DestroyCursorInfoRec(state->InfoPtr); + mailbox_deinit(state->mailbox_fd); + } +} + diff --git a/src/raspi_hwcursor.h b/src/raspi_hwcursor.h new file mode 100644 index 0000000..ac35dce --- /dev/null +++ b/src/raspi_hwcursor.h @@ -0,0 +1,60 @@ +/* + * Copyright © 2014 James Hughes jnahughes@googlemail.com + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "raspi_mailbox.h" + +#ifndef RASPI_CURSOR_H_ +#define RASPI_CURSOR_H_ + +typedef struct +{ + int enabled; + int x; + int y; + + int width; + int height; + int format; // Not used + int hotspotx; + int hotspoty; + + uint32_t foreground_colour; + uint32_t background_colour; + + xf86CursorInfoPtr InfoPtr; + int mailbox_fd; + + VIDEOCORE_MEMORY_H transfer_buffer; + int transfer_buffer_size; + + int realised_width; + int realised_height; +} raspberry_cursor_state_s; + +#define MAX_ARGB_CURSOR_HEIGHT 64 +#define MAX_ARGB_CURSOR_WIDTH 64 + +extern raspberry_cursor_state_s *raspberry_cursor_init(ScreenPtr pScreen); +extern void raspberry_cursor_close(ScreenPtr pScreen); + +#endif /* RASPI_CURSOR_H_ */ diff --git a/src/raspi_mailbox.c b/src/raspi_mailbox.c new file mode 100644 index 0000000..53b4320 --- /dev/null +++ b/src/raspi_mailbox.c @@ -0,0 +1,428 @@ + /* + * Copyright © 2014 James Hughes jnahughes@googlemail.com + * Based on some code copyright Herman Hermitage + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "raspi_mailbox.h" + +// Use a page size of 4k +static const int page_size = 4*1024; +static const int alignment = 4*1024; + +// Might be a define for this somewhere in the raspi userland headers somewhere? +#define MEMORY_ALLOCATE_FLAG 0x0c + +// device parameters +#define MAILBOX_DEVICE_FILENAME "/dev/vc4mail" +#define MAJOR 100 +#define MINOR 0 +#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR, MINOR, char *) + + + +static int set_mailbox_property(int file_desc, void *buf) +{ + int retval = ioctl(file_desc, IOCTL_MBOX_PROPERTY, buf); + + if (retval < 0) + { + printf("ioctl_set_msg failed:%d\n", retval); + } + return retval; +} + + +/** map the specified address in to userspace + * + * @param base + * @param size + * + * @return pointer to mapped memory, NULL if failed for any reason. + * + */ +static void *map_memory(unsigned int base, unsigned int size) +{ + int fd; + unsigned int offset = base % page_size; + void *memory; + + base = base - offset; + + if ((fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) + { + return NULL; + } + + memory = mmap(0, + size, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, + base); + + if (memory == MAP_FAILED) + { + return NULL; + } + + close(fd); + + return memory + offset; +} + +/** Unmap previously mapped memory + * + * @param addr + * @param size + * + */ +static void *unmap_memory(void *addr, unsigned int size) +{ + int s = munmap(addr, size); + + if (s != 0) + { + // how to report error? + return NULL; + } + + return NULL; +} + +/** Alloc a block of relocatable memory on the Videocore via mailbox call + * + * @param fd file descriptor of the mailbox driver + * @param size size of block to allocate + * @param align ALignment requirements + * @param flags VC4 Allocation flag + * @return Handle to the memory block, or NULL + */ +unsigned int mailbox_memory_alloc(int fd, unsigned int size, unsigned int align, unsigned int flags) +{ + int i=0; + unsigned int p[32]; + p[i++] = 0; // size. Filled in below + p[i++] = 0x00000000; + + p[i++] = 0x3000c; // (the tag id) + p[i++] = 12; // (size of the buffer) + p[i++] = 12; // (size of the data) + p[i++] = size; // (num bytes? or pages?) + p[i++] = align; // + p[i++] = flags; // (MEM_FLAG_L1_NONALLOCATING) + + p[i++] = 0x00000000; // end tag + p[0] = i*sizeof(*p); // actual size + + set_mailbox_property(fd, p); + + return p[5]; +} + +/** Free memory previously allocated on the Videocore via mailbox call + * + * @param fd file descriptor of the mailbox driver + * @param handle Handle to thememory block as returned by the alloc call + * + */ +unsigned int mailbox_memory_free(int file_desc, unsigned int handle) +{ + int i=0; + unsigned int p[32]; + p[i++] = 0; + p[i++] = 0x00000000; + + p[i++] = 0x3000f; + p[i++] = 4; + p[i++] = 4; + p[i++] = handle; + + p[i++] = 0x00000000; // end tag + p[0] = i*sizeof(*p); // actual size + + set_mailbox_property(file_desc, p); + + return p[5]; +} + +/** Lock a block of relocatable memory Videocore via mailbox call + * + * @param fd file descriptor of the mailbox driver + * @param handle Handle to thememory block as returned by the alloc call + * @return Pointer (in video core address space) to the locked block + */ +unsigned int mailbox_memory_lock(int file_desc, unsigned int handle) +{ + int i=0; + unsigned int p[32]; + p[i++] = 0; + p[i++] = 0x00000000; + + p[i++] = 0x3000d; + p[i++] = 4; + p[i++] = 4; + p[i++] = handle; + + p[i++] = 0x00000000; // end tag + p[0] = i*sizeof(*p); // actual size + + set_mailbox_property(file_desc, p); + + return p[5]; +} + +/** Lock a block of relocatable memory Videocore via mailbox call + * + * @param fd file descriptor of the mailbox driver + * @param handle Handle to the memory block as returned by the alloc call + * @return ??? Dunno + */ +unsigned int mailbox_memory_unlock(int file_desc, unsigned handle) +{ + int i=0; + unsigned int p[32]; + p[i++] = 0; + p[i++] = 0x00000000; + + p[i++] = 0x3000e; + p[i++] = 4; + p[i++] = 4; + p[i++] = handle; + + p[i++] = 0x00000000; // end tag + p[0] = i*sizeof(*p); // actual size + + set_mailbox_property(file_desc, p); + + return p[5]; +} + +/** Function that wraps the mailbox calls above to make a easy to use + * allocation function + * + * @param fd file descriptor of the mailbox driver + * @param size AMount of memory to allocate + * @return A structure containing the allocation details. + */ +VIDEOCORE_MEMORY_H mailbox_videocore_alloc(int fd, int size) +{ + VIDEOCORE_MEMORY_H mem; + + // allocate memory on GPU, map it ready for use + mem.handle = mailbox_memory_alloc(fd, size, alignment, MEMORY_ALLOCATE_FLAG); + mem.buffer = mailbox_memory_lock(fd, mem.handle); + mem.user = map_memory(mem.buffer, size); + mem.size = size; + + return mem; +} + +/** Function that wraps the mailbox calls above to make a easy to use + * deallocation function + * + * @param fd file descriptor of the mailbox driver + * @param mem Structure that was the result of the allocate call + */ +void mailbox_videocore_free(int file_desc, VIDEOCORE_MEMORY_H mem) +{ + unmap_memory(mem.user, mem.size); + mailbox_memory_unlock(file_desc, mem.handle); + mailbox_memory_free(file_desc, mem.handle); +} + + +/** Function that sets the HW cursor position on the display + * + * @param file_desc file descriptor of the mailbox driver + * @param enabled Flag to enable/disable the cursor + * @param x X position + * @param y Y position + * @param flag Bitfield. Bit 0 : 0 = display coords 1 = framebuffer coords. + */ +unsigned int mailbox_set_cursor_position(int file_desc, int enabled, int x, int y, int flag) +{ + int i=0; + unsigned p[32]; + p[i++] = 0; // size + p[i++] = 0x00000000; // process request + p[i++] = 0x00008011; // set cursor state + p[i++] = 12; // buffer size + p[i++] = 12; // data size + + p[i++] = enabled; + p[i++] = x; + p[i++] = y; + p[i++] = flag; + + p[i++] = 0x00000000; // end tag + p[0] = i*sizeof *p; // actual size + + set_mailbox_property(file_desc, p); + return p[5]; +} + +/** Function that sets the HW cursor image, size and hotspots + * + * @param file_desc file descriptor of the mailbox driver + * @param width Width of cursor, max 64 + * @param height Height of cursor, max 64 + * @param format Not presently used + * @param Handle to Videocore memory buffer, as returned in VIDEOCORE_MEMORY_H.buffer in the mailbox_videocore_alloc call + * @param hotspotx X point in image that is the 'hotspot' + * @param hotspoty Y point in image that is the 'hotspot' + * + * @return ?? + */ +unsigned int mailbox_set_cursor_info(int file_desc, int width, int height, int format, uint32_t buffer, int hotspotx, int hotspoty) +{ + int i=0; + unsigned int p[32]; + p[i++] = 0; // size + p[i++] = 0x00000000; // process request + p[i++] = 0x00008010; // set cursor state + p[i++] = 24; // buffer size + p[i++] = 24; // data size + + p[i++] = width; + p[i++] = height; + p[i++] = format; + p[i++] = buffer; // ptr to VC memory buffer. Doesn't work in 64bit.... + p[i++] = hotspotx; + p[i++] = hotspoty; + + p[i++] = 0x00000000; // end tag + p[0] = i*sizeof(*p); // actual size + + set_mailbox_property( file_desc, p); + return p[5]; + +} + +/** Function that gets the current VC version number + * + * @param file_desc file descriptor of the mailbox driver + * @return The firmware version number (which is time of build) + */ +unsigned int mailbox_get_version(int file_desc) +{ + int i=0; + unsigned p[32]; + p[i++] = 0; // size + p[i++] = 0x00000000; // process request + + p[i++] = 0x00000001; // get firmware version + p[i++] = 0x00000004; // buffer size + p[i++] = 0x00000000; // request size + p[i++] = 0x00000000; // value buffer + + p[i++] = 0x00000000; // end tag + p[0] = i*sizeof *p; // actual size + + set_mailbox_property(file_desc, p); + return p[5]; +} + +/** Function that gets the current overscan settings + * + * @param file_desc file descriptor of the mailbox driver + * @param[out] top, bottom, left, right + * @return ?? + */ +unsigned int mailbox_get_overscan(int file_desc, int *top, int *bottom, int *left, int *right) +{ + int i=0; + unsigned p[32]; + p[i++] = 0; // size + p[i++] = 0x00000000; // process request + + p[i++] = 0x0004000a; // get firmware version + p[i++] = 0x00000010; // buffer size + p[i++] = 0x00000000; // request size + + p[i++] = 0x00000000; // top + p[i++] = 0x00000000; // bottom + p[i++] = 0x00000000; // left + p[i++] = 0x00000000; // right + + p[i++] = 0x00000000; // end tag + p[0] = i*sizeof *p; // actual size + + set_mailbox_property(file_desc, p); + + *top = p[5]; + *bottom = p[6]; + *left = p[7]; + *right = p[8]; + + return p[5]; +} + + + +/** Function to initialise the mailbox system + * + * @return Returns a file descriptor for use in mailbox_* calls or 0 if failed + */ +int mailbox_init(void) +{ + struct stat stat_buf; + int fd; + + // See if we have a device node, if not create one. + if (stat(MAILBOX_DEVICE_FILENAME, &stat_buf) == -1) + { + // No node so attempt to create one. + // Character device, readable by all + if (mknod(MAILBOX_DEVICE_FILENAME, S_IFCHR | S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, makedev(MAJOR, MINOR)) == -1) + return 0; + } + + // First check to see if we have the mailbox char device + fd = open(MAILBOX_DEVICE_FILENAME, 0); + if (fd < 0) + { + return 0; + } + + return fd; +} + +/** Function to close down the mailbox system and release resources + * + * @param fd File descriptor returned from the init call. + */ +void mailbox_deinit(int fd) +{ + close(fd); + + // Should I delete the node? +} diff --git a/src/raspi_mailbox.h b/src/raspi_mailbox.h new file mode 100644 index 0000000..94693a1 --- /dev/null +++ b/src/raspi_mailbox.h @@ -0,0 +1,55 @@ + /* + * Copyright © 2014 James Hughes jnahughes@googlemail.com + * Based on some code copyright Herman Hermitage + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef RASPI_MEMORY_H_ +#define RASPI_MEMORY_H_ + +typedef struct +{ + uint32_t handle; + uint32_t buffer; + void *user; + uint32_t size; +} VIDEOCORE_MEMORY_H; + +int mailbox_init(void); +void mailbox_deinit(int fd); + +unsigned int mailbox_memory_alloc(int file_desc, unsigned int size, unsigned int align, unsigned int flags); +unsigned int mailbox_memory_free(int file_desc, unsigned int handle); +unsigned int mailbox_memory_lock(int file_desc, unsigned int handle); +unsigned int mailbox_memory_unlock(int file_desc, unsigned int handle); + + +VIDEOCORE_MEMORY_H mailbox_videocore_alloc(int file_desc, int size); +void mailbox_videocore_free(int file_desc, VIDEOCORE_MEMORY_H mem); + +unsigned int mailbox_set_cursor_position(int file_desc, int enabled, int x, int y, int flag); +unsigned int mailbox_set_cursor_info(int file_desc, int width, int height, int format, uint32_t buffer, int hotspotx, int hotspoty); + +unsigned int mailbox_get_version(int file_desc); +unsigned int mailbox_get_overscan(int file_desc, int *top, int *bottom, int *left, int *right); + + +#endif /* RASPI_MEMORY_H_ */