port bc_cat to this driver
[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     
373     psDevInfo->ui32NumBuffers = 0;
374     psDevInfo->sBufferInfo.pixelformat = PVRSRV_PIXEL_FORMAT_UNKNOWN;
375     psDevInfo->sBufferInfo.ui32Width = 0;
376     psDevInfo->sBufferInfo.ui32Height = 0;
377     psDevInfo->sBufferInfo.ui32ByteStride = 0;    
378     psDevInfo->sBufferInfo.ui32BufferDeviceID = id;
379     psDevInfo->sBufferInfo.ui32Flags = 0;
380     psDevInfo->sBufferInfo.ui32BufferCount = psDevInfo->ui32NumBuffers;
381
382     return PVRSRV_OK;
383 }
384
385
386 static PVRSRV_ERROR BC_Register(id)
387 {
388     BC_CAT_DEVINFO  *psDevInfo;
389     
390     psDevInfo = GetAnchorPtr(id);
391
392     if (psDevInfo) {
393         psDevInfo->ui32RefCount++;
394         return PVRSRV_OK;
395     }
396
397     psDevInfo = (BC_CAT_DEVINFO *)BCAllocKernelMem(sizeof(BC_CAT_DEVINFO));
398
399     if (!psDevInfo)
400         return PVRSRV_ERROR_OUT_OF_MEMORY;
401     
402     psDevInfo->ref = 0;
403     psDevInfo->ui32RefCount = 0;
404     SetAnchorPtr(id, (IMG_VOID*)psDevInfo);
405
406     if (BCOpenPVRServices(&psDevInfo->hPVRServices) != PVRSRV_OK)
407         return PVRSRV_ERROR_INIT_FAILURE;
408
409     if (!PVRGetBufferClassJTable(&psDevInfo->sPVRJTable))
410         return PVRSRV_ERROR_INIT_FAILURE;
411
412     psDevInfo->ui32NumBuffers = 0;
413
414     psDevInfo->sBufferInfo.pixelformat = PVRSRV_PIXEL_FORMAT_UNKNOWN;
415     psDevInfo->sBufferInfo.ui32Width = 0;
416     psDevInfo->sBufferInfo.ui32Height = 0;
417     psDevInfo->sBufferInfo.ui32ByteStride = 0;    
418     psDevInfo->sBufferInfo.ui32BufferDeviceID = id;
419     psDevInfo->sBufferInfo.ui32Flags = 0;
420     psDevInfo->sBufferInfo.ui32BufferCount = psDevInfo->ui32NumBuffers;
421
422     psDevInfo->sBCJTable.ui32TableSize = sizeof(PVRSRV_BC_SRV2BUFFER_KMJTABLE);
423 #if 0
424     psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice;
425 #else
426     if (id == 0) {
427         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice0;
428     } else if (id == 1) {
429         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice1;
430     } else if (id == 2) {
431         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice2;
432     } else if (id == 3) {
433         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice3;
434     } else if (id == 4) {
435         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice4;
436     } else if (id == 5) {
437         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice5;
438     } else if (id == 6) {
439         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice6;
440     } else if (id == 7) {
441         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice7;
442     } else if (id == 8) {
443         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice8;
444     } else if (id == 9) {
445         psDevInfo->sBCJTable.pfnOpenBCDevice = OpenBCDevice9;
446     } else {
447         printk("bad device id: %d\n", id);
448         return PVRSRV_ERROR_DEVICE_REGISTER_FAILED;
449     }
450 #endif
451     psDevInfo->sBCJTable.pfnCloseBCDevice = CloseBCDevice;
452     psDevInfo->sBCJTable.pfnGetBCBuffer = GetBCBuffer;
453     psDevInfo->sBCJTable.pfnGetBCInfo = GetBCInfo;
454     psDevInfo->sBCJTable.pfnGetBufferAddr = GetBCBufferAddr;
455     
456     if (psDevInfo->sPVRJTable.pfnPVRSRVRegisterBCDevice(
457                 &psDevInfo->sBCJTable,
458                 &psDevInfo->ui32DeviceID) != PVRSRV_OK)
459         return PVRSRV_ERROR_DEVICE_REGISTER_FAILED;
460
461     psDevInfo->ui32RefCount++;
462     
463     return PVRSRV_OK;
464 }
465
466
467 static PVRSRV_ERROR BC_Unregister(int id)
468 {
469     BC_CAT_DEVINFO *psDevInfo;
470     PVRSRV_BC_BUFFER2SRV_KMJTABLE *psJTable;
471     
472     if ((psDevInfo = GetAnchorPtr(id)) == IMG_NULL)
473         return PVRSRV_ERROR_DEVICE_REGISTER_FAILED;
474     
475     psDevInfo->ui32RefCount--;
476
477     if (psDevInfo->ui32RefCount)
478         return PVRSRV_ERROR_RETRY;
479
480     psJTable = &psDevInfo->sPVRJTable;
481     
482     if (psJTable->pfnPVRSRVRemoveBCDevice(psDevInfo->ui32DeviceID) != PVRSRV_OK)
483         return PVRSRV_ERROR_GENERIC;
484
485     if (BCClosePVRServices(psDevInfo->hPVRServices) != PVRSRV_OK) {
486         psDevInfo->hPVRServices = IMG_NULL;
487         return PVRSRV_ERROR_GENERIC;
488     }
489
490     BCFreeKernelMem(psDevInfo);
491     SetAnchorPtr(id, IMG_NULL);
492     
493     return PVRSRV_OK;
494 }
495
496
497 static int __init bc_cat_init(void)
498 {
499     struct device *bc_dev;
500     int id;
501
502     /* texture buffer width should be multiple of 8 for OMAP3 ES3.x,
503      * or 32 for ES2.x */
504     width_align = (cpu_is_omap3530() && omap_rev() < OMAP3430_REV_ES3_0) ? 32 : 8;
505     
506     major = register_chrdev(0, DEVNAME, &bc_cat_fops);
507
508     if (major <= 0) {
509         printk(KERN_ERR DRVNAME ": unable to get major number\n");
510         goto ExitDisable;
511     }
512
513     bc_class = class_create(THIS_MODULE, DEVNAME);
514
515     if (IS_ERR(bc_class)) {
516        printk(KERN_ERR DRVNAME ": upable 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                 /* lets live with the drivers that we were able to create soi
533                  * far, even though it isn't as many as we'd like
534                  */
535                  break;
536             }
537             goto ExitUnregister;
538         }
539     }
540
541     return 0;
542
543 ExitDestroyClass:
544     class_destroy(bc_class);
545 ExitUnregister:
546     unregister_chrdev(major, DEVNAME);
547 ExitDisable:
548     return -EBUSY;
549
550
551 static void __exit bc_cat_cleanup(void)
552 {    
553     int id;
554
555     for (id = 0; id < DEVICE_COUNT; id++) {
556         if (BC_DestroyBuffers(id) != PVRSRV_OK) {
557             printk(KERN_ERR DRVNAME ": can't free texture buffers\n");
558             return;
559         }
560         if (BC_Unregister(id) != PVRSRV_OK) {
561             printk(KERN_ERR DRVNAME ": can't un-register BC service\n");
562             return;
563         }
564         device_destroy(bc_class, MKDEV(major, id));
565     }
566     class_destroy(bc_class);
567     unregister_chrdev(major, DEVNAME);
568
569
570
571 static IMG_VOID *BCAllocKernelMem(IMG_UINT32 ui32Size)
572 {
573     return kmalloc(ui32Size, GFP_KERNEL);
574 }
575
576 static IMG_VOID BCFreeKernelMem(IMG_VOID *pvMem)
577 {
578     kfree(pvMem);
579 }
580
581 static PVRSRV_ERROR BCAllocContigMemory(IMG_UINT32 ui32Size,
582                                  IMG_HANDLE unref__ *phMemHandle, 
583                                  IMG_CPU_VIRTADDR *pLinAddr, 
584                                  IMG_CPU_PHYADDR *pPhysAddr)
585 {
586     IMG_VOID *pvLinAddr;
587     gfp_t mask = GFP_KERNEL;
588     
589     pvLinAddr = alloc_pages_exact(ui32Size, mask);
590 /*    printk("pvLinAddr=%p, ui32Size=%ld\n", pvLinAddr, ui32Size);*/
591     
592     if (pvLinAddr == IMG_NULL)
593         return PVRSRV_ERROR_OUT_OF_MEMORY;
594
595     pPhysAddr->uiAddr = virt_to_phys(pvLinAddr);
596
597     *pLinAddr = pvLinAddr;
598
599     return PVRSRV_OK;
600 }
601
602 static IMG_VOID BCFreeContigMemory(IMG_UINT32 ui32Size,
603                         IMG_HANDLE unref__ hMemHandle, 
604                         IMG_CPU_VIRTADDR LinAddr, 
605                         IMG_CPU_PHYADDR PhysAddr)
606 {
607     free_pages_exact(LinAddr, ui32Size);
608 }
609
610 static IMG_SYS_PHYADDR CpuPAddrToSysPAddrBC(IMG_CPU_PHYADDR cpu_paddr)
611 {
612     IMG_SYS_PHYADDR sys_paddr;
613     
614     sys_paddr.uiAddr = cpu_paddr.uiAddr;
615     return sys_paddr;
616 }
617
618 static IMG_CPU_PHYADDR SysPAddrToCpuPAddrBC(IMG_SYS_PHYADDR sys_paddr)
619 {
620     IMG_CPU_PHYADDR cpu_paddr;
621     
622     cpu_paddr.uiAddr = sys_paddr.uiAddr;
623     return cpu_paddr;
624 }
625
626 static PVRSRV_ERROR BCOpenPVRServices (IMG_HANDLE *phPVRServices)
627 {
628     *phPVRServices = 0;
629     return PVRSRV_OK;
630 }
631
632
633 static PVRSRV_ERROR BCClosePVRServices (IMG_HANDLE unref__ hPVRServices)
634 {
635     return PVRSRV_OK;
636 }
637
638 static int bc_open(struct inode *i, struct file *f)
639 {
640     BC_CAT_DEVINFO *devinfo;
641     int id = file_to_id(f);
642
643     if ((devinfo = GetAnchorPtr(id)) == IMG_NULL) {
644         printk("no device %d\n", id);
645         return -ENODEV;
646     }
647
648     if (devinfo->ref) {
649         printk("device %d busy\n", id);
650         return -EBUSY;
651     }
652
653     devinfo->ref++;
654     return 0;
655 }
656
657
658 static int bc_release(struct inode *i, struct file *f)
659 {
660     BC_CAT_DEVINFO *devinfo;
661     int id = file_to_id(f);
662
663     if ((devinfo = GetAnchorPtr(id)) == IMG_NULL)
664         return -ENODEV;
665
666     if (devinfo->ref)
667         devinfo->ref--;
668     return 0;
669 }
670
671
672 static int bc_mmap(struct file *filp, struct vm_area_struct *vma)
673 {
674 #if defined(DEBUG)
675     printk("bc_mmap: vma->vm_start = %#lx\n", vma->vm_start);
676     printk("bc_mmap: vma->vm_pgoff = %#lx\n", vma->vm_pgoff);
677     printk("bc_mmap: size          = %#lx\n", vma->vm_end - vma->vm_start);
678 #endif
679
680     /*FIXME check start & size*/
681     if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
682                         vma->vm_end - vma->vm_start,
683                         vma->vm_page_prot)) {
684         printk("bc_mmap: failed remap_pfn_range\n");
685         return -EAGAIN;
686     }
687     return 0;
688 }
689
690 static long bc_ioctl(struct file *file,
691                     unsigned int cmd, unsigned long arg)
692 {
693     BC_CAT_DEVINFO *devinfo;
694     int id = file_to_id (file);
695
696     if ((devinfo = GetAnchorPtr(id)) == IMG_NULL)
697         return -ENODEV;
698
699     switch(_IOC_NR(cmd)) {
700         case _IOC_NR(BCIOGET_BUFFERCOUNT):
701         {    
702             BCIO_package *params = (BCIO_package *)arg;
703
704             if (!access_ok(VERIFY_WRITE, params, sizeof(BCIO_package)))
705                 return -EFAULT;
706
707             params->output = devinfo->sBufferInfo.ui32BufferCount;
708             break;
709         }
710         case _IOC_NR(BCIOGET_BUFFERPHYADDR):
711         {
712             int idx;
713             BCIO_package *params = (BCIO_package *)arg;
714
715             if (!access_ok(VERIFY_WRITE, params, sizeof(BCIO_package)))
716                 return -EFAULT;
717
718             idx = params->input;
719             if (idx < 0 || idx > devinfo->ui32NumBuffers) {
720                 printk(KERN_ERR DRVNAME
721                         ": BCIOGET_BUFFERADDR - idx out of range\n");
722                 return -EINVAL;
723             }
724             params->output = devinfo->psSystemBuffer[idx].sSysAddr.uiAddr;
725             break;
726         }
727         case _IOC_NR(BCIOGET_BUFFERIDX):
728         {
729             int idx;
730             BC_CAT_BUFFER  *buffer;
731             BCIO_package *params = (BCIO_package *)arg;
732
733             if (!access_ok(VERIFY_WRITE, params, sizeof(BCIO_package)))
734                 return -EFAULT;
735
736             for (idx = 0; idx < devinfo->ui32NumBuffers; idx++) {
737                 buffer = &devinfo->psSystemBuffer[idx];
738
739                 if (params->input == (int)buffer->sSysAddr.uiAddr) {
740                     params->output = idx;
741                     return 0;
742                 }
743             }
744             printk(KERN_ERR DRVNAME ": BCIOGET_BUFFERIDX- buffer not found\n");
745             return -EINVAL;
746             break;
747         }
748         case _IOC_NR(BCIOREQ_BUFFERS):
749         {
750             bc_buf_params_t *p = (bc_buf_params_t *) arg;
751             
752             if (!access_ok(VERIFY_WRITE, p, sizeof(bc_buf_params_t)))
753                 return -EFAULT;
754
755             return BC_CreateBuffers(id, p);
756             break;
757         }
758         case _IOC_NR(BCIOSET_BUFFERPHYADDR):
759         {
760             bc_buf_ptr_t p;
761             IMG_CPU_PHYADDR img_pa;
762
763             if (copy_from_user(&p, (void __user *)arg, sizeof(p)))
764                 return -EFAULT;
765
766             if (p.index >= devinfo->ui32NumBuffers || !p.pa)
767                 return -EINVAL;
768             
769             /*TODO check buffer size*/
770
771             img_pa.uiAddr = p.pa;
772
773             devinfo->psSystemBuffer[p.index].sCPUVAddr = phys_to_virt(p.pa);
774             devinfo->psSystemBuffer[p.index].sSysAddr =
775                     CpuPAddrToSysPAddrBC(img_pa);
776             devinfo->psSystemBuffer[p.index].sPageAlignSysAddr.uiAddr =
777                     devinfo->psSystemBuffer[p.index].sSysAddr.uiAddr &
778                     0xFFFFF000;
779             break;
780         }
781         default:
782             return -EFAULT;
783     }
784     return 0;
785 }
786
787 module_init(bc_cat_init);
788 module_exit(bc_cat_cleanup);
789
790 MODULE_LICENSE("GPL v2");