add files to build ducati (m3) side firmware
[gstreamer-omap:ndecs-libdce.git] / dce.c
1 /*
2  * Copyright (c) 2010, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 // XXX TODO split up into several src files..
34
35 #include "dce_priv.h"
36
37 #include <stdlib.h>
38 #include <string.h>
39 #include <stdio.h>
40
41 #ifdef SERVER
42 #  include <xdc/std.h>
43 #  include <xdc/runtime/System.h>
44 #  include <ti/sysbios/knl/Task.h>
45 #  include <ti/ipc/MultiProc.h>
46 #  include <ti/sdo/rcm/RcmServer.h>
47 #  include <ti/omap/slpm/slpm_interface.h>
48 #  define Rcm_Handle         RcmServer_Handle
49 #  define Rcm_Params         RcmServer_Params
50 #  define Rcm_init           RcmServer_init
51 #  define Rcm_Params_init    RcmServer_Params_init
52 #  define Rcm_create         RcmServer_create
53 #  define Rcm_delete         RcmServer_delete
54 #  define Rcm_exit           RcmServer_exit
55 #  define SETUP_FXN(handle, name) do {                                         \
56         UInt32 _f = 0;                                                         \
57         int _e = RcmServer_addSymbol((handle), #name, rpc_##name, &_f);        \
58         if ((_e < 0) || (_f == 0xffffffff)) {                                  \
59             ERROR("failed to register function " #name ": %08x", _e);          \
60             return _e;                                                         \
61         }                                                                      \
62     } while (0)
63 #else
64 #  include <Std.h>
65 /* arrrg..  why can't people use stdint types!! */
66 typedef UInt32 Uint32;
67 typedef UInt16 Uint16;
68 typedef UInt8  Uint8;
69 typedef UInt32 Uns;  /* WTF? */
70 #  include <MultiProc.h>
71 #  include <RcmClient.h>
72 #  include <IpcUsr.h>
73 #  include <sys/types.h>
74 #  include <unistd.h>
75 #  include <stdint.h>
76 #  include <pthread.h>
77 #  include <memmgr.h>
78 #  include <tilermem.h>
79 #  define Rcm_Handle         RcmClient_Handle
80 #  define Rcm_Params         RcmClient_Params
81 #  define Rcm_init           RcmClient_init
82 #  define Rcm_Params_init    RcmClient_Params_init
83 #  define Rcm_create         RcmClient_create
84 #  define Rcm_delete         RcmClient_delete
85 #  define Rcm_exit           RcmClient_exit
86 #  define SETUP_FXN(handle, name) do {                                         \
87         int _e = RcmClient_getSymbolIndex((handle), #name, &idx_##name);       \
88         if (_e < 0) {                                                          \
89             ERROR("failed to get function " #name ": %08x", _e);               \
90             return _e;                                                         \
91         }                                                                      \
92     } while (0)
93 static void init(void);
94 static void deinit(void);
95 #endif
96
97 #include <ti/sdo/ce/Engine.h>
98 #include <ti/sdo/ce/video3/viddec3.h>
99
100 static Rcm_Handle handle = NULL;
101
102 /* XXX append a git hash, or version # or something like this, to ensure
103  * server and client are built from same version of this code.
104  */
105 #define SERVER_NAME "dCE"
106
107
108 /*
109  * Memory allocation/mapping
110  */
111
112 typedef struct {
113     Uint32  size;
114     Uint32  ducati_addr;
115 } MemHeader;
116
117
118 #define P2H(p) (&(((MemHeader *)(p))[-1]))
119 #define H2P(h) ((void *)&(h)[1])
120
121 #ifndef SERVER
122
123 /**
124  * Allocate a memory block that can be passed as an argument to any of the
125  * CE functions.
126  */
127 void * dce_alloc(int sz)
128 {
129     /* TODO: for now, allocate in tiler paged mode (1d) container.. until DMM
130      * is enabled on ducati, this would make the physical address the same as
131      * the virtual address on ducati, which simplifies some things.  Maybe
132      * later use ducati heap instead..
133      */
134     MemAllocBlock block = {
135             .pixelFormat = PIXEL_FMT_PAGE,
136             .dim = {
137                     .len = sz + sizeof(MemHeader),
138             }
139     };
140     MemHeader *h = MemMgr_Alloc(&block, 1);
141
142     h->size = sz;
143     h->ducati_addr = TilerMem_VirtToPhys(H2P(h));
144
145     memset(H2P(h), 0, sz);
146
147     return H2P(h);
148 }
149
150 /**
151  * Free a block allocated by dce_alloc()
152  */
153 void dce_free(void *ptr)
154 {
155     MemMgr_Free(P2H(ptr));
156 }
157
158 /**
159  * Translate pointer address to ducati.. block should have been allocated
160  * with dce_alloc().
161  */
162 static Uint32 virt2ducati(void *ptr)
163 {
164     if (ptr)
165         return P2H(ptr)->ducati_addr;
166     return 0;
167 }
168
169 #else
170
171 /* AFAIK both TILER and heap are cached on ducati side.. so from wherever a9
172  * allocates, we need to deal with cache to avoid coherency issues..
173  *
174  * Hmm, when block is allocated, we need to somehow invalidate it.
175  */
176 #include <ti/sysbios/hal/Cache.h>
177
178 static void dce_clean(void *ptr)
179 {
180     Cache_wbInv (ptr, P2H(ptr)->size, Cache_Type_ALL, TRUE);
181 }
182 #endif
183
184 /*
185  * Tracking of memmgr's.. one per client process, so that codec's memory
186  * allocates are tracked per client, and memory is freed if client crashes
187  * or exits badly
188  */
189
190 #ifdef SERVER
191
192 #include <ti/sdo/rcm/RcmClient.h>
193 #include <ti/omap/mem/MemMgr.h>
194
195 typedef struct {
196     Int pid;                      /* value of zero means unused */
197     Int refs;
198     Engine_Handle    engines[10]; /* adjust size per max engines per client */
199     VIDDEC3_Handle   codecs[10];  /* adjust size per max codecs per client */
200 } Client;
201 static Client clients[10] = {0};  /* adjust size per max-clients .. */
202
203 static inline Client * get_client(Int pid)
204 {
205     int i;
206     for (i = 0; i < DIM(clients); i++) {
207         if (clients[i].pid == pid) {
208             return &clients[i];
209         }
210     }
211     return NULL;
212 }
213
214 static void dce_register_engine(Int pid, Engine_Handle engine)
215 {
216     Client *c;
217
218     // TODO register/unregister should have critical section..
219
220     c = get_client(pid);
221     if (c) {
222         int i;
223         INFO("found mem client: %p refs=%d", c, c->refs);
224         c->refs++;
225         for (i = 0; i < DIM(c->engines); i++) {
226             if (c->engines[i] == NULL) {
227                 c->engines[i] = engine;
228                 INFO("registered engine: pid=%d engine=%p", pid, engine);
229                 break;
230             }
231         }
232     } else {
233         c = get_client(0);
234         if (!c) {
235             ERROR("too many clients");
236             goto out;
237         }
238
239         c->pid = pid;
240         c->refs = 1;
241         c->engines[0] = engine;
242     }
243 out:
244     // end critical section..
245     return;
246 }
247
248 static void dce_unregister_engine(Int pid, Engine_Handle engine)
249 {
250     Client *c;
251
252     // TODO register/unregister should have critical section..
253
254     c = get_client(pid);
255     if (c) {
256         int i;
257
258         INFO("found mem client: %p refs=%d", c, c->refs);
259
260         for (i = 0; i < DIM(c->engines); i++) {
261             if (c->engines[i] == engine) {
262                 c->engines[i] = NULL;
263                 INFO("unregistered engine: pid=%d engine=%p", pid, engine);
264                 break;
265             }
266         }
267         c->refs--;
268
269         if (! c->refs) {
270             c->pid = 0;
271         }
272     }
273
274     // end critical section..
275 }
276
277 static void dce_register_codec(Int pid, VIDDEC3_Handle codec)
278 {
279     Client *c;
280
281     // TODO register/unregister should have critical section..
282
283     c = get_client(pid);
284     if (c) {
285         int i;
286         INFO("found mem client: %p refs=%d", c, c->refs);
287         c->refs++;
288         for (i = 0; i < DIM(c->codecs); i++) {
289             if (c->codecs[i] == NULL) {
290                 c->codecs[i] = codec;
291                 INFO("registering codec: pid=%d codec=%p", pid, codec);
292                 break;
293             }
294         }
295     }
296     // end critical section..
297     return;
298 }
299
300 static void dce_unregister_codec(Int pid, VIDDEC3_Handle codec)
301 {
302     Client *c;
303
304     // TODO register/unregister should have critical section..
305
306     c = get_client(pid);
307     if (c) {
308         int i;
309
310         INFO("found mem client: %p refs=%d", c, c->refs);
311
312         for (i = 0; i < DIM(c->codecs); i++) {
313             if (c->codecs[i] == codec) {
314                 c->codecs[i] = NULL;
315                 INFO("unregistered pid=%d codec=%p", pid, codec);
316                 break;
317             }
318         }
319         c->refs--;
320     }
321
322     // end critical section..
323 }
324
325 #else
326 static Int pid;
327 #endif
328
329 /*
330  * Engine_open:
331  */
332
333 typedef union {
334     struct {
335         Int    pid;
336         Char   name[25];
337         /* attrs not supported/needed yet */
338     } in;
339     struct {
340         Int    ec;
341         Uint32 engine;
342     } out;
343 } Engine_open__args;
344
345 #ifdef SERVER
346 static Int32 rpc_Engine_open(UInt32 size, UInt32 *data)
347 {
348     Engine_open__args *args = (Engine_open__args *)data;
349     Int pid = args->in.pid;
350     Engine_Error ec;
351
352     DEBUG(">> name=%s", args->in.name);
353     Task_setEnv(Task_self(), (Ptr) args->in.pid);
354     args->out.engine = (Uint32)Engine_open(args->in.name, NULL, &ec);
355     args->out.ec = ec;
356     DEBUG("<< engine=%08x, ec=%d", args->out.engine, args->out.ec);
357
358     if (args->out.engine) {
359         dce_register_engine(pid, (Engine_Handle)(args->out.engine));
360     }
361
362     return 0;
363 }
364 #else
365 static UInt32 idx_Engine_open;
366 Engine_Handle Engine_open(String name, Engine_Attrs *attrs, Engine_Error *ec)
367 {
368     int err;
369     Engine_Handle ret = NULL;
370     Engine_open__args *args;
371     RcmClient_Message *msg = NULL;
372
373     init();
374
375     DEBUG(">> name=%s, attrs=%p", name, attrs);
376
377     err = RcmClient_alloc(handle, sizeof(Engine_open__args), &msg);
378     if (err < 0) {
379         ERROR("fail: %08x", err);
380         goto out;
381     }
382
383     msg->fxnIdx = idx_Engine_open;
384     args = (Engine_open__args *)&(msg->data);
385     args->in.pid = pid;
386     strncpy(args->in.name, name, DIM(args->in.name)-1);
387
388     err = RcmClient_exec(handle, msg, &msg);
389     if (err < 0) {
390         ERROR("fail: %08x", err);
391         goto out;
392     }
393
394     args = (Engine_open__args *)&(msg->data);
395     if (ec) {
396         *ec = args->out.ec;
397     }
398
399     ret = (Engine_Handle)args->out.engine;
400
401     DEBUG("<< engine=%p, ec=%d", ret, args->out.ec);
402
403 out:
404     if (msg) {
405         RcmClient_free (handle, msg);
406     }
407
408     return ret;
409 }
410 #endif
411
412 /*
413  * Engine_close:
414  */
415
416 typedef union {
417     struct {
418         Int    pid;
419         Uint32 engine;
420     } in;
421 } Engine_close__args;
422
423 #ifdef SERVER
424 static Int32 rpc_Engine_close(UInt32 size, UInt32 *data)
425 {
426     Engine_close__args *args = (Engine_close__args *)data;
427
428     dce_unregister_engine(args->in.pid, (Engine_Handle)(args->in.engine));
429
430     DEBUG(">> engine=%08x", args->in.engine);
431     Task_setEnv(Task_self(), (Ptr) args->in.pid);
432     Engine_close((Engine_Handle)(args->in.engine));
433     DEBUG("<<");
434
435     return 0;
436 }
437 #else
438 static UInt32 idx_Engine_close;
439 Void Engine_close(Engine_Handle engine)
440 {
441     int err;
442     Engine_close__args *args;
443     RcmClient_Message *msg = NULL;
444
445     DEBUG(">> engine=%p", engine);
446
447     err = RcmClient_alloc(handle, sizeof(Engine_close__args), &msg);
448     if (err < 0) {
449         ERROR("fail: %08x", err);
450         goto out;
451     }
452
453     msg->fxnIdx = idx_Engine_close;
454     args = (Engine_close__args *)&(msg->data);
455     args->in.pid    = pid;
456     args->in.engine = (Uint32)engine;
457
458     err = RcmClient_exec(handle, msg, &msg);
459     if (err < 0) {
460         ERROR("fail: %08x", err);
461         goto out;
462     }
463
464     DEBUG("<<");
465
466 out:
467     if (msg) {
468         RcmClient_free (handle, msg);
469     }
470
471     deinit();
472 }
473 #endif
474
475 /*
476  * VIDDEC3_create
477  */
478
479 typedef union {
480     struct {
481         Int    pid;
482         Uint32 engine;
483         Char   name[25];
484         Uint32 params;
485     } in;
486     struct {
487         Uint32 codec;
488     } out;
489 } VIDDEC3_create__args;
490
491 #ifdef SERVER
492 static Int32 rpc_VIDDEC3_create(UInt32 size, UInt32 *data)
493 {
494     VIDDEC3_create__args *args = (VIDDEC3_create__args *)data;
495     VIDDEC3_Params *params = (VIDDEC3_Params *)args->in.params;
496     Int pid = args->in.pid;
497
498     DEBUG(">> engine=%08x, name=%s, params=%p", args->in.engine, args->in.name, params);
499     Task_setEnv(Task_self(), (Ptr) args->in.pid);
500     args->out.codec = (Uint32)
501             VIDDEC3_create((Engine_Handle)args->in.engine, args->in.name, params);
502     dce_clean (params);
503     DEBUG("<< codec=%08x", args->out.codec);
504
505     if (args->out.codec) {
506         dce_register_codec(pid, (VIDDEC3_Handle)(args->out.codec));
507     }
508
509     return 0;
510 }
511 #else
512 static UInt32 idx_VIDDEC3_create;
513 VIDDEC3_Handle VIDDEC3_create(Engine_Handle engine, String name,
514         VIDDEC3_Params *params)
515 {
516     int err;
517     VIDDEC3_Handle ret;
518     VIDDEC3_create__args *args;
519     RcmClient_Message *msg = NULL;
520
521     DEBUG(">> engine=%p, name=%s, params=%p", engine, name, params);
522
523     err = RcmClient_alloc(handle, sizeof(VIDDEC3_create__args), &msg);
524     if (err < 0) {
525         ERROR("fail: %08x", err);
526         goto out;
527     }
528
529     msg->fxnIdx = idx_VIDDEC3_create;
530     args = (VIDDEC3_create__args *)&(msg->data);
531     args->in.pid    = pid;
532     args->in.engine = (Uint32)engine;
533     strncpy(args->in.name, name, DIM(args->in.name)-1);
534     args->in.params = virt2ducati(params);
535
536     err = RcmClient_exec(handle, msg, &msg);
537     if (err < 0) {
538         ERROR("fail: %08x", err);
539         goto out;
540     }
541
542     args = (VIDDEC3_create__args *)&(msg->data);
543     ret = (VIDDEC3_Handle)args->out.codec;
544
545     DEBUG("<< codec=%p", ret);
546
547 out:
548     if (msg) {
549         RcmClient_free (handle, msg);
550     }
551
552     return ret;
553 }
554 #endif
555
556 /*
557  * VIDDEC3_control
558  */
559
560 typedef union {
561     struct {
562         Int             pid;
563         Uint32          codec;
564         VIDDEC3_Cmd     id;
565         Uint32          dynParams;
566         Uint32          status;
567     } in;
568     struct {
569         XDAS_Int32      ret;
570     } out;
571 } VIDDEC3_control__args;
572
573 #ifdef SERVER
574 static Int32 rpc_VIDDEC3_control(UInt32 size, UInt32 *data)
575 {
576     VIDDEC3_control__args *args = (VIDDEC3_control__args *)data;
577     VIDDEC3_DynamicParams *dynParams =
578             (VIDDEC3_DynamicParams *)args->in.dynParams;
579     VIDDEC3_Status *status = (VIDDEC3_Status *)args->in.status;
580
581     DEBUG(">> codec=%p, id=%d, dynParams=%p, status=%p",
582             args->in.codec, args->in.id, dynParams, status);
583     Task_setEnv(Task_self(), (Ptr) args->in.pid);
584     args->out.ret = (Uint32)VIDDEC3_control(
585             (VIDDEC3_Handle)args->in.codec, args->in.id, dynParams, status);
586     dce_clean (dynParams);
587     dce_clean (status);
588     DEBUG("<< ret=%d", args->out.ret);
589
590     return 0;
591 }
592 #else
593 static UInt32 idx_VIDDEC3_control;
594 XDAS_Int32 VIDDEC3_control(VIDDEC3_Handle codec, VIDDEC3_Cmd id,
595         VIDDEC3_DynamicParams *dynParams, VIDDEC3_Status *status)
596 {
597     int err;
598     XDAS_Int32 ret;
599     VIDDEC3_control__args *args;
600     RcmClient_Message *msg = NULL;
601
602     DEBUG(">> codec=%p, id=%d, dynParams=%p, status=%p",
603             codec, id, dynParams, status);
604
605     err = RcmClient_alloc(handle, sizeof(VIDDEC3_control__args), &msg);
606     if (err < 0) {
607         ERROR("fail: %08x", err);
608         goto out;
609     }
610
611     msg->fxnIdx = idx_VIDDEC3_control;
612     args = (VIDDEC3_control__args *)&(msg->data);
613     args->in.pid        = pid;
614     args->in.codec      = (Uint32)codec;
615     args->in.id         = id;
616     args->in.dynParams  = virt2ducati(dynParams);
617     args->in.status     = virt2ducati(status);
618
619     err = RcmClient_exec(handle, msg, &msg);
620     if (err < 0) {
621         ERROR("fail: %08x", err);
622         goto out;
623     }
624
625     args = (VIDDEC3_control__args *)&(msg->data);
626     ret = args->out.ret;
627
628     DEBUG("<< ret=%d", ret);
629
630 out:
631     if (msg) {
632         RcmClient_free (handle, msg);
633     }
634
635     return ret;
636 }
637 #endif
638
639 /*
640  * VIDDEC3_process
641  */
642
643 typedef union {
644     struct {
645         Int        pid;
646         Uint32     codec;
647         Uint32     inBufs;
648         Uint32     outBufs;
649         Uint32     inArgs;
650         Uint32     outArgs;
651     } in;
652     struct {
653         XDAS_Int32 ret;
654     } out;
655 } VIDDEC3_process__args;
656
657 #ifdef SERVER
658 static Int32 rpc_VIDDEC3_process(UInt32 size, UInt32 *data)
659 {
660     VIDDEC3_process__args *args = (VIDDEC3_process__args *)data;
661     XDM2_BufDesc    *inBufs  = (XDM2_BufDesc *)args->in.inBufs;
662     XDM2_BufDesc    *outBufs = (XDM2_BufDesc *)args->in.outBufs;
663     VIDDEC3_InArgs  *inArgs  = (VIDDEC3_InArgs *)args->in.inArgs;
664     VIDDEC3_OutArgs *outArgs = (VIDDEC3_OutArgs *)args->in.outArgs;
665
666     DEBUG(">> codec=%p, inBufs=%p, outBufs=%p, inArgs=%p, outArgs=%p",
667             args->in.codec, inBufs, outBufs, inArgs, outArgs);
668     Task_setEnv(Task_self(), (Ptr) args->in.pid);
669     ivahd_acquire();
670     args->out.ret = (Uint32)VIDDEC3_process(
671             (VIDDEC3_Handle)args->in.codec, inBufs, outBufs, inArgs, outArgs);
672     ivahd_release();
673     dce_clean (inBufs);
674     dce_clean (outBufs);
675     dce_clean (inArgs);
676     dce_clean (outArgs);
677     DEBUG("<< ret=%d", args->out.ret);
678
679     return 0;
680 }
681 #else
682 static UInt32 idx_VIDDEC3_process;
683 XDAS_Int32 VIDDEC3_process(VIDDEC3_Handle codec,
684         XDM2_BufDesc *inBufs, XDM2_BufDesc *outBufs,
685         VIDDEC3_InArgs *inArgs, VIDDEC3_OutArgs *outArgs)
686 {
687     int err;
688     XDAS_Int32 ret;
689     VIDDEC3_process__args *args;
690     RcmClient_Message *msg = NULL;
691
692     DEBUG(">> codec=%p, inBufs=%p, outBufs=%p, inArgs=%p, outArgs=%p",
693             codec, inBufs, outBufs, inArgs, outArgs);
694
695     err = RcmClient_alloc(handle, sizeof(VIDDEC3_process__args), &msg);
696     if (err < 0) {
697         ERROR("fail: %08x", err);
698         goto out;
699     }
700
701     msg->fxnIdx = idx_VIDDEC3_process;
702     args = (VIDDEC3_process__args *)&(msg->data);
703     args->in.pid     = pid;
704     args->in.codec   = (Uint32)codec;
705     args->in.inBufs  = virt2ducati(inBufs);
706     args->in.outBufs = virt2ducati(outBufs);
707     args->in.inArgs  = virt2ducati(inArgs);
708     args->in.outArgs = virt2ducati(outArgs);
709
710     err = RcmClient_exec(handle, msg, &msg);
711     if (err < 0) {
712         ERROR("fail: %08x", err);
713         goto out;
714     }
715
716     args = (VIDDEC3_process__args *)&(msg->data);
717     ret = args->out.ret;
718
719     DEBUG("<< ret=%d", ret);
720
721 out:
722     if (msg) {
723         RcmClient_free (handle, msg);
724     }
725
726     return ret;
727 }
728 #endif
729
730 /*
731  * VIDDEC3_delete
732  */
733
734 typedef union {
735     struct {
736         Int    pid;
737         Uint32 codec;
738     } in;
739 } VIDDEC3_delete__args;
740
741 #ifdef SERVER
742 static Int32 rpc_VIDDEC3_delete(UInt32 size, UInt32 *data)
743 {
744     VIDDEC3_delete__args *args = (VIDDEC3_delete__args *)data;
745
746     dce_unregister_codec(args->in.pid, (VIDDEC3_Handle)(args->in.codec));
747
748     DEBUG(">> codec=%08x", args->in.codec);
749     Task_setEnv(Task_self(), (Ptr) args->in.pid);
750     VIDDEC3_delete((VIDDEC3_Handle)(args->in.codec));
751     DEBUG("<<");
752
753     return 0;
754 }
755 #else
756 static UInt32 idx_VIDDEC3_delete;
757 Void VIDDEC3_delete(VIDDEC3_Handle codec)
758 {
759     int err;
760     VIDDEC3_delete__args *args;
761     RcmClient_Message *msg = NULL;
762
763     DEBUG(">> codec=%p", codec);
764
765     err = RcmClient_alloc(handle, sizeof(VIDDEC3_delete__args), &msg);
766     if (err < 0) {
767         ERROR("fail: %08x", err);
768         goto out;
769     }
770
771     msg->fxnIdx = idx_VIDDEC3_delete;
772     args = (VIDDEC3_delete__args *)&(msg->data);
773     args->in.pid   = pid;
774     args->in.codec = (Uint32)codec;
775
776     err = RcmClient_exec(handle, msg, &msg);
777     if (err < 0) {
778         ERROR("fail: %08x", err);
779         goto out;
780     }
781
782     DEBUG("<<");
783
784 out:
785     if (msg) {
786         RcmClient_free (handle, msg);
787     }
788 }
789 #endif
790
791 /*
792  * Startup/Shutdown/Cleanup
793  */
794
795 #ifdef SERVER
796 static void dce_cleanup_cb (slpm_eventType evt, UInt32 pid, int *err)
797 {
798     Client *c;
799
800     if (evt != slpm_PROC_OBIT) {
801         return;
802     }
803
804     // TODO should be synchronized, but re-entrant..
805
806     c = get_client(pid);
807     INFO("cleanup: pid=%d, c=%p", pid, c);
808
809     if (c) {
810         int i;
811
812         /* delete all codecs first */
813         for (i = 0; i < DIM(c->codecs); i++) {
814             if (c->codecs[i]) {
815                 VIDDEC3_delete__args args;
816                 INFO("automatically deleting codec: %p", c->codecs[i]);
817                 args.in.pid = pid;
818                 args.in.codec = (Uint32)c->codecs[i];
819                 rpc_VIDDEC3_delete(sizeof(args), (Uint32 *)&args);
820             }
821         }
822
823         /* and lastly close all engines */
824         for (i = 0; i < DIM(c->engines); i++) {
825             if (c->engines[i]) {
826                 Engine_close__args args;
827                 INFO("automatically closing engine: %p", c->engines[i]);
828                 args.in.pid = pid;
829                 args.in.engine = (Uint32)c->engines[i];
830                 rpc_Engine_close(sizeof(args), (Uint32 *)&args);
831             }
832         }
833     }
834 }
835 #endif
836
837 int dce_init(void)
838 {
839     int err = 0;
840     Rcm_Params params = {0};
841
842 #ifdef SERVER
843     Int32 appm3;
844     RcmServer_ThreadPoolDesc pool = {
845             .name = "General Pool",
846             .count = 3,
847             .priority = Thread_Priority_NORMAL,
848     };
849 #endif
850
851     Rcm_init();
852     Rcm_Params_init(&params);
853
854 #ifdef SERVER
855     params.workerPools.length = 1;
856     params.workerPools.elem = &pool;
857 #else
858     params.heapId = 1; //XXX do I need this?
859 #endif
860
861     err = Rcm_create(SERVER_NAME, &params, &handle);
862     if (err < 0) {
863         ERROR("failed to create " SERVER_NAME ": 0x%08x", err);
864         return err;
865     }
866
867     /* Local Function Registration starts on  RCM server */
868     SETUP_FXN(handle, Engine_open);
869     SETUP_FXN(handle, Engine_close);
870     SETUP_FXN(handle, VIDDEC3_create);
871     SETUP_FXN(handle, VIDDEC3_control);
872     SETUP_FXN(handle, VIDDEC3_process);
873     SETUP_FXN(handle, VIDDEC3_delete);
874
875 #ifdef SERVER
876     RcmServer_start(handle);
877
878     err = slpm_request_pm_resource(&appm3, slpm_APPM3, NULL);
879     if (err) {
880         ERROR("could not request appm3");
881     }
882
883     err = slpm_register_callback(&appm3, slpm_PROC_OBIT, 0, dce_cleanup_cb);
884     if (err) {
885         ERROR("could not register resource cleanup callback");
886     }
887 #endif
888
889     DEBUG(SERVER_NAME " running");
890
891     return err;
892 }
893
894 int dce_deinit(void)
895 {
896     int err = 0;
897
898     DEBUG("shutdown");
899
900     if (handle) {
901         err = Rcm_delete(&handle);
902         if (err < 0) {
903             ERROR("failed to delete " SERVER_NAME ": %08x", err);
904         }
905         handle = NULL;
906     }
907
908     Rcm_exit();
909
910     DEBUG("deleted " SERVER_NAME);
911
912     return err;
913 }
914
915 #ifndef SERVER
916 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
917 static int count = 0;
918
919 static void init(void)
920 {
921     int err;
922     Ipc_Config config = {0};
923
924     pthread_mutex_lock(&mutex);
925
926     if (count > 0) {
927         goto out;
928     }
929
930     count++;
931
932     Ipc_getConfig(&config);
933
934     err = Ipc_setup(&config);
935     DEBUG("Ipc_setup() -> %08x", err);
936
937     pid = getpid();
938
939     err = dce_init();
940     DEBUG("dce_init() -> %08x", err);
941
942 out:
943     pthread_mutex_unlock(&mutex);
944 }
945
946 static void deinit(void)
947 {
948     int err;
949
950     pthread_mutex_lock(&mutex);
951
952     count--;
953
954     if (count > 0) {
955         goto out;
956     }
957
958     err = dce_deinit();
959     DEBUG("dce_deinit() -> %08x", err);
960
961     err = Ipc_destroy();
962     DEBUG("Ipc_destroy() -> %08x", err);
963
964 out:
965     pthread_mutex_unlock(&mutex);
966 }
967 #endif