aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/cdv/bc_video/bufferclass_video_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/cdv/bc_video/bufferclass_video_linux.c')
-rw-r--r--drivers/staging/cdv/bc_video/bufferclass_video_linux.c838
1 files changed, 838 insertions, 0 deletions
diff --git a/drivers/staging/cdv/bc_video/bufferclass_video_linux.c b/drivers/staging/cdv/bc_video/bufferclass_video_linux.c
new file mode 100644
index 000000000000..f70418a0f0c6
--- /dev/null
+++ b/drivers/staging/cdv/bc_video/bufferclass_video_linux.c
@@ -0,0 +1,838 @@
+/****************************************************************************
+ *
+ * Copyright © 2011 Intel Corporation
+ *
+ * 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 <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#if defined(LMA)
+#include <linux/pci.h>
+#else
+#include <linux/dma-mapping.h>
+#endif
+
+#include <drm/drmP.h>
+#include <drm/drm.h>
+#include "psb_drv.h"
+#include "ttm/ttm_bo_api.h"
+#include "ttm/ttm_placement.h"
+#include "ttm/ttm_object.h"
+
+#include "bufferclass_video.h"
+#include "bufferclass_video_linux.h"
+#include "pvrmodule.h"
+#include "sys_pvr_drm_export.h"
+
+#define DEVNAME "bc_video"
+#define DRVNAME DEVNAME
+
+#if defined(BCE_USE_SET_MEMORY)
+#undef BCE_USE_SET_MEMORY
+#endif
+
+#if defined(__i386__) && defined(SUPPORT_LINUX_X86_PAT) && defined(SUPPORT_LINUX_X86_WRITECOMBINE)
+#include <asm/cacheflush.h>
+#define BCE_USE_SET_MEMORY
+#endif
+
+#define BC_CDV_COUNT 32
+#define BC_CDV_STRIDE 2048
+#define BC_CDV_HEIGHT 2048
+#define BC_CDV_WIDTH 2048
+
+static int width_align;
+unsigned int bc_video_id_usage[BC_VIDEO_DEVICE_MAX_ID];
+
+MODULE_SUPPORTED_DEVICE (DEVNAME);
+
+int FillBuffer (unsigned int uiBufferIndex);
+
+#if defined(LDM_PLATFORM) || defined(LDM_PCI)
+static struct class *psPvrClass;
+#endif
+
+static int AssignedMajorNumber;
+
+#define unref__ __attribute__ ((unused))
+
+#if defined(LMA)
+#define PVR_BUFFERCLASS_MEMOFFSET (220 * 1024 * 1024)
+#define PVR_BUFFERCLASS_MEMSIZE (4 * 1024 * 1024)
+
+unsigned long g_ulMemBase = 0;
+unsigned long g_ulMemCurrent = 0;
+
+#define VENDOR_ID_PVR 0x1010
+#define DEVICE_ID_PVR 0x1CF1
+
+#define PVR_MEM_PCI_BASENUM 2
+#endif
+
+#define file_to_id(file) (iminor(file->f_path.dentry->d_inode))
+
+int
+BC_Video_ModInit (void)
+{
+ int i, j;
+ /*LDM_PCI is defined, while LDM_PLATFORM and LMA are not defined.*/
+#if defined(LDM_PLATFORM) || defined(LDM_PCI)
+ struct device *psDev;
+#endif
+
+#if defined(LMA)
+ struct pci_dev *psPCIDev;
+ int error;
+#endif
+
+ /* video width is 4 byte aligned */
+ width_align = 4;
+
+#if defined(LMA)
+ psPCIDev = pci_get_device (VENDOR_ID_PVR, DEVICE_ID_PVR, NULL);
+ if (psPCIDev == NULL)
+ {
+ printk (KERN_ERR DRVNAME
+ ": BC_Video_ModInit: pci_get_device failed\n");
+ goto ExitError;
+ }
+
+ if ((error = pci_enable_device (psPCIDev)) != 0)
+ {
+ printk (KERN_ERR DRVNAME
+ ": BC_Video_ModInit: pci_enable_device failed (%d)\n", error);
+ goto ExitError;
+ }
+#endif
+
+#if defined(DEBUG)
+ printk (KERN_ERR DRVNAME ": BC_Video_ModInit: major device %d\n",
+ AssignedMajorNumber);
+#endif
+
+#if defined(LDM_PLATFORM) || defined(LDM_PCI)
+ psPvrClass = class_create (THIS_MODULE, "bc_video");
+ if (IS_ERR (psPvrClass))
+ {
+ printk (KERN_ERR DRVNAME
+ ": BC_Video_ModInit: unable to create class (%ld)",
+ PTR_ERR (psPvrClass));
+ goto ExitUnregister;
+ }
+
+ psDev = device_create (psPvrClass, NULL, MKDEV (AssignedMajorNumber, 0),
+ NULL,
+ DEVNAME);
+ if (IS_ERR (psDev))
+ {
+ printk (KERN_ERR DRVNAME
+ ": BC_Video_ModInit: unable to create device (%ld)",
+ PTR_ERR (psDev));
+ goto ExitDestroyClass;
+ }
+#endif
+
+#if defined(LMA)
+ g_ulMemBase =
+ pci_resource_start (psPCIDev,
+ PVR_MEM_PCI_BASENUM) + PVR_BUFFERCLASS_MEMOFFSET;
+#endif
+
+ for (i = 0; i < BC_VIDEO_DEVICE_MAX_ID; i++)
+ {
+ bc_video_id_usage[i] = 0;
+ if (BC_Video_Init (i) != BCE_OK)
+ {
+ printk (KERN_ERR DRVNAME
+ ": BC_Video_ModInit: can't init video bc device %d.\n", i);
+ for (j = i; j >= 0; j--)
+ {
+ BC_Video_Deinit (j);
+ }
+ goto ExitUnregister;
+ }
+ }
+
+#if defined(LMA)
+ pci_disable_device (psPCIDev);
+#endif
+
+ return 0;
+
+#if defined(LDM_PLATFORM) || defined(LDM_PCI)
+ExitDestroyClass:
+ class_destroy (psPvrClass);
+#endif
+ExitUnregister:
+ unregister_chrdev (AssignedMajorNumber, DEVNAME);
+ //ExitDisable:
+#if defined(LMA)
+ pci_disable_device (psPCIDev);
+ExitError:
+#endif
+ return -EBUSY;
+}
+
+int
+BC_Video_ModCleanup (void)
+{
+ int i;
+#if defined(LDM_PLATFORM) || defined(LDM_PCI)
+ device_destroy (psPvrClass, MKDEV (AssignedMajorNumber, 0));
+ class_destroy (psPvrClass);
+#endif
+
+ for (i = 0; i < BC_VIDEO_DEVICE_MAX_ID; i++)
+ {
+ if (BC_Video_Deinit (i) != BCE_OK)
+ {
+ printk (KERN_ERR DRVNAME
+ ": BC_Video_ModCleanup: can't deinit video device %d.\n",
+ i);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+ void *
+BCAllocKernelMem (unsigned long ulSize)
+{
+ return kmalloc (ulSize, GFP_KERNEL);
+}
+
+void
+BCFreeKernelMem (void *pvMem)
+{
+ kfree (pvMem);
+}
+
+#define RANGE_TO_PAGES(range) (((range) + (PAGE_SIZE - 1)) >> PAGE_SHIFT)
+#define VMALLOC_TO_PAGE_PHYS(vAddr) page_to_phys(vmalloc_to_page(vAddr))
+
+BCE_ERROR
+BCAllocDiscontigMemory (unsigned long ulSize,
+ BCE_HANDLE unref__ * phMemHandle,
+ IMG_CPU_VIRTADDR * pLinAddr,
+ IMG_SYS_PHYADDR ** ppPhysAddr)
+{
+ unsigned long ulPages = RANGE_TO_PAGES (ulSize);
+ IMG_SYS_PHYADDR *pPhysAddr;
+ unsigned long ulPage;
+ IMG_CPU_VIRTADDR LinAddr;
+
+ LinAddr =
+ __vmalloc (ulSize, GFP_KERNEL | __GFP_HIGHMEM,
+ pgprot_noncached (PAGE_KERNEL));
+ if (!LinAddr)
+ {
+ return BCE_ERROR_OUT_OF_MEMORY;
+ }
+
+ pPhysAddr = kmalloc (ulPages * sizeof (IMG_SYS_PHYADDR), GFP_KERNEL);
+ if (!pPhysAddr)
+ {
+ vfree (LinAddr);
+ return BCE_ERROR_OUT_OF_MEMORY;
+ }
+
+ *pLinAddr = LinAddr;
+
+ for (ulPage = 0; ulPage < ulPages; ulPage++)
+ {
+ pPhysAddr[ulPage].uiAddr = VMALLOC_TO_PAGE_PHYS (LinAddr);
+
+ LinAddr += PAGE_SIZE;
+ }
+
+ *ppPhysAddr = pPhysAddr;
+
+ return BCE_OK;
+}
+
+void
+BCFreeDiscontigMemory (unsigned long ulSize,
+ BCE_HANDLE unref__ hMemHandle,
+ IMG_CPU_VIRTADDR LinAddr, IMG_SYS_PHYADDR * pPhysAddr)
+{
+ kfree (pPhysAddr);
+
+ vfree (LinAddr);
+}
+
+ BCE_ERROR
+BCAllocContigMemory (unsigned long ulSize,
+ BCE_HANDLE unref__ * phMemHandle,
+ IMG_CPU_VIRTADDR * pLinAddr, IMG_CPU_PHYADDR * pPhysAddr)
+{
+#if defined(LMA)
+ void *pvLinAddr;
+
+
+ if (g_ulMemCurrent + ulSize >= PVR_BUFFERCLASS_MEMSIZE)
+ {
+ return (BCE_ERROR_OUT_OF_MEMORY);
+ }
+
+ pvLinAddr = ioremap (g_ulMemBase + g_ulMemCurrent, ulSize);
+
+ if (pvLinAddr)
+ {
+ pPhysAddr->uiAddr = g_ulMemBase + g_ulMemCurrent;
+ *pLinAddr = pvLinAddr;
+
+ g_ulMemCurrent += ulSize;
+ return (BCE_OK);
+ }
+ return (BCE_ERROR_OUT_OF_MEMORY);
+#else
+#if defined(BCE_USE_SET_MEMORY)
+ void *pvLinAddr;
+ unsigned long ulAlignedSize = PAGE_ALIGN (ulSize);
+ int iPages = (int) (ulAlignedSize >> PAGE_SHIFT);
+ int iError;
+
+ pvLinAddr = kmalloc (ulAlignedSize, GFP_KERNEL);
+ if (pvLinAddr == NULL)
+ return BCE_ERROR_OUT_OF_MEMORY;
+
+ BUG_ON (((unsigned long) pvLinAddr) & ~PAGE_MASK);
+
+ iError = set_memory_wc ((unsigned long) pvLinAddr, iPages);
+ if (iError != 0)
+ {
+ printk (KERN_ERR DRVNAME
+ ": BCAllocContigMemory: set_memory_wc failed (%d)\n", iError);
+ kfree(pvLinAddr);
+ return (BCE_ERROR_OUT_OF_MEMORY);
+ }
+
+ pPhysAddr->uiAddr = virt_to_phys (pvLinAddr);
+ *pLinAddr = pvLinAddr;
+
+ return (BCE_OK);
+#else
+ dma_addr_t dma;
+ void *pvLinAddr;
+
+ pvLinAddr = dma_alloc_coherent (NULL, ulSize, &dma, GFP_KERNEL);
+ if (pvLinAddr == NULL)
+ {
+ return (BCE_ERROR_OUT_OF_MEMORY);
+ }
+
+ pPhysAddr->uiAddr = dma;
+ *pLinAddr = pvLinAddr;
+
+ return (BCE_OK);
+#endif
+#endif
+}
+
+void
+BCFreeContigMemory (unsigned long ulSize,
+ BCE_HANDLE unref__ hMemHandle,
+ IMG_CPU_VIRTADDR LinAddr, IMG_CPU_PHYADDR PhysAddr)
+{
+#if defined(LMA)
+ g_ulMemCurrent -= ulSize;
+ iounmap (LinAddr);
+#else
+#if defined(BCE_USE_SET_MEMORY)
+ unsigned long ulAlignedSize = PAGE_ALIGN (ulSize);
+ int iError;
+ int iPages = (int) (ulAlignedSize >> PAGE_SHIFT);
+
+ iError = set_memory_wb ((unsigned long) LinAddr, iPages);
+ if (iError != 0)
+ {
+ printk (KERN_ERR DRVNAME
+ ": BCFreeContigMemory: set_memory_wb failed (%d)\n", iError);
+ }
+ kfree (LinAddr);
+#else
+ dma_free_coherent (NULL, ulSize, LinAddr, (dma_addr_t) PhysAddr.uiAddr);
+#endif
+#endif
+}
+
+ IMG_SYS_PHYADDR
+CpuPAddrToSysPAddrBC (IMG_CPU_PHYADDR cpu_paddr)
+{
+ IMG_SYS_PHYADDR sys_paddr;
+ sys_paddr.uiAddr = cpu_paddr.uiAddr;
+ return sys_paddr;
+}
+
+ IMG_CPU_PHYADDR
+SysPAddrToCpuPAddrBC (IMG_SYS_PHYADDR sys_paddr)
+{
+ IMG_CPU_PHYADDR cpu_paddr;
+ cpu_paddr.uiAddr = sys_paddr.uiAddr;
+ return cpu_paddr;
+}
+
+BCE_ERROR
+BCOpenPVRServices (BCE_HANDLE * phPVRServices)
+{
+ *phPVRServices = 0;
+ return (BCE_OK);
+}
+
+
+BCE_ERROR
+BCClosePVRServices (BCE_HANDLE unref__ hPVRServices)
+{
+ return (BCE_OK);
+}
+
+BCE_ERROR
+BCGetLibFuncAddr (BCE_HANDLE unref__ hExtDrv, char *szFunctionName,
+ PFN_BC_GET_PVRJTABLE * ppfnFuncTable)
+{
+ if (strcmp ("PVRGetBufferClassJTable", szFunctionName) != 0)
+ {
+ return (BCE_ERROR_INVALID_PARAMS);
+ }
+
+ *ppfnFuncTable = PVRGetBufferClassJTable;
+
+ return (BCE_OK);
+}
+
+int
+BC_CreateBuffers (int id, bc_buf_params_t * p, IMG_BOOL is_conti_addr)
+{
+ BC_VIDEO_DEVINFO *psDevInfo;
+ IMG_UINT32 i, stride, size;
+ PVRSRV_PIXEL_FORMAT pixel_fmt;
+
+ if (p->count <= 0 || p->count > BC_CDV_COUNT)
+ return -EINVAL;
+
+ if (p->width <= 1 || p->width % width_align || p->height <= 1)
+ return -EINVAL;
+
+ if ((p->width > BC_CDV_WIDTH) || (p->height > BC_CDV_HEIGHT) ||
+ (p->stride > BC_CDV_STRIDE) || (p->stride < 32))
+ return -EINVAL;
+
+ switch (p->fourcc)
+ {
+ case BC_PIX_FMT_NV12:
+ pixel_fmt = PVRSRV_PIXEL_FORMAT_NV12;
+ break;
+ case BC_PIX_FMT_UYVY:
+ pixel_fmt = PVRSRV_PIXEL_FORMAT_FOURCC_ORG_UYVY;
+ break;
+ case BC_PIX_FMT_RGB565:
+ pixel_fmt = PVRSRV_PIXEL_FORMAT_RGB565;
+ p->stride = p->stride << 1; /* stride for RGB from user space is uncorrect */
+ break;
+ case BC_PIX_FMT_YUYV:
+ pixel_fmt = PVRSRV_PIXEL_FORMAT_FOURCC_ORG_YUYV;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ stride = p->stride;
+
+ if (p->type != BC_MEMORY_MMAP && p->type != BC_MEMORY_USERPTR)
+ return -EINVAL;
+
+ if ((psDevInfo = GetAnchorPtr (id)) == IMG_NULL)
+ return -ENODEV;
+
+ if (psDevInfo->ulNumBuffers)
+ BC_DestroyBuffers (id);
+
+ psDevInfo->buf_type = p->type;
+ psDevInfo->psSystemBuffer =
+ BCAllocKernelMem (sizeof (BC_VIDEO_BUFFER) * p->count);
+
+ if (!psDevInfo->psSystemBuffer)
+ return -ENOMEM;
+
+ memset (psDevInfo->psSystemBuffer, 0, sizeof (BC_VIDEO_BUFFER) * p->count);
+ size = p->height * stride;
+ if (pixel_fmt == PVRSRV_PIXEL_FORMAT_NV12)
+ size += (stride >> 1) * (p->height >> 1) << 1;
+
+ for (i = 0; i < p->count; i++)
+ {
+ IMG_SYS_PHYADDR *pPhysAddr;
+ if (is_conti_addr)
+ {
+ pPhysAddr = BCAllocKernelMem (1 * sizeof (IMG_SYS_PHYADDR));
+ if (!pPhysAddr)
+ {
+ goto out_of_memory;
+ }
+ memset (pPhysAddr, 0, 1 * sizeof (IMG_SYS_PHYADDR));
+ }
+ else
+ {
+ unsigned long ulPages = RANGE_TO_PAGES (size);
+ pPhysAddr = BCAllocKernelMem (ulPages * sizeof (IMG_SYS_PHYADDR));
+ if (!pPhysAddr)
+ {
+ goto out_of_memory;
+ }
+ memset (pPhysAddr, 0, ulPages * sizeof (IMG_SYS_PHYADDR));
+ }
+ psDevInfo->psSystemBuffer[i].psSysAddr = pPhysAddr;
+ /*
+ * Only after the memory is allocated successfully, try to modify
+ * the psDevInfo->psSystemBuffer and update the number of
+ * allocated buffers.
+ */
+ psDevInfo->ulNumBuffers++;
+ psDevInfo->psSystemBuffer[i].ulSize = size;
+ psDevInfo->psSystemBuffer[i].psSyncData = IMG_NULL;
+
+ /*for discontig buffers, allocate memory for pPhysAddr */
+ psDevInfo->psSystemBuffer[i].is_conti_addr = is_conti_addr;
+ }
+ p->count = psDevInfo->ulNumBuffers;
+
+ psDevInfo->sBufferInfo.ui32BufferCount = psDevInfo->ulNumBuffers;
+ psDevInfo->sBufferInfo.pixelformat = pixel_fmt;
+ psDevInfo->sBufferInfo.ui32Width = p->width;
+ psDevInfo->sBufferInfo.ui32Height = p->height;
+ psDevInfo->sBufferInfo.ui32ByteStride = stride;
+ psDevInfo->sBufferInfo.ui32BufferDeviceID = id;
+ psDevInfo->sBufferInfo.ui32Flags = PVRSRV_BC_FLAGS_YUVCSC_FULL_RANGE |
+ PVRSRV_BC_FLAGS_YUVCSC_BT601;
+ return 0;
+
+out_of_memory:
+ BC_DestroyBuffers (id);
+ return -ENOMEM;
+}
+
+int
+BC_DestroyBuffers (int id)
+{
+ BC_VIDEO_DEVINFO *psDevInfo;
+ IMG_UINT32 i;
+ if ((psDevInfo = GetAnchorPtr (id)) == IMG_NULL)
+ return -ENODEV;
+
+ if (!psDevInfo->ulNumBuffers)
+ return 0;
+
+ for (i = 0; i < psDevInfo->ulNumBuffers; i++) {
+ vfree(psDevInfo->psSystemBuffer[i].sCPUVAddr);
+ BCFreeKernelMem (psDevInfo->psSystemBuffer[i].psSysAddr);
+ psDevInfo->psSystemBuffer[i].psSysAddr = NULL;
+ }
+
+ BCFreeKernelMem (psDevInfo->psSystemBuffer);
+
+ psDevInfo->psSystemBuffer = NULL;
+ psDevInfo->ulNumBuffers = 0;
+ psDevInfo->sBufferInfo.pixelformat = PVRSRV_PIXEL_FORMAT_UNKNOWN;
+ psDevInfo->sBufferInfo.ui32Width = 0;
+ psDevInfo->sBufferInfo.ui32Height = 0;
+ psDevInfo->sBufferInfo.ui32ByteStride = 0;
+ psDevInfo->sBufferInfo.ui32BufferDeviceID = id;
+ psDevInfo->sBufferInfo.ui32Flags = 0;
+ psDevInfo->sBufferInfo.ui32BufferCount = psDevInfo->ulNumBuffers;
+
+ return 0;
+}
+
+int
+GetBufferCount (unsigned int *puiBufferCount, int id)
+{
+ BC_VIDEO_DEVINFO *psDevInfo = GetAnchorPtr (id);
+
+ if (psDevInfo == IMG_NULL)
+ {
+ return -1;
+ }
+
+ *puiBufferCount = (unsigned int) psDevInfo->sBufferInfo.ui32BufferCount;
+
+ return 0;
+}
+
+int
+BC_Video_Bridge (struct drm_device *dev, IMG_VOID * arg,
+ struct drm_file *file_priv)
+{
+ int err = -EFAULT;
+
+ BC_VIDEO_DEVINFO *devinfo;
+ int i;
+ BC_Video_ioctl_package *psBridge = (BC_Video_ioctl_package *) arg;
+ int command = psBridge->ioctl_cmd;
+ int id = 0;
+ /*
+ * It is noted that the command of "request_buffer" should be the
+ * first request. Otherwise it will fail in the other BC_request.
+ */
+ if (command == BC_Video_ioctl_request_buffers)
+ {
+ for (i = 0; i < BC_VIDEO_DEVICE_MAX_ID; i++)
+ {
+ if (bc_video_id_usage[i] == 0)
+ {
+ id = i;
+ break;
+ }
+ }
+ if (i == BC_VIDEO_DEVICE_MAX_ID)
+ {
+ printk (KERN_ERR DRVNAME
+ " : Does you really need to run more than 5 video simulateously.\n");
+ return -1;
+ } else
+ psb_fpriv(file_priv)->bcd_index = id;
+ }
+ else {
+ id = psBridge->device_id;
+ if ((id >= BC_VIDEO_DEVICE_MAX_ID) || id < 0 ||
+ !bc_video_id_usage[id]) {
+ printk (KERN_ERR DRVNAME
+ " : Invalid device ID\n");
+ return -EINVAL;
+ }
+ }
+ if ((devinfo = GetAnchorPtr (id)) == IMG_NULL)
+ return -ENODEV;
+
+ switch (command)
+ {
+ case BC_Video_ioctl_get_buffer_count:
+ {
+ if (GetBufferCount (&psBridge->outputparam, id) == -1)
+ {
+ printk (KERN_ERR DRVNAME
+ " : GetBufferCount error in BC_Video_Bridge.\n");
+ return err;
+ }
+ return 0;
+ break;
+ }
+ case BC_Video_ioctl_get_buffer_index:
+ {
+ int idx;
+ BC_VIDEO_BUFFER *buffer;
+
+ for (idx = 0; idx < devinfo->ulNumBuffers; idx++)
+ {
+ buffer = &devinfo->psSystemBuffer[idx];
+
+ if (psBridge->inputparam == buffer->sBufferHandle)
+ {
+ psBridge->outputparam = idx;
+ return 0;
+ }
+ }
+ printk (KERN_ERR DRVNAME ": BCIOGET_BUFFERIDX- buffer not found\n");
+ return -EINVAL;
+ break;
+ }
+ case BC_Video_ioctl_request_buffers:
+ {
+ bc_buf_params_t p;
+ int ret;
+ if (copy_from_user
+ (&p, (void __user *) (psBridge->inputparam), sizeof (p)))
+ return -EFAULT;
+
+ ret = BC_CreateBuffers (id, &p, IMG_FALSE);
+ if (ret) {
+ printk (KERN_ERR " : Failure in BC_buffer requests.\n");
+ return ret;
+ }
+ bc_video_id_usage[id] = 1;
+ psBridge->outputparam = id;
+ break;
+ }
+ case BC_Video_ioctl_set_buffer_phyaddr:
+ {
+ bc_buf_ptr_t p;
+ struct ttm_buffer_object *bo = NULL;
+ struct ttm_tt *ttm = NULL;
+ struct ttm_object_file *tfile = psb_fpriv (file_priv)->tfile;
+
+ if (copy_from_user
+ (&p, (void __user *) (psBridge->inputparam), sizeof (p)))
+ return -EFAULT;
+
+ if (p.index >= devinfo->ulNumBuffers || !p.handle)
+ {
+ printk (KERN_ERR DRVNAME
+ " : index big than NumBuffers or p.handle is NULL.\n");
+ return -EINVAL;
+ }
+
+ bo = ttm_buffer_object_lookup (tfile, p.handle);
+ if (unlikely (bo == NULL))
+ {
+ printk (KERN_ERR DRVNAME
+ " : Could not find buffer object for setstatus.\n");
+ return -EINVAL;
+ }
+ ttm = bo->ttm;
+
+ devinfo->psSystemBuffer[p.index].sCPUVAddr = NULL;
+ devinfo->psSystemBuffer[p.index].sBufferHandle = p.handle;
+ for (i = 0; i < ttm->num_pages; i++)
+ {
+ if (ttm->pages[i] == NULL)
+ {
+ printk (KERN_ERR " : Debug: the page is NULL.\n");
+ ttm_bo_unref(&bo);
+ return -EINVAL;
+ }
+ devinfo->psSystemBuffer[p.index].psSysAddr[i].uiAddr =
+ page_to_pfn (ttm->pages[i]) << PAGE_SHIFT;
+ }
+ if (bo)
+ ttm_bo_unref (&bo);
+ return 0;
+ break;
+ }
+ case BC_Video_ioctl_release_buffer_device:
+ {
+ bc_video_id_usage[id] = 0;
+
+ BC_DestroyBuffers (id);
+ return 0;
+ break;
+ }
+ case BC_Video_ioctl_alloc_buffer:
+ {
+ bc_buf_ptr_t p;
+ IMG_VOID *pvBuf;
+ IMG_UINT32 ui32Size;
+ IMG_UINT32 ulCounter;
+ BUFFER_INFO *bufferInfo;
+
+ if (copy_from_user
+ (&p, (void __user *) (psBridge->inputparam), sizeof (p)))
+ return -EFAULT;
+
+ if (p.index >= devinfo->ulNumBuffers)
+ {
+ printk (KERN_ERR DRVNAME " : index big than NumBuffers.\n");
+ return -EINVAL;
+ }
+
+ bufferInfo = &(devinfo->sBufferInfo);
+ if (bufferInfo->pixelformat != PVRSRV_PIXEL_FORMAT_NV12)
+ {
+ printk (KERN_ERR DRVNAME
+ " : BC_Video_ioctl_alloc_buffer only support NV12 format.\n");
+ return -EINVAL;
+ }
+ if (devinfo->psSystemBuffer[p.index].sCPUVAddr) {
+ printk(KERN_ERR DRVNAME
+ " : Try to allow memory twice for one slot.\n");
+ return -EFAULT;
+ }
+ ui32Size = bufferInfo->ui32Height * bufferInfo->ui32ByteStride;
+ ui32Size +=
+ (bufferInfo->ui32ByteStride >> 1) *
+ (bufferInfo->ui32Height >> 1) << 1;
+
+ pvBuf =
+ __vmalloc (ui32Size, GFP_KERNEL | __GFP_HIGHMEM,
+ __pgprot ((pgprot_val (PAGE_KERNEL) & ~_PAGE_CACHE_MASK)
+ | _PAGE_CACHE_WC));
+ if (pvBuf == NULL)
+ {
+ printk (KERN_ERR DRVNAME
+ " : Failed to allocate %d bytes buffer.\n", ui32Size);
+ return -EINVAL;
+ }
+ devinfo->psSystemBuffer[p.index].sCPUVAddr = pvBuf;
+ devinfo->psSystemBuffer[p.index].sBufferHandle = 0;
+
+ i = 0;
+
+ for (ulCounter = 0; ulCounter < ui32Size; ulCounter += PAGE_SIZE)
+ {
+ devinfo->psSystemBuffer[p.index].psSysAddr[i++].uiAddr =
+ vmalloc_to_pfn (pvBuf + ulCounter) << PAGE_SHIFT;
+ }
+
+ if (p.handle)
+ {
+ printk (KERN_ERR DRVNAME
+ " : fill data %d bytes from user space 0x%x.\n", ui32Size,
+ (int) p.handle);
+ if (copy_from_user (pvBuf, (void __user *) p.handle, ui32Size)) {
+ devinfo->psSystemBuffer[p.index].sCPUVAddr = NULL;
+ vfree(pvBuf);
+ return -EFAULT;
+ }
+ }
+ psBridge->outputparam = (int) pvBuf;
+
+ return 0;
+ break;
+ }
+ case BC_Video_ioctl_free_buffer:
+ {
+ bc_buf_ptr_t p;
+
+ if (copy_from_user
+ (&p, (void __user *) (psBridge->inputparam), sizeof (p)))
+ {
+ return -EFAULT;
+ }
+ if (p.index >= devinfo->ulNumBuffers)
+ {
+ printk (KERN_ERR " : index big than NumBuffers.\n");
+ return -EINVAL;
+ }
+
+ if (devinfo->psSystemBuffer[p.index].sCPUVAddr) {
+ vfree(devinfo->psSystemBuffer[p.index].sCPUVAddr);
+ devinfo->psSystemBuffer[p.index].sCPUVAddr = NULL;
+ } else {
+ printk(KERN_ERR DRVNAME
+ " : Try to free the invalid memory.\n");
+ return -EFAULT;
+ }
+ return 0;
+ break;
+ }
+ default:
+ return err;
+ }
+
+ return 0;
+}
+