fixes for bc_cat
[sgx.git] / pvr / bc_cat.c
1 /**********************************************************************
2  *
3  * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
4  * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
5  * 
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  * 
10  * This program is distributed in the hope it will be useful but, except 
11  * as otherwise stated in writing, without any warranty; without even the 
12  * implied warranty of merchantability or fitness for a particular purpose. 
13  * See the GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18  * 
19  * The full GNU General Public License is included in this distribution in
20  * the file called "COPYING".
21  *
22  * Contact Information:
23  * Imagination Technologies Ltd. <gpl-support@imgtec.com>
24  * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
25  *
26  ******************************************************************************/
27
28 #include <linux/kernel.h>
29 #include <linux/module.h>
30 #include <linux/fs.h>
31 #include <linux/slab.h>
32 #include <asm/uaccess.h>
33 #include <asm/io.h>
34 #include "img_defs.h"
35 #include "img_types.h"
36 #include "servicesext.h"
37 #include "kernelbuffer.h"
38 #include "bc_cat.h"
39
40 #include <linux/dma-mapping.h>
41
42 #ifndef IMG_NULL
43 #define IMG_IMPORT
44 #define IMG_NULL        0
45 typedef unsigned int    IMG_UINT32,     *IMG_PUINT32;
46 typedef char            IMG_CHAR,       *IMG_PCHAR;
47 typedef void            IMG_VOID, *IMG_PVOID;
48 typedef IMG_PVOID       IMG_HANDLE;
49
50 typedef IMG_PVOID       IMG_CPU_VIRTADDR;
51
52 typedef struct IMG_SYS_PHYADDR IMG_SYS_PHYADDR;
53 typedef struct IMG_CPU_PHYADDR IMG_CPU_PHYADDR;
54 typedef struct BUFFER_INFO BUFFER_INFO;
55 typedef struct PVRSRV_SYNC_DATA PVRSRV_SYNC_DATA;
56 typedef struct PVRSRV_BC_BUFFER2SRV_KMJTABLE PVRSRV_BC_BUFFER2SRV_KMJTABLE;
57 typedef struct PVRSRV_BC_SRV2BUFFER_KMJTABLE PVRSRV_BC_SRV2BUFFER_KMJTABLE;
58 typedef enum PVRSRV_ERROR PVRSRV_ERROR;
59 typedef enum PVRSRV_PIXEL_FORMAT PVRSRV_PIXEL_FORMAT;
60 #endif
61
62 #define DEVNAME             "bccat"
63 #define DRVNAME             DEVNAME
64 #define DEVICE_COUNT        10
65
66 MODULE_SUPPORTED_DEVICE(DEVNAME);
67
68 #define unref__ __attribute__ ((unused))
69
70 typedef struct BC_CAT_BUFFER_TAG
71 {
72     IMG_UINT32                   ui32Size;
73     IMG_HANDLE                   hMemHandle;
74     IMG_SYS_PHYADDR              sSysAddr;
75     IMG_SYS_PHYADDR              sPageAlignSysAddr;
76     IMG_CPU_VIRTADDR             sCPUVAddr;
77     PVRSRV_SYNC_DATA            *psSyncData;
78     struct BC_CAT_BUFFER_TAG    *psNext;
79 } BC_CAT_BUFFER;
80
81
82 typedef struct BC_CAT_DEVINFO_TAG
83 {
84     int                       ref;
85     IMG_UINT32                ui32DeviceID;
86     BC_CAT_BUFFER            *psSystemBuffer;
87     BUFFER_INFO               sBufferInfo;
88     IMG_UINT32                ui32NumBuffers;
89     PVRSRV_BC_BUFFER2SRV_KMJTABLE    sPVRJTable;
90     PVRSRV_BC_SRV2BUFFER_KMJTABLE    sBCJTable;
91     IMG_HANDLE                hPVRServices;
92     IMG_UINT32                ui32RefCount;
93     enum BC_memory            buf_type;
94 } BC_CAT_DEVINFO;
95
96
97 extern IMG_IMPORT IMG_BOOL PVRGetBufferClassJTable(
98                     PVRSRV_BC_BUFFER2SRV_KMJTABLE *psJTable);
99
100 static int bc_open(struct inode *i, struct file *f);
101 static int bc_release(struct inode *i, struct file *f);
102 static long bc_ioctl(struct file *file,
103                     unsigned int cmd, unsigned long arg);
104 static int bc_mmap(struct file *filp, struct vm_area_struct *vma);
105
106 static int BC_CreateBuffers(int id, bc_buf_params_t *p);
107 static PVRSRV_ERROR BC_DestroyBuffers(int id);
108 static PVRSRV_ERROR BC_Register(int id);
109 static PVRSRV_ERROR BC_Unregister(int id);
110
111 static PVRSRV_ERROR BCOpenPVRServices(IMG_HANDLE *phPVRServices);
112 static PVRSRV_ERROR BCClosePVRServices(IMG_HANDLE hPVRServices);
113
114 static IMG_VOID *BCAllocKernelMem(IMG_UINT32 ui32Size);
115 static IMG_VOID BCFreeKernelMem(IMG_VOID *pvMem);
116
117 static PVRSRV_ERROR BCAllocContigMemory(IMG_UINT32 ui32Size,
118                                IMG_HANDLE * phMemHandle,
119                                IMG_CPU_VIRTADDR *pLinAddr,
120                                IMG_CPU_PHYADDR *pPhysAddr);
121 static IMG_VOID BCFreeContigMemory(IMG_UINT32 ui32Size, 
122                           IMG_HANDLE hMemHandle,
123                           IMG_CPU_VIRTADDR LinAddr, 
124                           IMG_CPU_PHYADDR PhysAddr);
125
126 static IMG_SYS_PHYADDR CpuPAddrToSysPAddrBC(IMG_CPU_PHYADDR cpu_paddr);
127 static IMG_CPU_PHYADDR SysPAddrToCpuPAddrBC(IMG_SYS_PHYADDR sys_paddr);
128
129 static BC_CAT_DEVINFO * GetAnchorPtr(int id);
130
131
132 static int major;
133 static struct class *bc_class;
134 static IMG_VOID *device[DEVICE_COUNT] = { 0 };
135 static int width_align;
136
137 static struct file_operations bc_cat_fops = {
138     .open =  bc_open,
139     .release = bc_release,
140     .unlocked_ioctl = bc_ioctl,
141     .mmap =  bc_mmap,
142 };
143
144
145 /*****************************************************************************
146  * func implementation
147  * **************************************************************************/
148
149 #define file_to_id(file)  (iminor(file->f_path.dentry->d_inode))
150
151 static BC_CAT_DEVINFO * GetAnchorPtr(int id)
152 {
153     return (BC_CAT_DEVINFO *)device[id];
154 }
155
156 static IMG_VOID SetAnchorPtr(int id, BC_CAT_DEVINFO *psDevInfo)
157 {
158     device[id] = (IMG_VOID*)psDevInfo;
159 }
160
161
162 #if 0
163 static PVRSRV_ERROR OpenBCDevice(IMG_HANDLE *phDevice)
164 {
165     BC_CAT_DEVINFO *psDevInfo;
166
167     psDevInfo = GetAnchorPtr(id);
168     *phDevice = (IMG_HANDLE)psDevInfo;
169
170     return PVRSRV_OK;
171 }
172 #else
173
174 #define OPEN_FXN(id)                   \
175 static PVRSRV_ERROR OpenBCDevice##id(IMG_HANDLE *phDevice)\
176 {                                      \
177     BC_CAT_DEVINFO *psDevInfo;           \
178     psDevInfo = GetAnchorPtr (id);       \
179     *phDevice = (IMG_HANDLE) psDevInfo;  \
180     return PVRSRV_OK;                    \
181 }
182
183 OPEN_FXN(0)
184 OPEN_FXN(1)
185 OPEN_FXN(2)
186 OPEN_FXN(3)
187 OPEN_FXN(4)
188 OPEN_FXN(5)
189 OPEN_FXN(6)
190 OPEN_FXN(7)
191 OPEN_FXN(8)
192 OPEN_FXN(9)
193 #endif
194
195 static PVRSRV_ERROR CloseBCDevice(IMG_HANDLE hDevice)
196 {
197     PVR_UNREFERENCED_PARAMETER(hDevice);
198
199     return PVRSRV_OK;
200 }
201
202 static PVRSRV_ERROR GetBCBuffer(IMG_HANDLE            hDevice,
203                                 IMG_UINT32            ui32BufferNumber,
204                                 PVRSRV_SYNC_DATA    *psSyncData,
205                                 IMG_HANDLE            *phBuffer)
206 {
207     BC_CAT_DEVINFO    *psDevInfo;
208
209     if (!hDevice || !phBuffer)
210         return PVRSRV_ERROR_INVALID_PARAMS;
211
212     psDevInfo = (BC_CAT_DEVINFO*)hDevice;
213
214     if (ui32BufferNumber < psDevInfo->sBufferInfo.ui32BufferCount)  {
215         psDevInfo->psSystemBuffer[ui32BufferNumber].psSyncData = psSyncData;
216         *phBuffer = (IMG_HANDLE)&psDevInfo->psSystemBuffer[ui32BufferNumber];
217     } else {
218         return PVRSRV_ERROR_INVALID_PARAMS;
219     }
220
221     return PVRSRV_OK;
222 }
223
224
225 static PVRSRV_ERROR GetBCInfo(IMG_HANDLE hDevice, BUFFER_INFO *psBCInfo)
226 {
227     BC_CAT_DEVINFO    *psDevInfo;
228
229     if (!hDevice || !psBCInfo)
230         return PVRSRV_ERROR_INVALID_PARAMS;
231
232     psDevInfo = (BC_CAT_DEVINFO*)hDevice;
233     *psBCInfo = psDevInfo->sBufferInfo;
234
235     return PVRSRV_OK;
236 }
237
238
239 static PVRSRV_ERROR GetBCBufferAddr(IMG_HANDLE        hDevice,
240                                     IMG_HANDLE        hBuffer,
241                                     IMG_SYS_PHYADDR    **ppsSysAddr,
242                                     IMG_UINT32        *pui32ByteSize,
243                                     IMG_VOID        **ppvCpuVAddr,
244                                     IMG_HANDLE        *phOSMapInfo,
245                                     IMG_BOOL        *pbIsContiguous)
246 {
247     BC_CAT_BUFFER *psBuffer;
248
249     if (!hDevice || !hBuffer || !ppsSysAddr || !pui32ByteSize)
250         return PVRSRV_ERROR_INVALID_PARAMS;
251
252     psBuffer = (BC_CAT_BUFFER *) hBuffer;
253     *ppsSysAddr = &psBuffer->sPageAlignSysAddr;
254     *ppvCpuVAddr = psBuffer->sCPUVAddr;
255     *pui32ByteSize = psBuffer->ui32Size;
256
257     *phOSMapInfo = IMG_NULL;
258     *pbIsContiguous = IMG_TRUE;
259
260     return PVRSRV_OK;
261 }
262
263
264 static int BC_CreateBuffers(int id, bc_buf_params_t *p)
265 {
266     BC_CAT_DEVINFO  *psDevInfo;
267     IMG_CPU_PHYADDR  paddr;
268     IMG_UINT32       i, stride, size;
269     PVRSRV_PIXEL_FORMAT pixel_fmt;
270
271     if (p->count <= 0)
272         return -EINVAL;
273
274     if (p->width <= 1  || p->width % width_align || p->height <= 1)
275         return -EINVAL;
276
277     switch (p->fourcc) {
278     case BC_PIX_FMT_NV12:
279         pixel_fmt = PVRSRV_PIXEL_FORMAT_NV12;
280         stride = p->width;
281         break;
282     case BC_PIX_FMT_UYVY:
283         pixel_fmt = PVRSRV_PIXEL_FORMAT_FOURCC_ORG_UYVY;
284         stride = p->width << 1;
285         break;
286     case BC_PIX_FMT_RGB565:
287         pixel_fmt = PVRSRV_PIXEL_FORMAT_RGB565;
288         stride = p->width << 1;
289         break;
290     case BC_PIX_FMT_YUYV:
291         pixel_fmt = PVRSRV_PIXEL_FORMAT_FOURCC_ORG_YUYV;
292         stride = p->width << 1;
293         break;
294     default:
295         return -EINVAL;
296         break;
297     }
298
299     if (p->type != BC_MEMORY_MMAP && p->type != BC_MEMORY_USERPTR)
300         return -EINVAL;
301
302     if ((psDevInfo = GetAnchorPtr(id)) == IMG_NULL)
303         return -ENODEV;
304
305     if (psDevInfo->ui32NumBuffers)
306         BC_DestroyBuffers(id);
307
308     psDevInfo->buf_type = p->type;
309     psDevInfo->psSystemBuffer =
310             BCAllocKernelMem(sizeof(BC_CAT_BUFFER) * p->count);
311
312     if (!psDevInfo->psSystemBuffer)
313         return -ENOMEM;
314
315     memset(psDevInfo->psSystemBuffer, 0, sizeof(BC_CAT_BUFFER) * p->count);
316
317     size = p->height * stride;
318     if (pixel_fmt == PVRSRV_PIXEL_FORMAT_NV12)
319         size += (stride >> 1) * (p->height >> 1) << 1;
320
321     for (i=0; i < p->count; i++) {
322         if (psDevInfo->buf_type == BC_MEMORY_MMAP) {
323             if (BCAllocContigMemory(size,
324                                   &psDevInfo->psSystemBuffer[i].hMemHandle,
325                                   &psDevInfo->psSystemBuffer[i].sCPUVAddr,
326                                   &paddr) != PVRSRV_OK)
327                 /*TODO should free() and return failure*/
328                 break;
329
330             psDevInfo->psSystemBuffer[i].sSysAddr = CpuPAddrToSysPAddrBC(paddr);
331             psDevInfo->psSystemBuffer[i].sPageAlignSysAddr.uiAddr =
332                     psDevInfo->psSystemBuffer[i].sSysAddr.uiAddr & 0xFFFFF000;
333         }
334         psDevInfo->ui32NumBuffers++;
335         psDevInfo->psSystemBuffer[i].ui32Size = size;
336         psDevInfo->psSystemBuffer[i].psSyncData = IMG_NULL;
337     }
338     p->count = psDevInfo->ui32NumBuffers;
339
340     psDevInfo->sBufferInfo.ui32BufferCount = psDevInfo->ui32NumBuffers;
341     psDevInfo->sBufferInfo.pixelformat = pixel_fmt;
342     psDevInfo->sBufferInfo.ui32Width = p->width;
343     psDevInfo->sBufferInfo.ui32Height = p->height;
344     psDevInfo->sBufferInfo.ui32ByteStride = stride;    
345     psDevInfo->sBufferInfo.ui32BufferDeviceID = id;
346     psDevInfo->sBufferInfo.ui32Flags = PVRSRV_BC_FLAGS_YUVCSC_FULL_RANGE |
347                                        PVRSRV_BC_FLAGS_YUVCSC_BT601;
348     return 0;
349 }
350
351
352 static PVRSRV_ERROR BC_DestroyBuffers(int id)
353 {
354     BC_CAT_DEVINFO *psDevInfo;
355     IMG_UINT32 i;
356     
357     if ((psDevInfo = GetAnchorPtr(id)) == IMG_NULL)
358         return PVRSRV_ERROR_DEVICE_REGISTER_FAILED;
359     
360     if (!psDevInfo->ui32NumBuffers)
361         return PVRSRV_OK;
362
363     if (psDevInfo->buf_type == BC_MEMORY_MMAP)
364         for (i = 0; i < psDevInfo->ui32NumBuffers; i++) {
365             BCFreeContigMemory(psDevInfo->psSystemBuffer[i].ui32Size,
366                     psDevInfo->psSystemBuffer[i].hMemHandle,
367                     psDevInfo->psSystemBuffer[i].sCPUVAddr,
368                     SysPAddrToCpuPAddrBC(psDevInfo->psSystemBuffer[i].sSysAddr));
369         }
370
371     BCFreeKernelMem(psDevInfo->psSystemBuffer);
372     psDevInfo->psSystemBuffer = NULL;
373     
374     psDevInfo->ui32NumBuffers = 0;
375     psDevInfo->sBufferInfo.pixelformat = PVRSRV_PIXEL_FORMAT_UNKNOWN;
376     psDevInfo->sBufferInfo.ui32Width = 0;
377     psDevInfo->sBufferInfo.ui32Height = 0;
378     psDevInfo->sBufferInfo.ui32ByteStride = 0;    
379     psDevInfo->sBufferInfo.ui32BufferDeviceID = id;
380     psDevInfo->sBufferInfo.ui32Flags = 0;
381     psDevInfo->sBufferInfo.ui32BufferCount = psDevInfo->ui32NumBuffers;
382
383     return PVRSRV_OK;
384 }
385
386
387 static PVRSRV_ERROR BC_Register(id)
388 {
389     BC_CAT_DEVINFO  *psDevInfo;
390     
391     psDevInfo = GetAnchorPtr(id);
392
393     if (psDevInfo) {
394         psDevInfo->ui32RefCount++;
395         return PVRSRV_OK;
396     }
397
398     psDevInfo = (BC_CAT_DEVINFO *)BCAllocKernelMem(sizeof(BC_CAT_DEVINFO));
399
400     if (!psDevInfo)
401         return PVRSRV_ERROR_OUT_OF_MEMORY;
402     
403     psDevInfo->ref = 0;
404     psDevInfo->ui32RefCount = 0;
405     SetAnchorPtr(id, (IMG_VOID*)psDevInfo);
406
407     if (BCOpenPVRServices(&psDevInfo->hPVRServices) != PVRSRV_OK)
408         return PVRSRV_ERROR_INIT_FAILURE;
409
410     if (!PVRGetBufferClassJTable(&psDevInfo->sPVRJTable))
411         return PVRSRV_ERROR_INIT_FAILURE;
412
413     psDevInfo->ui32NumBuffers = 0;
414
415     psDevInfo->sBufferInfo.pixelformat = PVRSRV_PIXEL_FORMAT_UNKNOWN;
416     psDevInfo->sBufferInfo.ui32Width = 0;
417     psDevInfo->sBufferInfo.ui32Height = 0;
418     psDevInfo->sBufferInfo.ui32ByteStride = 0;    
419     psDevInfo->sBufferInfo.ui32BufferDeviceID = id;
420     psDevInfo->sBufferInfo.ui32Flags = 0;
421     psDevInfo->sBufferInfo.ui32BufferCount = psDevInfo->ui32NumBuffers;
422
423     psDevInfo->sBCJTable.ui32TableSize = sizeof(PVRSRV_BC_SRV2BUFFER_KMJTABLE);
424 #if 0
425     psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice;
426 #else
427     if (id == 0) {
428         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice0;
429     } else if (id == 1) {
430         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice1;
431     } else if (id == 2) {
432         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice2;
433     } else if (id == 3) {
434         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice3;
435     } else if (id == 4) {
436         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice4;
437     } else if (id == 5) {
438         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice5;
439     } else if (id == 6) {
440         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice6;
441     } else if (id == 7) {
442         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice7;
443     } else if (id == 8) {
444         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice8;
445     } else if (id == 9) {
446         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice9;
447     } else {
448         printk("bad device id: %d\n", id);
449         return PVRSRV_ERROR_DEVICE_REGISTER_FAILED;
450     }
451 #endif
452     psDevInfo->sBCJTable.pfnCloseBCDevice = CloseBCDevice;
453     psDevInfo->sBCJTable.pfnGetBCBuffer = GetBCBuffer;
454     psDevInfo->sBCJTable.pfnGetBCInfo = GetBCInfo;
455     psDevInfo->sBCJTable.pfnGetBufferAddr = GetBCBufferAddr;
456     
457     if (psDevInfo->sPVRJTable.pfnPVRSRVRegisterBCDevice(
458                 &psDevInfo->sBCJTable,
459                 &psDevInfo->ui32DeviceID) != PVRSRV_OK)
460         return PVRSRV_ERROR_DEVICE_REGISTER_FAILED;
461
462     psDevInfo->ui32RefCount++;
463     
464     return PVRSRV_OK;
465 }
466
467
468 static PVRSRV_ERROR BC_Unregister(int id)
469 {
470     BC_CAT_DEVINFO *psDevInfo;
471     PVRSRV_BC_BUFFER2SRV_KMJTABLE *psJTable;
472     
473     if ((psDevInfo = GetAnchorPtr(id)) == IMG_NULL)
474         return PVRSRV_ERROR_DEVICE_REGISTER_FAILED;
475     
476     psDevInfo->ui32RefCount--;
477
478     if (psDevInfo->ui32RefCount)
479         return PVRSRV_ERROR_RETRY;
480
481     psJTable = &psDevInfo->sPVRJTable;
482     
483     if (psJTable->pfnPVRSRVRemoveBCDevice(psDevInfo->ui32DeviceID) != PVRSRV_OK)
484         return PVRSRV_ERROR_GENERIC;
485
486     if (BCClosePVRServices(psDevInfo->hPVRServices) != PVRSRV_OK) {
487         psDevInfo->hPVRServices = IMG_NULL;
488         return PVRSRV_ERROR_GENERIC;
489     }
490
491     BCFreeKernelMem(psDevInfo);
492     SetAnchorPtr(id, IMG_NULL);
493     
494     return PVRSRV_OK;
495 }
496
497
498 static int __init bc_cat_init(void)
499 {
500     struct device *bc_dev;
501     int id = 0;
502
503     /* texture buffer width should be multiple of 8 for OMAP3 ES3.x,
504      * or 32 for ES2.x */
505     width_align = (cpu_is_omap3530() && omap_rev() < OMAP3430_REV_ES3_0) ? 32 : 8;
506     
507     major = register_chrdev(0, DEVNAME, &bc_cat_fops);
508
509     if (major <= 0) {
510         printk(KERN_ERR DRVNAME ": unable to get major number\n");
511         goto ExitDisable;
512     }
513
514     bc_class = class_create(THIS_MODULE, DEVNAME);
515     if (IS_ERR(bc_class)) {
516        printk(KERN_ERR DRVNAME ": unable to create device class\n");
517        goto ExitUnregister;
518     }
519
520     for (id = 0; id < DEVICE_COUNT; id++) {
521         bc_dev = device_create(bc_class, NULL, MKDEV(major, id), NULL,
522                                DEVNAME "%d", id);
523
524         if (IS_ERR(bc_dev)) {
525            printk(KERN_ERR DRVNAME ": unable to create device %d\n", id);
526            goto ExitDestroyClass;
527         }
528
529         if (BC_Register(id) != PVRSRV_OK) {
530             printk (KERN_ERR DRVNAME ": can't register BC service %d\n", id);
531             if (id > 0) {
532                 /* let's live with the drivers that we were able to create so
533                  * far, even though it isn't as many as we'd like
534                  */
535                  device_destroy(bc_class, MKDEV(major, id));
536                  break;
537             }
538             goto ExitDestroyClass;
539         }
540     }
541
542     return 0;
543
544 ExitDestroyClass:
545     for (; id >= 0; id--) {
546         BC_Unregister(id);
547         device_destroy(bc_class, MKDEV(major, id));
548     }
549     class_destroy(bc_class);
550 ExitUnregister:
551     unregister_chrdev(major, DEVNAME);
552 ExitDisable:
553     return -EBUSY;
554
555
556 static void __exit bc_cat_cleanup(void)
557 {    
558     int id;
559
560     for (id = 0; id < DEVICE_COUNT; id++) {
561         if (BC_DestroyBuffers(id) != PVRSRV_OK) {
562             printk(KERN_ERR DRVNAME ": can't free texture buffers, dev %d\n", id);
563         }
564         if (BC_Unregister(id) != PVRSRV_OK) {
565             printk(KERN_ERR DRVNAME ": can't un-register BC service, dev %d\n", id);
566         }
567         device_destroy(bc_class, MKDEV(major, id));
568     }
569     class_destroy(bc_class);
570     unregister_chrdev(major, DEVNAME);
571
572
573
574 static IMG_VOID *BCAllocKernelMem(IMG_UINT32 ui32Size)
575 {
576     return kmalloc(ui32Size, GFP_KERNEL);
577 }
578
579 static IMG_VOID BCFreeKernelMem(IMG_VOID *pvMem)
580 {
581     kfree(pvMem);
582 }
583
584 static PVRSRV_ERROR BCAllocContigMemory(IMG_UINT32 ui32Size,
585                                  IMG_HANDLE unref__ *phMemHandle, 
586                                  IMG_CPU_VIRTADDR *pLinAddr, 
587                                  IMG_CPU_PHYADDR *pPhysAddr)
588 {
589     dma_addr_t dma;
590     void *pvLinAddr;
591
592     pvLinAddr = dma_alloc_coherent(NULL, ui32Size, &dma, GFP_KERNEL);
593     if (pvLinAddr == NULL)
594     {
595             return PVRSRV_ERROR_OUT_OF_MEMORY;
596     }
597
598     pPhysAddr->uiAddr = dma;
599     *pLinAddr = pvLinAddr;
600
601     return PVRSRV_OK;
602 }
603
604 static IMG_VOID BCFreeContigMemory(IMG_UINT32 ui32Size,
605                         IMG_HANDLE unref__ hMemHandle, 
606                         IMG_CPU_VIRTADDR LinAddr, 
607                         IMG_CPU_PHYADDR PhysAddr)
608 {
609     dma_free_coherent(NULL, ui32Size, LinAddr, (dma_addr_t)PhysAddr.uiAddr);
610 }
611
612 static IMG_SYS_PHYADDR CpuPAddrToSysPAddrBC(IMG_CPU_PHYADDR cpu_paddr)
613 {
614     IMG_SYS_PHYADDR sys_paddr;
615     
616     sys_paddr.uiAddr = cpu_paddr.uiAddr;
617     return sys_paddr;
618 }
619
620 static IMG_CPU_PHYADDR SysPAddrToCpuPAddrBC(IMG_SYS_PHYADDR sys_paddr)
621 {
622     IMG_CPU_PHYADDR cpu_paddr;
623     
624     cpu_paddr.uiAddr = sys_paddr.uiAddr;
625     return cpu_paddr;
626 }
627
628 static PVRSRV_ERROR BCOpenPVRServices (IMG_HANDLE *phPVRServices)
629 {
630     *phPVRServices = 0;
631     return PVRSRV_OK;
632 }
633
634
635 static PVRSRV_ERROR BCClosePVRServices (IMG_HANDLE unref__ hPVRServices)
636 {
637     return PVRSRV_OK;
638 }
639
640 static int bc_open(struct inode *i, struct file *f)
641 {
642     BC_CAT_DEVINFO *devinfo;
643     int id = file_to_id(f);
644
645     if ((devinfo = GetAnchorPtr(id)) == IMG_NULL) {
646         printk("no device %d\n", id);
647         return -ENODEV;
648     }
649
650     if (devinfo->ref) {
651         printk("device %d busy\n", id);
652         return -EBUSY;
653     }
654
655     devinfo->ref++;
656     return 0;
657 }
658
659
660 static int bc_release(struct inode *i, struct file *f)
661 {
662     BC_CAT_DEVINFO *devinfo;
663     int id = file_to_id(f);
664
665     if ((devinfo = GetAnchorPtr(id)) == IMG_NULL)
666         return -ENODEV;
667
668     if (devinfo->ref)
669         devinfo->ref--;
670     return 0;
671 }
672
673
674 static int bc_mmap(struct file *filp, struct vm_area_struct *vma)
675 {
676 #if defined(DEBUG)
677     printk("bc_mmap: vma->vm_start = %#lx\n", vma->vm_start);
678     printk("bc_mmap: vma->vm_pgoff = %#lx\n", vma->vm_pgoff);
679     printk("bc_mmap: size          = %#lx\n", vma->vm_end - vma->vm_start);
680 #endif
681
682     /*FIXME check start & size*/
683     if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
684                         vma->vm_end - vma->vm_start,
685                         vma->vm_page_prot)) {
686         printk("bc_mmap: failed remap_pfn_range\n");
687         return -EAGAIN;
688     }
689     return 0;
690 }
691
692 static long bc_ioctl(struct file *file,
693                     unsigned int cmd, unsigned long arg)
694 {
695     BC_CAT_DEVINFO *devinfo;
696     int id = file_to_id (file);
697
698     if ((devinfo = GetAnchorPtr(id)) == IMG_NULL)
699         return -ENODEV;
700
701     switch(_IOC_NR(cmd)) {
702         case _IOC_NR(BCIOGET_BUFFERCOUNT):
703         {    
704             BCIO_package *params = (BCIO_package *)arg;
705
706             if (!access_ok(VERIFY_WRITE, params, sizeof(BCIO_package)))
707                 return -EFAULT;
708
709             params->output = devinfo->sBufferInfo.ui32BufferCount;
710             break;
711         }
712         case _IOC_NR(BCIOGET_BUFFERPHYADDR):
713         {
714             int idx;
715             BCIO_package *params = (BCIO_package *)arg;
716
717             if (!access_ok(VERIFY_WRITE, params, sizeof(BCIO_package)))
718                 return -EFAULT;
719
720             idx = params->input;
721             if (idx < 0 || idx >= devinfo->ui32NumBuffers) {
722                 printk(KERN_ERR DRVNAME
723                         ": BCIOGET_BUFFERADDR - idx out of range\n");
724                 return -EINVAL;
725             }
726             params->output = devinfo->psSystemBuffer[idx].sSysAddr.uiAddr;
727             break;
728         }
729         case _IOC_NR(BCIOGET_BUFFERIDX):
730         {
731             int idx;
732             BC_CAT_BUFFER  *buffer;
733             BCIO_package *params = (BCIO_package *)arg;
734
735             if (!access_ok(VERIFY_WRITE, params, sizeof(BCIO_package)))
736                 return -EFAULT;
737
738             for (idx = 0; idx < devinfo->ui32NumBuffers; idx++) {
739                 buffer = &devinfo->psSystemBuffer[idx];
740
741                 if (params->input == (int)buffer->sSysAddr.uiAddr) {
742                     params->output = idx;
743                     return 0;
744                 }
745             }
746             printk(KERN_ERR DRVNAME ": BCIOGET_BUFFERIDX- buffer not found\n");
747             return -EINVAL;
748             break;
749         }
750         case _IOC_NR(BCIOREQ_BUFFERS):
751         {
752             bc_buf_params_t *p = (bc_buf_params_t *) arg;
753             
754             if (!access_ok(VERIFY_WRITE, p, sizeof(bc_buf_params_t)))
755                 return -EFAULT;
756
757             return BC_CreateBuffers(id, p);
758             break;
759         }
760         case _IOC_NR(BCIOSET_BUFFERPHYADDR):
761         {
762             bc_buf_ptr_t p;
763             IMG_CPU_PHYADDR img_pa;
764
765             if (copy_from_user(&p, (void __user *)arg, sizeof(p)))
766                 return -EFAULT;
767
768             if (p.index >= devinfo->ui32NumBuffers || !p.pa)
769                 return -EINVAL;
770             
771             /*TODO check buffer size*/
772
773             img_pa.uiAddr = p.pa;
774
775             devinfo->psSystemBuffer[p.index].sCPUVAddr = phys_to_virt(p.pa);
776             devinfo->psSystemBuffer[p.index].sSysAddr =
777                     CpuPAddrToSysPAddrBC(img_pa);
778             devinfo->psSystemBuffer[p.index].sPageAlignSysAddr.uiAddr =
779                     devinfo->psSystemBuffer[p.index].sSysAddr.uiAddr &
780                     0xFFFFF000;
781             break;
782         }
783         default:
784             return -EFAULT;
785     }
786     return 0;
787 }
788
789 module_init(bc_cat_init);
790 module_exit(bc_cat_cleanup);
791
792 MODULE_LICENSE("GPL v2");