typedef struct // 64 bytes { +0 - EXI callback +4 - TC callback +8 - EXT callback +12 +16 - immediate length (used only for read imm) +20 - immediate buffer (used only for read imm) +24 - last locked device number +28 +32 +36 - number of unlock callbacks +40 dev \ +44 cb | | +48 dev | unlocked callbacks FIFO : +52 cb | first goes device number, | then callback address +56 dev | +60 cb / } EXICHAN; EXICHAN Ecb[3]; // 64 * 3 = 0xc0 bytes // check for device, connected with specified chan BOOL __EXIProbe(s32 chan) { BOOL level; u32 status; if(chan == 2) return 1; level = OSDisableInterrupts(); r6 = 0xcc006800 + chan * 20; // EXI status = EXI.status; if(((u32)Ecb[chan][12] & 8) == 0) { if(status & 0x800) { EXI.status = (status & 0x07f5) | 0x0800; (u32)Ecb[chan][32] = 0 0x800030c0 + chan * 4 = 0 } if(status & bit19) { [0x800000f8] .. . . OSGetTime() div2i() div2i() [0x800030c0 + chan * 4] = 1 OSRestoreInterrupts(level); return 0; } [0x80000020] = 0 [0x800030c0 + chan * 4] = 0 OSRestoreInterrupts(level); return 0; } else { if((status & bit19) == 0) { if(status & bit20) { [0x80000020] = 0 [0x800030c0 + chan * 4] = 0 OSRestoreInterrupts(level); return 0; } } } OSRestoreInterrupts(level); return 1; } BOOL EXIProbe(s32 chan) { char id[...]; if(__EXIProbe(chan)) { if(Ecb[chan][32] == NULL) { if(EXIGetID(chan, 0, id)) return 1; } } return 0; } // maybe incorrect void SetExiInterruptMask(s32 chan, u32 *exi) { switch(chan) { case 0: if(((*exi != 0) && (*exi[12] & 0x10)) || (Ecb[2][0] == 0)) { __OSMaskInterrupts(0x00410000); } else { __OSUnmaskInterrupts(0x00410000); } break; case 1: if((*exi == 0) || (*exi[12] & 0x10)) { __OSMaskInterrupts(0x00080000); return; } else { __OSUnmaskInterrupts(0x00080000); return; } break; case 2: if(__OSGetInterruptHandler(25) && (*exi[12] & 0x10)) { __OSMaskInterrupts(0x00400000); } else { __OSMaskInterrupts(0x00400000); } break; } } void EXIInit() { // mask all EXI interrupts __OSMaskInterrupts(0x007f8000); [0xcc006800] = 0 [0xcc006814] = 0 [0xcc006828] = 0 [0xcc006800] = 0x2000 __OSSetInterruptHandler(9, EXIIntrruptHandler); // EXI0 EXI __OSSetInterruptHandler(10, TCIntrruptHandler); // EXI0 TC __OSSetInterruptHandler(11, EXTIntrruptHandler); // EXI0 EXT __OSSetInterruptHandler(12, EXIIntrruptHandler); // EXI1 EXI __OSSetInterruptHandler(14, EXTIntrruptHandler); // EXI1 EXT __OSSetInterruptHandler(15, EXIIntrruptHandler); // EXI2 EXI __OSSetInterruptHandler(16, TCIntrruptHandler); // EXI2 TC if(OSGetConsoleType() & OS_CONSOLE_DEVELOPMENT) { (u32)[0x800030c0] = 0; (u32)[0x800030c4] = 0; (u32)Ecb[0].[32] = 0; (u32)Ecb[1].[32] = 0; __EXIProbe(0); __EXIProbe(1); } } int EXIDma(s32 chan, u32 *buf, s32 len, int type, void (*callback)()) { BOOL level; level = OSDisableInterrupts(); if(!(Ecb[chan][12] & 4) || (Ecb[chan][12] & 3)) { OSRestoreInterrupts(level); return 0; } if(Ecb[chan][4] = callback) { // unmask EXI TC interrupt EXIClearInterrupts(chan, 0, 1, 0); __OSUnmaskInterrupts(0x00200000 >> (chan * 3)); } Ecb[chan][12] |= 1 r4 = 0xcc006800 + chan * 20; // EXI EXI.dmabuf = buf & 0x03ffffe0; EXI.dmalen = len; EXI.control = (type << 2) | 3; OSRestoreInterrupts(level) return 1; } BOOL EXILock(s32 chan, s32 dev, void (*unlockedCallback)()) { BOOL level = OSDisableInterrupts(); if(Ecb[chan][12] & 0x10) { // reinstall unlock callback if(unlockedCallback) { for(i=0; i 0) { void (*callback)() = Ecb[chan][44]; if(--Ecb[chan][36]) { memmove(&Ecb[chan][40], &Ecb[chan][48], Ecb[chan][36] * 8); } callback(chan, 0); } OSRestoreInterrupts(level); return 1; } BOOL EXISelect(s32 chan, s32 dev, s32 freq) { BOOL level = OSDisableInterrupts(); // already selected ? if(Ecb[chan][12] & 4) { OSRestoreInterrupts(level); return 0; } if(chan != 2) { if(dev == 0) { if(!(Ecb[chan][12] & 8)) { if(__EXIProbe(chan) == 0) { OSRestoreInterrupts(level); return 0; } } } // check locked flag if(Ecb[chan][12] & 0x10) { OSRestoreInterrupts(level); return 0; } // check for last locked device if(Ecb[chan][24] != dev) { OSRestoreInterrupts(level); return 0; } } // set selected flag Ecb[chan][12] |= 4; r5 = 0xcc006800 + chan * 20; // EXI EXI.status = (EXI.status & 0x0405) | (0x80 << dev) | (freq << 4); if(Ecb[chan][12] & 8) { switch(chan) { case 0: __OSMaskInterrupts(0x00100000); // EXI0 EXT break; case 1: __OSMaskInterrupts(0x00020000); // EXI1 EXT break; } } OSRestoreInterrupts(level); return 1; } BOOL EXIDeselect(s32 chan) { BOOL level = OSDisableInterrupts(); u32 status; // already deselected ? if(!(Ecb[chan][12] & 4)) { OSDisableInterrupts(level); return 0; } // clear selected flag Ecb[chan][12] &= ~4; r3 = 0xcc006800 + chan * 20; // EXI status = EXI.status; EXI.status = status & 0x0405; if(Ecb[chan][12] & 8) { switch(chan) { case 0: __OSUnmaskInterrupts(0x00100000); // EXI0 EXT break; case 1: __OSUnmaskInterrupts(0x00020000); // EXI1 EXT break; } } OSRestoreInterrupts(level); if(chan != 2) { if(status & bit24) { if(__EXIProbe(chan) == 0) return 0; } } return 1; } void EXIClearInterrupts(s32 chan, BOOL exi, BOOL tc, BOOL ext) { u32 status; r7 = 0xcc006800 + chan * 20; // EXI status = EXI.status & 0x07f5; if(exi) status |= 2; if(tc ) status |= 8; if(ext) status |= 0x800; EXI.status = status; } /// UNCOMPLETE STUFFFF !!!!!!!!!!!!! u32 EXISync(s32 chan) { BOOL level; r31 = &Ecb[chan] r29 = 0xcc006800 + chan * 20; do { if((Ecb[chan][12] & 1) == 0) { level = OSDisableInterrupts(); if((Ecb[chan][12] & 4) == 0) { OSRestoreInterrupts(level); break; } if(if(Ecb[chan][12] & 3) { } } } while(Ecb[chan][12] & 4); return 0; } 00000640 : BOOL EXIImm(s32 chan, u32 *buf, s32 len, BOOL type, void (*callback)()) { BOOL level = OSDisableInterrupts(); s32 size; r28 = chan r29 = buf r30 = len r31 = type r19 = callback r27 = &Ecb[chan]; if(Ecb[chan][12] & 3) { OSRestoreInterrupts(level); return 0; } if(Ecb[chan][4] = callback) { EXIClearInterrupts(chan, 0, 1, 0); __OSUnmaskInterrupts(0x00200000 >> (chan * 3)); } Ecb[chan][12] |= 2; if(type) { } else { Ecb[chan][20] = buf; Ecb[chan][16] = (type) ? (0) : (len); r3 = 0xcc006800 + chan * 20; // EXI EXI.control = ((len - 1) << 4) | (type << 2) | 1; OSRestoreInterrupts(level); return 1; } } :