gpu: pvr: pdumpfs: add stream_frames debugfs entry
[sgx.git] / pvr / deviceclass.c
1 /**********************************************************************
2  *
3  * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful but, except
10  * as otherwise stated in writing, without any warranty; without even the
11  * implied warranty of merchantability or fitness for a particular purpose.
12  * See the GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * The full GNU General Public License is included in this distribution in
19  * the file called "COPYING".
20  *
21  * Contact Information:
22  * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23  * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
24  *
25  ******************************************************************************/
26 #include <linux/module.h>
27
28 #include "services_headers.h"
29 #include "buffer_manager.h"
30 #include "kernelbuffer.h"
31 #include "pvr_bridge_km.h"
32
33 struct PVRSRV_DC_SRV2DISP_KMJTABLE;
34
35 struct PVRSRV_DC_BUFFER {
36         struct PVRSRV_DEVICECLASS_BUFFER sDeviceClassBuffer;
37         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
38         struct PVRSRV_DC_SWAPCHAIN *psSwapChain;
39 };
40
41 struct PVRSRV_DC_SWAPCHAIN {
42         void *hExtSwapChain;
43         struct PVRSRV_QUEUE_INFO *psQueue;
44         struct PVRSRV_DC_BUFFER asBuffer[PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS];
45         u32 ui32BufferCount;
46         struct PVRSRV_DC_BUFFER *psLastFlipBuffer;
47         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
48         void *hResItem;
49 };
50
51 struct PVRSRV_DISPLAYCLASS_INFO {
52         u32 ui32RefCount;
53         u32 ui32DeviceID;
54         void *hExtDevice;
55         struct PVRSRV_DC_SRV2DISP_KMJTABLE *psFuncTable;
56         void *hDevMemContext;
57         struct PVRSRV_DC_BUFFER sSystemBuffer;
58 };
59
60 struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO {
61         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
62         struct RESMAN_ITEM *hResItem;
63 };
64
65 struct PVRSRV_BC_SRV2BUFFER_KMJTABLE;
66
67 struct PVRSRV_BC_BUFFER {
68         struct PVRSRV_DEVICECLASS_BUFFER sDeviceClassBuffer;
69         struct PVRSRV_BUFFERCLASS_INFO *psBCInfo;
70 };
71
72 struct PVRSRV_BUFFERCLASS_INFO {
73         u32 ui32RefCount;
74         u32 ui32DeviceID;
75         void *hExtDevice;
76         struct PVRSRV_BC_SRV2BUFFER_KMJTABLE *psFuncTable;
77         void *hDevMemContext;
78
79         u32 ui32BufferCount;
80         struct PVRSRV_BC_BUFFER *psBuffer;
81
82 };
83
84 struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO {
85         struct PVRSRV_BUFFERCLASS_INFO *psBCInfo;
86         void *hResItem;
87 };
88
89 static struct PVRSRV_DISPLAYCLASS_INFO *DCDeviceHandleToDCInfo(void *hDeviceKM)
90 {
91         struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo;
92
93         psDCPerContextInfo = (struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *)
94                                 hDeviceKM;
95
96         return psDCPerContextInfo->psDCInfo;
97 }
98
99 static struct PVRSRV_BUFFERCLASS_INFO *BCDeviceHandleToBCInfo(void *hDeviceKM)
100 {
101         struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo;
102
103         psBCPerContextInfo = (struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *)
104                                 hDeviceKM;
105
106         return psBCPerContextInfo->psBCInfo;
107 }
108
109 enum PVRSRV_ERROR PVRSRVEnumerateDCKM(enum PVRSRV_DEVICE_CLASS DeviceClass,
110                                      u32 *pui32DevCount, u32 *pui32DevID)
111 {
112         struct PVRSRV_DEVICE_NODE *psDeviceNode;
113         unsigned ui32DevCount = 0;
114         struct SYS_DATA *psSysData;
115
116         if (SysAcquireData(&psSysData) != PVRSRV_OK) {
117                 PVR_DPF(PVR_DBG_ERROR,
118                          "PVRSRVEnumerateDCKM: Failed to get SysData");
119                 return PVRSRV_ERROR_GENERIC;
120         }
121
122         psDeviceNode = psSysData->psDeviceNodeList;
123         while (psDeviceNode) {
124                 if ((psDeviceNode->sDevId.eDeviceClass == DeviceClass) &&
125                     (psDeviceNode->sDevId.eDeviceType ==
126                         PVRSRV_DEVICE_TYPE_EXT)) {
127                         ui32DevCount++;
128                         if (pui32DevID) {
129                                 *pui32DevID++ =
130                                     psDeviceNode->sDevId.ui32DeviceIndex;
131                         }
132                 }
133                 psDeviceNode = psDeviceNode->psNext;
134         }
135
136         if (pui32DevCount) {
137                 *pui32DevCount = ui32DevCount;
138         } else if (pui32DevID == NULL) {
139                 PVR_DPF(PVR_DBG_ERROR,
140                          "PVRSRVEnumerateDCKM: Invalid parameters");
141                 return PVRSRV_ERROR_INVALID_PARAMS;
142         }
143
144         return PVRSRV_OK;
145 }
146
147 static enum PVRSRV_ERROR PVRSRVRegisterDCDeviceKM(
148                         struct PVRSRV_DC_SRV2DISP_KMJTABLE *psFuncTable,
149                         u32 *pui32DeviceID)
150 {
151         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo = NULL;
152         struct PVRSRV_DEVICE_NODE *psDeviceNode;
153         struct SYS_DATA *psSysData;
154
155         if (SysAcquireData(&psSysData) != PVRSRV_OK) {
156                 PVR_DPF(PVR_DBG_ERROR,
157                          "PVRSRVRegisterDCDeviceKM: Failed to get SysData");
158                 return PVRSRV_ERROR_GENERIC;
159         }
160
161         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
162                        sizeof(*psDCInfo),
163                        (void **) &psDCInfo, NULL) != PVRSRV_OK) {
164                 PVR_DPF(PVR_DBG_ERROR,
165                          "PVRSRVRegisterDCDeviceKM: Failed psDCInfo alloc");
166                 return PVRSRV_ERROR_OUT_OF_MEMORY;
167         }
168         OSMemSet(psDCInfo, 0, sizeof(*psDCInfo));
169
170         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
171                        sizeof(struct PVRSRV_DC_SRV2DISP_KMJTABLE),
172                        (void **)&psDCInfo->psFuncTable,
173                        NULL) != PVRSRV_OK) {
174                 PVR_DPF(PVR_DBG_ERROR,
175                          "PVRSRVRegisterDCDeviceKM: Failed psFuncTable alloc");
176                 goto ErrorExit;
177         }
178         OSMemSet(psDCInfo->psFuncTable, 0,
179                  sizeof(struct PVRSRV_DC_SRV2DISP_KMJTABLE));
180
181         *psDCInfo->psFuncTable = *psFuncTable;
182
183         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
184                        sizeof(struct PVRSRV_DEVICE_NODE),
185                        (void **) &psDeviceNode, NULL) != PVRSRV_OK) {
186                 PVR_DPF(PVR_DBG_ERROR,
187                         "PVRSRVRegisterDCDeviceKM: Failed psDeviceNode alloc");
188                 goto ErrorExit;
189         }
190         OSMemSet(psDeviceNode, 0, sizeof(struct PVRSRV_DEVICE_NODE));
191
192         psDeviceNode->pvDevice = (void *) psDCInfo;
193         psDeviceNode->ui32pvDeviceSize = sizeof(*psDCInfo);
194         psDeviceNode->ui32RefCount = 1;
195         psDeviceNode->sDevId.eDeviceType = PVRSRV_DEVICE_TYPE_EXT;
196         psDeviceNode->sDevId.eDeviceClass = PVRSRV_DEVICE_CLASS_DISPLAY;
197         psDeviceNode->psSysData = psSysData;
198
199         AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex);
200         psDCInfo->ui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex;
201         if (pui32DeviceID)
202                 *pui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex;
203
204         SysRegisterExternalDevice(psDeviceNode);
205
206         psDeviceNode->psNext = psSysData->psDeviceNodeList;
207         psSysData->psDeviceNodeList = psDeviceNode;
208
209         return PVRSRV_OK;
210
211 ErrorExit:
212
213         if (psDCInfo->psFuncTable)
214                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
215                           sizeof(struct PVRSRV_DC_SRV2DISP_KMJTABLE),
216                           psDCInfo->psFuncTable, NULL);
217
218         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
219                   sizeof(struct PVRSRV_DISPLAYCLASS_INFO),
220                   psDCInfo, NULL);
221
222         return PVRSRV_ERROR_OUT_OF_MEMORY;
223 }
224
225 static enum PVRSRV_ERROR PVRSRVRemoveDCDeviceKM(u32 ui32DevIndex)
226 {
227         struct SYS_DATA *psSysData;
228         struct PVRSRV_DEVICE_NODE **ppsDeviceNode, *psDeviceNode;
229         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
230
231         if (SysAcquireData(&psSysData) != PVRSRV_OK) {
232                 PVR_DPF(PVR_DBG_ERROR,
233                          "PVRSRVRemoveDCDeviceKM: Failed to get SysData");
234                 return PVRSRV_ERROR_GENERIC;
235         }
236
237         ppsDeviceNode = &psSysData->psDeviceNodeList;
238         while (*ppsDeviceNode) {
239                 switch ((*ppsDeviceNode)->sDevId.eDeviceClass) {
240                 case PVRSRV_DEVICE_CLASS_DISPLAY:
241                         {
242                                 if ((*ppsDeviceNode)->sDevId.ui32DeviceIndex ==
243                                     ui32DevIndex)
244                                         goto FoundDevice;
245                                 break;
246                         }
247                 default:
248                         {
249                                 break;
250                         }
251                 }
252                 ppsDeviceNode = &((*ppsDeviceNode)->psNext);
253         }
254
255         PVR_DPF(PVR_DBG_ERROR,
256                  "PVRSRVRemoveDCDeviceKM: requested device %d not present",
257                  ui32DevIndex);
258
259         return PVRSRV_ERROR_GENERIC;
260
261 FoundDevice:
262
263         psDeviceNode = *ppsDeviceNode;
264
265         psDCInfo = (struct PVRSRV_DISPLAYCLASS_INFO *)psDeviceNode->pvDevice;
266
267         if (psDCInfo->ui32RefCount == 0) {
268                 *ppsDeviceNode = psDeviceNode->psNext;
269                 SysRemoveExternalDevice(psDeviceNode);
270                 PVR_ASSERT(psDCInfo->ui32RefCount == 0);
271                 FreeDeviceID(psSysData, ui32DevIndex);
272                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
273                           sizeof(struct PVRSRV_DC_SRV2DISP_KMJTABLE),
274                           psDCInfo->psFuncTable, NULL);
275                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
276                           sizeof(struct PVRSRV_DISPLAYCLASS_INFO), psDCInfo,
277                           NULL);
278                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
279                           sizeof(struct PVRSRV_DEVICE_NODE), psDeviceNode,
280                           NULL);
281         } else {
282                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVRemoveDCDeviceKM: "
283                                 "failed as %d Services DC API "
284                                 "connections are still open",
285                          psDCInfo->ui32RefCount);
286                 return PVRSRV_ERROR_GENERIC;
287         }
288
289         return PVRSRV_OK;
290 }
291
292 static enum PVRSRV_ERROR PVRSRVRegisterBCDeviceKM(
293                 struct PVRSRV_BC_SRV2BUFFER_KMJTABLE *psFuncTable,
294                 u32 *pui32DeviceID)
295 {
296         struct PVRSRV_BUFFERCLASS_INFO *psBCInfo = NULL;
297         struct PVRSRV_DEVICE_NODE *psDeviceNode;
298         struct SYS_DATA *psSysData;
299
300         if (SysAcquireData(&psSysData) != PVRSRV_OK) {
301                 PVR_DPF(PVR_DBG_ERROR,
302                          "PVRSRVRegisterBCDeviceKM: Failed to get SysData");
303                 return PVRSRV_ERROR_GENERIC;
304         }
305
306         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
307                        sizeof(*psBCInfo),
308                        (void **) &psBCInfo, NULL) != PVRSRV_OK) {
309                 PVR_DPF(PVR_DBG_ERROR,
310                          "PVRSRVRegisterBCDeviceKM: Failed psBCInfo alloc");
311                 return PVRSRV_ERROR_OUT_OF_MEMORY;
312         }
313         OSMemSet(psBCInfo, 0, sizeof(*psBCInfo));
314
315         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
316                        sizeof(struct PVRSRV_BC_SRV2BUFFER_KMJTABLE),
317                        (void **) &psBCInfo->psFuncTable,
318                        NULL) != PVRSRV_OK) {
319                 PVR_DPF(PVR_DBG_ERROR,
320                          "PVRSRVRegisterBCDeviceKM: Failed psFuncTable alloc");
321                 goto ErrorExit;
322         }
323         OSMemSet(psBCInfo->psFuncTable, 0,
324                  sizeof(struct PVRSRV_BC_SRV2BUFFER_KMJTABLE));
325
326         *psBCInfo->psFuncTable = *psFuncTable;
327
328         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
329                        sizeof(struct PVRSRV_DEVICE_NODE),
330                        (void **) &psDeviceNode, NULL) != PVRSRV_OK) {
331                 PVR_DPF(PVR_DBG_ERROR,
332                         "PVRSRVRegisterBCDeviceKM: Failed psDeviceNode alloc");
333                 goto ErrorExit;
334         }
335         OSMemSet(psDeviceNode, 0, sizeof(struct PVRSRV_DEVICE_NODE));
336
337         psDeviceNode->pvDevice = (void *) psBCInfo;
338         psDeviceNode->ui32pvDeviceSize = sizeof(*psBCInfo);
339         psDeviceNode->ui32RefCount = 1;
340         psDeviceNode->sDevId.eDeviceType = PVRSRV_DEVICE_TYPE_EXT;
341         psDeviceNode->sDevId.eDeviceClass = PVRSRV_DEVICE_CLASS_BUFFER;
342         psDeviceNode->psSysData = psSysData;
343
344         AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex);
345         psBCInfo->ui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex;
346         if (pui32DeviceID)
347                 *pui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex;
348
349         psDeviceNode->psNext = psSysData->psDeviceNodeList;
350         psSysData->psDeviceNodeList = psDeviceNode;
351
352         return PVRSRV_OK;
353
354 ErrorExit:
355
356         if (psBCInfo->psFuncTable)
357                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
358                           sizeof(struct PVRSRV_BC_SRV2BUFFER_KMJTABLE *),
359                           psBCInfo->psFuncTable, NULL);
360
361         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
362                   sizeof(struct PVRSRV_BUFFERCLASS_INFO), psBCInfo, NULL);
363
364         return PVRSRV_ERROR_OUT_OF_MEMORY;
365 }
366
367 static enum PVRSRV_ERROR PVRSRVRemoveBCDeviceKM(u32 ui32DevIndex)
368 {
369         struct SYS_DATA *psSysData;
370         struct PVRSRV_DEVICE_NODE **ppsDevNode, *psDevNode;
371         struct PVRSRV_BUFFERCLASS_INFO *psBCInfo;
372
373         if (SysAcquireData(&psSysData) != PVRSRV_OK) {
374                 PVR_DPF(PVR_DBG_ERROR,
375                          "PVRSRVRemoveBCDeviceKM: Failed to get SysData");
376                 return PVRSRV_ERROR_GENERIC;
377         }
378
379         ppsDevNode = &psSysData->psDeviceNodeList;
380         while (*ppsDevNode) {
381                 switch ((*ppsDevNode)->sDevId.eDeviceClass) {
382                 case PVRSRV_DEVICE_CLASS_BUFFER:
383                         {
384                                 if ((*ppsDevNode)->sDevId.ui32DeviceIndex ==
385                                     ui32DevIndex)
386                                         goto FoundDevice;
387                                 break;
388                         }
389                 default:
390                         {
391                                 break;
392                         }
393                 }
394                 ppsDevNode = &(*ppsDevNode)->psNext;
395         }
396
397         PVR_DPF(PVR_DBG_ERROR,
398                  "PVRSRVRemoveBCDeviceKM: requested device %d not present",
399                  ui32DevIndex);
400
401         return PVRSRV_ERROR_GENERIC;
402
403 FoundDevice:
404
405         psDevNode = *(ppsDevNode);
406
407         psBCInfo = (struct PVRSRV_BUFFERCLASS_INFO *)psDevNode->pvDevice;
408
409         if (psBCInfo->ui32RefCount == 0) {
410                 *ppsDevNode = psDevNode->psNext;
411                 FreeDeviceID(psSysData, ui32DevIndex);
412                 psBCInfo =
413                     (struct PVRSRV_BUFFERCLASS_INFO *)psDevNode->pvDevice;
414                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
415                           sizeof(struct PVRSRV_BC_SRV2BUFFER_KMJTABLE),
416                           psBCInfo->psFuncTable, NULL);
417                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
418                           sizeof(struct PVRSRV_BUFFERCLASS_INFO), psBCInfo,
419                           NULL);
420                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
421                           sizeof(struct PVRSRV_DEVICE_NODE), psDevNode, NULL);
422         } else {
423                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVRemoveBCDeviceKM: "
424                                 "failed as %d Services BC API "
425                                 "connections are still open",
426                          psBCInfo->ui32RefCount);
427                 return PVRSRV_ERROR_GENERIC;
428         }
429
430         return PVRSRV_OK;
431 }
432
433 enum PVRSRV_ERROR PVRSRVCloseDCDeviceKM(void *hDeviceKM,
434                                        IMG_BOOL bResManCallback)
435 {
436         struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo;
437
438         PVR_UNREFERENCED_PARAMETER(bResManCallback);
439
440         psDCPerContextInfo = (struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *)
441                                                                 hDeviceKM;
442
443         ResManFreeResByPtr(psDCPerContextInfo->hResItem);
444
445         return PVRSRV_OK;
446 }
447
448 static enum PVRSRV_ERROR CloseDCDeviceCallBack(void *pvParam, u32 ui32Param)
449 {
450         struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo;
451         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
452
453         PVR_UNREFERENCED_PARAMETER(ui32Param);
454
455         psDCPerContextInfo = (struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *)
456                                                                         pvParam;
457         psDCInfo = psDCPerContextInfo->psDCInfo;
458
459         psDCInfo->ui32RefCount--;
460         if (psDCInfo->ui32RefCount == 0) {
461                 struct PVRSRV_DC_SRV2DISP_KMJTABLE *jtbl;
462
463                 jtbl = psDCInfo->psFuncTable;
464
465                 jtbl->pfnCloseDCDevice(psDCInfo->hExtDevice);
466
467                 PVRSRVFreeSyncInfoKM(psDCInfo->sSystemBuffer.sDeviceClassBuffer.
468                                      psKernelSyncInfo);
469
470                 psDCInfo->hDevMemContext = NULL;
471                 psDCInfo->hExtDevice = NULL;
472
473                 module_put(jtbl->owner);
474         }
475
476         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
477                   sizeof(struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO),
478                   psDCPerContextInfo, NULL);
479
480         return PVRSRV_OK;
481 }
482
483 enum PVRSRV_ERROR PVRSRVOpenDCDeviceKM(
484                                 struct PVRSRV_PER_PROCESS_DATA *psPerProc,
485                                 u32 ui32DeviceID, void *hDevCookie,
486                                 void **phDeviceKM)
487 {
488         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
489         struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo;
490         struct PVRSRV_DEVICE_NODE *psDeviceNode;
491         struct SYS_DATA *psSysData;
492
493         if (!phDeviceKM || !hDevCookie) {
494                 PVR_DPF(PVR_DBG_ERROR,
495                          "PVRSRVOpenDCDeviceKM: Invalid params");
496                 return PVRSRV_ERROR_GENERIC;
497         }
498
499         if (SysAcquireData(&psSysData) != PVRSRV_OK) {
500                 PVR_DPF(PVR_DBG_ERROR,
501                          "PVRSRVOpenDCDeviceKM: Failed to get SysData");
502                 return PVRSRV_ERROR_GENERIC;
503         }
504
505         psDeviceNode = psSysData->psDeviceNodeList;
506         while (psDeviceNode) {
507                 if ((psDeviceNode->sDevId.eDeviceClass ==
508                      PVRSRV_DEVICE_CLASS_DISPLAY) &&
509                      (psDeviceNode->sDevId.ui32DeviceIndex == ui32DeviceID)) {
510
511                         psDCInfo = (struct PVRSRV_DISPLAYCLASS_INFO *)
512                                                         psDeviceNode->pvDevice;
513                         goto FoundDevice;
514                 }
515                 psDeviceNode = psDeviceNode->psNext;
516         }
517
518         PVR_DPF(PVR_DBG_ERROR,
519                  "PVRSRVOpenDCDeviceKM: no devnode matching index %d",
520                  ui32DeviceID);
521
522         return PVRSRV_ERROR_GENERIC;
523
524 FoundDevice:
525
526         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psDCPerContextInfo),
527                        (void **)&psDCPerContextInfo, NULL) != PVRSRV_OK) {
528                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenDCDeviceKM: "
529                                         "Failed psDCPerContextInfo alloc");
530                 return PVRSRV_ERROR_OUT_OF_MEMORY;
531         }
532         OSMemSet(psDCPerContextInfo, 0, sizeof(*psDCPerContextInfo));
533
534         if (psDCInfo->ui32RefCount++ == 0) {
535                 enum PVRSRV_ERROR eError;
536                 struct PVRSRV_DC_SRV2DISP_KMJTABLE *jtbl;
537
538                 psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie;
539
540                 jtbl = psDCInfo->psFuncTable;
541                 if (!try_module_get(jtbl->owner)) {
542                         PVR_DPF(PVR_DBG_ERROR, "%s: can't get DC module");
543                         return PVRSRV_ERROR_INVALID_DEVICE;
544                 }
545
546                 psDCInfo->hDevMemContext =
547                     (void *) psDeviceNode->sDevMemoryInfo.pBMKernelContext;
548
549                 eError = PVRSRVAllocSyncInfoKM(NULL,
550                                        (void *)psDeviceNode->
551                                                sDevMemoryInfo.pBMKernelContext,
552                                        &psDCInfo->sSystemBuffer.
553                                                sDeviceClassBuffer.
554                                                        psKernelSyncInfo);
555                 if (eError != PVRSRV_OK) {
556                         PVR_DPF(PVR_DBG_ERROR,
557                                "PVRSRVOpenDCDeviceKM: Failed sync info alloc");
558                         psDCInfo->ui32RefCount--;
559                         module_put(jtbl->owner);
560                         return eError;
561                 }
562
563                 eError = jtbl->pfnOpenDCDevice(ui32DeviceID,
564                         &psDCInfo->hExtDevice,
565                         (struct PVRSRV_SYNC_DATA *)psDCInfo->sSystemBuffer.
566                                 sDeviceClassBuffer.psKernelSyncInfo->
567                                         psSyncDataMemInfoKM->pvLinAddrKM);
568                 if (eError != PVRSRV_OK) {
569                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenDCDeviceKM: "
570                                         "Failed to open external DC device");
571                         psDCInfo->ui32RefCount--;
572                         module_put(jtbl->owner);
573                         PVRSRVFreeSyncInfoKM(psDCInfo->sSystemBuffer.
574                                            sDeviceClassBuffer.psKernelSyncInfo);
575                         return eError;
576                 }
577         }
578
579         psDCPerContextInfo->psDCInfo = psDCInfo;
580         psDCPerContextInfo->hResItem =
581             ResManRegisterRes(psPerProc->hResManContext,
582                               RESMAN_TYPE_DISPLAYCLASS_DEVICE,
583                               psDCPerContextInfo, 0, CloseDCDeviceCallBack);
584
585         *phDeviceKM = (void *) psDCPerContextInfo;
586
587         return PVRSRV_OK;
588 }
589
590 enum PVRSRV_ERROR PVRSRVEnumDCFormatsKM(void *hDeviceKM,
591                                        u32 *pui32Count,
592                                        struct DISPLAY_FORMAT *psFormat)
593 {
594         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
595
596         if (!hDeviceKM || !pui32Count || !psFormat) {
597                 PVR_DPF(PVR_DBG_ERROR,
598                          "PVRSRVEnumDCFormatsKM: Invalid parameters");
599                 return PVRSRV_ERROR_INVALID_PARAMS;
600         }
601
602         psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
603
604         return psDCInfo->psFuncTable->pfnEnumDCFormats(psDCInfo->hExtDevice,
605                                                        pui32Count, psFormat);
606 }
607
608 enum PVRSRV_ERROR PVRSRVEnumDCDimsKM(void *hDeviceKM,
609                                     struct DISPLAY_FORMAT *psFormat,
610                                     u32 *pui32Count, struct DISPLAY_DIMS *psDim)
611 {
612         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
613
614         if (!hDeviceKM || !pui32Count || !psFormat) {
615                 PVR_DPF(PVR_DBG_ERROR,
616                          "PVRSRVEnumDCDimsKM: Invalid parameters");
617                 return PVRSRV_ERROR_INVALID_PARAMS;
618         }
619
620         psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
621
622         return psDCInfo->psFuncTable->pfnEnumDCDims(psDCInfo->hExtDevice,
623                                                   psFormat, pui32Count, psDim);
624 }
625
626 enum PVRSRV_ERROR PVRSRVGetDCSystemBufferKM(void *hDeviceKM, void **phBuffer)
627 {
628         enum PVRSRV_ERROR eError;
629         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
630         void *hExtBuffer;
631
632         if (!hDeviceKM || !phBuffer) {
633                 PVR_DPF(PVR_DBG_ERROR,
634                          "PVRSRVGetDCSystemBufferKM: Invalid parameters");
635                 return PVRSRV_ERROR_INVALID_PARAMS;
636         }
637
638         psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
639
640         eError =
641             psDCInfo->psFuncTable->pfnGetDCSystemBuffer(psDCInfo->hExtDevice,
642                                                         &hExtBuffer);
643         if (eError != PVRSRV_OK) {
644                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVGetDCSystemBufferKM: "
645                      "Failed to get valid buffer handle from external driver");
646                 return eError;
647         }
648
649         psDCInfo->sSystemBuffer.sDeviceClassBuffer.pfnGetBufferAddr =
650             psDCInfo->psFuncTable->pfnGetBufferAddr;
651         psDCInfo->sSystemBuffer.sDeviceClassBuffer.hDevMemContext =
652             psDCInfo->hDevMemContext;
653         psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtDevice =
654             psDCInfo->hExtDevice;
655         psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtBuffer = hExtBuffer;
656
657         psDCInfo->sSystemBuffer.psDCInfo = psDCInfo;
658
659         *phBuffer = (void *) &(psDCInfo->sSystemBuffer);
660
661         return PVRSRV_OK;
662 }
663
664 enum PVRSRV_ERROR PVRSRVGetDCInfoKM(void *hDeviceKM,
665                                 struct DISPLAY_INFO *psDisplayInfo)
666 {
667         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
668         enum PVRSRV_ERROR eError;
669
670         if (!hDeviceKM || !psDisplayInfo) {
671                 PVR_DPF(PVR_DBG_ERROR,
672                          "PVRSRVGetDCInfoKM: Invalid parameters");
673                 return PVRSRV_ERROR_INVALID_PARAMS;
674         }
675
676         psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
677
678         eError = psDCInfo->psFuncTable->pfnGetDCInfo(psDCInfo->hExtDevice,
679                                                         psDisplayInfo);
680         if (eError != PVRSRV_OK)
681                 return eError;
682
683         if (psDisplayInfo->ui32MaxSwapChainBuffers >
684             PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS) {
685                 psDisplayInfo->ui32MaxSwapChainBuffers =
686                     PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS;
687         }
688
689         return PVRSRV_OK;
690 }
691
692 enum PVRSRV_ERROR PVRSRVDestroyDCSwapChainKM(void *hSwapChain)
693 {
694         struct PVRSRV_DC_SWAPCHAIN *psSwapChain;
695
696         if (!hSwapChain) {
697                 PVR_DPF(PVR_DBG_ERROR,
698                          "PVRSRVDestroyDCSwapChainKM: Invalid parameters");
699                 return PVRSRV_ERROR_INVALID_PARAMS;
700         }
701
702         psSwapChain = hSwapChain;
703
704         ResManFreeResByPtr(psSwapChain->hResItem);
705
706         return PVRSRV_OK;
707 }
708
709 static enum PVRSRV_ERROR DestroyDCSwapChainCallBack(void *pvParam,
710                                                u32 ui32Param)
711 {
712         enum PVRSRV_ERROR eError;
713         struct PVRSRV_DC_SWAPCHAIN *psSwapChain = pvParam;
714         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo = psSwapChain->psDCInfo;
715         u32 i;
716
717         PVR_UNREFERENCED_PARAMETER(ui32Param);
718
719         PVRSRVDestroyCommandQueueKM(psSwapChain->psQueue);
720
721         eError =
722             psDCInfo->psFuncTable->pfnDestroyDCSwapChain(psDCInfo->hExtDevice,
723                                                          psSwapChain->
724                                                                  hExtSwapChain);
725
726         if (eError != PVRSRV_OK) {
727                 PVR_DPF(PVR_DBG_ERROR, "DestroyDCSwapChainCallBack: "
728                                         "Failed to destroy DC swap chain");
729                 return eError;
730         }
731
732         for (i = 0; i < psSwapChain->ui32BufferCount; i++)
733                 if (psSwapChain->asBuffer[i].sDeviceClassBuffer.
734                     psKernelSyncInfo)
735                         PVRSRVFreeSyncInfoKM(psSwapChain->asBuffer[i].
736                                                      sDeviceClassBuffer.
737                                                              psKernelSyncInfo);
738
739         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct PVRSRV_DC_SWAPCHAIN),
740                   psSwapChain, NULL);
741
742         return eError;
743 }
744
745 enum PVRSRV_ERROR PVRSRVCreateDCSwapChainKM(
746                                 struct PVRSRV_PER_PROCESS_DATA *psPerProc,
747                                 void *hDeviceKM, u32 ui32Flags,
748                                 struct DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib,
749                                 struct DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib,
750                                 u32 ui32BufferCount, u32 ui32OEMFlags,
751                                 void **phSwapChain, u32 *pui32SwapChainID)
752 {
753         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
754         struct PVRSRV_DC_SWAPCHAIN *psSwapChain = NULL;
755         struct PVRSRV_SYNC_DATA *apsSyncData[PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS];
756         struct PVRSRV_QUEUE_INFO *psQueue = NULL;
757         enum PVRSRV_ERROR eError;
758         u32 i;
759
760         if (!hDeviceKM || !psDstSurfAttrib || !psSrcSurfAttrib ||
761             !phSwapChain || !pui32SwapChainID) {
762                 PVR_DPF(PVR_DBG_ERROR,
763                          "PVRSRVCreateDCSwapChainKM: Invalid parameters");
764                 return PVRSRV_ERROR_INVALID_PARAMS;
765         }
766
767         if (ui32BufferCount > PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS) {
768                 PVR_DPF(PVR_DBG_ERROR,
769                          "PVRSRVCreateDCSwapChainKM: Too many buffers");
770                 return PVRSRV_ERROR_TOOMANYBUFFERS;
771         }
772
773         if (ui32BufferCount < 2) {
774                 PVR_DPF(PVR_DBG_ERROR,
775                          "PVRSRVCreateDCSwapChainKM: Too few buffers");
776                 return PVRSRV_ERROR_TOO_FEW_BUFFERS;
777         }
778
779         psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
780
781         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
782                        sizeof(struct PVRSRV_DC_SWAPCHAIN),
783                        (void **) &psSwapChain, NULL) != PVRSRV_OK) {
784                 PVR_DPF(PVR_DBG_ERROR,
785                          "PVRSRVCreateDCSwapChainKM: Failed psSwapChain alloc");
786                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
787                 goto ErrorExit;
788         }
789         OSMemSet(psSwapChain, 0, sizeof(struct PVRSRV_DC_SWAPCHAIN));
790
791         eError = PVRSRVCreateCommandQueueKM(1024, &psQueue);
792         if (eError != PVRSRV_OK) {
793                 PVR_DPF(PVR_DBG_ERROR,
794                         "PVRSRVCreateDCSwapChainKM: Failed to create CmdQueue");
795                 goto ErrorExit;
796         }
797
798         psSwapChain->psQueue = psQueue;
799
800         for (i = 0; i < ui32BufferCount; i++) {
801                 eError = PVRSRVAllocSyncInfoKM(NULL,
802                                                psDCInfo->hDevMemContext,
803                                                &psSwapChain->asBuffer[i].
804                                                        sDeviceClassBuffer.
805                                                               psKernelSyncInfo);
806                 if (eError != PVRSRV_OK) {
807                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVCreateDCSwapChainKM: "
808                                 "Failed to alloc syninfo for psSwapChain");
809                         goto ErrorExit;
810                 }
811
812                 psSwapChain->asBuffer[i].sDeviceClassBuffer.pfnGetBufferAddr =
813                     psDCInfo->psFuncTable->pfnGetBufferAddr;
814                 psSwapChain->asBuffer[i].sDeviceClassBuffer.hDevMemContext =
815                     psDCInfo->hDevMemContext;
816                 psSwapChain->asBuffer[i].sDeviceClassBuffer.hExtDevice =
817                     psDCInfo->hExtDevice;
818
819                 psSwapChain->asBuffer[i].psDCInfo = psDCInfo;
820                 psSwapChain->asBuffer[i].psSwapChain = psSwapChain;
821
822                 apsSyncData[i] =
823                     (struct PVRSRV_SYNC_DATA *)psSwapChain->asBuffer[i].
824                             sDeviceClassBuffer.psKernelSyncInfo->
825                                         psSyncDataMemInfoKM->pvLinAddrKM;
826         }
827
828         psSwapChain->ui32BufferCount = ui32BufferCount;
829         psSwapChain->psDCInfo = psDCInfo;
830
831         eError =
832             psDCInfo->psFuncTable->pfnCreateDCSwapChain(psDCInfo->hExtDevice,
833                                                 ui32Flags,
834                                                 psDstSurfAttrib,
835                                                 psSrcSurfAttrib,
836                                                 ui32BufferCount,
837                                                 apsSyncData,
838                                                 ui32OEMFlags,
839                                                 &psSwapChain->hExtSwapChain,
840                                                 pui32SwapChainID);
841         if (eError != PVRSRV_OK) {
842                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVCreateDCSwapChainKM: "
843                                 "Failed to create 3rd party SwapChain");
844                 goto ErrorExit;
845         }
846
847         *phSwapChain = (void *) psSwapChain;
848
849         psSwapChain->hResItem = ResManRegisterRes(psPerProc->hResManContext,
850                                           RESMAN_TYPE_DISPLAYCLASS_SWAPCHAIN,
851                                           psSwapChain, 0,
852                                           DestroyDCSwapChainCallBack);
853
854         return eError;
855
856 ErrorExit:
857
858         for (i = 0; i < ui32BufferCount; i++) {
859                 if (psSwapChain->asBuffer[i].sDeviceClassBuffer.
860                     psKernelSyncInfo) {
861                         PVRSRVFreeSyncInfoKM(psSwapChain->asBuffer[i].
862                                                      sDeviceClassBuffer.
863                                                              psKernelSyncInfo);
864                 }
865         }
866
867         if (psQueue)
868                 PVRSRVDestroyCommandQueueKM(psQueue);
869
870         if (psSwapChain) {
871                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
872                           sizeof(struct PVRSRV_DC_SWAPCHAIN), psSwapChain,
873                           NULL);
874         }
875
876         return eError;
877 }
878
879 enum PVRSRV_ERROR PVRSRVSetDCDstRectKM(void *hDeviceKM, void *hSwapChain,
880                                        struct IMG_RECT *psRect)
881 {
882         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
883         struct PVRSRV_DC_SWAPCHAIN *psSwapChain;
884
885         if (!hDeviceKM || !hSwapChain) {
886                 PVR_DPF(PVR_DBG_ERROR,
887                          "PVRSRVSetDCDstRectKM: Invalid parameters");
888                 return PVRSRV_ERROR_INVALID_PARAMS;
889         }
890
891         psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
892         psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain;
893
894         return psDCInfo->psFuncTable->pfnSetDCDstRect(psDCInfo->hExtDevice,
895                                         psSwapChain->hExtSwapChain, psRect);
896 }
897
898 enum PVRSRV_ERROR PVRSRVSetDCSrcRectKM(void *hDeviceKM, void *hSwapChain,
899                                        struct IMG_RECT *psRect)
900 {
901         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
902         struct PVRSRV_DC_SWAPCHAIN *psSwapChain;
903
904         if (!hDeviceKM || !hSwapChain) {
905                 PVR_DPF(PVR_DBG_ERROR,
906                          "PVRSRVSetDCSrcRectKM: Invalid parameters");
907                 return PVRSRV_ERROR_INVALID_PARAMS;
908         }
909
910         psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
911         psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain;
912
913         return psDCInfo->psFuncTable->pfnSetDCSrcRect(psDCInfo->hExtDevice,
914                                         psSwapChain->hExtSwapChain, psRect);
915 }
916
917 enum PVRSRV_ERROR PVRSRVSetDCDstColourKeyKM(void *hDeviceKM, void *hSwapChain,
918                                        u32 ui32CKColour)
919 {
920         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
921         struct PVRSRV_DC_SWAPCHAIN *psSwapChain;
922
923         if (!hDeviceKM || !hSwapChain) {
924                 PVR_DPF(PVR_DBG_ERROR,
925                          "PVRSRVSetDCDstColourKeyKM: Invalid parameters");
926                 return PVRSRV_ERROR_INVALID_PARAMS;
927         }
928
929         psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
930         psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain;
931
932         return psDCInfo->psFuncTable->pfnSetDCDstColourKey(psDCInfo->hExtDevice,
933                                      psSwapChain->hExtSwapChain, ui32CKColour);
934 }
935
936 enum PVRSRV_ERROR PVRSRVSetDCSrcColourKeyKM(void *hDeviceKM, void *hSwapChain,
937                                            u32 ui32CKColour)
938 {
939         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
940         struct PVRSRV_DC_SWAPCHAIN *psSwapChain;
941
942         if (!hDeviceKM || !hSwapChain) {
943                 PVR_DPF(PVR_DBG_ERROR,
944                          "PVRSRVSetDCSrcColourKeyKM: Invalid parameters");
945                 return PVRSRV_ERROR_INVALID_PARAMS;
946         }
947
948         psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
949         psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain;
950
951         return psDCInfo->psFuncTable->pfnSetDCSrcColourKey(psDCInfo->hExtDevice,
952                                      psSwapChain->hExtSwapChain, ui32CKColour);
953 }
954
955 enum PVRSRV_ERROR PVRSRVGetDCBuffersKM(void *hDeviceKM, void *hSwapChain,
956                                       u32 *pui32BufferCount, void **phBuffer)
957 {
958         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
959         struct PVRSRV_DC_SWAPCHAIN *psSwapChain;
960         void *ahExtBuffer[PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS];
961         enum PVRSRV_ERROR eError;
962         u32 i;
963
964         if (!hDeviceKM || !hSwapChain || !phBuffer) {
965                 PVR_DPF(PVR_DBG_ERROR,
966                          "PVRSRVGetDCBuffersKM: Invalid parameters");
967                 return PVRSRV_ERROR_INVALID_PARAMS;
968         }
969
970         psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
971         psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain;
972
973         eError = psDCInfo->psFuncTable->pfnGetDCBuffers(psDCInfo->hExtDevice,
974                                                 psSwapChain->hExtSwapChain,
975                                                 pui32BufferCount, ahExtBuffer);
976
977         PVR_ASSERT(*pui32BufferCount <= PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS);
978
979         for (i = 0; i < *pui32BufferCount; i++) {
980                 psSwapChain->asBuffer[i].sDeviceClassBuffer.hExtBuffer =
981                                                                 ahExtBuffer[i];
982                 phBuffer[i] = (void *)&psSwapChain->asBuffer[i];
983         }
984
985         return eError;
986 }
987
988 enum PVRSRV_ERROR PVRSRVSwapToDCBufferKM(void *hDeviceKM, void *hBuffer,
989                                         u32 ui32SwapInterval, void *hPrivateTag,
990                                         u32 ui32ClipRectCount,
991                                         struct IMG_RECT *psClipRect)
992 {
993         enum PVRSRV_ERROR eError;
994         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
995         struct PVRSRV_DC_BUFFER *psBuffer;
996         struct PVRSRV_QUEUE_INFO *psQueue;
997         struct DISPLAYCLASS_FLIP_COMMAND *psFlipCmd;
998         u32 i;
999         u32 ui32NumSrcSyncs = 1;
1000         struct PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[2];
1001         struct PVRSRV_COMMAND *psCommand;
1002
1003         if (!hDeviceKM || !hBuffer || !psClipRect) {
1004                 PVR_DPF(PVR_DBG_ERROR,
1005                          "PVRSRVSwapToDCBufferKM: Invalid parameters");
1006                 return PVRSRV_ERROR_INVALID_PARAMS;
1007         }
1008
1009         psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
1010         psBuffer = (struct PVRSRV_DC_BUFFER *)hBuffer;
1011
1012         psQueue = psBuffer->psSwapChain->psQueue;
1013
1014         apsSrcSync[0] = psBuffer->sDeviceClassBuffer.psKernelSyncInfo;
1015         if (psBuffer->psSwapChain->psLastFlipBuffer &&
1016             psBuffer != psBuffer->psSwapChain->psLastFlipBuffer) {
1017                 apsSrcSync[1] =
1018                     psBuffer->psSwapChain->psLastFlipBuffer->sDeviceClassBuffer.
1019                     psKernelSyncInfo;
1020                 ui32NumSrcSyncs++;
1021         }
1022
1023         eError = PVRSRVInsertCommandKM(psQueue, &psCommand,
1024                                       psDCInfo->ui32DeviceID, DC_FLIP_COMMAND,
1025                                       0, NULL, ui32NumSrcSyncs, apsSrcSync,
1026                                       sizeof(struct DISPLAYCLASS_FLIP_COMMAND) +
1027                                       (sizeof(struct IMG_RECT) *
1028                                                            ui32ClipRectCount));
1029         if (eError != PVRSRV_OK) {
1030                 PVR_DPF(PVR_DBG_ERROR,
1031                         "PVRSRVSwapToDCBufferKM: Failed to get space in queue");
1032                 goto Exit;
1033         }
1034
1035         psFlipCmd = (struct DISPLAYCLASS_FLIP_COMMAND *)psCommand->pvData;
1036         psFlipCmd->hExtDevice = psDCInfo->hExtDevice;
1037         psFlipCmd->hExtSwapChain = psBuffer->psSwapChain->hExtSwapChain;
1038         psFlipCmd->hExtBuffer = psBuffer->sDeviceClassBuffer.hExtBuffer;
1039         psFlipCmd->hPrivateTag = hPrivateTag;
1040         psFlipCmd->ui32ClipRectCount = ui32ClipRectCount;
1041         psFlipCmd->psClipRect =
1042             (struct IMG_RECT *)((u8 *) psFlipCmd +
1043                           sizeof(struct DISPLAYCLASS_FLIP_COMMAND));
1044
1045         for (i = 0; i < ui32ClipRectCount; i++)
1046                 psFlipCmd->psClipRect[i] = psClipRect[i];
1047
1048         psFlipCmd->ui32SwapInterval = ui32SwapInterval;
1049
1050         eError = PVRSRVSubmitCommandKM(psQueue, psCommand);
1051         if (eError != PVRSRV_OK) {
1052                 PVR_DPF(PVR_DBG_ERROR,
1053                          "PVRSRVSwapToDCBufferKM: Failed to submit command");
1054                 goto Exit;
1055         }
1056
1057         LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) {
1058                 if (PVRSRVProcessQueues(IMG_FALSE) !=
1059                     PVRSRV_ERROR_PROCESSING_BLOCKED) {
1060                         goto ProcessedQueues;
1061                 }
1062                 OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT);
1063         }
1064         END_LOOP_UNTIL_TIMEOUT();
1065
1066         PVR_DPF(PVR_DBG_ERROR,
1067                  "PVRSRVSwapToDCBufferKM: Failed to process queues");
1068
1069         eError = PVRSRV_ERROR_GENERIC;
1070         goto Exit;
1071
1072 ProcessedQueues:
1073
1074         psBuffer->psSwapChain->psLastFlipBuffer = psBuffer;
1075
1076 Exit:
1077         return eError;
1078 }
1079
1080 enum PVRSRV_ERROR PVRSRVSwapToDCSystemKM(void *hDeviceKM, void *hSwapChain)
1081 {
1082         enum PVRSRV_ERROR eError;
1083         struct PVRSRV_QUEUE_INFO *psQueue;
1084         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
1085         struct PVRSRV_DC_SWAPCHAIN *psSwapChain;
1086         struct DISPLAYCLASS_FLIP_COMMAND *psFlipCmd;
1087         u32 ui32NumSrcSyncs = 1;
1088         struct PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[2];
1089         struct PVRSRV_COMMAND *psCommand;
1090
1091         if (!hDeviceKM || !hSwapChain) {
1092                 PVR_DPF(PVR_DBG_ERROR,
1093                          "PVRSRVSwapToDCSystemKM: Invalid parameters");
1094                 return PVRSRV_ERROR_INVALID_PARAMS;
1095         }
1096
1097         psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM);
1098         psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain;
1099
1100         psQueue = psSwapChain->psQueue;
1101
1102         apsSrcSync[0] =
1103             psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo;
1104         if (psSwapChain->psLastFlipBuffer) {
1105                 if (apsSrcSync[0] !=
1106                     psSwapChain->psLastFlipBuffer->sDeviceClassBuffer.
1107                             psKernelSyncInfo) {
1108                         apsSrcSync[1] =
1109                             psSwapChain->psLastFlipBuffer->sDeviceClassBuffer.
1110                                             psKernelSyncInfo;
1111                         ui32NumSrcSyncs++;
1112                 }
1113         }
1114
1115         eError = PVRSRVInsertCommandKM(psQueue, &psCommand,
1116                                       psDCInfo->ui32DeviceID, DC_FLIP_COMMAND,
1117                                       0, NULL, ui32NumSrcSyncs, apsSrcSync,
1118                                       sizeof(struct DISPLAYCLASS_FLIP_COMMAND));
1119         if (eError != PVRSRV_OK) {
1120                 PVR_DPF(PVR_DBG_ERROR,
1121                         "PVRSRVSwapToDCSystemKM: Failed to get space in queue");
1122                 goto Exit;
1123         }
1124
1125         psFlipCmd = (struct DISPLAYCLASS_FLIP_COMMAND *)psCommand->pvData;
1126         psFlipCmd->hExtDevice = psDCInfo->hExtDevice;
1127         psFlipCmd->hExtSwapChain = psSwapChain->hExtSwapChain;
1128         psFlipCmd->hExtBuffer =
1129             psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtBuffer;
1130         psFlipCmd->hPrivateTag = NULL;
1131         psFlipCmd->ui32ClipRectCount = 0;
1132         psFlipCmd->ui32SwapInterval = 1;
1133
1134         eError = PVRSRVSubmitCommandKM(psQueue, psCommand);
1135         if (eError != PVRSRV_OK) {
1136                 PVR_DPF(PVR_DBG_ERROR,
1137                          "PVRSRVSwapToDCSystemKM: Failed to submit command");
1138                 goto Exit;
1139         }
1140
1141         LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) {
1142                 if (PVRSRVProcessQueues(IMG_FALSE) !=
1143                     PVRSRV_ERROR_PROCESSING_BLOCKED) {
1144                         goto ProcessedQueues;
1145                 }
1146                 OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT);
1147         }
1148         END_LOOP_UNTIL_TIMEOUT();
1149
1150         PVR_DPF(PVR_DBG_ERROR,
1151                  "PVRSRVSwapToDCSystemKM: Failed to process queues");
1152         eError = PVRSRV_ERROR_GENERIC;
1153         goto Exit;
1154
1155 ProcessedQueues:
1156
1157         psSwapChain->psLastFlipBuffer = &psDCInfo->sSystemBuffer;
1158
1159         eError = PVRSRV_OK;
1160
1161 Exit:
1162         return eError;
1163 }
1164
1165 static enum PVRSRV_ERROR PVRSRVRegisterSystemISRHandler(
1166                                         IMG_BOOL (*pfnISRHandler)(void *),
1167                                         void *pvISRHandlerData,
1168                                         u32 ui32ISRSourceMask,
1169                                         u32 ui32DeviceID)
1170 {
1171         struct SYS_DATA *psSysData;
1172         struct PVRSRV_DEVICE_NODE *psDevNode;
1173
1174         PVR_UNREFERENCED_PARAMETER(ui32ISRSourceMask);
1175
1176         if (SysAcquireData(&psSysData) != PVRSRV_OK) {
1177                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVRegisterSystemISRHandler: "
1178                                         "Failed to get SysData");
1179                 return PVRSRV_ERROR_GENERIC;
1180         }
1181
1182         psDevNode = psSysData->psDeviceNodeList;
1183         while (psDevNode) {
1184                 if (psDevNode->sDevId.ui32DeviceIndex == ui32DeviceID)
1185                         break;
1186                 psDevNode = psDevNode->psNext;
1187         }
1188
1189         if (psDevNode == NULL) {
1190                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVRegisterSystemISRHandler: "
1191                                         "Failed to get psDevNode");
1192                 PVR_DBG_BREAK;
1193                 return PVRSRV_ERROR_GENERIC;
1194         }
1195
1196         psDevNode->pvISRData = (void *) pvISRHandlerData;
1197
1198         psDevNode->pfnDeviceISR = pfnISRHandler;
1199
1200         return PVRSRV_OK;
1201 }
1202
1203 void PVRSRVSetDCState(u32 ui32State)
1204 {
1205         struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo;
1206         struct PVRSRV_DEVICE_NODE *psDeviceNode;
1207         struct SYS_DATA *psSysData;
1208
1209         if (SysAcquireData(&psSysData) != PVRSRV_OK) {
1210                 PVR_DPF(PVR_DBG_ERROR,
1211                          "PVRSRVSetDCState: Failed to get SysData");
1212                 return;
1213         }
1214
1215         psDeviceNode = psSysData->psDeviceNodeList;
1216         while (psDeviceNode != NULL) {
1217                 if (psDeviceNode->sDevId.eDeviceClass ==
1218                     PVRSRV_DEVICE_CLASS_DISPLAY) {
1219                         psDCInfo = (struct PVRSRV_DISPLAYCLASS_INFO *)
1220                                                         psDeviceNode->pvDevice;
1221                         if (psDCInfo->psFuncTable->pfnSetDCState &&
1222                             psDCInfo->hExtDevice)
1223                                 psDCInfo->psFuncTable->pfnSetDCState(
1224                                                         psDCInfo->hExtDevice,
1225                                                         ui32State);
1226                 }
1227                 psDeviceNode = psDeviceNode->psNext;
1228         }
1229 }
1230
1231 IMG_BOOL PVRGetDisplayClassJTable(struct PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable)
1232 {
1233         psJTable->ui32TableSize = sizeof(struct PVRSRV_DC_DISP2SRV_KMJTABLE);
1234         psJTable->pfnPVRSRVRegisterDCDevice = PVRSRVRegisterDCDeviceKM;
1235         psJTable->pfnPVRSRVRemoveDCDevice = PVRSRVRemoveDCDeviceKM;
1236         psJTable->pfnPVRSRVOEMFunction = SysOEMFunction;
1237         psJTable->pfnPVRSRVRegisterCmdProcList = PVRSRVRegisterCmdProcListKM;
1238         psJTable->pfnPVRSRVRemoveCmdProcList = PVRSRVRemoveCmdProcListKM;
1239         psJTable->pfnPVRSRVCmdComplete = PVRSRVCommandCompleteKM;
1240         psJTable->pfnPVRSRVRegisterSystemISRHandler =
1241             PVRSRVRegisterSystemISRHandler;
1242         psJTable->pfnPVRSRVRegisterPowerDevice = PVRSRVRegisterPowerDevice;
1243
1244         return IMG_TRUE;
1245 }
1246 EXPORT_SYMBOL(PVRGetDisplayClassJTable);
1247
1248 enum PVRSRV_ERROR PVRSRVCloseBCDeviceKM(void *hDeviceKM,
1249                                        IMG_BOOL bResManCallback)
1250 {
1251         struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo;
1252
1253         PVR_UNREFERENCED_PARAMETER(bResManCallback);
1254
1255         psBCPerContextInfo = (struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *)
1256                                 hDeviceKM;
1257
1258         ResManFreeResByPtr(psBCPerContextInfo->hResItem);
1259
1260         return PVRSRV_OK;
1261 }
1262
1263 static enum PVRSRV_ERROR CloseBCDeviceCallBack(void *pvParam, u32 ui32Param)
1264 {
1265         struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo;
1266         struct PVRSRV_BUFFERCLASS_INFO *psBCInfo;
1267
1268         PVR_UNREFERENCED_PARAMETER(ui32Param);
1269
1270         psBCPerContextInfo = (struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *)
1271                                 pvParam;
1272         psBCInfo = psBCPerContextInfo->psBCInfo;
1273
1274         psBCInfo->ui32RefCount--;
1275         if (psBCInfo->ui32RefCount == 0) {
1276                 u32 i;
1277
1278                 psBCInfo->psFuncTable->pfnCloseBCDevice(psBCInfo->hExtDevice);
1279
1280                 for (i = 0; i < psBCInfo->ui32BufferCount; i++)
1281                         if (psBCInfo->psBuffer[i].sDeviceClassBuffer.
1282                                     psKernelSyncInfo)
1283                                 PVRSRVFreeSyncInfoKM(psBCInfo->psBuffer[i].
1284                                                         sDeviceClassBuffer.
1285                                                               psKernelSyncInfo);
1286
1287                 if (psBCInfo->psBuffer)
1288                         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
1289                                   sizeof(struct PVRSRV_BC_BUFFER),
1290                                   psBCInfo->psBuffer, NULL);
1291         }
1292
1293         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
1294                   sizeof(struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO),
1295                   psBCPerContextInfo, NULL);
1296
1297         return PVRSRV_OK;
1298 }
1299
1300 enum PVRSRV_ERROR PVRSRVOpenBCDeviceKM(
1301                                 struct PVRSRV_PER_PROCESS_DATA *psPerProc,
1302                                 u32 ui32DeviceID, void *hDevCookie,
1303                                 void **phDeviceKM)
1304 {
1305         struct PVRSRV_BUFFERCLASS_INFO *psBCInfo;
1306         struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo;
1307         struct PVRSRV_DEVICE_NODE *psDeviceNode;
1308         struct SYS_DATA *psSysData;
1309         u32 i;
1310         enum PVRSRV_ERROR eError;
1311
1312         if (!phDeviceKM || !hDevCookie) {
1313                 PVR_DPF(PVR_DBG_ERROR,
1314                          "PVRSRVOpenBCDeviceKM: Invalid params");
1315                 return PVRSRV_ERROR_GENERIC;
1316         }
1317
1318         if (SysAcquireData(&psSysData) != PVRSRV_OK) {
1319                 PVR_DPF(PVR_DBG_ERROR,
1320                          "PVRSRVOpenBCDeviceKM: Failed to get SysData");
1321                 return PVRSRV_ERROR_GENERIC;
1322         }
1323
1324         psDeviceNode = psSysData->psDeviceNodeList;
1325         while (psDeviceNode) {
1326                 if ((psDeviceNode->sDevId.eDeviceClass ==
1327                      PVRSRV_DEVICE_CLASS_BUFFER) &&
1328                       (psDeviceNode->sDevId.ui32DeviceIndex == ui32DeviceID)) {
1329
1330                         psBCInfo = (struct PVRSRV_BUFFERCLASS_INFO *)
1331                                                         psDeviceNode->pvDevice;
1332                         goto FoundDevice;
1333                 }
1334                 psDeviceNode = psDeviceNode->psNext;
1335         }
1336
1337         PVR_DPF(PVR_DBG_ERROR,
1338                  "PVRSRVOpenBCDeviceKM: No devnode matching index %d",
1339                  ui32DeviceID);
1340
1341         return PVRSRV_ERROR_GENERIC;
1342
1343 FoundDevice:
1344
1345         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
1346                        sizeof(*psBCPerContextInfo),
1347                        (void **)&psBCPerContextInfo, NULL) != PVRSRV_OK) {
1348                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: "
1349                                         "Failed psBCPerContextInfo alloc");
1350                 return PVRSRV_ERROR_OUT_OF_MEMORY;
1351         }
1352         OSMemSet(psBCPerContextInfo, 0, sizeof(*psBCPerContextInfo));
1353
1354         if (psBCInfo->ui32RefCount++ == 0) {
1355                 struct BUFFER_INFO sBufferInfo;
1356
1357                 psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie;
1358
1359                 psBCInfo->hDevMemContext =
1360                     (void *) psDeviceNode->sDevMemoryInfo.pBMKernelContext;
1361
1362                 eError =
1363                     psBCInfo->psFuncTable->pfnOpenBCDevice(&psBCInfo->
1364                                                            hExtDevice);
1365                 if (eError != PVRSRV_OK) {
1366                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: "
1367                                         "Failed to open external BC device");
1368                         return eError;
1369                 }
1370
1371                 eError =
1372                     psBCInfo->psFuncTable->pfnGetBCInfo(psBCInfo->hExtDevice,
1373                                                         &sBufferInfo);
1374                 if (eError != PVRSRV_OK) {
1375                         PVR_DPF(PVR_DBG_ERROR,
1376                                 "PVRSRVOpenBCDeviceKM : Failed to get BC Info");
1377                         return eError;
1378                 }
1379
1380                 psBCInfo->ui32BufferCount = sBufferInfo.ui32BufferCount;
1381
1382                 eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
1383                                     sizeof(struct PVRSRV_BC_BUFFER) *
1384                                     sBufferInfo.ui32BufferCount,
1385                                     (void **) &psBCInfo->psBuffer,
1386                                     NULL);
1387                 if (eError != PVRSRV_OK) {
1388                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: "
1389                                         "Failed to allocate BC buffers");
1390                         return eError;
1391                 }
1392                 OSMemSet(psBCInfo->psBuffer, 0,
1393                          sizeof(struct PVRSRV_BC_BUFFER) *
1394                          sBufferInfo.ui32BufferCount);
1395
1396                 for (i = 0; i < psBCInfo->ui32BufferCount; i++) {
1397
1398                         eError = PVRSRVAllocSyncInfoKM(NULL,
1399                                       psBCInfo->hDevMemContext,
1400                                       &psBCInfo->psBuffer[i].sDeviceClassBuffer.
1401                                                         psKernelSyncInfo);
1402                         if (eError != PVRSRV_OK) {
1403                                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: "
1404                                                 "Failed sync info alloc");
1405                                 goto ErrorExit;
1406                         }
1407
1408                         eError = psBCInfo->psFuncTable->pfnGetBCBuffer(
1409                                     psBCInfo->hExtDevice, i,
1410                                     psBCInfo->psBuffer[i].sDeviceClassBuffer.
1411                                                           psKernelSyncInfo->
1412                                                                      psSyncData,
1413                                     &psBCInfo->psBuffer[i].sDeviceClassBuffer.
1414                                                           hExtBuffer);
1415                         if (eError != PVRSRV_OK) {
1416                                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: "
1417                                                 "Failed to get BC buffers");
1418                                 goto ErrorExit;
1419                         }
1420
1421                         psBCInfo->psBuffer[i].sDeviceClassBuffer.
1422                             pfnGetBufferAddr =
1423                                     psBCInfo->psFuncTable->pfnGetBufferAddr;
1424                         psBCInfo->psBuffer[i].sDeviceClassBuffer.
1425                             hDevMemContext = psBCInfo->hDevMemContext;
1426                         psBCInfo->psBuffer[i].sDeviceClassBuffer.hExtDevice =
1427                             psBCInfo->hExtDevice;
1428                 }
1429         }
1430
1431         psBCPerContextInfo->psBCInfo = psBCInfo;
1432         psBCPerContextInfo->hResItem =
1433             ResManRegisterRes(psPerProc->hResManContext,
1434                               RESMAN_TYPE_BUFFERCLASS_DEVICE,
1435                               psBCPerContextInfo, 0, CloseBCDeviceCallBack);
1436
1437         *phDeviceKM = (void *)psBCPerContextInfo;
1438
1439         return PVRSRV_OK;
1440
1441 ErrorExit:
1442
1443         for (i = 0; i < psBCInfo->ui32BufferCount; i++) {
1444                 if (psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo) {
1445                         PVRSRVFreeSyncInfoKM(psBCInfo->psBuffer[i].
1446                                                      sDeviceClassBuffer.
1447                                                              psKernelSyncInfo);
1448                 }
1449         }
1450
1451         if (psBCInfo->psBuffer) {
1452                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
1453                           sizeof(struct PVRSRV_BC_BUFFER), psBCInfo->psBuffer,
1454                           NULL);
1455         }
1456
1457         return eError;
1458 }
1459
1460 enum PVRSRV_ERROR PVRSRVGetBCInfoKM(void *hDeviceKM,
1461                                     struct BUFFER_INFO *psBufferInfo)
1462 {
1463         struct PVRSRV_BUFFERCLASS_INFO *psBCInfo;
1464         enum PVRSRV_ERROR eError;
1465
1466         if (!hDeviceKM || !psBufferInfo) {
1467                 PVR_DPF(PVR_DBG_ERROR,
1468                          "PVRSRVGetBCInfoKM: Invalid parameters");
1469                 return PVRSRV_ERROR_INVALID_PARAMS;
1470         }
1471
1472         psBCInfo = BCDeviceHandleToBCInfo(hDeviceKM);
1473
1474         eError =
1475             psBCInfo->psFuncTable->pfnGetBCInfo(psBCInfo->hExtDevice,
1476                                                 psBufferInfo);
1477
1478         if (eError != PVRSRV_OK) {
1479                 PVR_DPF(PVR_DBG_ERROR,
1480                          "PVRSRVGetBCInfoKM : Failed to get BC Info");
1481                 return eError;
1482         }
1483
1484         return PVRSRV_OK;
1485 }
1486
1487 enum PVRSRV_ERROR PVRSRVGetBCBufferKM(void *hDeviceKM, u32 ui32BufferIndex,
1488                                  void **phBuffer)
1489 {
1490         struct PVRSRV_BUFFERCLASS_INFO *psBCInfo;
1491
1492         if (!hDeviceKM || !phBuffer) {
1493                 PVR_DPF(PVR_DBG_ERROR,
1494                          "PVRSRVGetBCBufferKM: Invalid parameters");
1495                 return PVRSRV_ERROR_INVALID_PARAMS;
1496         }
1497
1498         psBCInfo = BCDeviceHandleToBCInfo(hDeviceKM);
1499
1500         if (ui32BufferIndex < psBCInfo->ui32BufferCount) {
1501                 *phBuffer = (void *)&psBCInfo->psBuffer[ui32BufferIndex];
1502         } else {
1503                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVGetBCBufferKM: "
1504                                 "Buffer index %d out of range (%d)",
1505                          ui32BufferIndex, psBCInfo->ui32BufferCount);
1506                 return PVRSRV_ERROR_INVALID_PARAMS;
1507         }
1508
1509         return PVRSRV_OK;
1510 }
1511
1512 IMG_BOOL PVRGetBufferClassJTable(struct PVRSRV_BC_BUFFER2SRV_KMJTABLE *psJTable)
1513 {
1514         psJTable->ui32TableSize = sizeof(struct PVRSRV_BC_BUFFER2SRV_KMJTABLE);
1515
1516         psJTable->pfnPVRSRVRegisterBCDevice = PVRSRVRegisterBCDeviceKM;
1517         psJTable->pfnPVRSRVRemoveBCDevice = PVRSRVRemoveBCDeviceKM;
1518
1519         return IMG_TRUE;
1520 }
1521 EXPORT_SYMBOL(PVRGetBufferClassJTable);
1522