diff --git a/BuildConf/armv7/tegra2.mk b/BuildConf/armv7/tegra2.mk index ad787821311a745484180efa54508b6913864a13..ece6ccf57aafd8a7364dab69ffe32d89b2e1e3a9 100644 --- a/BuildConf/armv7/tegra2.mk +++ b/BuildConf/armv7/tegra2.mk @@ -1,4 +1,4 @@ include $(ACESSDIR)/BuildConf/armv7/default.mk -#MODULES += Display/Tegra2 +MODULES += Display/Tegra2 diff --git a/Kernel/Makefile b/Kernel/Makefile index 9c65db88f3c89812768a16335539969fb725355c..48a2c9f44ede30a2154be30dc527bc8aafcb1dbd 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -23,7 +23,7 @@ endif ASFLAGS += -D ARCHDIR_IS_$(ARCHDIR)=1 -D PLATFORM_is_$(PLATFORM)=1 CPPFLAGS += -I./include -I./arch/$(ARCHDIR)/include -D_MODULE_NAME_=\"Kernel\" -CPPFLAGS += -D ARCH=$(ARCH) -D ARCHDIR=$(ARCHDIR) -D ARCHDIR_IS_$(ARCHDIR)=1 -D PLATFORM_is_$(PLATFORM)=1 +CPPFLAGS += -D ARCH=$(ARCH) -D ARCHDIR=$(ARCHDIR) -D PLATFORM=\"$(PLATFORM)\" -D ARCHDIR_IS_$(ARCHDIR)=1 -D PLATFORM_is_$(PLATFORM)=1 CPPFLAGS += -D KERNEL_VERSION=$(KERNEL_VERSION) CFLAGS += -Wall -fno-stack-protector -Wstrict-prototypes -g CFLAGS += -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wuninitialized diff --git a/Kernel/arch/x86/desctab.asm b/Kernel/arch/x86/desctab.asm index 0c19fc0a013a740bb5326ca25334b4b9f3682f6c..8c7d320eba90201412fb483ab031b82a5741816e 100644 --- a/Kernel/arch/x86/desctab.asm +++ b/Kernel/arch/x86/desctab.asm @@ -3,30 +3,8 @@ ; desctab.asm [BITS 32] -%if USE_MP -MAX_CPUS equ 8 -%else -MAX_CPUS equ 1 -%endif -GDT_SIZE equ (1+2*2+1+MAX_CPUS)*8 [section .data] -; GDT -[global gGDT] -gGDT: - ; PL0 - Kernel - ; PL3 - User - dd 0x00000000, 0x00000000 ; 00 NULL Entry - dd 0x0000FFFF, 0x00CF9A00 ; 08 PL0 Code - dd 0x0000FFFF, 0x00CF9200 ; 10 PL0 Data - dd 0x0000FFFF, 0x00CFFA00 ; 18 PL3 Code - dd 0x0000FFFF, 0x00CFF200 ; 20 PL3 Data - dd 26*4-1, 0x00408900 ; 28 Double Fault TSS - times MAX_CPUS dd 26*4-1, 0x00408900 ; 30+ TSSes -[global gGDTPtr] -gGDTPtr: - dw GDT_SIZE-1 - dd gGDT ; IDT ALIGN 8 [global gIDT] @@ -42,17 +20,6 @@ gIDTPtr: [global Desctab_Install] Desctab_Install: - ; Set GDT - lgdt [gGDTPtr] - mov ax, 0x10 ; PL0 Data - mov ss, ax - mov ds, ax - mov es, ax - mov gs, ax - mov fs, ax - jmp 0x08:.pl0code -.pl0code: - ; Set up IDT ; Helper Macros ; - Set an IDT entry to an ISR diff --git a/Kernel/arch/x86/kpanic.c b/Kernel/arch/x86/kpanic.c index 6a7b9b0fac943877d52db6e1650ba72785d8e390..9300c69ef20e36932526cadfb41a7957eba36a59 100644 --- a/Kernel/arch/x86/kpanic.c +++ b/Kernel/arch/x86/kpanic.c @@ -105,7 +105,7 @@ void KernelPanic_SetMode(void) for( i = 0; i < giNumCPUs; i ++ ) { if(i == GetCPUNum()) continue ; - FB[i] = BGC|'A'+i; + FB[i] = BGC|('A'+i); MP_SendIPIVector(i, 0xED); } #endif diff --git a/Kernel/arch/x86/lib.c b/Kernel/arch/x86/lib.c index 3858eff3eee7ccf75abfcc235e2a338c48221f50..ecc575c1ad240b3c57693025ad1c73437d076430 100644 --- a/Kernel/arch/x86/lib.c +++ b/Kernel/arch/x86/lib.c @@ -22,6 +22,7 @@ extern struct sShortSpinlock glThreadListLock; extern int GetCPUNum(void); // === PROTOTYPES == +Uint64 __divmod64(Uint64 Num, Uint64 Den, Uint64 *Rem); Uint64 __udivdi3(Uint64 Num, Uint64 Den); Uint64 __umoddi3(Uint64 Num, Uint64 Den); @@ -330,9 +331,12 @@ void *memcpyd(void *Dest, const void *Src, size_t Num) return Dest; } +#include "../helpers.h" + +DEF_DIVMOD(64); + Uint64 DivMod64U(Uint64 Num, Uint64 Div, Uint64 *Rem) { - Uint64 ret; if( Div < 0x100000000ULL && Num < 0xFFFFFFFF * Div ) { Uint32 rem, ret_32; __asm__ __volatile__( @@ -344,9 +348,7 @@ Uint64 DivMod64U(Uint64 Num, Uint64 Div, Uint64 *Rem) return ret_32; } - ret = __udivdi3(Num, Div); - if(Rem) *Rem = __umoddi3(Num, Div); - return ret; + return __divmod64(Num, Div, Rem); } /** @@ -355,11 +357,10 @@ Uint64 DivMod64U(Uint64 Num, Uint64 Div, Uint64 *Rem) */ Uint64 __udivdi3(Uint64 Num, Uint64 Den) { - Uint64 P[2]; - Uint64 q = 0; - int i; - - if(Den == 0) __asm__ __volatile__ ("int $0x0"); + if(Den == 0) { + __asm__ __volatile__ ("int $0x0"); + return -1; + } // Common speedups if(Num <= 0xFFFFFFFF && Den <= 0xFFFFFFFF) return (Uint32)Num / (Uint32)Den; @@ -375,46 +376,8 @@ Uint64 __udivdi3(Uint64 Num, Uint64 Den) if(Num < Den) return 0; if(Num < Den*2) return 1; if(Num == Den*2) return 2; - - #if 1 - i = 0; // Shut up - P[0] = Num; - P[1] = Den; - __asm__ __volatile__ ( - "fildq %2\n\t" // Num - "fildq %1\n\t" // Den - "fdivp\n\t" - "fistpq %0" - : "=m" (q) - : "m" (P[0]), "m" (P[1]) - ); - - //Log("%llx / %llx = %llx\n", Num, Den, q); - #else - // Restoring division, from wikipedia - // http://en.wikipedia.org/wiki/Division_(digital) - P[0] = Num; P[1] = 0; - for( i = 64; i--; ) - { - // P <<= 1; - P[1] = (P[1] << 1) | (P[0] >> 63); - P[0] = P[0] << 1; - - // P -= Den << 64 - P[1] -= Den; - - // P >= 0 - if( !(P[1] & (1ULL<<63)) ) { - q |= (Uint64)1 << (63-i); - } - else { - //q |= 0 << (63-i); - P[1] += Den; - } - } - #endif - - return q; + + return __divmod64(Num, Den, NULL); } /** @@ -423,7 +386,11 @@ Uint64 __udivdi3(Uint64 Num, Uint64 Den) */ Uint64 __umoddi3(Uint64 Num, Uint64 Den) { - if(Den == 0) __asm__ __volatile__ ("int $0x0"); // Call Div by Zero Error + Uint64 ret = 0; + if(Den == 0) { + __asm__ __volatile__ ("int $0x0"); // Call Div by Zero Error + return -1; + } if(Den == 1) return 0; // Speed Hacks if(Den == 2) return Num & 1; // Speed Hacks if(Den == 4) return Num & 3; // Speed Hacks @@ -437,7 +404,8 @@ Uint64 __umoddi3(Uint64 Num, Uint64 Den) if(Num >> 32 == 0 && Den >> 32 == 0) return (Uint32)Num % (Uint32)Den; - return Num - __udivdi3(Num, Den) * Den; + __divmod64(Num, Den, &ret); + return ret; } diff --git a/Kernel/arch/x86/main.c b/Kernel/arch/x86/main.c index d7c06e7952122e8dd3ec991cff5813262b742fb6..2106b6afe2b47e2ef960c1ed1e43701e4cded5ac 100644 --- a/Kernel/arch/x86/main.c +++ b/Kernel/arch/x86/main.c @@ -45,7 +45,7 @@ int kmain(Uint MbMagic, void *MbInfoPtr) tMBoot_Module *mods; tMBoot_Info *mbInfo; - LogF("Acess2 x86 v"EXPAND_STR(KERNEL_VERSION)"\n"); + LogF("Acess2 x86-"PLATFORM" v"EXPAND_STR(KERNEL_VERSION)"\n"); LogF(" Build %i, Git Hash %s\n", BUILD_NUM, gsGitHash); Log("MbMagic = %08x, MbInfoPtr = %p", MbMagic, MbInfoPtr); @@ -81,7 +81,6 @@ int kmain(Uint MbMagic, void *MbInfoPtr) MM_InstallVirtual(); // Clean up virtual address space Heap_Install(); // Create initial heap - //Log_Log("Arch", "Starting Multitasking..."); // Start Multitasking Threads_Init(); diff --git a/Kernel/arch/x86/mm_virt.c b/Kernel/arch/x86/mm_virt.c index 73e19d3bbe835e9e4a7b843e0b9b8e2e43234015..137240c9cf214c84778ee7f00c9240f62f1a5d13 100644 --- a/Kernel/arch/x86/mm_virt.c +++ b/Kernel/arch/x86/mm_virt.c @@ -212,14 +212,15 @@ void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs) ); } - Log("Code at %p accessed %p", Regs->eip, Addr); + Log("CPU %i - Code at %p accessed %p", GetCPUNum(), Regs->eip, Addr); // Print Stack Backtrace Error_Backtrace(Regs->eip, Regs->ebp); - + + #if 0 Log("gaPageDir[0x%x] = 0x%x", Addr>>22, gaPageDir[Addr>>22]); if( gaPageDir[Addr>>22] & PF_PRESENT ) Log("gaPageTable[0x%x] = 0x%x", Addr>>12, gaPageTable[Addr>>12]); - + #endif //MM_DumpTables(0, -1); // Register Dump diff --git a/Kernel/arch/x86/proc.asm b/Kernel/arch/x86/proc.asm index 74a25d46b18618c93a903a5d67c913d85fcef8b7..014cfed1cac482bce97c168e1c976cf7211cdf3f 100644 --- a/Kernel/arch/x86/proc.asm +++ b/Kernel/arch/x86/proc.asm @@ -55,11 +55,14 @@ SwitchTasks: ; Old IP mov eax, [esp+0x20+16] + test eax, eax + jz .nosave mov DWORD [eax], .restore ; Old SP mov eax, [esp+0x20+8] mov [eax], esp +.nosave: mov ecx, [esp+0x20+12] ; New IP mov eax, [esp+0x20+20] ; New CR3 mov esp, [esp+0x20+ 4] ; New SP @@ -376,4 +379,4 @@ User_Syscall_Exit: mov ebx, [esp+4] int 0xAC -; vim: ft=nasm, ts=8 +; vim: ft=nasm ts=8 diff --git a/Kernel/arch/x86/proc.c b/Kernel/arch/x86/proc.c index 1cd11067256f2af745f32076d9d7a3704854b5c8..7d54d0c2ea1004121fe48b859f88d5a3bc6e53dd 100644 --- a/Kernel/arch/x86/proc.c +++ b/Kernel/arch/x86/proc.c @@ -14,9 +14,9 @@ #include <hal_proc.h> // === FLAGS === -#define DEBUG_TRACE_SWITCH 1 +#define DEBUG_TRACE_SWITCH 0 #define DEBUG_DISABLE_DOUBLEFAULT 1 -#define DEBUG_VERY_SLOW_SWITCH 0 +#define DEBUG_VERY_SLOW_PERIOD 0 // === CONSTANTS === // Base is 1193182 @@ -165,6 +165,7 @@ void ArchThreads_Init(void) { int i; tMPTable_Ent *ents; + #if DUMP_MP_TABLE Log("gMPFloatPtr = %p", gMPFloatPtr); Log("*gMPFloatPtr = {"); Log("\t.Sig = 0x%08x", gMPFloatPtr->Sig); @@ -178,8 +179,10 @@ void ArchThreads_Init(void) gMPFloatPtr->Features[4] ); Log("}"); - + #endif + mptable = (void*)( KERNEL_BASE|gMPFloatPtr->MPConfig ); + #if DUMP_MP_TABLE Log("mptable = %p", mptable); Log("*mptable = {"); Log("\t.Sig = 0x%08x", mptable->Sig); @@ -195,6 +198,7 @@ void ArchThreads_Init(void) Log("\t.ExtendedTableLen = 0x%04x", mptable->ExtendedTableLen); Log("\t.ExtendedTableChecksum = 0x%02x", mptable->ExtendedTableChecksum); Log("}"); + #endif gpMP_LocalAPIC = (void*)MM_MapHWPages(mptable->LocalAPICMemMap, 1); @@ -208,13 +212,14 @@ void ArchThreads_Init(void) { case 0: // Processor entSize = 20; + #if DUMP_MP_TABLE Log("%i: Processor", i); Log("\t.APICID = %i", ents->Proc.APICID); Log("\t.APICVer = 0x%02x", ents->Proc.APICVer); Log("\t.CPUFlags = 0x%02x", ents->Proc.CPUFlags); Log("\t.CPUSignature = 0x%08x", ents->Proc.CPUSignature); Log("\t.FeatureFlags = 0x%08x", ents->Proc.FeatureFlags); - + #endif if( !(ents->Proc.CPUFlags & 1) ) { Log("DISABLED"); @@ -240,7 +245,7 @@ void ArchThreads_Init(void) break; - #if DUMP_MP_TABLES + #if DUMP_MP_TABLE >= 2 case 1: // Bus entSize = 8; Log("%i: Bus", i); @@ -942,11 +947,22 @@ void Proc_Reschedule(void) Proc_DisableSSE(); } - SwitchTasks( - nextthread->SavedState.ESP, &curthread->SavedState.ESP, - nextthread->SavedState.EIP, &curthread->SavedState.EIP, - nextthread->MemState.CR3 - ); + if( curthread ) + { + SwitchTasks( + nextthread->SavedState.ESP, &curthread->SavedState.ESP, + nextthread->SavedState.EIP, &curthread->SavedState.EIP, + nextthread->MemState.CR3 + ); + } + else + { + SwitchTasks( + nextthread->SavedState.ESP, 0, + nextthread->SavedState.EIP, 0, + nextthread->MemState.CR3 + ); + } return ; } diff --git a/Kernel/arch/x86/start.asm b/Kernel/arch/x86/start.asm index 68bdc55d74979fbb3e445452cd82efc50ea1c7b3..b6026de6b936ccbe97ba75dd6d8c53066b83ba91 100644 --- a/Kernel/arch/x86/start.asm +++ b/Kernel/arch/x86/start.asm @@ -68,17 +68,23 @@ start: ; Start Paging mov ecx, gaInitPageDir - KERNEL_BASE mov cr3, ecx - mov ecx, cr0 or ecx, 0x80010000 ; PG and WP mov cr0, ecx mov WORD [0xB8002], 0x0763 ; 'c' - mov WORD [0xB8004], 0x0765 ; 'e' - lea ecx, [.higherHalf] - jmp ecx -.higherHalf: + ; Set GDT + lgdt [gGDTPtr] + mov cx, 0x10 ; PL0 Data + mov ss, cx + mov ds, cx + mov es, cx + mov gs, cx + mov fs, cx + mov WORD [0xB8004], 0x0765 ; 'e' + jmp 0x08:.higher_half +.higher_half: mov WORD [0xB8006], 0x0773 ; 's' mov WORD [0xB8008], 0x0773 ; 's' @@ -99,8 +105,6 @@ start: ; Multiprocessing AP Startup Code (Must be within 0 - 0x10FFF0) ; %if USE_MP -[extern gGDT] -[extern gGDTPtr] [extern gIDTPtr] [extern gpMP_LocalAPIC] [extern giMP_TimerCount] @@ -108,6 +112,7 @@ start: [extern gaCPUs] [extern giNumInitingCPUs] [extern MM_NewKStack] +[extern Proc_InitialiseSSE] lGDTPtr: ; Local GDT Pointer dw 3*8-1 @@ -195,6 +200,9 @@ APStartup: mov DWORD [ebp+0x360], 0x000100D2 ; ##Enable LINT1 on IVT#0xD2 mov DWORD [ebp+0x370], 0x000100E1 ; ##Enable Error on IVT#0xE1 mov DWORD [ebp+0x0B0], 0 ; Send an EOI (just in case) + + ; Initialise SSE support + call Proc_InitialiseSSE ; CPU is now marked as initialised @@ -230,6 +238,25 @@ CallWithArgArray: pop ebp ret +[section .data] +; GDT +GDT_SIZE equ (1+2*2+1+MAX_CPUS)*8 +[global gGDT] +gGDT: + ; PL0 - Kernel + ; PL3 - User + dd 0x00000000, 0x00000000 ; 00 NULL Entry + dd 0x0000FFFF, 0x00CF9A00 ; 08 PL0 Code + dd 0x0000FFFF, 0x00CF9200 ; 10 PL0 Data + dd 0x0000FFFF, 0x00CFFA00 ; 18 PL3 Code + dd 0x0000FFFF, 0x00CFF200 ; 20 PL3 Data + dd 26*4-1, 0x00408900 ; 28 Double Fault TSS + times MAX_CPUS dd 26*4-1, 0x00408900 ; 30+ TSSes +[global gGDTPtr] +gGDTPtr: + dw GDT_SIZE-1 + dd gGDT + [section .initpd] [global gaInitPageDir] [global gaInitPageTable] diff --git a/Kernel/arch/x86/vm8086.c b/Kernel/arch/x86/vm8086.c index 879cec64dfe966e8dbcd134522b19227ea39f1b9..839a640bef450c06f85f439440a54b31a93f9c96 100644 --- a/Kernel/arch/x86/vm8086.c +++ b/Kernel/arch/x86/vm8086.c @@ -59,12 +59,15 @@ Uint32 gaVM8086_MemBitmap[VM8086_BLOCKCOUNT/32]; int VM8086_Install(char **Arguments) { tPID pid; + + Semaphore_Init(&gVM8086_TasksToDo, 0, 10, "VM8086", "TasksToDo"); // Lock to avoid race conditions Mutex_Acquire( &glVM8086_Process ); // Create BIOS Call process pid = Proc_Clone(CLONE_VM); + Log_Debug("VM8086", "pid = %i", pid); if(pid == -1) { Log_Error("VM8086", "Unable to clone kernel into VM8086 worker"); @@ -75,17 +78,16 @@ int VM8086_Install(char **Arguments) Uint * volatile stacksetup; // Initialising Stack Uint16 * volatile rmstack; // Real Mode Stack int i; - + + Log_Debug("VM8086", "Initialising worker"); + // Set Image Name Threads_SetName("VM8086"); -// Log_Debug("VM8086", "Mapping memory"); - // Map ROM Area for(i=0xA0;i<0x100;i++) { MM_Map( i * 0x1000, i * 0x1000 ); } -// Log_Debug("VM8086", "ROM area mapped"); MM_Map( 0, 0 ); // IVT / BDA // Map (but allow allocation) of 0x1000 - 0x9F000 // - So much hack, it isn't funny @@ -102,7 +104,6 @@ int VM8086_Install(char **Arguments) gVM8086_WorkerPID = 0; Threads_Exit(0, 1); } -// Log_Debug("VM8086", "Mapped low memory"); *(Uint8*)(0x100000) = VM8086_OP_IRET; *(Uint8*)(0x100001) = 0x07; // POP ES @@ -148,9 +149,10 @@ int VM8086_Install(char **Arguments) } gVM8086_WorkerPID = pid; -// Log_Log("VM8086", "gVM8086_WorkerPID = %i", pid); - while( gpVM8086_State != NULL ) - Threads_Yield(); // Yield to allow the child to initialise + + // It's released when the GPF fires + Mutex_Acquire( &glVM8086_Process ); + Mutex_Release( &glVM8086_Process ); // Worker killed itself if( gVM8086_WorkerPID != pid ) { @@ -164,7 +166,7 @@ void VM8086_GPF(tRegs *Regs) { Uint8 opcode; - //Log_Log("VM8086", "GPF - %04x:%04x", Regs->cs, Regs->eip); +// Log_Log("VM8086", "GPF - %04x:%04x", Regs->cs, Regs->eip); if(Regs->eip == VM8086_MAGIC_IP && Regs->cs == VM8086_MAGIC_CS && Threads_GetPID() == gVM8086_WorkerPID) @@ -174,8 +176,8 @@ void VM8086_GPF(tRegs *Regs) gpVM8086_State = NULL; Mutex_Release( &glVM8086_Process ); // Release lock obtained in VM8086_Install } - //Log_Log("VM8086", "gpVM8086_State = %p, gVM8086_CallingThread = %i", - // gpVM8086_State, gVM8086_CallingThread); +// Log_Log("VM8086", "gpVM8086_State = %p, gVM8086_CallingThread = %i", +// gpVM8086_State, gVM8086_CallingThread); if( gpVM8086_State ) { gpVM8086_State->AX = Regs->eax; gpVM8086_State->CX = Regs->ecx; gpVM8086_State->DX = Regs->edx; gpVM8086_State->BX = Regs->ebx; @@ -192,12 +194,12 @@ void VM8086_GPF(tRegs *Regs) Semaphore_Wait(&gVM8086_TasksToDo, 1); //Log_Log("VM8086", "We have a task (%p)", gpVM8086_State); - Regs->esp -= 2; *(Uint16*volatile)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = VM8086_MAGIC_CS; - Regs->esp -= 2; *(Uint16*volatile)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = VM8086_MAGIC_IP; - Regs->esp -= 2; *(Uint16*volatile)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->CS; - Regs->esp -= 2; *(Uint16*volatile)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->IP; - Regs->esp -= 2; *(Uint16*volatile)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->DS; - Regs->esp -= 2; *(Uint16*volatile)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->ES; + Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = VM8086_MAGIC_CS; + Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = VM8086_MAGIC_IP; + Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->CS; + Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->IP; + Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->DS; + Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->ES; // Set Registers Regs->eip = 0x11; Regs->cs = 0xFFFF; @@ -222,8 +224,9 @@ void VM8086_GPF(tRegs *Regs) #endif break; case VM8086_OP_POPF: //POPF - Regs->eflags &= 0xFFFF0002; - Regs->eflags |= *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) & 0xFFFD; // Changing IF is not allowed + // Changing IF is not allowed + Regs->eflags &= 0xFFFF0202; + Regs->eflags |= *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ); Regs->esp += 2; #if TRACE_EMU Log_Debug("VM8086", "Emulated POPF"); @@ -236,8 +239,8 @@ void VM8086_GPF(tRegs *Regs) id = *(Uint8*)( Regs->cs*16 +(Regs->eip&0xFFFF)); Regs->eip ++; - Regs->esp -= 2; *(Uint16*volatile)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->cs; - Regs->esp -= 2; *(Uint16*volatile)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->eip; + Regs->esp -= 2; *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->cs; + Regs->esp -= 2; *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->eip; Regs->cs = *(Uint16*)(4*id + 2); Regs->eip = *(Uint16*)(4*id); diff --git a/Kernel/debug.c b/Kernel/debug.c index 25ffda1912e37d09958953308b8490d674d316d1..355624d5c483769fafc237442a7ad64aaff4767f 100644 --- a/Kernel/debug.c +++ b/Kernel/debug.c @@ -9,7 +9,7 @@ #define DEBUG_MAX_LINE_LEN 256 -#define LOCK_DEBUG_OUTPUT 0 +#define LOCK_DEBUG_OUTPUT 1 #define TRACE_TO_KTERM 0 diff --git a/Kernel/heap.c b/Kernel/heap.c index 5593c68f70f91b14fa61e6eb6f434818e8ebb09c..921cc6b95d58893392b67a31df711baa3ac7a576 100644 --- a/Kernel/heap.c +++ b/Kernel/heap.c @@ -700,6 +700,7 @@ void Heap_Stats(void) // Scan and get distribution #if 1 + if(nBlocks > 0) { struct { Uint Size; diff --git a/Kernel/lib.c b/Kernel/lib.c index 953264b79eb6e2664a006ad4b7986955076685b7..76cc4286268fa0a84f4d2cae83656226fc1ccb91 100644 --- a/Kernel/lib.c +++ b/Kernel/lib.c @@ -210,8 +210,10 @@ int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args) size_t pos = 0; // Flags int bPadLeft = 0; + + auto void _putch(char ch); - inline void _putch(char ch) + void _putch(char ch) { if(pos < __maxlen) { diff --git a/Modules/Display/Tegra2/Makefile b/Modules/Display/Tegra2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3155db3ce4149d5add29549eff5eb516f1cbbd92 --- /dev/null +++ b/Modules/Display/Tegra2/Makefile @@ -0,0 +1,7 @@ +# +# + +OBJ = main.o +NAME = Tegra2 + +-include ../Makefile.tpl diff --git a/Modules/Display/Tegra2/main.c b/Modules/Display/Tegra2/main.c new file mode 100644 index 0000000000000000000000000000000000000000..dfafb2a2d40b2314814a7b4193fd8ea648d19811 --- /dev/null +++ b/Modules/Display/Tegra2/main.c @@ -0,0 +1,281 @@ +/** + * main.c + * - Driver core + */ +#define DEBUG 0 +#define VERSION ((0<<8)|10) +#include <acess.h> +#include <errno.h> +#include <modules.h> +#include <vfs.h> +#include <fs_devfs.h> +#include <drv_pci.h> +#include <api_drv_video.h> +#include <lib/keyvalue.h> +#include <options.h> // ARM Arch +#include "tegra2.h" + +#define ABS(a) ((a)>0?(a):-(a)) + +// === PROTOTYPES === +// Driver + int Tegra2Vid_Install(char **Arguments); +void Tegra2Vid_Uninstall(); +// Internal +// Filesystem +Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer); +Uint64 Tegra2Vid_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer); + int Tegra2Vid_IOCtl(tVFS_Node *node, int id, void *data); +// -- Internals + int Tegra2Vid_int_SetMode(int Mode); + +// === GLOBALS === +MODULE_DEFINE(0, VERSION, Video_Tegra2, Tegra2Vid_Install, NULL, NULL); +tDevFS_Driver gTegra2Vid_DriverStruct = { + NULL, "PL110", + { + .Read = Tegra2Vid_Read, + .Write = Tegra2Vid_Write, + .IOCtl = Tegra2Vid_IOCtl + } +}; +// -- Options +tPAddr gTegra2Vid_PhysBase = TEGRA2VID_BASE; + int gbTegra2Vid_IsVersatile = 1; +// -- KeyVal parse rules +const tKeyVal_ParseRules gTegra2Vid_KeyValueParser = { + NULL, + { + {"Base", "P", &gTegra2Vid_PhysBase}, + {NULL, NULL, NULL} + } +}; +// -- Driver state + int giTegra2Vid_CurrentMode = 0; + int giTegra2Vid_BufferMode; +size_t giTegra2Vid_FramebufferSize; +Uint8 *gpTegra2Vid_IOMem; +tPAddr gTegra2Vid_FramebufferPhys; +void *gpTegra2Vid_Framebuffer; +// -- Misc +tDrvUtil_Video_BufInfo gTegra2Vid_DrvUtil_BufInfo; +tVideo_IOCtl_Pos gTegra2Vid_CursorPos; + +// === CODE === +/** + */ +int Tegra2Vid_Install(char **Arguments) +{ +// KeyVal_Parse(&gTegra2Vid_KeyValueParser, Arguments); + + gpTegra2Vid_IOMem = (void*)MM_MapHWPages(gTegra2Vid_PhysBase, 256/4); + + Tegra2Vid_int_SetMode(4); + + DevFS_AddDevice( &gTegra2Vid_DriverStruct ); + + return 0; +} + +/** + * \brief Clean up resources for driver unloading + */ +void Tegra2Vid_Uninstall() +{ +} + +/** + * \brief Read from the framebuffer + */ +Uint64 Tegra2Vid_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer) +{ + return 0; +} + +/** + * \brief Write to the framebuffer + */ +Uint64 Tegra2Vid_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) +{ + gTegra2Vid_DrvUtil_BufInfo.BufferFormat = giTegra2Vid_BufferMode; + return DrvUtil_Video_WriteLFB(&gTegra2Vid_DrvUtil_BufInfo, Offset, Length, Buffer); +} + +const char *csaTegra2Vid_IOCtls[] = {DRV_IOCTLNAMES, DRV_VIDEO_IOCTLNAMES, NULL}; + +/** + * \brief Handle messages to the device + */ +int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data) +{ + int ret = -2; + ENTER("pNode iID pData", Node, ID, Data); + + switch(ID) + { + BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls); + + case VIDEO_IOCTL_SETBUFFORMAT: + DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo ); + ret = giTegra2Vid_BufferMode; + if(Data) giTegra2Vid_BufferMode = *(int*)Data; + if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT) + DrvUtil_Video_SetCursor( &gTegra2Vid_DrvUtil_BufInfo, &gDrvUtil_TextModeCursor ); + break; + + case VIDEO_IOCTL_GETSETMODE: + if(Data) + { + int newMode; + + if( !CheckMem(Data, sizeof(int)) ) + LEAVE_RET('i', -1); + + newMode = *(int*)Data; + + if(newMode < 0 || newMode >= ciTegra2Vid_ModeCount) + LEAVE_RET('i', -1); + + if(newMode != giTegra2Vid_CurrentMode) + { + giTegra2Vid_CurrentMode = newMode; + Tegra2Vid_int_SetMode( newMode ); + } + } + ret = giTegra2Vid_CurrentMode; + break; + + case VIDEO_IOCTL_FINDMODE: + { + tVideo_IOCtl_Mode *mode = Data; + int closest, closestArea, reqArea = 0; + if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode))) + LEAVE_RET('i', -1); + if( mode->bpp != 32 ) + LEAVE_RET('i', 0); + if( mode->flags != 0 ) + LEAVE_RET('i', 0); + + ret = 0; + + for( int i = 0; i < ciTegra2Vid_ModeCount; i ++ ) + { + int area; + if(mode->width == caTegra2Vid_Modes[i].W && mode->height == caTegra2Vid_Modes[i].H) { + mode->id = i; + ret = 1; + break; + } + + area = caTegra2Vid_Modes[i].W * caTegra2Vid_Modes[i].H; + if(!reqArea) { + reqArea = mode->width * mode->height; + closest = i; + closestArea = area; + } + else if( ABS(area - reqArea) < ABS(closestArea - reqArea) ) { + closest = i; + closestArea = area; + } + } + + if( ret == 0 ) + { + mode->id = closest; + ret = 1; + } + mode->width = caTegra2Vid_Modes[mode->id].W; + mode->height = caTegra2Vid_Modes[mode->id].H; + break; + } + + case VIDEO_IOCTL_MODEINFO: + { + tVideo_IOCtl_Mode *mode = Data; + if(!Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Mode))) + LEAVE_RET('i', -1); + if(mode->id < 0 || mode->id >= ciTegra2Vid_ModeCount) + LEAVE_RET('i', 0); + + + mode->bpp = 32; + mode->flags = 0; + mode->width = caTegra2Vid_Modes[mode->id].W; + mode->height = caTegra2Vid_Modes[mode->id].H; + + ret = 1; + break; + } + + case VIDEO_IOCTL_SETCURSOR: + if( !Data || !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) ) + LEAVE_RET('i', -1); + + DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo ); + + gTegra2Vid_CursorPos = *(tVideo_IOCtl_Pos*)Data; + if(gTegra2Vid_DrvUtil_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT) + DrvUtil_Video_DrawCursor( + &gTegra2Vid_DrvUtil_BufInfo, + gTegra2Vid_CursorPos.x*giVT_CharWidth, + gTegra2Vid_CursorPos.y*giVT_CharHeight + ); + else + DrvUtil_Video_DrawCursor( + &gTegra2Vid_DrvUtil_BufInfo, + gTegra2Vid_CursorPos.x, + gTegra2Vid_CursorPos.y + ); + break; + + default: + LEAVE('i', -2); + return -2; + } + + LEAVE('i', ret); + return ret; +} + +// +// +// + +int Tegra2Vid_int_SetMode(int Mode) +{ + const struct sTegra2_Disp_Mode *mode = &caTegra2Vid_Modes[Mode]; + int w = mode->W, h = mode->H; // Horizontal/Vertical Active + *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_FRONT_PORCH_0) = (mode->VFP << 16) | mode->HFP; + *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_SYNC_WIDTH_0) = (mode->HS << 16) | mode->HS; + *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_BACK_PORCH_0) = (mode->VBP << 16) | mode->HBP; + *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_ACTIVE_0) = (mode->H << 16) | mode->W; + + *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_POSITION_0) = 0; + *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_SIZE_0) = (mode->H << 16) | mode->W; + *(Uint8*)(gpTegra2Vid_IOMem + DC_WIN_A_COLOR_DEPTH_0) = 12; // Could be 13 (BGR/RGB) + *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_PRESCALED_SIZE_0) = (mode->H << 16) | mode->W; + + if( !gpTegra2Vid_Framebuffer || w*h*4 != giTegra2Vid_FramebufferSize ) + { + if( gpTegra2Vid_Framebuffer ) + { + // TODO: Free framebuffer for reallocation + } + + giTegra2Vid_FramebufferSize = w*h*4; + + gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA( + (giTegra2Vid_FramebufferSize + PAGE_SIZE-1) / PAGE_SIZE, + 32, + &gTegra2Vid_FramebufferPhys + ); + // TODO: Catch allocation failures + + // Tell hardware + *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_START_ADDR_0) = gTegra2Vid_FramebufferPhys; + *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_V_OFFSET_0) = 0; // Y offset + *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_H_OFFSET_0) = 0; // X offset + } + + return 0; +} diff --git a/Modules/Display/Tegra2/tegra2.h b/Modules/Display/Tegra2/tegra2.h new file mode 100644 index 0000000000000000000000000000000000000000..b05ca8c135d1d551165e23ad96e58170a8c8cc00 --- /dev/null +++ b/Modules/Display/Tegra2/tegra2.h @@ -0,0 +1,73 @@ +/* + * Acess2 NVidia Tegra2 Display Driver + * - By John Hodge (thePowersGang) + * + * tegra2.h + * - Driver definitions + */ +#ifndef _TEGRA2_DISP_H_ +#define _TEGRA2_DISP_H_ + +#define TEGRA2VID_BASE 0x54200000 // 0x40000 Large (256 KB) + +const struct sTegra2_Disp_Mode +{ + Uint16 W, H; + Uint16 HFP, VFP; + Uint16 HS, VS; + Uint16 HBP, VBP; +} caTegra2Vid_Modes[] = { + // TODO: VESA timings + {720, 487, 16,33, 63, 33, 59, 133}, // NTSC 2 + {720, 576, 12,33, 63, 33, 69, 193}, // PAL 2 (VFP shown as 2/33, used 33) + {720, 483, 16, 6, 63, 6, 59, 30}, // 480p + {1280, 720, 70, 5, 804, 6, 220, 20}, // 720p + {1920,1080, 44, 4, 884, 5, 148, 36}, // 1080p + // TODO: Can all but HA/VA be constant and those select the resolution? +}; +const int ciTegra2Vid_ModeCount = sizeof(caTegra2Vid_Modes)/sizeof(caTegra2Vid_Modes[0]); + +enum eTegra2_Disp_Regs +{ + DC_DISP_DISP_SIGNAL_OPTIONS0_0 = 0x400, + DC_DISP_DISP_SIGNAL_OPTIONS1_0, + DC_DISP_DISP_WIN_OPTIONS_0, + DC_DISP_MEM_HIGH_PRIORITY_0, + DC_DISP_MEM_HIGH_PRIORITY_TIMER_0, + DC_DISP_DISP_TIMING_OPTIONS_0, + DC_DISP_REF_TO_SYNC_0, + DC_DISP_SYNC_WIDTH_0, + DC_DISP_BACK_PORCH_0, + DC_DISP_DISP_ACTIVE_0, + DC_DISP_FRONT_PORCH_0, + + DC_DISP_H_PULSE0_CONTROL_0, + + DC_WINC_A_COLOR_PALETTE_0 = 0x500, + DC_WINC_A_PALETTE_COLOR_EXT_0 = 0x600, + DC_WIN_A_WIN_OPTIONS_0 = 0x700, + DC_WIN_A_BYTE_SWAP_0, + DC_WIN_A_BUFFER_CONTROL_0, + DC_WIN_A_COLOR_DEPTH_0, + DC_WIN_A_POSITION_0, + DC_WIN_A_SIZE_0, + DC_WIN_A_PRESCALED_SIZE_0, + DC_WIN_A_H_INITIAL_DDA_0, + DC_WIN_A_V_INITIAL_DDA_0, + DC_WIN_A_DDA_INCREMENT_0, + DC_WIN_A_LINE_STRIDE_0, + DC_WIN_A_BUF_STRIDE_0, + DC_WIN_A_BUFFER_ADDR_MODE_0, + DC_WIN_A_DV_CONTROL_0, + DC_WIN_A_BLEND_NOKEY_0, + + DC_WINBUF_A_START_ADDR_0 = 0x800, + DC_WINBUF_A_START_ADDR_NS_0, + DC_WINBUF_A_ADDR_H_OFFSET_0, + DC_WINBUF_A_ADDR_H_OFFSET_NS_0, + DC_WINBUF_A_ADDR_V_OFFSET_0, + DC_WINBUF_A_ADDR_V_OFFSET_NS_0, +}; + +#endif + diff --git a/Modules/Display/VESA/main.c b/Modules/Display/VESA/main.c index 6f056f33fb752107b1c92fc005db6e295300c3ba..55083b043a808ed16f07775536beb6f6ffc12143 100644 --- a/Modules/Display/VESA/main.c +++ b/Modules/Display/VESA/main.c @@ -51,6 +51,7 @@ tVM8086 *gpVesa_BiosState; tVesa_Mode *gVesa_Modes; tVesa_Mode *gpVesaCurMode; int giVesaModeCount = 0; + int gbVesaModesChecked; // --- Framebuffer --- char *gpVesa_Framebuffer = (void*)VESA_DEFAULT_FRAMEBUFFER; int giVesaPageCount = 0; //!< Framebuffer size in pages @@ -67,15 +68,12 @@ int Vesa_Install(char **Arguments) { tVesa_CallInfo *info; tFarPtr infoPtr; - tVesa_CallModeInfo *modeinfo; - tFarPtr modeinfoPtr; Uint16 *modes; int i; // Allocate Info Block gpVesa_BiosState = VM8086_Init(); info = VM8086_Allocate(gpVesa_BiosState, 512, &infoPtr.seg, &infoPtr.ofs); - modeinfo = VM8086_Allocate(gpVesa_BiosState, 512, &modeinfoPtr.seg, &modeinfoPtr.ofs); // Set Requested Version memcpy(info->signature, "VBE2", 4); // Set Registers @@ -109,36 +107,9 @@ int Vesa_Install(char **Arguments) for( i = 1; i < giVesaModeCount; i++ ) { gVesa_Modes[i].code = modes[i]; - // Get Mode info - gpVesa_BiosState->AX = 0x4F01; - gpVesa_BiosState->CX = gVesa_Modes[i].code; - gpVesa_BiosState->ES = modeinfoPtr.seg; - gpVesa_BiosState->DI = modeinfoPtr.ofs; - VM8086_Int(gpVesa_BiosState, 0x10); - - // Parse Info - gVesa_Modes[i].flags = 0; - if ( (modeinfo->attributes & 0x90) == 0x90 ) - { - gVesa_Modes[i].flags |= FLAG_LFB; - gVesa_Modes[i].framebuffer = modeinfo->physbase; - gVesa_Modes[i].fbSize = modeinfo->Yres*modeinfo->pitch; - } else { - gVesa_Modes[i].framebuffer = 0; - gVesa_Modes[i].fbSize = 0; - } - - gVesa_Modes[i].pitch = modeinfo->pitch; - gVesa_Modes[i].width = modeinfo->Xres; - gVesa_Modes[i].height = modeinfo->Yres; - gVesa_Modes[i].bpp = modeinfo->bpp; - - #if DEBUG - Log_Log("VESA", "0x%x - %ix%ix%i", - gVesa_Modes[i].code, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp); - #endif } - + +// VM8086_Deallocate( info ); // Install Device giVesaDriverId = DevFS_AddDevice( &gVesa_DriverStruct ); @@ -147,6 +118,53 @@ int Vesa_Install(char **Arguments) return MODULE_ERR_OK; } +void Vesa_int_FillModeList(void) +{ + if( !gbVesaModesChecked ) + { + int i; + tVesa_CallModeInfo *modeinfo; + tFarPtr modeinfoPtr; + + modeinfo = VM8086_Allocate(gpVesa_BiosState, 512, &modeinfoPtr.seg, &modeinfoPtr.ofs); + for( i = 1; i < giVesaModeCount; i ++ ) + { + // Get Mode info + gpVesa_BiosState->AX = 0x4F01; + gpVesa_BiosState->CX = gVesa_Modes[i].code; + gpVesa_BiosState->ES = modeinfoPtr.seg; + gpVesa_BiosState->DI = modeinfoPtr.ofs; + VM8086_Int(gpVesa_BiosState, 0x10); + + // Parse Info + gVesa_Modes[i].flags = 0; + if ( (modeinfo->attributes & 0x90) == 0x90 ) + { + gVesa_Modes[i].flags |= FLAG_LFB; + gVesa_Modes[i].framebuffer = modeinfo->physbase; + gVesa_Modes[i].fbSize = modeinfo->Yres*modeinfo->pitch; + } else { + gVesa_Modes[i].framebuffer = 0; + gVesa_Modes[i].fbSize = 0; + } + + gVesa_Modes[i].pitch = modeinfo->pitch; + gVesa_Modes[i].width = modeinfo->Xres; + gVesa_Modes[i].height = modeinfo->Yres; + gVesa_Modes[i].bpp = modeinfo->bpp; + + #if DEBUG + Log_Log("VESA", "0x%x - %ix%ix%i", + gVesa_Modes[i].code, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp); + #endif + } + +// VM8086_Deallocate( modeinfo ); + + gbVesaModesChecked = 1; + } +} + /* Read from the framebuffer */ Uint64 Vesa_Read(tVFS_Node *Node, Uint64 off, Uint64 len, void *buffer) @@ -225,6 +243,8 @@ int Vesa_Int_SetMode(int mode) // Check for fast return if(mode == giVesaCurrentMode) return 1; + Vesa_int_FillModeList(); + Time_RemoveTimer(giVesaCursorTimer); giVesaCursorTimer = -1; @@ -274,6 +294,8 @@ int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data) int factor, tmp; ENTER("idata->width idata->height idata->bpp", data->width, data->height, data->bpp); + + Vesa_int_FillModeList(); for(i=0;i<giVesaModeCount;i++) { @@ -329,6 +351,9 @@ int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data) int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data) { if(data->id < 0 || data->id > giVesaModeCount) return -1; + + Vesa_int_FillModeList(); + data->width = gVesa_Modes[data->id].width; data->height = gVesa_Modes[data->id].height; data->bpp = gVesa_Modes[data->id].bpp; diff --git a/Modules/USB/Core/usb_io.c b/Modules/USB/Core/usb_io.c index cd8fbcd3b91a9c916a54785237a866ff06b6dabe..25ff59d260dcb3f8d19cb20de1c79341c62d3145 100644 --- a/Modules/USB/Core/usb_io.c +++ b/Modules/USB/Core/usb_io.c @@ -103,6 +103,7 @@ void USB_AsyncCallback(void *Ptr, void *Buf, int Length) void USB_AsyncThread(void *Unused) { + Threads_SetName("USB Async IO Thread"); for(;;) { tAsyncOp *op = Workqueue_GetWork(&gUSB_AsyncQueue); diff --git a/Modules/USB/Core/usb_poll.c b/Modules/USB/Core/usb_poll.c index ec03036f16ca6a8164edfac8d7f1564dfa9f56e5..b6927fed2bb31afda01f28afcf932347cef552aa 100644 --- a/Modules/USB/Core/usb_poll.c +++ b/Modules/USB/Core/usb_poll.c @@ -70,6 +70,8 @@ int USB_PollThread(void *unused) } } +// Log_Debug("USBPoll", "giUSB_PollPosition = %i", giUSB_PollPosition); + // A little evil for neater code prev = (void*)( (tVAddr)&gUSB_PollQueues[giUSB_PollPosition] - offsetof(tUSBEndpoint, Next) );