dvd fixed (hopefully)
[libogc.git] / libogc / ipc.c
blob375d6751e89925138db351f3fe2c1e5188d3d409
1 /*-------------------------------------------------------------
3 ipc.c -- Interprocess Communication with Starlet
5 Copyright (C) 2008
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
8 Hector Martin (marcan)
10 This software is provided 'as-is', without any express or implied
11 warranty. In no event will the authors be held liable for any
12 damages arising from the use of this software.
14 Permission is granted to anyone to use this software for any
15 purpose, including commercial applications, and to alter it and
16 redistribute it freely, subject to the following restrictions:
18 1. The origin of this software must not be misrepresented; you
19 must not claim that you wrote the original software. If you use
20 this software in a product, an acknowledgment in the product
21 documentation would be appreciated but is not required.
23 2. Altered source versions must be plainly marked as such, and
24 must not be misrepresented as being the original software.
26 3. This notice may not be removed or altered from any source
27 distribution.
29 -------------------------------------------------------------*/
31 #if defined(HW_RVL)
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdarg.h>
37 #include <ctype.h>
38 #include <malloc.h>
39 #include <time.h>
40 #include <gcutil.h>
41 #include "asm.h"
42 #include "processor.h"
43 #include "lwp.h"
44 #include "irq.h"
45 #include "ipc.h"
46 #include "cache.h"
47 #include "system.h"
48 #include "lwp_heap.h"
49 #include "lwp_wkspace.h"
51 //#define DEBUG_IPC
53 #define IPC_REQ_MAGIC 0x4C4F4743
55 #define IPC_HEAP_SIZE 4096
56 #define IPC_REQUESTSIZE 64
57 #define IPC_NUMHEAPS 16
59 #define IOS_MAXFMT_PARAMS 32
61 #define IOS_OPEN 0x01
62 #define IOS_CLOSE 0x02
63 #define IOS_READ 0x03
64 #define IOS_WRITE 0x04
65 #define IOS_SEEK 0x05
66 #define IOS_IOCTL 0x06
67 #define IOS_IOCTLV 0x07
69 #define RELNCH_RELAUNCH 1
70 #define RELNCH_BACKGROUND 2
72 struct _ipcreq
73 { //ipc struct size: 32
74 u32 cmd; //0
75 s32 result; //4
76 union { //8
77 s32 fd;
78 u32 req_cmd;
80 union {
81 struct {
82 char *filepath;
83 u32 mode;
84 } open;
85 struct {
86 void *data;
87 u32 len;
88 } read, write;
89 struct {
90 s32 where;
91 s32 whence;
92 } seek;
93 struct {
94 u32 ioctl;
95 void *buffer_in;
96 u32 len_in;
97 void *buffer_io;
98 u32 len_io;
99 } ioctl;
100 struct {
101 u32 ioctl;
102 u32 argcin;
103 u32 argcio;
104 struct _ioctlv *argv;
105 } ioctlv;
106 u32 args[5];
109 ipccallback cb; //32
110 void *usrdata; //36
111 u32 relnch; //40
112 lwpq_t syncqueue; //44
113 u32 magic; //48 - used to avoid spurious responses, like from zelda.
114 u8 pad1[12]; //52 - 60
115 } ATTRIBUTE_PACKED;
117 struct _ipcreqres
119 u32 cnt_sent;
120 u32 cnt_queue;
121 u32 req_send_no;
122 u32 req_queue_no;
123 struct _ipcreq *reqs[16];
126 struct _ipcheap
128 void *membase;
129 u32 size;
130 heap_cntrl heap;
133 struct _ioctlvfmt_bufent
135 void *ipc_buf;
136 void *io_buf;
137 s32 copy_len;
140 struct _ioctlvfmt_cbdata
142 ipccallback user_cb;
143 void *user_data;
144 s32 num_bufs;
145 u32 hId;
146 struct _ioctlvfmt_bufent *bufs;
149 static s32 _ipc_hid = -1;
150 static s32 _ipc_mailboxack = 1;
151 static u32 _ipc_relnchFl = 0;
152 static u32 _ipc_initialized = 0;
153 static u32 _ipc_clntinitialized = 0;
154 static u64 _ipc_spuriousresponsecnt = 0;
155 static struct _ipcreq *_ipc_relnchRpc = NULL;
157 static void *_ipc_bufferlo = NULL;
158 static void *_ipc_bufferhi = NULL;
159 static void *_ipc_currbufferlo = NULL;
160 static void *_ipc_currbufferhi = NULL;
162 static struct _ipcreqres _ipc_responses;
164 static struct _ipcheap _ipc_heaps[IPC_NUMHEAPS] =
166 {NULL, 0, {}} // all other elements should be inited to zero, says C standard, so this should do
169 static vu32* const _ipcReg = (u32*)0xCD000000;
171 extern void __MaskIrq(u32 nMask);
172 extern void __UnmaskIrq(u32 nMask);
173 extern void* __SYS_GetIPCBufferLo(void);
174 extern void* __SYS_GetIPCBufferHi(void);
176 u32 IPC_ReadReg(u32 reg)
178 return _ipcReg[reg];
181 static __inline__ void IPC_WriteReg(u32 reg,u32 val)
183 _ipcReg[reg] = val;
186 static __inline__ void ACR_WriteReg(u32 reg,u32 val)
188 _ipcReg[reg>>2] = val;
191 static __inline__ void* __ipc_allocreq()
193 return iosAlloc(_ipc_hid,IPC_REQUESTSIZE);
196 static __inline__ void __ipc_freereq(void *ptr)
198 iosFree(_ipc_hid,ptr);
201 static s32 __ioctlvfmtCB(s32 result,void *userdata)
203 ipccallback user_cb;
204 void *user_data;
205 struct _ioctlvfmt_cbdata *cbdata;
206 struct _ioctlvfmt_bufent *pbuf;
208 cbdata = (struct _ioctlvfmt_cbdata*)userdata;
210 // deal with data buffers
211 if(cbdata->bufs) {
212 pbuf = cbdata->bufs;
213 while(cbdata->num_bufs--) {
214 if(pbuf->ipc_buf) {
215 // copy data if needed
216 if(pbuf->io_buf && pbuf->copy_len)
217 memcpy(pbuf->io_buf, pbuf->ipc_buf, pbuf->copy_len);
218 // then free the buffer
219 iosFree(cbdata->hId, pbuf->ipc_buf);
221 pbuf++;
225 user_cb = cbdata->user_cb;
226 user_data = cbdata->user_data;
228 // free buffer list
229 __lwp_wkspace_free(cbdata->bufs);
231 // free callback data
232 __lwp_wkspace_free(cbdata);
234 // call the user callback
235 if(user_cb)
236 return user_cb(result, user_data);
238 return result;
241 static s32 __ipc_queuerequest(struct _ipcreq *req)
243 u32 cnt;
244 u32 level;
245 #ifdef DEBUG_IPC
246 printf("__ipc_queuerequest(0x%p)\n",req);
247 #endif
248 _CPU_ISR_Disable(level);
250 cnt = (_ipc_responses.cnt_queue - _ipc_responses.cnt_sent);
251 if(cnt>=16) {
252 _CPU_ISR_Restore(level);
253 return IPC_EQUEUEFULL;
256 _ipc_responses.reqs[_ipc_responses.req_queue_no] = req;
257 _ipc_responses.req_queue_no = ((_ipc_responses.req_queue_no+1)&0x0f);
258 _ipc_responses.cnt_queue++;
260 _CPU_ISR_Restore(level);
261 return IPC_OK;
264 static s32 __ipc_syncqueuerequest(struct _ipcreq *req)
266 u32 cnt;
267 #ifdef DEBUG_IPC
268 printf("__ipc_syncqueuerequest(0x%p)\n",req);
269 #endif
270 cnt = (_ipc_responses.cnt_queue - _ipc_responses.cnt_sent);
271 if(cnt>=16) {
272 return IPC_EQUEUEFULL;
275 _ipc_responses.reqs[_ipc_responses.req_queue_no] = req;
276 _ipc_responses.req_queue_no = ((_ipc_responses.req_queue_no+1)&0x0f);
277 _ipc_responses.cnt_queue++;
279 return IPC_OK;
282 static void __ipc_sendrequest()
284 u32 cnt;
285 u32 ipc_send;
286 struct _ipcreq *req;
287 #ifdef DEBUG_IPC
288 printf("__ipc_sendrequest()\n");
289 #endif
290 cnt = (_ipc_responses.cnt_queue - _ipc_responses.cnt_sent);
291 if(cnt>0) {
292 req = _ipc_responses.reqs[_ipc_responses.req_send_no];
293 if(req!=NULL) {
294 req->magic = IPC_REQ_MAGIC;
295 if(req->relnch&RELNCH_RELAUNCH) {
296 _ipc_relnchFl = 1;
297 _ipc_relnchRpc = req;
298 if(!(req->relnch&RELNCH_BACKGROUND))
299 _ipc_mailboxack--;
301 DCFlushRange(req,sizeof(struct _ipcreq));
303 IPC_WriteReg(0,MEM_VIRTUAL_TO_PHYSICAL(req));
304 _ipc_responses.req_send_no = ((_ipc_responses.req_send_no+1)&0x0f);
305 _ipc_responses.cnt_sent++;
306 _ipc_mailboxack--;
308 ipc_send = ((IPC_ReadReg(1)&0x30)|0x01);
309 IPC_WriteReg(1,ipc_send);
314 static void __ipc_replyhandler()
316 u32 ipc_ack,cnt;
317 struct _ipcreq *req = NULL;
318 ioctlv *v = NULL;
319 #ifdef DEBUG_IPC
320 printf("__ipc_replyhandler()\n");
321 #endif
322 req = (struct _ipcreq*)IPC_ReadReg(2);
323 if(req==NULL) return;
325 ipc_ack = ((IPC_ReadReg(1)&0x30)|0x04);
326 IPC_WriteReg(1,ipc_ack);
327 ACR_WriteReg(48,0x40000000);
329 req = MEM_PHYSICAL_TO_K0(req);
330 DCInvalidateRange(req,32);
332 if(req->magic==IPC_REQ_MAGIC) {
333 #ifdef DEBUG_IPC
334 printf("IPC res: cmd %08x rcmd %08x res %08x\n",req->cmd,req->req_cmd,req->result);
335 #endif
336 if(req->req_cmd==IOS_READ) {
337 if(req->read.data!=NULL) {
338 req->read.data = MEM_PHYSICAL_TO_K0(req->read.data);
339 if(req->result>0) DCInvalidateRange(req->read.data,req->result);
341 } else if(req->req_cmd==IOS_IOCTL) {
342 if(req->ioctl.buffer_io!=NULL) {
343 req->ioctl.buffer_io = MEM_PHYSICAL_TO_K0(req->ioctl.buffer_io);
344 DCInvalidateRange(req->ioctl.buffer_io,req->ioctl.len_io);
346 DCInvalidateRange(req->ioctl.buffer_in,req->ioctl.len_in);
347 } else if(req->req_cmd==IOS_IOCTLV) {
348 if(req->ioctlv.argv!=NULL) {
349 req->ioctlv.argv = MEM_PHYSICAL_TO_K0(req->ioctlv.argv);
350 DCInvalidateRange(req->ioctlv.argv,((req->ioctlv.argcin+req->ioctlv.argcio)*sizeof(struct _ioctlv)));
353 cnt = 0;
354 v = (ioctlv*)req->ioctlv.argv;
355 while(cnt<(req->ioctlv.argcin+req->ioctlv.argcio)) {
356 if(v[cnt].data!=NULL) {
357 v[cnt].data = MEM_PHYSICAL_TO_K0(v[cnt].data);
358 DCInvalidateRange(v[cnt].data,v[cnt].len);
360 cnt++;
362 if(_ipc_relnchFl && _ipc_relnchRpc==req) {
363 _ipc_relnchFl = 0;
364 if(_ipc_mailboxack<1) _ipc_mailboxack++;
369 if(req->cb!=NULL) {
370 req->cb(req->result,req->usrdata);
371 __ipc_freereq(req);
372 } else
373 LWP_ThreadSignal(req->syncqueue);
374 } else {
375 // NOTE: we really want to find out if this ever happens
376 // and take steps to prevent it beforehand (because it will
377 // clobber memory, among other things). I suggest leaving this in
378 // even in non-DEBUG mode. Maybe even cause a system halt.
379 // It is the responsibility of the loader to clear these things,
380 // but we want to find out if they happen so loaders can be fixed.
381 #ifdef DEBUG_IPC
382 printf("Received unknown IPC response (magic %08x):\n", req->magic);
383 printf(" CMD %08x RES %08x REQCMD %08x\n", req->cmd, req->result, req->req_cmd);
384 printf(" Args: %08x %08x %08x %08x %08x\n", req->args[0], req->args[1], req->args[2], req->args[3], req->args[4]);
385 printf(" CB %08x DATA %08x REL %08x QUEUE %08x\n", (u32)req->cb, (u32)req->usrdata, req->relnch, (u32)req->syncqueue);
386 #endif
387 _ipc_spuriousresponsecnt++;
389 ipc_ack = ((IPC_ReadReg(1)&0x30)|0x08);
390 IPC_WriteReg(1,ipc_ack);
393 static void __ipc_ackhandler()
395 u32 ipc_ack;
396 #ifdef DEBUG_IPC
397 printf("__ipc_ackhandler()\n");
398 #endif
399 ipc_ack = ((IPC_ReadReg(1)&0x30)|0x02);
400 IPC_WriteReg(1,ipc_ack);
401 ACR_WriteReg(48,0x40000000);
403 if(_ipc_mailboxack<1) _ipc_mailboxack++;
404 if(_ipc_mailboxack>0) {
405 if(_ipc_relnchFl){
406 _ipc_relnchRpc->result = 0;
407 _ipc_relnchFl = 0;
409 LWP_ThreadSignal(_ipc_relnchRpc->syncqueue);
411 ipc_ack = ((IPC_ReadReg(1)&0x30)|0x08);
412 IPC_WriteReg(1,ipc_ack);
414 __ipc_sendrequest();
419 static void __ipc_interrupthandler(u32 irq,void *ctx)
421 u32 ipc_int;
422 #ifdef DEBUG_IPC
423 printf("__ipc_interrupthandler(%d)\n",irq);
424 #endif
425 ipc_int = IPC_ReadReg(1);
426 if((ipc_int&0x0014)==0x0014) __ipc_replyhandler();
428 ipc_int = IPC_ReadReg(1);
429 if((ipc_int&0x0022)==0x0022) __ipc_ackhandler();
432 static s32 __ios_ioctlvformat_parse(const char *format,va_list args,struct _ioctlvfmt_cbdata *cbdata,s32 *cnt_in,s32 *cnt_io,struct _ioctlv **argv,s32 hId)
434 s32 ret,i;
435 void *pdata;
436 void *iodata;
437 char type,*ps;
438 s32 len,maxbufs = 0;
439 ioctlv *argp = NULL;
440 struct _ioctlvfmt_bufent *bufp;
442 if(hId == IPC_HEAP) hId = _ipc_hid;
443 if(hId < 0) return IPC_EINVAL;
445 maxbufs = strnlen(format,IOS_MAXFMT_PARAMS);
446 if(maxbufs>=IOS_MAXFMT_PARAMS) return IPC_EINVAL;
448 cbdata->hId = hId;
449 cbdata->bufs = __lwp_wkspace_allocate((sizeof(struct _ioctlvfmt_bufent)*(maxbufs+1)));
450 if(cbdata->bufs==NULL) return IPC_ENOMEM;
452 argp = iosAlloc(hId,(sizeof(struct _ioctlv)*(maxbufs+1)));
453 if(argp==NULL) {
454 __lwp_wkspace_free(cbdata->bufs);
455 return IPC_ENOMEM;
458 *argv = argp;
459 bufp = cbdata->bufs;
460 memset(argp,0,(sizeof(struct _ioctlv)*(maxbufs+1)));
461 memset(bufp,0,(sizeof(struct _ioctlvfmt_bufent)*(maxbufs+1)));
463 cbdata->num_bufs = 1;
464 bufp->ipc_buf = argp;
465 bufp++;
467 *cnt_in = 0;
468 *cnt_io = 0;
470 ret = IPC_OK;
471 while(*format) {
472 type = tolower(*format);
473 switch(type) {
474 case 'b':
475 pdata = iosAlloc(hId,sizeof(u8));
476 if(pdata==NULL) {
477 ret = IPC_ENOMEM;
478 goto free_and_error;
480 *(u8*)pdata = va_arg(args,u32);
481 argp->data = pdata;
482 argp->len = sizeof(u8);
483 bufp->ipc_buf = pdata;
484 cbdata->num_bufs++;
485 (*cnt_in)++;
486 argp++;
487 bufp++;
488 break;
489 case 'h':
490 pdata = iosAlloc(hId,sizeof(u16));
491 if(pdata==NULL) {
492 ret = IPC_ENOMEM;
493 goto free_and_error;
495 *(u16*)pdata = va_arg(args,u32);
496 argp->data = pdata;
497 argp->len = sizeof(u16);
498 bufp->ipc_buf = pdata;
499 cbdata->num_bufs++;
500 (*cnt_in)++;
501 argp++;
502 bufp++;
503 break;
504 case 'i':
505 pdata = iosAlloc(hId,sizeof(u32));
506 if(pdata==NULL) {
507 ret = IPC_ENOMEM;
508 goto free_and_error;
510 *(u32*)pdata = va_arg(args,u32);
511 argp->data = pdata;
512 argp->len = sizeof(u32);
513 bufp->ipc_buf = pdata;
514 cbdata->num_bufs++;
515 (*cnt_in)++;
516 argp++;
517 bufp++;
518 break;
519 case 'q':
520 pdata = iosAlloc(hId,sizeof(u64));
521 if(pdata==NULL) {
522 ret = IPC_ENOMEM;
523 goto free_and_error;
525 *(u64*)pdata = va_arg(args,u64);
526 argp->data = pdata;
527 argp->len = sizeof(u64);
528 bufp->ipc_buf = pdata;
529 cbdata->num_bufs++;
530 (*cnt_in)++;
531 argp++;
532 bufp++;
533 break;
534 case 'd':
535 argp->data = va_arg(args, void*);
536 argp->len = va_arg(args, u32);
537 (*cnt_in)++;
538 argp++;
539 break;
540 case 's':
541 ps = va_arg(args, char*);
542 len = strnlen(ps,256);
543 if(len>=256) {
544 ret = IPC_EINVAL;
545 goto free_and_error;
548 pdata = iosAlloc(hId,(len+1));
549 if(pdata==NULL) {
550 ret = IPC_ENOMEM;
551 goto free_and_error;
553 memcpy(pdata,ps,(len+1));
554 argp->data = pdata;
555 argp->len = (len+1);
556 bufp->ipc_buf = pdata;
557 cbdata->num_bufs++;
558 (*cnt_in)++;
559 argp++;
560 bufp++;
561 break;
562 case ':':
563 format++;
564 goto parse_io_params;
565 default:
566 ret = IPC_EINVAL;
567 goto free_and_error;
569 format++;
572 parse_io_params:
573 while(*format) {
574 type = tolower(*format);
575 switch(type) {
576 case 'b':
577 pdata = iosAlloc(hId,sizeof(u8));
578 if(pdata==NULL) {
579 ret = IPC_ENOMEM;
580 goto free_and_error;
582 iodata = va_arg(args,u8*);
583 *(u8*)pdata = *(u8*)iodata;
584 argp->data = pdata;
585 argp->len = sizeof(u8);
586 bufp->ipc_buf = pdata;
587 bufp->io_buf = iodata;
588 bufp->copy_len = sizeof(u8);
589 cbdata->num_bufs++;
590 (*cnt_io)++;
591 argp++;
592 bufp++;
593 break;
594 case 'h':
595 pdata = iosAlloc(hId,sizeof(u16));
596 if(pdata==NULL) {
597 ret = IPC_ENOMEM;
598 goto free_and_error;
600 iodata = va_arg(args,u16*);
601 *(u16*)pdata = *(u16*)iodata;
602 argp->data = pdata;
603 argp->len = sizeof(u16);
604 bufp->ipc_buf = pdata;
605 bufp->io_buf = iodata;
606 bufp->copy_len = sizeof(u16);
607 cbdata->num_bufs++;
608 (*cnt_io)++;
609 argp++;
610 bufp++;
611 break;
612 case 'i':
613 pdata = iosAlloc(hId,sizeof(u32));
614 if(pdata==NULL) {
615 ret = IPC_ENOMEM;
616 goto free_and_error;
618 iodata = va_arg(args,u32*);
619 *(u32*)pdata = *(u32*)iodata;
620 argp->data = pdata;
621 argp->len = sizeof(u32);
622 bufp->ipc_buf = pdata;
623 bufp->io_buf = iodata;
624 bufp->copy_len = sizeof(u32);
625 cbdata->num_bufs++;
626 (*cnt_io)++;
627 argp++;
628 bufp++;
629 break;
630 case 'q':
631 pdata = iosAlloc(hId,sizeof(u64));
632 if(pdata==NULL) {
633 ret = IPC_ENOMEM;
634 goto free_and_error;
636 iodata = va_arg(args,u64*);
637 *(u64*)pdata = *(u64*)iodata;
638 argp->data = pdata;
639 argp->len = sizeof(u64);
640 bufp->ipc_buf = pdata;
641 bufp->io_buf = iodata;
642 bufp->copy_len = sizeof(u64);
643 cbdata->num_bufs++;
644 (*cnt_io)++;
645 argp++;
646 bufp++;
647 break;
648 case 'd':
649 argp->data = va_arg(args, void*);
650 argp->len = va_arg(args, u32);
651 (*cnt_io)++;
652 argp++;
653 break;
654 default:
655 ret = IPC_EINVAL;
656 goto free_and_error;
658 format++;
660 return IPC_OK;
662 free_and_error:
663 for(i=0;i<cbdata->num_bufs;i++) {
664 if(cbdata->bufs[i].ipc_buf!=NULL) iosFree(hId,cbdata->bufs[i].ipc_buf);
666 __lwp_wkspace_free(cbdata->bufs);
667 return ret;
670 static s32 __ipc_asyncrequest(struct _ipcreq *req)
672 s32 ret;
673 u32 level;
675 ret = __ipc_queuerequest(req);
676 if(ret) __ipc_freereq(req);
677 else {
678 _CPU_ISR_Disable(level);
679 if(_ipc_mailboxack>0) __ipc_sendrequest();
680 _CPU_ISR_Restore(level);
682 return ret;
685 static s32 __ipc_syncrequest(struct _ipcreq *req)
687 s32 ret;
688 u32 level;
690 LWP_InitQueue(&req->syncqueue);
692 _CPU_ISR_Disable(level);
693 ret = __ipc_syncqueuerequest(req);
694 if(ret==0) {
695 if(_ipc_mailboxack>0) __ipc_sendrequest();
696 LWP_ThreadSleep(req->syncqueue);
697 ret = req->result;
699 _CPU_ISR_Restore(level);
701 LWP_CloseQueue(req->syncqueue);
702 return ret;
705 s32 iosCreateHeap(s32 size)
707 s32 i,ret;
708 s32 free;
709 u32 level;
710 u32 ipclo,ipchi;
711 #ifdef DEBUG_IPC
712 printf("iosCreateHeap(%d)\n",size);
713 #endif
714 _CPU_ISR_Disable(level);
716 i=0;
717 while(i<IPC_NUMHEAPS) {
718 if(_ipc_heaps[i].membase==NULL) break;
719 i++;
721 if(i>=IPC_NUMHEAPS) {
722 _CPU_ISR_Restore(level);
723 return IPC_ENOHEAP;
726 ipclo = (((u32)IPC_GetBufferLo()+0x1f)&~0x1f);
727 ipchi = (u32)IPC_GetBufferHi();
728 free = (ipchi - (ipclo + size));
729 if(free<0) return IPC_ENOMEM;
731 _ipc_heaps[i].membase = (void*)ipclo;
732 _ipc_heaps[i].size = size;
734 ret = __lwp_heap_init(&_ipc_heaps[i].heap,(void*)ipclo,size,PPC_CACHE_ALIGNMENT);
735 if(ret<=0) return IPC_ENOMEM;
737 IPC_SetBufferLo((void*)(ipclo+size));
738 _CPU_ISR_Restore(level);
739 return i;
742 s32 iosDestroyHeap(s32 hid)
744 s32 ret = 0;
745 u32 level;
746 #ifdef DEBUG_IPC
747 printf("iosDestroyHeap(%d)\n",hid);
748 #endif
749 _CPU_ISR_Disable(level);
751 if(hid>=0 && hid<IPC_NUMHEAPS) {
752 if(_ipc_heaps[hid].membase!=NULL) {
753 _ipc_heaps[hid].membase = NULL;
754 _ipc_heaps[hid].size = 0;
756 } else
757 ret = IPC_EINVAL;
759 _CPU_ISR_Restore(level);
760 return ret;
763 void* iosAlloc(s32 hid,s32 size)
765 #ifdef DEBUG_IPC
766 printf("iosAlloc(%d,%d)\n",hid,size);
767 #endif
768 if(hid<0 || hid>=IPC_NUMHEAPS || size<=0) return NULL;
769 return __lwp_heap_allocate(&_ipc_heaps[hid].heap,size);
772 void iosFree(s32 hid,void *ptr)
774 #ifdef DEBUG_IPC
775 printf("iosFree(%d,0x%p)\n",hid,ptr);
776 #endif
777 if(hid<0 || hid>=IPC_NUMHEAPS || ptr==NULL) return;
778 __lwp_heap_free(&_ipc_heaps[hid].heap,ptr);
781 void* IPC_GetBufferLo()
783 return _ipc_currbufferlo;
786 void* IPC_GetBufferHi()
788 return _ipc_currbufferhi;
791 void IPC_SetBufferLo(void *bufferlo)
793 if(_ipc_bufferlo<=bufferlo) _ipc_currbufferlo = bufferlo;
796 void IPC_SetBufferHi(void *bufferhi)
798 if(bufferhi<=_ipc_bufferhi) _ipc_currbufferhi = bufferhi;
801 void __IPC_Init(void)
803 if(!_ipc_initialized) {
804 _ipc_bufferlo = _ipc_currbufferlo = __SYS_GetIPCBufferLo();
805 _ipc_bufferhi = _ipc_currbufferhi = __SYS_GetIPCBufferHi();
806 _ipc_initialized = 1;
810 u32 __IPC_ClntInit(void)
812 if(!_ipc_clntinitialized) {
813 _ipc_clntinitialized = 1;
815 __IPC_Init();
817 _ipc_hid = iosCreateHeap(IPC_HEAP_SIZE);
818 IRQ_Request(IRQ_PI_ACR,__ipc_interrupthandler,NULL);
819 __UnmaskIrq(IM_PI_ACR);
820 IPC_WriteReg(1,56);
822 return IPC_OK;
825 void __IPC_Reinitialize(void)
827 u32 level;
829 _CPU_ISR_Disable(level);
831 IPC_WriteReg(1,56);
833 _ipc_mailboxack = 1;
834 _ipc_relnchFl = 0;
835 _ipc_relnchRpc = NULL;
837 _ipc_responses.req_queue_no = 0;
838 _ipc_responses.cnt_queue = 0;
839 _ipc_responses.req_send_no = 0;
840 _ipc_responses.cnt_sent = 0;
842 _CPU_ISR_Restore(level);
845 s32 IOS_Open(const char *filepath,u32 mode)
847 s32 ret;
848 struct _ipcreq *req;
850 if(filepath==NULL) return IPC_EINVAL;
852 req = __ipc_allocreq();
853 if(req==NULL) return IPC_ENOMEM;
855 req->cmd = IOS_OPEN;
856 req->cb = NULL;
857 req->relnch = 0;
859 DCFlushRange((void*)filepath,strnlen(filepath,IPC_MAXPATH_LEN) + 1);
861 req->open.filepath = (char*)MEM_VIRTUAL_TO_PHYSICAL(filepath);
862 req->open.mode = mode;
864 ret = __ipc_syncrequest(req);
866 if(req!=NULL) __ipc_freereq(req);
867 return ret;
870 s32 IOS_OpenAsync(const char *filepath,u32 mode,ipccallback ipc_cb,void *usrdata)
872 struct _ipcreq *req;
874 req = __ipc_allocreq();
875 if(req==NULL) return IPC_ENOMEM;
877 req->cmd = IOS_OPEN;
878 req->cb = ipc_cb;
879 req->usrdata = usrdata;
880 req->relnch = 0;
882 DCFlushRange((void*)filepath,strnlen(filepath,IPC_MAXPATH_LEN) + 1);
884 req->open.filepath = (char*)MEM_VIRTUAL_TO_PHYSICAL(filepath);
885 req->open.mode = mode;
887 return __ipc_asyncrequest(req);
890 s32 IOS_Close(s32 fd)
892 s32 ret;
893 struct _ipcreq *req;
895 req = __ipc_allocreq();
896 if(req==NULL) return IPC_ENOMEM;
898 req->cmd = IOS_CLOSE;
899 req->fd = fd;
900 req->cb = NULL;
901 req->relnch = 0;
903 ret = __ipc_syncrequest(req);
905 if(req!=NULL) __ipc_freereq(req);
906 return ret;
909 s32 IOS_CloseAsync(s32 fd,ipccallback ipc_cb,void *usrdata)
911 struct _ipcreq *req;
913 req = __ipc_allocreq();
914 if(req==NULL) return IPC_ENOMEM;
916 req->cmd = IOS_CLOSE;
917 req->fd = fd;
918 req->cb = ipc_cb;
919 req->usrdata = usrdata;
920 req->relnch = 0;
922 return __ipc_asyncrequest(req);
925 s32 IOS_Read(s32 fd,void *buf,s32 len)
927 s32 ret;
928 struct _ipcreq *req;
930 req = __ipc_allocreq();
931 if(req==NULL) return IPC_ENOMEM;
933 req->cmd = IOS_READ;
934 req->fd = fd;
935 req->cb = NULL;
936 req->relnch = 0;
938 DCInvalidateRange(buf,len);
939 req->read.data = (void*)MEM_VIRTUAL_TO_PHYSICAL(buf);
940 req->read.len = len;
942 ret = __ipc_syncrequest(req);
944 if(req!=NULL) __ipc_freereq(req);
945 return ret;
948 s32 IOS_ReadAsync(s32 fd,void *buf,s32 len,ipccallback ipc_cb,void *usrdata)
950 struct _ipcreq *req;
952 req = __ipc_allocreq();
953 if(req==NULL) return IPC_ENOMEM;
955 req->cmd = IOS_READ;
956 req->fd = fd;
957 req->cb = ipc_cb;
958 req->usrdata = usrdata;
959 req->relnch = 0;
961 DCInvalidateRange(buf,len);
962 req->read.data = (void*)MEM_VIRTUAL_TO_PHYSICAL(buf);
963 req->read.len = len;
965 return __ipc_asyncrequest(req);
968 s32 IOS_Write(s32 fd,const void *buf,s32 len)
970 s32 ret;
971 struct _ipcreq *req;
973 req = __ipc_allocreq();
974 if(req==NULL) return IPC_ENOMEM;
976 req->cmd = IOS_WRITE;
977 req->fd = fd;
978 req->cb = NULL;
979 req->relnch = 0;
981 DCFlushRange((void*)buf,len);
982 req->write.data = (void*)MEM_VIRTUAL_TO_PHYSICAL(buf);
983 req->write.len = len;
985 ret = __ipc_syncrequest(req);
987 if(req!=NULL) __ipc_freereq(req);
988 return ret;
991 s32 IOS_WriteAsync(s32 fd,const void *buf,s32 len,ipccallback ipc_cb,void *usrdata)
993 struct _ipcreq *req;
995 req = __ipc_allocreq();
996 if(req==NULL) return IPC_ENOMEM;
998 req->cmd = IOS_WRITE;
999 req->fd = fd;
1000 req->cb = ipc_cb;
1001 req->usrdata = usrdata;
1002 req->relnch = 0;
1004 DCFlushRange((void*)buf,len);
1005 req->write.data = (void*)MEM_VIRTUAL_TO_PHYSICAL(buf);
1006 req->write.len = len;
1008 return __ipc_asyncrequest(req);
1011 s32 IOS_Seek(s32 fd,s32 where,s32 whence)
1013 s32 ret;
1014 struct _ipcreq *req;
1016 req = __ipc_allocreq();
1017 if(req==NULL) return IPC_ENOMEM;
1019 req->cmd = IOS_SEEK;
1020 req->fd = fd;
1021 req->cb = NULL;
1022 req->relnch = 0;
1024 req->seek.where = where;
1025 req->seek.whence = whence;
1027 ret = __ipc_syncrequest(req);
1029 if(req!=NULL) __ipc_freereq(req);
1030 return ret;
1033 s32 IOS_SeekAsync(s32 fd,s32 where,s32 whence,ipccallback ipc_cb,void *usrdata)
1035 struct _ipcreq *req;
1037 req = __ipc_allocreq();
1038 if(req==NULL) return IPC_ENOMEM;
1040 req->cmd = IOS_SEEK;
1041 req->fd = fd;
1042 req->cb = ipc_cb;
1043 req->usrdata = usrdata;
1044 req->relnch = 0;
1046 req->seek.where = where;
1047 req->seek.whence = whence;
1049 return __ipc_asyncrequest(req);
1052 s32 IOS_Ioctl(s32 fd,s32 ioctl,void *buffer_in,s32 len_in,void *buffer_io,s32 len_io)
1054 s32 ret;
1055 struct _ipcreq *req;
1057 req = __ipc_allocreq();
1058 if(req==NULL) return IPC_ENOMEM;
1060 req->cmd = IOS_IOCTL;
1061 req->fd = fd;
1062 req->cb = NULL;
1063 req->relnch = 0;
1065 req->ioctl.ioctl = ioctl;
1066 req->ioctl.buffer_in = (void*)MEM_VIRTUAL_TO_PHYSICAL(buffer_in);
1067 req->ioctl.len_in = len_in;
1068 req->ioctl.buffer_io = (void*)MEM_VIRTUAL_TO_PHYSICAL(buffer_io);
1069 req->ioctl.len_io = len_io;
1071 DCFlushRange(buffer_in,len_in);
1072 DCFlushRange(buffer_io,len_io);
1074 ret = __ipc_syncrequest(req);
1076 if(req!=NULL) __ipc_freereq(req);
1077 return ret;
1080 s32 IOS_IoctlAsync(s32 fd,s32 ioctl,void *buffer_in,s32 len_in,void *buffer_io,s32 len_io,ipccallback ipc_cb,void *usrdata)
1082 struct _ipcreq *req;
1084 req = __ipc_allocreq();
1085 if(req==NULL) return IPC_ENOMEM;
1087 req->cmd = IOS_IOCTL;
1088 req->fd = fd;
1089 req->cb = ipc_cb;
1090 req->usrdata = usrdata;
1091 req->relnch = 0;
1093 req->ioctl.ioctl = ioctl;
1094 req->ioctl.buffer_in = (void*)MEM_VIRTUAL_TO_PHYSICAL(buffer_in);
1095 req->ioctl.len_in = len_in;
1096 req->ioctl.buffer_io = (void*)MEM_VIRTUAL_TO_PHYSICAL(buffer_io);
1097 req->ioctl.len_io = len_io;
1099 DCFlushRange(buffer_in,len_in);
1100 DCFlushRange(buffer_io,len_io);
1102 return __ipc_asyncrequest(req);
1105 s32 IOS_Ioctlv(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv)
1107 s32 i,ret;
1108 struct _ipcreq *req;
1110 req = __ipc_allocreq();
1111 if(req==NULL) return IPC_ENOMEM;
1113 req->cmd = IOS_IOCTLV;
1114 req->fd = fd;
1115 req->cb = NULL;
1116 req->relnch = 0;
1118 req->ioctlv.ioctl = ioctl;
1119 req->ioctlv.argcin = cnt_in;
1120 req->ioctlv.argcio = cnt_io;
1121 req->ioctlv.argv = (struct _ioctlv*)MEM_VIRTUAL_TO_PHYSICAL(argv);
1123 i = 0;
1124 while(i<cnt_in) {
1125 if(argv[i].data!=NULL && argv[i].len>0) {
1126 DCFlushRange(argv[i].data,argv[i].len);
1127 argv[i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[i].data);
1129 i++;
1132 i = 0;
1133 while(i<cnt_io) {
1134 if(argv[cnt_in+i].data!=NULL && argv[cnt_in+i].len>0) {
1135 DCFlushRange(argv[cnt_in+i].data,argv[cnt_in+i].len);
1136 argv[cnt_in+i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[cnt_in+i].data);
1138 i++;
1140 DCFlushRange(argv,((cnt_in+cnt_io)<<3));
1142 ret = __ipc_syncrequest(req);
1144 if(req!=NULL) __ipc_freereq(req);
1145 return ret;
1149 s32 IOS_IoctlvAsync(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv,ipccallback ipc_cb,void *usrdata)
1151 s32 i;
1152 struct _ipcreq *req;
1154 req = __ipc_allocreq();
1155 if(req==NULL) return IPC_ENOMEM;
1157 req->cmd = IOS_IOCTLV;
1158 req->fd = fd;
1159 req->cb = ipc_cb;
1160 req->usrdata = usrdata;
1161 req->relnch = 0;
1163 req->ioctlv.ioctl = ioctl;
1164 req->ioctlv.argcin = cnt_in;
1165 req->ioctlv.argcio = cnt_io;
1166 req->ioctlv.argv = (struct _ioctlv*)MEM_VIRTUAL_TO_PHYSICAL(argv);
1168 i = 0;
1169 while(i<cnt_in) {
1170 if(argv[i].data!=NULL && argv[i].len>0) {
1171 DCFlushRange(argv[i].data,argv[i].len);
1172 argv[i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[i].data);
1174 i++;
1177 i = 0;
1178 while(i<cnt_io) {
1179 if(argv[cnt_in+i].data!=NULL && argv[cnt_in+i].len>0) {
1180 DCFlushRange(argv[cnt_in+i].data,argv[cnt_in+i].len);
1181 argv[cnt_in+i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[cnt_in+i].data);
1183 i++;
1185 DCFlushRange(argv,((cnt_in+cnt_io)<<3));
1187 return __ipc_asyncrequest(req);
1190 s32 IOS_IoctlvFormat(s32 hId,s32 fd,s32 ioctl,const char *format,...)
1192 s32 ret;
1193 va_list args;
1194 s32 cnt_in,cnt_io;
1195 struct _ioctlv *argv;
1196 struct _ioctlvfmt_cbdata *cbdata;
1198 cbdata = __lwp_wkspace_allocate(sizeof(struct _ioctlvfmt_cbdata));
1199 if(cbdata==NULL) return IPC_ENOMEM;
1201 memset(cbdata,0,sizeof(struct _ioctlvfmt_cbdata));
1203 va_start(args,format);
1204 ret = __ios_ioctlvformat_parse(format,args,cbdata,&cnt_in,&cnt_io,&argv,hId);
1205 va_end(args);
1206 if(ret<0) {
1207 __lwp_wkspace_free(cbdata);
1208 return ret;
1211 ret = IOS_Ioctlv(fd,ioctl,cnt_in,cnt_io,argv);
1212 __ioctlvfmtCB(ret,cbdata);
1214 return ret;
1217 s32 IOS_IoctlvFormatAsync(s32 hId,s32 fd,s32 ioctl,ipccallback usr_cb,void *usr_data,const char *format,...)
1219 s32 ret;
1220 va_list args;
1221 s32 cnt_in,cnt_io;
1222 struct _ioctlv *argv;
1223 struct _ioctlvfmt_cbdata *cbdata;
1225 cbdata = __lwp_wkspace_allocate(sizeof(struct _ioctlvfmt_cbdata));
1226 if(cbdata==NULL) return IPC_ENOMEM;
1228 memset(cbdata,0,sizeof(struct _ioctlvfmt_cbdata));
1230 va_start(args,format);
1231 ret = __ios_ioctlvformat_parse(format,args,cbdata,&cnt_in,&cnt_io,&argv,hId);
1232 va_end(args);
1233 if(ret<0) {
1234 __lwp_wkspace_free(cbdata);
1235 return ret;
1238 cbdata->user_cb = usr_cb;
1239 cbdata->user_data = usr_data;
1240 return IOS_IoctlvAsync(fd,ioctl,cnt_in,cnt_io,argv,__ioctlvfmtCB,cbdata);
1243 s32 IOS_IoctlvReboot(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv)
1245 s32 i,ret;
1246 struct _ipcreq *req;
1248 req = __ipc_allocreq();
1249 if(req==NULL) return IPC_ENOMEM;
1251 req->cmd = IOS_IOCTLV;
1252 req->fd = fd;
1253 req->cb = NULL;
1254 req->relnch = RELNCH_RELAUNCH;
1256 req->ioctlv.ioctl = ioctl;
1257 req->ioctlv.argcin = cnt_in;
1258 req->ioctlv.argcio = cnt_io;
1259 req->ioctlv.argv = (struct _ioctlv*)MEM_VIRTUAL_TO_PHYSICAL(argv);
1261 i = 0;
1262 while(i<cnt_in) {
1263 if(argv[i].data!=NULL && argv[i].len>0) {
1264 DCFlushRange(argv[i].data,argv[i].len);
1265 argv[i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[i].data);
1267 i++;
1270 i = 0;
1271 while(i<cnt_io) {
1272 if(argv[cnt_in+i].data!=NULL && argv[cnt_in+i].len>0) {
1273 DCFlushRange(argv[cnt_in+i].data,argv[cnt_in+i].len);
1274 argv[cnt_in+i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[cnt_in+i].data);
1276 i++;
1278 DCFlushRange(argv,((cnt_in+cnt_io)<<3));
1280 ret = __ipc_syncrequest(req);
1282 if(req!=NULL) __ipc_freereq(req);
1283 return ret;
1286 s32 IOS_IoctlvRebootBackground(s32 fd,s32 ioctl,s32 cnt_in,s32 cnt_io,ioctlv *argv)
1288 s32 i,ret;
1289 struct _ipcreq *req;
1291 req = __ipc_allocreq();
1292 if(req==NULL) return IPC_ENOMEM;
1294 req->cmd = IOS_IOCTLV;
1295 req->result = 0;
1296 req->fd = fd;
1297 req->cb = NULL;
1298 req->relnch = RELNCH_BACKGROUND|RELNCH_RELAUNCH;
1300 req->ioctlv.ioctl = ioctl;
1301 req->ioctlv.argcin = cnt_in;
1302 req->ioctlv.argcio = cnt_io;
1303 req->ioctlv.argv = (struct _ioctlv*)MEM_VIRTUAL_TO_PHYSICAL(argv);
1305 i = 0;
1306 while(i<cnt_in) {
1307 if(argv[i].data!=NULL && argv[i].len>0) {
1308 DCFlushRange(argv[i].data,argv[i].len);
1309 argv[i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[i].data);
1311 i++;
1314 i = 0;
1315 while(i<cnt_io) {
1316 if(argv[cnt_in+i].data!=NULL && argv[cnt_in+i].len>0) {
1317 DCFlushRange(argv[cnt_in+i].data,argv[cnt_in+i].len);
1318 argv[cnt_in+i].data = (void*)MEM_VIRTUAL_TO_PHYSICAL(argv[cnt_in+i].data);
1320 i++;
1322 DCFlushRange(argv,((cnt_in+cnt_io)<<3));
1324 ret = __ipc_syncrequest(req);
1326 if(req!=NULL) __ipc_freereq(req);
1327 return ret;
1330 #endif