diff --git a/reactos/apps/utils/ps/ps.c b/reactos/apps/utils/ps/ps.c index eec31179f95..1f1dc35fb32 100644 --- a/reactos/apps/utils/ps/ps.c +++ b/reactos/apps/utils/ps/ps.c @@ -1,4 +1,4 @@ -/* $Id$ +/* * * ReactOS ps - process list console viewer * @@ -26,6 +26,67 @@ /* NOTE: W32API ddk/ntapi.h header has wrong definition of SYSTEM_PROCESSES. */ #include +typedef struct _SYSTEM_THREADS + { + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER CreateTime; + ULONG WaitTime; + PVOID StartAddress; + CLIENT_ID ClientId; + KPRIORITY Priority; + LONG BasePriority; + ULONG ContextSwitches; + ULONG ThreadState; + ULONG WaitReason; + } SYSTEM_THREADS, *PSYSTEM_THREADS; + + typedef struct _SYSTEM_PROCESSES + { + ULONG NextEntryOffset; + ULONG NumberOfThreads; + LARGE_INTEGER SpareLi1; + LARGE_INTEGER SpareLi2; + LARGE_INTEGER SpareLi3; + LARGE_INTEGER CreateTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER KernelTime; + UNICODE_STRING ImageName; + KPRIORITY BasePriority; + HANDLE UniqueProcessId; + HANDLE InheritedFromUniqueProcessId; + ULONG HandleCount; + ULONG SessionId; + ULONG PageDirectoryFrame; + + /* + * This part corresponds to VM_COUNTERS_EX. + * NOTE: *NOT* THE SAME AS VM_COUNTERS! + */ + ULONG PeakVirtualSize; + ULONG VirtualSize; + ULONG PageFaultCount; + ULONG PeakWorkingSetSize; + ULONG WorkingSetSize; + ULONG QuotaPeakPagedPoolUsage; + ULONG QuotaPagedPoolUsage; + ULONG QuotaPeakNonPagedPoolUsage; + ULONG QuotaNonPagedPoolUsage; + ULONG PagefileUsage; + ULONG PeakPagefileUsage; + ULONG PrivateUsage; + + /* This part corresponds to IO_COUNTERS */ + LARGE_INTEGER ReadOperationCount; + LARGE_INTEGER WriteOperationCount; + LARGE_INTEGER OtherOperationCount; + LARGE_INTEGER ReadTransferCount; + LARGE_INTEGER WriteTransferCount; + LARGE_INTEGER OtherTransferCount; + + SYSTEM_THREADS Threads [1]; + } SYSTEM_PROCESSES, *PSYSTEM_PROCESSES; + // x00000000 00000000 000:00:00 000:00:00 () static char* title = "P PID PPID KTime UTime NAME\n"; @@ -36,7 +97,7 @@ static char* title2 = "w PID Hwnd WndStile TID WndName\n"; struct status { DWORD state; char desc[10]; -} thread_stat[8 + 1] = { +} thread_stat[8 + 1] = { {0, "Init "}, {1, "Ready "}, {2, "Running "}, @@ -50,39 +111,45 @@ struct status { struct waitres { DWORD state; - char desc[11]; -} waitreason[28 + 1] = { - {0, "Executive "}, - {1, "FreePage "}, - {2, "PageIn "}, - {3, "PoolAlloc "}, - {4, "DelayExec "}, - {5, "Suspended "}, - {6, "UserReq "}, - {7, "WrExecutive"}, - {8, "WrFreePage "}, - {9, "WrPageIn "}, - {10,"WrPoolAlloc"}, - {11,"WrDelayExec"}, - {12,"WrSuspended"}, - {13,"WrUserReq "}, - {14,"WrEventPair"}, - {15,"WrQueue "}, - {16,"WrLpcRec "}, - {17,"WrLpcReply "}, - {18,"WrVirtualMm"}, - {19,"WrPageOut "}, - {20,"WrRendez "}, - {21,"Spare1 "}, - {22,"Spare2 "}, - {23,"Spare3 "}, - {24,"Spare4 "}, - {25,"Spare5 "}, - {26,"Spare6 "}, - {27,"WrKernel "}, - {-1," ? "} + char desc[17]; +} waitreason[35 + 1] = { + {0, "Executive "}, + {1, "FreePage "}, + {2, "PageIn "}, + {3, "PoolAllocation "}, + {4, "DelayExecution "}, + {5, "Suspended "}, + {6, "UserRequest "}, + {7, "WrExecutive "}, + {8, "WrFreePage "}, + {9, "WrPageIn "}, + {10,"WrPoolAllocation "}, + {11,"WrDelayExecution "}, + {12,"WrSuspended "}, + {13,"WrUserRequest "}, + {14,"WrEventPair "}, + {15,"WrQueue "}, + {16,"WrLpcReceive "}, + {17,"WrLpcReply "}, + {18,"WrVirtualMemory "}, + {19,"WrPageOut "}, + {20,"WrRendezvous "}, + {21,"Spare2 "}, + {22,"WrGuardedMutex "}, + {23,"Spare4 "}, + {24,"Spare5 "}, + {25,"Spare6 "}, + {26,"WrKernel "}, + {27,"WrResource "}, + {28,"WrPushLock "}, + {29,"WrMutex "}, + {30,"WrQuantumEnd "}, + {31,"WrDispatchInt "}, + {32,"WrPreempted "}, + {33,"WrYieldExecution "}, + {34,"MaximumWaitReason"}, + {-1," ? "} }; - BOOL CALLBACK EnumThreadProc(HWND hwnd, LPARAM lp) { @@ -90,9 +157,9 @@ EnumThreadProc(HWND hwnd, LPARAM lp) LONG style; HANDLE stdout = GetStdHandle(STD_OUTPUT_HANDLE); char buf[256]; - + GetWindowText(hwnd, (LPTSTR)lp, 30); - + if(hwnd != 0) { style = GetWindowLong(hwnd, GWL_STYLE); @@ -110,13 +177,13 @@ int main() DWORD r; ANSI_STRING astring; HANDLE stdout = GetStdHandle(STD_OUTPUT_HANDLE); - PSYSTEM_PROCESS_INFORMATION SystemProcesses = NULL; - PSYSTEM_PROCESS_INFORMATION CurrentProcess; + PSYSTEM_PROCESSES SystemProcesses = NULL; + PSYSTEM_PROCESSES CurrentProcess; ULONG BufferSize, ReturnSize; NTSTATUS Status; char buf[256]; char buf1[256]; - + WriteFile(stdout, title, lstrlen(title), &r, NULL); WriteFile(stdout, title1, lstrlen(title1), &r, NULL); WriteFile(stdout, title2, lstrlen(title2), &r, NULL); @@ -153,7 +220,7 @@ int main() hour = (ptime.QuadPart / (10000000LL * 3600LL)); minute = (ptime.QuadPart / (10000000LL * 60LL)) % 60LL; seconds = (ptime.QuadPart / 10000000LL) % 60LL; - + ptime.QuadPart = CurrentProcess->UserTime.QuadPart; hour1 = (ptime.QuadPart / (10000000LL * 3600LL)); minute1 = (ptime.QuadPart / (10000000LL * 60LL)) % 60LL; @@ -166,7 +233,7 @@ int main() hour, minute, seconds, hour1, minute1, seconds1, astring.Buffer); WriteFile(stdout, buf, lstrlen(buf), &r, NULL); - + RtlFreeAnsiString(&astring); for (ti = 0; ti < CurrentProcess->NumberOfThreads; ti++) @@ -175,37 +242,37 @@ int main() struct waitres *waitt; char szWindowName[30] = {" "}; - ptime = CurrentProcess->TH[ti].KernelTime; + ptime = CurrentProcess->Threads[ti].KernelTime; thour = (ptime.QuadPart / (10000000LL * 3600LL)); tmin = (ptime.QuadPart / (10000000LL * 60LL)) % 60LL; tsec = (ptime.QuadPart / 10000000LL) % 60LL; - ptime = CurrentProcess->TH[ti].UserTime; + ptime = CurrentProcess->Threads[ti].UserTime; thour1 = (ptime.QuadPart / (10000000LL * 3600LL)); tmin1 = (ptime.QuadPart / (10000000LL * 60LL)) % 60LL; tsec1 = (ptime.QuadPart / 10000000LL) % 60LL; statt = thread_stat; - while (statt->state != CurrentProcess->TH[ti].ThreadState && statt->state >= 0) + while (statt->state != CurrentProcess->Threads[ti].ThreadState && statt->state >= 0) statt++; waitt = waitreason; - while (waitt->state != CurrentProcess->TH[ti].WaitReason && waitt->state >= 0) + while (waitt->state != CurrentProcess->Threads[ti].WaitReason && waitt->state >= 0) waitt++; - wsprintf (buf1, + wsprintf (buf1, "t% %8d %3d:%02d:%02d %3d:%02d:%02d %s %s\n", - CurrentProcess->TH[ti].ClientId.UniqueThread, + CurrentProcess->Threads[ti].ClientId.UniqueThread, thour, tmin, tsec, thour1, tmin1, tsec1, statt->desc , waitt->desc); WriteFile(stdout, buf1, lstrlen(buf1), &r, NULL); - EnumThreadWindows((DWORD)CurrentProcess->TH[ti].ClientId.UniqueThread, + EnumThreadWindows((DWORD)CurrentProcess->Threads[ti].ClientId.UniqueThread, (ENUMWINDOWSPROC) EnumThreadProc, (LPARAM)(LPTSTR) szWindowName ); } - CurrentProcess = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)CurrentProcess + + CurrentProcess = (PSYSTEM_PROCESSES)((ULONG_PTR)CurrentProcess + CurrentProcess->NextEntryOffset); - } + } return (0); } diff --git a/reactos/boot/freeldr/freeldr/arch/i386/hardware.c b/reactos/boot/freeldr/freeldr/arch/i386/hardware.c index 4322d4eeb44..aaa8c1d324b 100644 --- a/reactos/boot/freeldr/freeldr/arch/i386/hardware.c +++ b/reactos/boot/freeldr/freeldr/arch/i386/hardware.c @@ -1715,7 +1715,7 @@ DetectKeyboardPeripheral(FRLDRHKEY ControllerKey) /* Set 'Identifier' value */ strcpy(Buffer, "PCAT_ENHANCED"); - Error = RegSetValue(ControllerKey, + Error = RegSetValue(PeripheralKey, "Identifier", REG_SZ, Buffer, diff --git a/reactos/boot/freeldr/freeldr/arch/i386/i386disk.c b/reactos/boot/freeldr/freeldr/arch/i386/i386disk.c index 42bb8c82ed5..95f766d2e1b 100644 --- a/reactos/boot/freeldr/freeldr/arch/i386/i386disk.c +++ b/reactos/boot/freeldr/freeldr/arch/i386/i386disk.c @@ -205,9 +205,27 @@ BOOL i386DiskGetBootVolume(PULONG DriveNumber, PULONGLONG StartSector, PULONGLON { // Partition requested was zero which means the boot partition if (! DiskGetActivePartitionEntry(i386BootDrive, &PartitionTableEntry)) + { + /* Try partition-less disk */ + *StartSector = 0; + *SectorCount = 0; + } + /* Check for valid partition */ + else if (PartitionTableEntry.SystemIndicator == PARTITION_ENTRY_UNUSED) { return FALSE; } + else + { + *StartSector = PartitionTableEntry.SectorCountBeforePartition; + *SectorCount = PartitionTableEntry.PartitionSectorCount; + } + } + else if (0xff == i386BootPartition) + { + /* Partition-less disk */ + *StartSector = 0; + *SectorCount = 0; } else { @@ -216,25 +234,26 @@ BOOL i386DiskGetBootVolume(PULONG DriveNumber, PULONGLONG StartSector, PULONGLON { return FALSE; } - } - - // Check for valid partition - if (PartitionTableEntry.SystemIndicator == PARTITION_ENTRY_UNUSED) - { - return FALSE; + /* Check for valid partition */ + else if (PartitionTableEntry.SystemIndicator == PARTITION_ENTRY_UNUSED) + { + return FALSE; + } + else + { + *StartSector = PartitionTableEntry.SectorCountBeforePartition; + *SectorCount = PartitionTableEntry.PartitionSectorCount; + } } // Try to recognize the file system - if (!FsRecognizeVolume(i386BootDrive, PartitionTableEntry.SectorCountBeforePartition, &VolumeType)) + if (!FsRecognizeVolume(i386BootDrive, *StartSector, &VolumeType)) { return FALSE; } *DriveNumber = i386BootDrive; - *StartSector = PartitionTableEntry.SectorCountBeforePartition; - *SectorCount = PartitionTableEntry.PartitionSectorCount; - //switch (PartitionTableEntry.SystemIndicator) switch (VolumeType) { case PARTITION_FAT_12: diff --git a/reactos/boot/freeldr/freeldr/disk/partition.c b/reactos/boot/freeldr/freeldr/disk/partition.c index b33a9daa382..1589cff04eb 100644 --- a/reactos/boot/freeldr/freeldr/disk/partition.c +++ b/reactos/boot/freeldr/freeldr/disk/partition.c @@ -63,12 +63,12 @@ BOOL DiskGetActivePartitionEntry(ULONG DriveNumber, PPARTITION_TABLE_ENTRY Parti // Make sure there was only one bootable partition if (BootablePartitionCount == 0) { - DiskError("No bootable (active) partitions found.", 0); + DbgPrint((DPRINT_DISK, "No bootable (active) partitions found.\n")); return FALSE; } else if (BootablePartitionCount != 1) { - DiskError("Too many bootable (active) partitions found.", 0); + DbgPrint((DPRINT_DISK, "Too many bootable (active) partitions found.\n")); return FALSE; } diff --git a/reactos/boot/freeldr/freeldr/freeldr.c b/reactos/boot/freeldr/freeldr/freeldr.c index 05913e561d0..54e8638bbef 100644 --- a/reactos/boot/freeldr/freeldr/freeldr.c +++ b/reactos/boot/freeldr/freeldr/freeldr.c @@ -35,7 +35,7 @@ VOID BootMain(char *CmdLine) DebugInit(); - DbgPrint((DPRINT_WARNING, "BootMain() called. BootDrive = 0x%x BootPartition = %d\n", BootDrive, BootPartition)); + DbgPrint((DPRINT_WARNING, "BootMain() called.\n")); if (!MmInitializeMemoryManager()) { diff --git a/reactos/boot/freeldr/freeldr/mm/mm.c b/reactos/boot/freeldr/freeldr/mm/mm.c index 402069a634e..6b81d8e16ef 100644 --- a/reactos/boot/freeldr/freeldr/mm/mm.c +++ b/reactos/boot/freeldr/freeldr/mm/mm.c @@ -36,10 +36,30 @@ VOID DecrementAllocationCount(VOID); VOID MemAllocTest(VOID); #endif // DEBUG +/* + * Hack alert + * Normally, we allocate whole pages. This is ofcourse wastefull for small + * allocations (a few bytes). So, for small allocations (smaller than a page) + * we sub-allocate. When the first small allocation is done, a page is + * requested. We keep a pointer to that page in SubAllocationPage. The alloc + * is satisfied by returning a pointer to the beginning of the page. We also + * keep track of how many bytes are still available in the page in SubAllocationRest. + * When the next small request comes in, we try to allocate it just after the + * memory previously allocated. If it won't fit, we allocate a new page and + * the whole process starts again. + * Note that suballocations are done back-to-back, there's no bookkeeping at all. + * That also means that we cannot really free suballocations. So, when a free is + * done and it is determined that this might be a free of a sub-allocation, we + * just no-op the free. + * Perhaps we should use the heap routines from ntdll here. + */ +static PVOID SubAllocationPage = NULL; +static unsigned SubAllocationRest = 0; + PVOID MmAllocateMemory(ULONG MemorySize) { - ULONG PagesNeeded; - ULONG FirstFreePageFromEnd; + ULONG PagesNeeded; + ULONG FirstFreePageFromEnd; PVOID MemPointer; if (MemorySize == 0) @@ -49,6 +69,14 @@ PVOID MmAllocateMemory(ULONG MemorySize) return NULL; } + MemorySize = ROUND_UP(MemorySize, 4); + if (MemorySize <= SubAllocationRest) + { + MemPointer = SubAllocationPage + MM_PAGE_SIZE - SubAllocationRest; + SubAllocationRest -= MemorySize; + return MemPointer; + } + // Find out how many blocks it will take to // satisfy this allocation PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE; @@ -76,6 +104,13 @@ PVOID MmAllocateMemory(ULONG MemorySize) FreePagesInLookupTable -= PagesNeeded; MemPointer = (PVOID)(FirstFreePageFromEnd * MM_PAGE_SIZE); + if (MemorySize < MM_PAGE_SIZE) + { + SubAllocationPage = MemPointer; + SubAllocationRest = MM_PAGE_SIZE - MemorySize; + } + + #ifdef DEBUG IncrementAllocationCount(); DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d. AllocCount: %d\n", MemorySize, PagesNeeded, FirstFreePageFromEnd, AllocationCount)); @@ -235,6 +270,13 @@ VOID MmFreeMemory(PVOID MemoryPointer) #endif + /* If this allocation is only a single page, it could be a sub-allocated page. + * Just don't free it */ + if (1 == PageCount) + { + return; + } + // Loop through our array and mark all the // blocks as free for (Idx=PageNumber; Idx<(PageNumber + PageCount); Idx++) diff --git a/reactos/boot/freeldr/freeldr/reactos/reactos.c b/reactos/boot/freeldr/freeldr/reactos/reactos.c index c8ad963e42a..7180945b8ea 100644 --- a/reactos/boot/freeldr/freeldr/reactos/reactos.c +++ b/reactos/boot/freeldr/freeldr/reactos/reactos.c @@ -756,6 +756,16 @@ LoadAndBootReactOS(PCHAR OperatingSystemName) if (!FrLdrLoadDriver(szHalName, 10)) return; +#if 0 + /* Load bootvid */ + strcpy(value, "INBV.DLL"); + strcpy(szHalName, szBootPath); + strcat(szHalName, "SYSTEM32\\"); + strcat(szHalName, value); + + if (!FrLdrLoadDriver(szHalName, 10)) + return; +#endif /* * Load the System hive from disk */ diff --git a/reactos/boot/freeldr/freeldr/reactos/setupldr.c b/reactos/boot/freeldr/freeldr/reactos/setupldr.c index 3dd936a6200..78e01a6feea 100644 --- a/reactos/boot/freeldr/freeldr/reactos/setupldr.c +++ b/reactos/boot/freeldr/freeldr/reactos/setupldr.c @@ -34,7 +34,7 @@ #include "registry.h" -//#define USE_UI +#define USE_UI static BOOL @@ -88,7 +88,7 @@ LoadKernel(PCHAR szSourcePath, PCHAR szFileName) * Update the status bar with the current file */ #ifdef USE_UI - sprintf(szBuffer, "Reading %s", szShortName); + sprintf(szBuffer, "Setup is loading files (%s)", szShortName); UiDrawStatusText(szBuffer); #else printf("Reading %s\n", szShortName); @@ -155,7 +155,7 @@ LoadDriver(PCHAR szSourcePath, PCHAR szFileName) * Update the status bar with the current file */ #ifdef USE_UI - sprintf(szBuffer, "Reading %s", szShortName); + sprintf(szBuffer, "Setup is loading files (%s)", szShortName); UiDrawStatusText(szBuffer); #else printf("Reading %s\n", szShortName); @@ -220,7 +220,7 @@ LoadNlsFile(PCHAR szSourcePath, PCHAR szFileName, PCHAR szModuleName) * Update the status bar with the current file */ #ifdef USE_UI - sprintf(szBuffer, "Reading %s", szShortName); + sprintf(szBuffer, "Setup is loading files (%s)", szShortName); UiDrawStatusText(szBuffer); #else printf("Reading %s\n", szShortName); @@ -232,6 +232,7 @@ LoadNlsFile(PCHAR szSourcePath, PCHAR szFileName, PCHAR szModuleName) return(TRUE); } +BOOL SetupUiInitialize(VOID); VOID RunLoader(VOID) { @@ -294,7 +295,7 @@ VOID RunLoader(VOID) #endif #ifdef USE_UI - UiInitialize(); + SetupUiInitialize(); UiDrawStatusText(""); #endif diff --git a/reactos/boot/freeldr/freeldr/ui/ui.c b/reactos/boot/freeldr/freeldr/ui/ui.c index 1c21029f668..8e976135e8b 100644 --- a/reactos/boot/freeldr/freeldr/ui/ui.c +++ b/reactos/boot/freeldr/freeldr/ui/ui.c @@ -27,6 +27,7 @@ #include #include #include +#include ULONG UiScreenWidth = 80; // Screen Width ULONG UiScreenHeight = 25; // Screen Height @@ -196,6 +197,39 @@ BOOL UiInitialize(BOOLEAN ShowGui) UserInterfaceUp = TRUE; + DbgPrint((DPRINT_UI, "UiInitialize() returning TRUE.\n")); + return TRUE; +} + +BOOL SetupUiInitialize(VOID) +{ + + CHAR DisplayModeText[260]; + ULONG Depth; + + + DisplayModeText[0] = '\0'; + + + UiDisplayMode = MachVideoSetDisplayMode(DisplayModeText, TRUE); + MachVideoGetDisplaySize(&UiScreenWidth, &UiScreenHeight, &Depth); + + TuiInitialize(); + + // Draw the backdrop and fade it in if special effects are enabled + TuiFillArea(0, + 0, + UiScreenWidth - 1, + UiScreenHeight - 2, + 0, + ATTR(UiBackdropFgColor, UiBackdropBgColor)); + + UiStatusBarBgColor = 7; + UserInterfaceUp = TRUE; + + TuiDrawText(4, 1, "ReactOS " KERNEL_VERSION_STR " Setup", ATTR(COLOR_GRAY, UiBackdropBgColor)); + TuiDrawText(3, 2, "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD", ATTR(COLOR_GRAY, UiBackdropBgColor)); + DbgPrint((DPRINT_UI, "UiInitialize() returning TRUE.\n")); return TRUE; diff --git a/reactos/bootdata/hivesys.inf b/reactos/bootdata/hivesys.inf index 8c1cc25e33a..f8367e6e240 100644 --- a/reactos/bootdata/hivesys.inf +++ b/reactos/bootdata/hivesys.inf @@ -46,6 +46,9 @@ HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E975-E325-11CE-BFC1-08002BE103 HKLM,"SYSTEM\CurrentControlSet\Control\ComputerName",,0x00000012 HKLM,"SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName","ComputerName",0x00000002,"COMPUTERNAME" +; Device classes key +HKLM,"SYSTEM\CurrentControlSet\Control\DeviceClasses",,0x00000012 + ; Hardware profile settings HKLM,"SYSTEM\CurrentControlSet\Control\IDConfigDB",,0x00000012 HKLM,"SYSTEM\CurrentControlSet\Control\IDConfigDB","CurrentConfig",0x00010001,0x00000000 @@ -529,7 +532,7 @@ HKLM,"SYSTEM\CurrentControlSet\Services\Class2","Type",0x00010001,0x00000001 HKLM,"SYSTEM\CurrentControlSet\Services\DebugOut","ErrorControl",0x00010001,0x00000000 HKLM,"SYSTEM\CurrentControlSet\Services\DebugOut","Group",0x00000000,"Debug" HKLM,"SYSTEM\CurrentControlSet\Services\DebugOut","ImagePath",0x00020000,"system32\drivers\debugout.sys" -HKLM,"SYSTEM\CurrentControlSet\Services\DebugOut","Start",0x00010001,0x00000001 +HKLM,"SYSTEM\CurrentControlSet\Services\DebugOut","Start",0x00010001,0x00000004 HKLM,"SYSTEM\CurrentControlSet\Services\DebugOut","Type",0x00010001,0x00000001 ; Disk class driver @@ -675,7 +678,7 @@ HKLM,"SYSTEM\CurrentControlSet\Services\Ndis","Type",0x00010001,0x00000001 HKLM,"SYSTEM\CurrentControlSet\Services\Ne2000","ErrorControl",0x00010001,0x00000001 HKLM,"SYSTEM\CurrentControlSet\Services\Ne2000","Group",0x00000000,"NDIS" HKLM,"SYSTEM\CurrentControlSet\Services\Ne2000","ImagePath",0x00020000,"system32\drivers\ne2000.sys" -HKLM,"SYSTEM\CurrentControlSet\Services\Ne2000","Start",0x00010001,0x00000004 +HKLM,"SYSTEM\CurrentControlSet\Services\Ne2000","Start",0x00010001,0x00000003 HKLM,"SYSTEM\CurrentControlSet\Services\Ne2000","Type",0x00010001,0x00000001 HKLM,"SYSTEM\CurrentControlSet\Services\Ne2000","Route",0x00000000,"Ne20001" @@ -687,8 +690,8 @@ HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE103 HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0001\Linkage","Export",0x00000000,"\Device\Ne20001" HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0001\Linkage","RootDevice",0x00000000,"Ne20001" HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0001\Linkage","UpperBind",0x00000000,"Tcpip" -HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0001","Port",0x00000000,"280" -HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0001","Irq",0x00000000,"9" +HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0001","Port",0x00000000,"c100" +HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0001","Irq",0x00000000,"B" HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0001","NetworkAddress",0x00000000,"001122334455" HKLM,"SYSTEM\CurrentControlSet\Services\Ne20001\Parameters\Tcpip","DefaultGateway",0x00010000,"0.0.0.0" HKLM,"SYSTEM\CurrentControlSet\Services\Ne20001\Parameters\Tcpip","IPAddress",0x00010000,"0.0.0.0" @@ -926,6 +929,12 @@ HKLM,"SYSTEM\CurrentControlSet\Services\VBE","Start",0x00010001,0x00000004 HKLM,"SYSTEM\CurrentControlSet\Services\VBE","Type",0x00010001,0x00000001 HKLM,"SYSTEM\CurrentControlSet\Services\VBE\Device0","InstalledDisplayDrivers",0x00010000,"framebuf" +HKLM,"SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\VBE\Device0","DefaultSettings.VRefresh",0x00010001,1 +HKLM,"SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\VBE\Device0","DefaultSettings.BitsPerPel",0x00010001,8 +HKLM,"SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\VBE\Device0","DefaultSettings.XResolution",0x00010001,640 +HKLM,"SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Services\VBE\Device0","DefaultSettings.YResolution",0x00010001,480 + + ; VGA miniport driver HKLM,"SYSTEM\CurrentControlSet\Services\Vga","ErrorControl",0x00010001,0x00000000 HKLM,"SYSTEM\CurrentControlSet\Services\Vga","Group",0x00000000,"Video Save" @@ -934,6 +943,7 @@ HKLM,"SYSTEM\CurrentControlSet\Services\Vga","Start",0x00010001,0x00000004 HKLM,"SYSTEM\CurrentControlSet\Services\Vga","Type",0x00010001,0x00000001 HKLM,"SYSTEM\CurrentControlSet\Services\Vga\Device0","InstalledDisplayDrivers",0x00010000,"vgaddi" + ; VMware SVGA driver HKLM,"SYSTEM\CurrentControlSet\Services\vmx_svga","ErrorControl",0x00010001,0x00000000 HKLM,"SYSTEM\CurrentControlSet\Services\vmx_svga","Group",0x00000000,"Video" diff --git a/reactos/bootdata/packages/reactos.dff b/reactos/bootdata/packages/reactos.dff index ce6d8b474a4..533513c9de7 100755 --- a/reactos/bootdata/packages/reactos.dff +++ b/reactos/bootdata/packages/reactos.dff @@ -16,7 +16,7 @@ Signature = "$ReactOS$" 1 = system32 2 = system32\drivers 3 = media\fonts -4 = . +4 = 5 = system32\drivers\etc 6 = inf diff --git a/reactos/drivers/bus/acpi/ospm/acpisys.c b/reactos/drivers/bus/acpi/ospm/acpisys.c index 2fac05b218d..facfd67c894 100644 --- a/reactos/drivers/bus/acpi/ospm/acpisys.c +++ b/reactos/drivers/bus/acpi/ospm/acpisys.c @@ -162,7 +162,7 @@ DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { - DbgPrint("Advanced Configuration and Power Interface Bus Driver\n"); + DPRINT("Advanced Configuration and Power Interface Bus Driver\n"); DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH) ACPIDispatchDeviceControl; DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH) ACPIPnpControl; diff --git a/reactos/drivers/bus/acpi/ospm/fdo.c b/reactos/drivers/bus/acpi/ospm/fdo.c index 4e77a3ee8bc..18923d73a4f 100644 --- a/reactos/drivers/bus/acpi/ospm/fdo.c +++ b/reactos/drivers/bus/acpi/ospm/fdo.c @@ -119,12 +119,16 @@ AcpiCreateInstanceIDString(PUNICODE_STRING InstanceID, static BOOLEAN AcpiCreateResourceList(PCM_RESOURCE_LIST* pResourceList, PULONG ResourceListSize, + PIO_RESOURCE_REQUIREMENTS_LIST* pRequirementsList, + PULONG RequirementsListSize, RESOURCE* resources) { BOOLEAN Done; ULONG NumberOfResources = 0; PCM_RESOURCE_LIST ResourceList; + PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList; PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor; + PIO_RESOURCE_DESCRIPTOR RequirementDescriptor; RESOURCE* resource; ULONG i; KIRQL Dirql; @@ -176,6 +180,24 @@ AcpiCreateResourceList(PCM_RESOURCE_LIST* pResourceList, ResourceList->List[0].PartialResourceList.Count = NumberOfResources; ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors; + *RequirementsListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + sizeof(IO_RESOURCE_DESCRIPTOR) * (NumberOfResources - 1); + RequirementsList = (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePool(PagedPool, *RequirementsListSize); + *pRequirementsList = RequirementsList; + if (!RequirementsList) + { + ExFreePool(ResourceList); + return FALSE; + } + RequirementsList->ListSize = *RequirementsListSize; + RequirementsList->InterfaceType = ResourceList->List[0].InterfaceType; + RequirementsList->BusNumber = ResourceList->List[0].BusNumber; + RequirementsList->SlotNumber = 0; /* Not used by WDM drivers */ + RequirementsList->AlternativeLists = 1; + RequirementsList->List[0].Version = 1; + RequirementsList->List[0].Revision = 1; + RequirementsList->List[0].Count = NumberOfResources; + RequirementDescriptor = RequirementsList->List[0].Descriptors; + /* Fill resources list structure */ Done = FALSE; resource = resources; @@ -199,7 +221,16 @@ AcpiCreateResourceList(PCM_RESOURCE_LIST* pResourceList, &Dirql, &ResourceDescriptor->u.Interrupt.Affinity); ResourceDescriptor->u.Interrupt.Level = (ULONG)Dirql; + + RequirementDescriptor->Option = 0; /* Required */ + RequirementDescriptor->Type = ResourceDescriptor->Type; + RequirementDescriptor->ShareDisposition = ResourceDescriptor->ShareDisposition; + RequirementDescriptor->Flags = ResourceDescriptor->Flags; + RequirementDescriptor->u.Interrupt.MinimumVector = RequirementDescriptor->u.Interrupt.MaximumVector + = irq_data->interrupts[i]; + ResourceDescriptor++; + RequirementDescriptor++; } break; } @@ -225,7 +256,16 @@ AcpiCreateResourceList(PCM_RESOURCE_LIST* pResourceList, case TRANSFER_8_16: ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8_AND_16; break; } ResourceDescriptor->u.Dma.Channel = dma_data->channels[i]; + + RequirementDescriptor->Option = 0; /* Required */ + RequirementDescriptor->Type = ResourceDescriptor->Type; + RequirementDescriptor->ShareDisposition = ResourceDescriptor->ShareDisposition; + RequirementDescriptor->Flags = ResourceDescriptor->Flags; + RequirementDescriptor->u.Dma.MinimumChannel = RequirementDescriptor->u.Dma.MaximumChannel + = ResourceDescriptor->u.Dma.Channel; + ResourceDescriptor++; + RequirementDescriptor++; } break; } @@ -242,7 +282,18 @@ AcpiCreateResourceList(PCM_RESOURCE_LIST* pResourceList, ResourceDescriptor->u.Port.Start.u.HighPart = 0; ResourceDescriptor->u.Port.Start.u.LowPart = io_data->min_base_address; ResourceDescriptor->u.Port.Length = io_data->range_length; + + RequirementDescriptor->Option = 0; /* Required */ + RequirementDescriptor->Type = ResourceDescriptor->Type; + RequirementDescriptor->ShareDisposition = ResourceDescriptor->ShareDisposition; + RequirementDescriptor->Flags = ResourceDescriptor->Flags; + RequirementDescriptor->u.Port.Length = ResourceDescriptor->u.Port.Length; + RequirementDescriptor->u.Port.Alignment = 1; /* Start address is specified, so it doesn't matter */ + RequirementDescriptor->u.Port.MinimumAddress = RequirementDescriptor->u.Port.MaximumAddress + = ResourceDescriptor->u.Port.Start; + ResourceDescriptor++; + RequirementDescriptor++; break; } case end_tag: @@ -366,6 +417,8 @@ FdoQueryBusRelations( } if (!AcpiCreateResourceList(&PdoDeviceExtension->ResourceList, &PdoDeviceExtension->ResourceListSize, + &PdoDeviceExtension->ResourceRequirementsList, + &PdoDeviceExtension->ResourceRequirementsListSize, (RESOURCE*)Buffer.pointer)) { ASSERT(FALSE); @@ -573,7 +626,9 @@ FdoStartDevice( } } +#ifndef NDEBUG ACPIPrintInfo(DeviceExtension); +#endif /* Initialize ACPI bus manager */ AcpiStatus = bm_initialize(); diff --git a/reactos/drivers/bus/acpi/ospm/include/acpisys.h b/reactos/drivers/bus/acpi/ospm/include/acpisys.h index c7154cd8580..c19f5cb4148 100644 --- a/reactos/drivers/bus/acpi/ospm/include/acpisys.h +++ b/reactos/drivers/bus/acpi/ospm/include/acpisys.h @@ -50,6 +50,9 @@ typedef struct _PDO_DEVICE_EXTENSION // Resource list PCM_RESOURCE_LIST ResourceList; ULONG ResourceListSize; + // Requirement list + PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirementsList; + ULONG ResourceRequirementsListSize; } PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION; diff --git a/reactos/drivers/bus/acpi/ospm/osl.c b/reactos/drivers/bus/acpi/ospm/osl.c index 24c90e2fc92..2cbae8ac881 100644 --- a/reactos/drivers/bus/acpi/ospm/osl.c +++ b/reactos/drivers/bus/acpi/ospm/osl.c @@ -98,7 +98,7 @@ acpi_os_vprintf(const NATIVE_CHAR *fmt, va_list args) static char Buffer[512]; LONG Size = vsprintf(Buffer, fmt, args); - DbgPrint("%s", Buffer); + DPRINT("%s", Buffer); return Size; } diff --git a/reactos/drivers/bus/acpi/ospm/pdo.c b/reactos/drivers/bus/acpi/ospm/pdo.c index 9471ff9b786..ead65b53f42 100644 --- a/reactos/drivers/bus/acpi/ospm/pdo.c +++ b/reactos/drivers/bus/acpi/ospm/pdo.c @@ -107,6 +107,35 @@ PdoQueryId( } +static NTSTATUS +PdoQueryResourceRequirements( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + PIO_STACK_LOCATION IrpSp) +{ + PPDO_DEVICE_EXTENSION DeviceExtension; + PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirementsList; + + DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + if (DeviceExtension->ResourceRequirementsListSize == 0) + { + return Irp->IoStatus.Status; + } + + ResourceRequirementsList = ExAllocatePool(PagedPool, DeviceExtension->ResourceRequirementsListSize); + if (!ResourceRequirementsList) + { + Irp->IoStatus.Information = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory(ResourceRequirementsList, DeviceExtension->ResourceRequirementsList, DeviceExtension->ResourceRequirementsListSize); + Irp->IoStatus.Information = (ULONG_PTR)ResourceRequirementsList; + return STATUS_SUCCESS; +} + + static NTSTATUS PdoQueryResources( IN PDEVICE_OBJECT DeviceObject, @@ -227,6 +256,9 @@ PdoPnpControl( break; case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: + Status = PdoQueryResourceRequirements(DeviceObject, + Irp, + IrpSp); break; case IRP_MN_QUERY_RESOURCES: diff --git a/reactos/drivers/bus/pci/pci.c b/reactos/drivers/bus/pci/pci.c index cd92acbdc03..8dd5c4074d2 100644 --- a/reactos/drivers/bus/pci/pci.c +++ b/reactos/drivers/bus/pci/pci.c @@ -172,7 +172,7 @@ DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { - DbgPrint("Peripheral Component Interconnect Bus Driver\n"); + DPRINT("Peripheral Component Interconnect Bus Driver\n"); DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PciDispatchDeviceControl; DriverObject->MajorFunction[IRP_MJ_PNP] = PciPnpControl; diff --git a/reactos/drivers/bus/pci/pdo.c b/reactos/drivers/bus/pci/pdo.c index 659a5bd87fb..6a738a962e6 100644 --- a/reactos/drivers/bus/pci/pdo.c +++ b/reactos/drivers/bus/pci/pdo.c @@ -409,6 +409,8 @@ PdoQueryResourceRequirements( ResourceList->ListSize = ListSize; ResourceList->InterfaceType = PCIBus; + ResourceList->BusNumber = DeviceExtension->BusNumber, + ResourceList->SlotNumber = DeviceExtension->SlotNumber.u.AsULONG, ResourceList->AlternativeLists = 1; ResourceList->List[0].Version = 1; @@ -433,7 +435,7 @@ PdoQueryResourceRequirements( if (Length == 0) { DPRINT("Unused address register\n"); - break; + continue; } /* Set preferred descriptor */ @@ -497,6 +499,7 @@ PdoQueryResourceRequirements( if (PciConfig.u.type0.InterruptPin != 0) { + Descriptor->Option = 0; /* Required */ Descriptor->Type = CmResourceTypeInterrupt; Descriptor->ShareDisposition = CmResourceShareShared; Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; @@ -522,7 +525,7 @@ PdoQueryResourceRequirements( if (Length == 0) { DPRINT("Unused address register\n"); - break; + continue; } /* Set preferred descriptor */ @@ -722,7 +725,7 @@ PdoQueryResources( if (Length == 0) { DPRINT("Unused address register\n"); - break; + continue; } if (Flags & PCI_ADDRESS_IO_SPACE) @@ -776,7 +779,7 @@ PdoQueryResources( if (Length == 0) { DPRINT("Unused address register\n"); - break; + continue; } if (Flags & PCI_ADDRESS_IO_SPACE) diff --git a/reactos/drivers/dd/serial/legacy.c b/reactos/drivers/dd/serial/legacy.c index 6702291d0f5..efb76e46155 100644 --- a/reactos/drivers/dd/serial/legacy.c +++ b/reactos/drivers/dd/serial/legacy.c @@ -83,12 +83,13 @@ DetectLegacyDevice( { ULONG ResourceListSize; PCM_RESOURCE_LIST ResourceList; + PCM_RESOURCE_LIST ResourceListTranslated; PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptorTranslated; BOOLEAN ConflictDetected; UART_TYPE UartType; PDEVICE_OBJECT Pdo = NULL; PDEVICE_OBJECT Fdo; - KIRQL Dirql; NTSTATUS Status; /* Create resource list */ @@ -96,29 +97,60 @@ DetectLegacyDevice( ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, ResourceListSize, SERIAL_TAG); if (!ResourceList) return STATUS_INSUFFICIENT_RESOURCES; - ResourceList->Count = 1; - ResourceList->List[0].InterfaceType = InterfaceTypeUndefined; - ResourceList->List[0].BusNumber = -1; /* unknown */ - ResourceList->List[0].PartialResourceList.Version = 1; - ResourceList->List[0].PartialResourceList.Revision = 1; - ResourceList->List[0].PartialResourceList.Count = 2; + ResourceListTranslated = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, ResourceListSize, SERIAL_TAG); + if (!ResourceListTranslated) + { + ExFreePoolWithTag(ResourceList, SERIAL_TAG); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Resource header */ + ResourceList->Count = ResourceListTranslated->Count + = 1; + ResourceList->List[0].InterfaceType = ResourceListTranslated->List[0].InterfaceType + = InterfaceTypeUndefined; + ResourceList->List[0].BusNumber = ResourceListTranslated->List[0].BusNumber + = -1; /* unknown */ + ResourceList->List[0].PartialResourceList.Version = ResourceListTranslated->List[0].PartialResourceList.Version + = 1; + ResourceList->List[0].PartialResourceList.Revision = ResourceListTranslated->List[0].PartialResourceList.Revision + = 1; + ResourceList->List[0].PartialResourceList.Count = ResourceListTranslated->List[0].PartialResourceList.Count + = 2; + + /* I/O port */ ResourceDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[0]; - ResourceDescriptor->Type = CmResourceTypePort; - ResourceDescriptor->ShareDisposition = CmResourceShareDriverExclusive; - ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO; - ResourceDescriptor->u.Port.Start.u.HighPart = 0; - ResourceDescriptor->u.Port.Start.u.LowPart = ComPortBase; - ResourceDescriptor->u.Port.Length = 8; + ResourceDescriptorTranslated = &ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[0]; + ResourceDescriptor->Type = ResourceDescriptorTranslated->Type + = CmResourceTypePort; + ResourceDescriptor->ShareDisposition = ResourceDescriptorTranslated->ShareDisposition + = CmResourceShareDriverExclusive; + ResourceDescriptor->Flags = ResourceDescriptorTranslated->Flags + = CM_RESOURCE_PORT_IO; + ResourceDescriptor->u.Port.Start.u.HighPart = ResourceDescriptorTranslated->u.Port.Start.u.HighPart + = 0; + ResourceDescriptor->u.Port.Start.u.LowPart = ResourceDescriptorTranslated->u.Port.Start.u.LowPart + = ComPortBase; + ResourceDescriptor->u.Port.Length = ResourceDescriptorTranslated->u.Port.Length + = 8; ResourceDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[1]; - ResourceDescriptor->Type = CmResourceTypeInterrupt; - ResourceDescriptor->ShareDisposition = CmResourceShareShared; - ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; - ResourceDescriptor->u.Interrupt.Vector = HalGetInterruptVector( - Internal, 0, 0, Irq, - &Dirql, + ResourceDescriptorTranslated = &ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[1]; + ResourceDescriptor->Type = ResourceDescriptorTranslated->Type + = CmResourceTypeInterrupt; + ResourceDescriptor->ShareDisposition = ResourceDescriptorTranslated->ShareDisposition + = CmResourceShareShared; + ResourceDescriptor->Flags = ResourceDescriptorTranslated->Flags + = CM_RESOURCE_INTERRUPT_LATCHED; + ResourceDescriptor->u.Interrupt.Level = Irq; + ResourceDescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector( + ResourceList->List[0].InterfaceType, + ResourceList->List[0].BusNumber, + ResourceDescriptor->u.Interrupt.Level, + ResourceDescriptor->u.Interrupt.Vector, + (PKIRQL)&ResourceDescriptorTranslated->u.Interrupt.Level, &ResourceDescriptor->u.Interrupt.Affinity); - ResourceDescriptor->u.Interrupt.Level = (ULONG)Dirql; + ResourceDescriptorTranslated->u.Interrupt.Affinity = ResourceDescriptor->u.Interrupt.Affinity; /* Report resource list */ Status = IoReportResourceForDetection( @@ -129,11 +161,13 @@ DetectLegacyDevice( { DPRINT("Serial: conflict detected for serial port at 0x%lx (Irq %lu)\n", ComPortBase, Irq); ExFreePoolWithTag(ResourceList, SERIAL_TAG); + ExFreePoolWithTag(ResourceListTranslated, SERIAL_TAG); return STATUS_DEVICE_NOT_CONNECTED; } if (!NT_SUCCESS(Status)) { ExFreePoolWithTag(ResourceList, SERIAL_TAG); + ExFreePoolWithTag(ResourceListTranslated, SERIAL_TAG); return Status; } @@ -154,7 +188,7 @@ DetectLegacyDevice( Status = SerialAddDeviceInternal(DriverObject, Pdo, UartType, pComPortNumber, &Fdo); if (NT_SUCCESS(Status)) { - Status = SerialPnpStartDevice(Fdo, ResourceList); + Status = SerialPnpStartDevice(Fdo, ResourceList, ResourceListTranslated); } } } @@ -168,6 +202,7 @@ DetectLegacyDevice( Status = STATUS_DEVICE_NOT_CONNECTED; } ExFreePoolWithTag(ResourceList, SERIAL_TAG); + ExFreePoolWithTag(ResourceListTranslated, SERIAL_TAG); return Status; } diff --git a/reactos/drivers/dd/serial/pnp.c b/reactos/drivers/dd/serial/pnp.c index 9b901405e5f..0826cb18f58 100644 --- a/reactos/drivers/dd/serial/pnp.c +++ b/reactos/drivers/dd/serial/pnp.c @@ -126,7 +126,8 @@ SerialAddDevice( NTSTATUS STDCALL SerialPnpStartDevice( IN PDEVICE_OBJECT DeviceObject, - IN PCM_RESOURCE_LIST ResourceList) + IN PCM_RESOURCE_LIST ResourceList, + IN PCM_RESOURCE_LIST ResourceListTranslated) { PSERIAL_DEVICE_EXTENSION DeviceExtension; WCHAR DeviceNameBuffer[32]; @@ -174,8 +175,8 @@ SerialPnpStartDevice( case CmResourceTypeInterrupt: if (Dirql != 0) return STATUS_UNSUCCESSFUL; - Dirql = (KIRQL)PartialDescriptor->u.Interrupt.Level; - Vector = PartialDescriptor->u.Interrupt.Vector; + Dirql = (KIRQL)ResourceListTranslated->List[i].PartialResourceList.PartialDescriptors[j].u.Interrupt.Level; + Vector = ResourceListTranslated->List[i].PartialResourceList.PartialDescriptors[j].u.Interrupt.Vector; Affinity = PartialDescriptor->u.Interrupt.Affinity; if (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) InterruptMode = Latched; @@ -338,16 +339,9 @@ SerialPnp( BOOLEAN ConflictDetected; DPRINT("Serial: IRP_MJ_PNP / IRP_MN_START_DEVICE\n"); - /* FIXME: first HACK: PnP manager can send multiple - * IRP_MN_START_DEVICE for one device - */ - if (((PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->PnpState != dsStopped) - { - DPRINT1("Serial: device already started. Ignoring this irp!\n"); - Status = STATUS_SUCCESS; - break; - } - /* FIXME: second HACK: verify that we have some allocated resources. + ASSERT(((PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->PnpState == dsStopped); + + /* FIXME: HACK: verify that we have some allocated resources. * It seems not to be always the case on some hardware */ if (Stack->Parameters.StartDevice.AllocatedResources == NULL) @@ -357,7 +351,7 @@ SerialPnp( Status = STATUS_INSUFFICIENT_RESOURCES; break; } - /* FIXME: third HACK: verify that we don't have resource conflict, + /* FIXME: HACK: verify that we don't have resource conflict, * because PnP manager doesn't do it automatically */ Status = IoReportResourceForDetection( @@ -377,7 +371,8 @@ SerialPnp( if (NT_SUCCESS(Status)) Status = SerialPnpStartDevice( DeviceObject, - Stack->Parameters.StartDevice.AllocatedResources); + Stack->Parameters.StartDevice.AllocatedResources, + Stack->Parameters.StartDevice.AllocatedResourcesTranslated); break; } case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x7 */ diff --git a/reactos/drivers/dd/serial/serial.h b/reactos/drivers/dd/serial/serial.h index 778125c6e56..eb4794fb00d 100644 --- a/reactos/drivers/dd/serial/serial.h +++ b/reactos/drivers/dd/serial/serial.h @@ -327,7 +327,8 @@ SerialAddDevice( NTSTATUS STDCALL SerialPnpStartDevice( IN PDEVICE_OBJECT DeviceObject, - IN PCM_RESOURCE_LIST ResourceList); + IN PCM_RESOURCE_LIST ResourceList, + IN PCM_RESOURCE_LIST ResourceListTranslated); NTSTATUS STDCALL SerialPnp( diff --git a/reactos/drivers/fs/np/create.c b/reactos/drivers/fs/np/create.c index b0269c61a26..9df3d350adc 100644 --- a/reactos/drivers/fs/np/create.c +++ b/reactos/drivers/fs/np/create.c @@ -96,7 +96,7 @@ NpfsSignalAndRemoveListeningServerInstance(PNPFS_PIPE Pipe, RemoveEntryList(&Waiter->Entry); Irp = CONTAINING_RECORD(Waiter, IRP, Tail.Overlay.DriverContext); - Irp->IoStatus.Status = STATUS_PIPE_CONNECTED; + Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); break; diff --git a/reactos/drivers/input/i8042prt/i8042prt.h b/reactos/drivers/input/i8042prt/i8042prt.h index 3c1f6d57494..fb9df9a1afa 100644 --- a/reactos/drivers/input/i8042prt/i8042prt.h +++ b/reactos/drivers/input/i8042prt/i8042prt.h @@ -86,7 +86,7 @@ typedef struct _I8042_SETTINGS DWORD OverrideKeyboardType; DWORD OverrideKeyboardSubtype; DWORD MouseResendStallTime; - DWORD MouseSynchIn100ns; + DWORD MouseSynchIn100ns; /* done */ DWORD MouseResolution; /* done */ DWORD NumberOfButtons; DWORD EnableWheelDetection; @@ -169,6 +169,7 @@ typedef struct _DEVICE_EXTENSION MOUSE_INPUT_DATA *MouseBuffer; ULONG MouseInBuffer; USHORT MouseButtonState; + ULARGE_INTEGER MousePacketStartTime; UCHAR MouseLogiBuffer[3]; UCHAR MouseLogitechID; diff --git a/reactos/drivers/input/i8042prt/keyboard.c b/reactos/drivers/input/i8042prt/keyboard.c index abee94475e4..41a853d283e 100644 --- a/reactos/drivers/input/i8042prt/keyboard.c +++ b/reactos/drivers/input/i8042prt/keyboard.c @@ -113,7 +113,7 @@ BOOLEAN STDCALL I8042InterruptServiceKbd(struct _KINTERRUPT *Interrupt, } while (Iterations < DevExt->Settings.PollStatusIterations); if (STATUS_SUCCESS != Status) { - DPRINT1("Spurious I8042 interrupt\n"); + DPRINT("Spurious I8042 interrupt\n"); return FALSE; } diff --git a/reactos/drivers/input/i8042prt/mouse.c b/reactos/drivers/input/i8042prt/mouse.c index f2f82fd3ca4..f7875748265 100644 --- a/reactos/drivers/input/i8042prt/mouse.c +++ b/reactos/drivers/input/i8042prt/mouse.c @@ -45,6 +45,39 @@ NTSTATUS STDCALL I8042SynchWritePortMouse(PVOID Context, WaitForAck); } +/* Test if packets are taking too long to come in. If they do, we + * might have gotten out of sync and should just drop what we have. + * + * If we want to be totally right, we'd also have to keep a count of + * errors, and totally reset the mouse after too much of them (can + * happen if the user is using a KVM switch and an OS on another port + * resets the mouse, or if the user hotplugs the mouse, or if we're just + * generally unlucky). Also note the input parsing routine where we + * drop invalid input packets. + */ +static VOID STDCALL I8042MouseInputTestTimeout(PDEVICE_EXTENSION DevExt) +{ + ULARGE_INTEGER Now; + + if (DevExt->MouseState == MouseExpectingACK || + DevExt->MouseState == MouseResetting) + return; + + Now.QuadPart = KeQueryInterruptTime(); + + if (DevExt->MouseState != MouseIdle) { + /* Check if the last byte came too long ago */ + if (Now.QuadPart - DevExt->MousePacketStartTime.QuadPart > + DevExt->Settings.MouseSynchIn100ns) { + DPRINT1("Mouse input packet timeout\n"); + DevExt->MouseState = MouseIdle; + } + } + + if (DevExt->MouseState == MouseIdle) + DevExt->MousePacketStartTime.QuadPart = Now.QuadPart; +} + /* * Call the customization hook. The Ret2 parameter is about wether * we should go on with the interrupt. The return value is what @@ -301,7 +334,7 @@ BOOLEAN STDCALL I8042MouseResetIsr(PDEVICE_EXTENSION DevExt, case ExpectingFinalResolutionACK: I8042IsrWritePortMouse(DevExt, DevExt->Settings.MouseResolution & 0xff); - DPRINT1("%x\n", DevExt->Settings.MouseResolution); + DPRINT("%x\n", DevExt->Settings.MouseResolution); DevExt->MouseResetState = ExpectingFinalResolutionValueACK; return TRUE; case ExpectingFinalResolutionValueACK: @@ -517,6 +550,8 @@ BOOLEAN STDCALL I8042InterruptServiceMouse(struct _KINTERRUPT *Interrupt, return TRUE; } + I8042MouseInputTestTimeout(DevExt); + if (I8042MouseResetIsr(DevExt, PortStatus, &Output)) { DPRINT("Handled by ResetIsr or hooked Isr\n"); if (NoChange != DevExt->MouseTimeoutState) { diff --git a/reactos/drivers/net/afd/afd/info.c b/reactos/drivers/net/afd/afd/info.c index 4518e3ba768..6efb4109757 100644 --- a/reactos/drivers/net/afd/afd/info.c +++ b/reactos/drivers/net/afd/afd/info.c @@ -141,7 +141,7 @@ AfdGetSockOrPeerName( PDEVICE_OBJECT DeviceObject, PIRP Irp, } /* MmUnlockPages( Mdl ); */ - IoFreeMdl( Mdl ); + /* IoFreeMdl( Mdl ); */ } else { Status = STATUS_INSUFFICIENT_RESOURCES; } diff --git a/reactos/drivers/net/ndis/include/miniport.h b/reactos/drivers/net/ndis/include/miniport.h index d0dfab89879..3065ecf4a4c 100644 --- a/reactos/drivers/net/ndis/include/miniport.h +++ b/reactos/drivers/net/ndis/include/miniport.h @@ -10,6 +10,7 @@ #include +struct _ADAPTER_BINDING; typedef struct _HARDWARE_ADDRESS { union { @@ -77,9 +78,9 @@ typedef struct _LOGICAL_ADAPTER KDPC MiniportDpc; /* DPC routine for adapter */ BOOLEAN MiniportBusy; /* A MiniportXxx routine is executing */ ULONG WorkQueueLevel; /* Number of used work item buffers */ - NDIS_MINIPORT_WORK_ITEM WorkQueue[NDIS_MINIPORT_WORK_QUEUE_SIZE]; - PNDIS_MINIPORT_WORK_ITEM WorkQueueHead; /* Head of work queue */ - PNDIS_MINIPORT_WORK_ITEM WorkQueueTail; /* Tail of work queue */ + INTERNAL_NDIS_MINIPORT_WORK_ITEM WorkQueue[NDIS_MINIPORT_WORK_QUEUE_SIZE]; + PINTERNAL_NDIS_MINIPORT_WORK_ITEM WorkQueueHead; /* Head of work queue */ + PINTERNAL_NDIS_MINIPORT_WORK_ITEM WorkQueueTail; /* Tail of work queue */ LIST_ENTRY ListEntry; /* Entry on global list */ LIST_ENTRY MiniportListEntry; /* Entry on miniport driver list */ LIST_ENTRY ProtocolListHead; /* List of bound protocols */ @@ -145,7 +146,7 @@ MiniQueryInformation( NDIS_STATUS FASTCALL MiniQueueWorkItem( - PLOGICAL_ADAPTER Adapter, + struct _ADAPTER_BINDING *AdapterBinding, NDIS_WORK_ITEM_TYPE WorkItemType, PVOID WorkItemContext); @@ -153,12 +154,13 @@ NDIS_STATUS FASTCALL MiniDequeueWorkItem( PLOGICAL_ADAPTER Adapter, + struct _ADAPTER_BINDING **AdapterBinding, NDIS_WORK_ITEM_TYPE *WorkItemType, PVOID *WorkItemContext); NDIS_STATUS MiniDoRequest( - PLOGICAL_ADAPTER Adapter, + struct _ADAPTER_BINDING *AdapterBinding, PNDIS_REQUEST NdisRequest); BOOLEAN diff --git a/reactos/drivers/net/ndis/include/ndissys.h b/reactos/drivers/net/ndis/include/ndissys.h index 5f385237e9c..ca55c9b5d27 100644 --- a/reactos/drivers/net/ndis/include/ndissys.h +++ b/reactos/drivers/net/ndis/include/ndissys.h @@ -27,6 +27,14 @@ typedef struct _ATM_ADDRESS *PATM_ADDRESS; #include #endif /* _MSC_VER */ +struct _ADAPTER_BINDING; + +typedef struct _INTERNAL_NDIS_MINIPORT_WORK_ITEM { + SINGLE_LIST_ENTRY Link; + struct _ADAPTER_BINDING *AdapterBinding; + NDIS_MINIPORT_WORK_ITEM RealWorkItem; +} INTERNAL_NDIS_MINIPORT_WORK_ITEM, *PINTERNAL_NDIS_MINIPORT_WORK_ITEM; + #include "miniport.h" #include "protocol.h" diff --git a/reactos/drivers/net/ndis/ndis/miniport.c b/reactos/drivers/net/ndis/ndis/miniport.c index 4115adc066b..3f5389c18dd 100644 --- a/reactos/drivers/net/ndis/ndis/miniport.c +++ b/reactos/drivers/net/ndis/ndis/miniport.c @@ -327,6 +327,23 @@ MiniResetComplete( } + +VOID STDCALL +MiniRequestComplete( + IN PADAPTER_BINDING AdapterBinding, + IN PNDIS_REQUEST Request, + IN NDIS_STATUS Status) +{ + NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n")); + + if( AdapterBinding->ProtocolBinding->Chars.RequestCompleteHandler ) { + (*AdapterBinding->ProtocolBinding->Chars.RequestCompleteHandler)( + AdapterBinding->NdisOpenBlock.NdisCommonOpenBlock.ProtocolBindingContext, + Request, + Status); + } +} + VOID STDCALL MiniSendComplete( IN NDIS_HANDLE MiniportAdapterHandle, @@ -615,7 +632,7 @@ MiniQueryInformation( NDIS_STATUS FASTCALL MiniQueueWorkItem( - PLOGICAL_ADAPTER Adapter, + PADAPTER_BINDING AdapterBinding, NDIS_WORK_ITEM_TYPE WorkItemType, PVOID WorkItemContext) /* @@ -630,49 +647,51 @@ MiniQueueWorkItem( * Status of operation */ { - PNDIS_MINIPORT_WORK_ITEM Item; - - NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); - - ASSERT(Adapter); - ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); + PINTERNAL_NDIS_MINIPORT_WORK_ITEM Item; + PLOGICAL_ADAPTER Adapter = AdapterBinding->Adapter; + NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); + + ASSERT(Adapter); + ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); + #if 0 - if (Adapter->WorkQueueLevel < NDIS_MINIPORT_WORK_QUEUE_SIZE - 1) + if (Adapter->WorkQueueLevel < NDIS_MINIPORT_WORK_QUEUE_SIZE - 1) { - Item = &Adapter->WorkQueue[Adapter->WorkQueueLevel]; - Adapter->WorkQueueLevel++; + Item = &Adapter->WorkQueue[Adapter->WorkQueueLevel]; + Adapter->WorkQueueLevel++; } - else + else #endif { - Item = ExAllocatePool(NonPagedPool, sizeof(NDIS_MINIPORT_WORK_ITEM)); - if (Item == NULL) + Item = ExAllocatePool(NonPagedPool, sizeof(INTERNAL_NDIS_MINIPORT_WORK_ITEM)); + if (Item == NULL) { - NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return NDIS_STATUS_RESOURCES; + NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return NDIS_STATUS_RESOURCES; } } - - Item->WorkItemType = WorkItemType; - Item->WorkItemContext = WorkItemContext; - - /* safe due to adapter lock held */ - Item->Link.Next = NULL; - if (!Adapter->WorkQueueHead) + + Item->AdapterBinding = AdapterBinding; + Item->RealWorkItem.WorkItemType = WorkItemType; + Item->RealWorkItem.WorkItemContext = WorkItemContext; + + /* safe due to adapter lock held */ + Item->Link.Next = NULL; + if (!Adapter->WorkQueueHead) { - Adapter->WorkQueueHead = Item; - Adapter->WorkQueueTail = Item; + Adapter->WorkQueueHead = Item; + Adapter->WorkQueueTail = Item; } - else + else { - Adapter->WorkQueueTail->Link.Next = (PSINGLE_LIST_ENTRY)Item; - Adapter->WorkQueueTail = Item; + Adapter->WorkQueueTail->Link.Next = (PSINGLE_LIST_ENTRY)Item; + Adapter->WorkQueueTail = Item; } - - KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL); - - return NDIS_STATUS_SUCCESS; + + KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL); + + return NDIS_STATUS_SUCCESS; } @@ -680,12 +699,14 @@ NDIS_STATUS FASTCALL MiniDequeueWorkItem( PLOGICAL_ADAPTER Adapter, + PADAPTER_BINDING *AdapterBinding, NDIS_WORK_ITEM_TYPE *WorkItemType, PVOID *WorkItemContext) /* * FUNCTION: Dequeues a work item from the work queue of a logical adapter * ARGUMENTS: * Adapter = Pointer to the logical adapter object to dequeue work item from + * AdapterBinding = Address of buffer for adapter binding for this request * WorkItemType = Address of buffer for work item type * WorkItemContext = Address of buffer for pointer to context information * NOTES: @@ -694,52 +715,55 @@ MiniDequeueWorkItem( * Status of operation */ { - PNDIS_MINIPORT_WORK_ITEM Item; - - NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); - - Item = Adapter->WorkQueueHead; - - if (Item) + PINTERNAL_NDIS_MINIPORT_WORK_ITEM Item; + + NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); + + Item = Adapter->WorkQueueHead; + + if (Item) { - /* safe due to adapter lock held */ - Adapter->WorkQueueHead = (PNDIS_MINIPORT_WORK_ITEM)Item->Link.Next; - - if (Item == Adapter->WorkQueueTail) - Adapter->WorkQueueTail = NULL; - - *WorkItemType = Item->WorkItemType; - *WorkItemContext = Item->WorkItemContext; - - ExFreePool(Item); - - return NDIS_STATUS_SUCCESS; + /* safe due to adapter lock held */ + Adapter->WorkQueueHead = (PINTERNAL_NDIS_MINIPORT_WORK_ITEM)Item->Link.Next; + + if (Item == Adapter->WorkQueueTail) + Adapter->WorkQueueTail = NULL; + + *AdapterBinding = Item->AdapterBinding; + *WorkItemType = Item->RealWorkItem.WorkItemType; + *WorkItemContext = Item->RealWorkItem.WorkItemContext; + + ExFreePool(Item); + + return NDIS_STATUS_SUCCESS; } - - return NDIS_STATUS_FAILURE; + + return NDIS_STATUS_FAILURE; } NDIS_STATUS MiniDoRequest( - PLOGICAL_ADAPTER Adapter, + PADAPTER_BINDING AdapterBinding, PNDIS_REQUEST NdisRequest) /* * FUNCTION: Sends a request to a miniport * ARGUMENTS: - * Adapter = Pointer to logical adapter object - * NdisRequest = Pointer to NDIS request structure describing request + * AdapterBinding = Pointer to binding used in the request + * NdisRequest = Pointer to NDIS request structure describing request * RETURNS: * Status of operation */ { - NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n")); + PLOGICAL_ADAPTER Adapter = AdapterBinding->Adapter; - Adapter->NdisMiniportBlock.MediaRequest = NdisRequest; - - switch (NdisRequest->RequestType) + NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n")); + + Adapter->NdisMiniportBlock.MediaRequest = NdisRequest; + + switch (NdisRequest->RequestType) { - case NdisRequestQueryInformation: + case NdisRequestQueryInformation: return (*Adapter->Miniport->Chars.QueryInformationHandler)( Adapter->NdisMiniportBlock.MiniportAdapterContext, NdisRequest->DATA.QUERY_INFORMATION.Oid, @@ -748,8 +772,8 @@ MiniDoRequest( (PULONG)&NdisRequest->DATA.QUERY_INFORMATION.BytesWritten, (PULONG)&NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded); break; - - case NdisRequestSetInformation: + + case NdisRequestSetInformation: return (*Adapter->Miniport->Chars.SetInformationHandler)( Adapter->NdisMiniportBlock.MiniportAdapterContext, NdisRequest->DATA.SET_INFORMATION.Oid, @@ -758,8 +782,8 @@ MiniDoRequest( (PULONG)&NdisRequest->DATA.SET_INFORMATION.BytesRead, (PULONG)&NdisRequest->DATA.SET_INFORMATION.BytesNeeded); break; - - default: + + default: return NDIS_STATUS_FAILURE; } } @@ -800,11 +824,14 @@ VOID STDCALL MiniportDpc( NDIS_STATUS NdisStatus; PVOID WorkItemContext; NDIS_WORK_ITEM_TYPE WorkItemType; + PADAPTER_BINDING AdapterBinding; PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(DeferredContext); NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n")); - NdisStatus = MiniDequeueWorkItem(Adapter, &WorkItemType, &WorkItemContext); + NdisStatus = + MiniDequeueWorkItem + (Adapter, &AdapterBinding, &WorkItemType, &WorkItemContext); if (NdisStatus == NDIS_STATUS_SUCCESS) { @@ -873,7 +900,7 @@ VOID STDCALL MiniportDpc( break; case NdisWorkItemRequest: - NdisStatus = MiniDoRequest(Adapter, (PNDIS_REQUEST)WorkItemContext); + NdisStatus = MiniDoRequest(AdapterBinding, (PNDIS_REQUEST)WorkItemContext); if (NdisStatus == NDIS_STATUS_PENDING) break; @@ -882,10 +909,12 @@ VOID STDCALL MiniportDpc( { case NdisRequestQueryInformation: NdisMQueryInformationComplete((NDIS_HANDLE)Adapter, NdisStatus); + MiniRequestComplete( AdapterBinding, (PNDIS_REQUEST)WorkItemContext, NdisStatus ); break; case NdisRequestSetInformation: NdisMSetInformationComplete((NDIS_HANDLE)Adapter, NdisStatus); + MiniRequestComplete( AdapterBinding, (PNDIS_REQUEST)WorkItemContext, NdisStatus ); break; default: diff --git a/reactos/drivers/net/ndis/ndis/protocol.c b/reactos/drivers/net/ndis/ndis/protocol.c index c2d5d75305b..da703d4bab7 100644 --- a/reactos/drivers/net/ndis/ndis/protocol.c +++ b/reactos/drivers/net/ndis/ndis/protocol.c @@ -158,7 +158,7 @@ ProRequest( /* MiniQueueWorkItem must be called at IRQL >= DISPATCH_LEVEL */ if (QueueWorkItem) { - MiniQueueWorkItem(Adapter, NdisWorkItemRequest, (PVOID)NdisRequest); + MiniQueueWorkItem(AdapterBinding, NdisWorkItemRequest, (PVOID)NdisRequest); KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql); return NDIS_STATUS_PENDING; } @@ -169,7 +169,7 @@ ProRequest( /* TODO (?): move the irql raise into MiniDoRequest */ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); { - NdisStatus = MiniDoRequest(Adapter, NdisRequest); + NdisStatus = MiniDoRequest(AdapterBinding, NdisRequest); NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n")); KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock); @@ -278,7 +278,7 @@ ProSend( if (QueueWorkItem) { - MiniQueueWorkItem(Adapter, NdisWorkItemSendLoopback, (PVOID)Packet); + MiniQueueWorkItem(AdapterBinding, NdisWorkItemSendLoopback, (PVOID)Packet); return NDIS_STATUS_PENDING; } @@ -315,7 +315,7 @@ ProSend( /* This is a normal send packet, not a loopback packet. */ if (QueueWorkItem) { - MiniQueueWorkItem(Adapter, NdisWorkItemSend, (PVOID)Packet); + MiniQueueWorkItem(AdapterBinding, NdisWorkItemSend, (PVOID)Packet); NDIS_DbgPrint(MAX_TRACE, ("Queued a work item and returning\n")); return NDIS_STATUS_PENDING; } diff --git a/reactos/drivers/net/tcpip/tcpip/main.c b/reactos/drivers/net/tcpip/tcpip/main.c index ee328a50da1..bd2d6d94623 100644 --- a/reactos/drivers/net/tcpip/tcpip/main.c +++ b/reactos/drivers/net/tcpip/tcpip/main.c @@ -9,7 +9,7 @@ */ #include "precomp.h" -//#define NDEBUG +#define NDEBUG #ifndef NDEBUG DWORD DebugTraceLevel = DEBUG_ULTRA & ~(DEBUG_LOCK | DEBUG_PBUFFER); diff --git a/reactos/drivers/storage/cdrom/cdrom.c b/reactos/drivers/storage/cdrom/cdrom.c index 51f85351864..e8baab68cc0 100644 --- a/reactos/drivers/storage/cdrom/cdrom.c +++ b/reactos/drivers/storage/cdrom/cdrom.c @@ -391,17 +391,10 @@ static VOID CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension, IN ULONG DeviceNumber) { - WCHAR NameBuffer[MAX_PATH]; - UNICODE_STRING Name; - swprintf (NameBuffer, - L"\\Device\\MediaChangeEvent%lu", - DeviceNumber); - RtlInitUnicodeString (&Name, - NameBuffer); DeviceExtension->MediaChangeEvent = - IoCreateSynchronizationEvent (&Name, + IoCreateSynchronizationEvent (NULL, &DeviceExtension->MediaChangeEventHandle); KeClearEvent (DeviceExtension->MediaChangeEvent); diff --git a/reactos/drivers/storage/disk/disk.c b/reactos/drivers/storage/disk/disk.c index 3ffb6ab7310..9b2cf1d5593 100644 --- a/reactos/drivers/storage/disk/disk.c +++ b/reactos/drivers/storage/disk/disk.c @@ -315,17 +315,8 @@ static VOID DiskClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension, IN ULONG DeviceNumber) { - WCHAR NameBuffer[MAX_PATH]; - UNICODE_STRING Name; - - swprintf (NameBuffer, - L"\\Device\\MediaChangeEvent%lu", - DeviceNumber); - RtlInitUnicodeString (&Name, - NameBuffer); - DeviceExtension->MediaChangeEvent = - IoCreateSynchronizationEvent (&Name, + IoCreateSynchronizationEvent (NULL, &DeviceExtension->MediaChangeEventHandle); KeClearEvent (DeviceExtension->MediaChangeEvent); diff --git a/reactos/drivers/usb/Makefile b/reactos/drivers/usb/Makefile index d389c4503d3..fb5210e9fd3 100644 --- a/reactos/drivers/usb/Makefile +++ b/reactos/drivers/usb/Makefile @@ -1,50 +1,50 @@ -# -# ReactOS USB Drivers -# - -PATH_TO_TOP = ../.. - -include $(PATH_TO_TOP)/rules.mak - -DRIVERS = usbport miniport/usbuhci miniport/usbehci miniport/usbohci usbhub usbd - -all: $(DRIVERS) - -depends: - -implib: $(DRIVERS:%=%_implib) - -clean: $(DRIVERS:%=%_clean) - -install: $(DRIVERS:%=%_install) - -bootcd: $(DRIVERS:%=%_bootcd) - -.PHONY: all depends implib clean install bootcd - - -# -# USB DRIVERS -# -$(DRIVERS): %: - $(MAKE) -C $* - -$(DRIVERS:%=%_implib): %_implib: - $(MAKE) -C $* implib - -$(DRIVERS:%=%_clean): %_clean: - $(MAKE) -C $* clean - -$(DRIVERS:%=%_install): %_install: - $(MAKE) -C $* install - -$(DRIVERS:%=%_bootcd): %_bootcd: - $(MAKE) -C $* bootcd - -.PHONY: $(DRIVERS) $(DRIVERS:%=%_implib) $(DRIVERS:%=%_clean) $(DRIVERS:%=%_install) $(DRIVERS:%=%_bootcd) - - -etags: - find . -name "*.[ch]" -print | etags --language=c - - -# EOF +# +# ReactOS USB Drivers +# + +PATH_TO_TOP = ../.. + +include $(PATH_TO_TOP)/rules.mak + +DRIVERS = usbport miniport/usbuhci miniport/usbehci miniport/usbohci usbhub usbd cromwell + +all: $(DRIVERS) + +depends: + +implib: $(DRIVERS:%=%_implib) + +clean: $(DRIVERS:%=%_clean) + +install: $(DRIVERS:%=%_install) + +bootcd: $(DRIVERS:%=%_bootcd) + +.PHONY: all depends implib clean install bootcd + + +# +# USB DRIVERS +# +$(DRIVERS): %: + $(MAKE) -C $* + +$(DRIVERS:%=%_implib): %_implib: + $(MAKE) -C $* implib + +$(DRIVERS:%=%_clean): %_clean: + $(MAKE) -C $* clean + +$(DRIVERS:%=%_install): %_install: + $(MAKE) -C $* install + +$(DRIVERS:%=%_bootcd): %_bootcd: + $(MAKE) -C $* bootcd + +.PHONY: $(DRIVERS) $(DRIVERS:%=%_implib) $(DRIVERS:%=%_clean) $(DRIVERS:%=%_install) $(DRIVERS:%=%_bootcd) + + +etags: + find . -name "*.[ch]" -print | etags --language=c - + +# EOF diff --git a/reactos/drivers/usb/cromwell/Makefile b/reactos/drivers/usb/cromwell/Makefile index 1f124735144..f2d4bf03902 100644 --- a/reactos/drivers/usb/cromwell/Makefile +++ b/reactos/drivers/usb/cromwell/Makefile @@ -1,50 +1,50 @@ -# -# ReactOS USB-Cromwell Drivers -# - -PATH_TO_TOP = ../../.. - -include $(PATH_TO_TOP)/rules.mak - -DRIVERS = core host uhci - -all: $(DRIVERS) - -depends: - -implib: $(DRIVERS:%=%_implib) - -clean: $(DRIVERS:%=%_clean) - -install: $(DRIVERS:%=%_install) - -bootcd: $(DRIVERS:%=%_bootcd) - -.PHONY: all depends implib clean install bootcd - - -# -# USB DRIVERS -# -$(DRIVERS): %: - $(MAKE) -C $* - -$(DRIVERS:%=%_implib): %_implib: - $(MAKE) -C $* implib - -$(DRIVERS:%=%_clean): %_clean: - $(MAKE) -C $* clean - -$(DRIVERS:%=%_install): %_install: - $(MAKE) -C $* install - -$(DRIVERS:%=%_bootcd): %_bootcd: - $(MAKE) -C $* bootcd - -.PHONY: $(DRIVERS) $(DRIVERS:%=%_implib) $(DRIVERS:%=%_clean) $(DRIVERS:%=%_install) $(DRIVERS:%=%_bootcd) - - -etags: - find . -name "*.[ch]" -print | etags --language=c - - -# EOF +# +# ReactOS USB-Cromwell Drivers +# + +PATH_TO_TOP = ../../.. + +include $(PATH_TO_TOP)/rules.mak + +DRIVERS = core host uhci + +all: $(DRIVERS) + +depends: + +implib: $(DRIVERS:%=%_implib) + +clean: $(DRIVERS:%=%_clean) + +install: $(DRIVERS:%=%_install) + +bootcd: $(DRIVERS:%=%_bootcd) + +.PHONY: all depends implib clean install bootcd + + +# +# USB DRIVERS +# +$(DRIVERS): %: + $(MAKE) -C $* + +$(DRIVERS:%=%_implib): %_implib: + $(MAKE) -C $* implib + +$(DRIVERS:%=%_clean): %_clean: + $(MAKE) -C $* clean + +$(DRIVERS:%=%_install): %_install: + $(MAKE) -C $* install + +$(DRIVERS:%=%_bootcd): %_bootcd: + $(MAKE) -C $* bootcd + +.PHONY: $(DRIVERS) $(DRIVERS:%=%_implib) $(DRIVERS:%=%_clean) $(DRIVERS:%=%_install) $(DRIVERS:%=%_bootcd) + + +etags: + find . -name "*.[ch]" -print | etags --language=c - + +# EOF diff --git a/reactos/drivers/usb/cromwell/core/buffer_simple.c b/reactos/drivers/usb/cromwell/core/buffer_simple.c index 7ac70ce30cb..b0c0470235d 100644 --- a/reactos/drivers/usb/cromwell/core/buffer_simple.c +++ b/reactos/drivers/usb/cromwell/core/buffer_simple.c @@ -1,42 +1,42 @@ -/* - * buffer_simple.c -- replacement for usb/core/buffer.c - * - * (c) Georg Acher, georg@acher.org - * - */ - -#include "../usb_wrapper.h" -#define __KERNEL__ -#define CONFIG_PCI -#include "hcd.h" - -/*------------------------------------------------------------------------*/ -int hcd_buffer_create (struct usb_hcd *hcd) -{ - return 0; -} -/*------------------------------------------------------------------------*/ -void hcd_buffer_destroy (struct usb_hcd *hcd) -{ -} -/*------------------------------------------------------------------------*/ -void *hcd_buffer_alloc ( - struct usb_bus *bus, - size_t size, - int mem_flags, - dma_addr_t *dma -) -{ - return kmalloc(size,0); -} -/*------------------------------------------------------------------------*/ -void hcd_buffer_free ( - struct usb_bus *bus, - size_t size, - void *addr, - dma_addr_t dma -) -{ - kfree(addr); -} - +/* + * buffer_simple.c -- replacement for usb/core/buffer.c + * + * (c) Georg Acher, georg@acher.org + * + */ + +#include "../usb_wrapper.h" +#define __KERNEL__ +#define CONFIG_PCI +#include "hcd.h" + +/*------------------------------------------------------------------------*/ +int hcd_buffer_create (struct usb_hcd *hcd) +{ + return 0; +} +/*------------------------------------------------------------------------*/ +void hcd_buffer_destroy (struct usb_hcd *hcd) +{ +} +/*------------------------------------------------------------------------*/ +void *hcd_buffer_alloc ( + struct usb_bus *bus, + size_t size, + int mem_flags, + dma_addr_t *dma +) +{ + return kmalloc(size,0); +} +/*------------------------------------------------------------------------*/ +void hcd_buffer_free ( + struct usb_bus *bus, + size_t size, + void *addr, + dma_addr_t dma +) +{ + kfree(addr); +} + diff --git a/reactos/drivers/usb/cromwell/core/config.c b/reactos/drivers/usb/cromwell/core/config.c index 7d400e982d8..1c40bbd1c95 100644 --- a/reactos/drivers/usb/cromwell/core/config.c +++ b/reactos/drivers/usb/cromwell/core/config.c @@ -1,508 +1,508 @@ -#if 0 -#include -#include -#include -#include -#include -#else -#include "../usb_wrapper.h" -#endif - -#define USB_MAXALTSETTING 128 /* Hard limit */ -#define USB_MAXENDPOINTS 30 /* Hard limit */ - -/* these maximums are arbitrary */ -#define USB_MAXCONFIG 8 -#define USB_ALTSETTINGALLOC 4 -#define USB_MAXINTERFACES 32 - -static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char *buffer, int size) -{ - struct usb_descriptor_header *header; - unsigned char *begin; - int parsed = 0, len, numskipped; - - header = (struct usb_descriptor_header *)buffer; - - /* Everything should be fine being passed into here, but we sanity */ - /* check JIC */ - if (header->bLength > size) { - err("ran out of descriptors parsing"); - return -1; - } - - if (header->bDescriptorType != USB_DT_ENDPOINT) { - warn("unexpected descriptor 0x%X, expecting endpoint, 0x%X", - header->bDescriptorType, USB_DT_ENDPOINT); - return parsed; - } - - if (header->bLength == USB_DT_ENDPOINT_AUDIO_SIZE) - memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_AUDIO_SIZE); - else - memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_SIZE); - - le16_to_cpus(&endpoint->desc.wMaxPacketSize); - - buffer += header->bLength; - size -= header->bLength; - parsed += header->bLength; - - /* Skip over the rest of the Class Specific or Vendor Specific */ - /* descriptors */ - begin = buffer; - numskipped = 0; - while (size >= sizeof(struct usb_descriptor_header)) { - header = (struct usb_descriptor_header *)buffer; - - if (header->bLength < 2) { - err("invalid descriptor length of %d", header->bLength); - return -1; - } - - /* If we find another "proper" descriptor then we're done */ - if ((header->bDescriptorType == USB_DT_ENDPOINT) || - (header->bDescriptorType == USB_DT_INTERFACE) || - (header->bDescriptorType == USB_DT_CONFIG) || - (header->bDescriptorType == USB_DT_DEVICE)) - break; - - dbg("skipping descriptor 0x%X", - header->bDescriptorType); - numskipped++; - - buffer += header->bLength; - size -= header->bLength; - parsed += header->bLength; - } - if (numskipped) - dbg("skipped %d class/vendor specific endpoint descriptors", numskipped); - - /* Copy any unknown descriptors into a storage area for drivers */ - /* to later parse */ - len = (int)(buffer - begin); - if (!len) { - endpoint->extra = NULL; - endpoint->extralen = 0; - return parsed; - } - - endpoint->extra = kmalloc(len, GFP_KERNEL); - - if (!endpoint->extra) { - err("couldn't allocate memory for endpoint extra descriptors"); - endpoint->extralen = 0; - return parsed; - } - - memcpy(endpoint->extra, begin, len); - endpoint->extralen = len; - - return parsed; -} - -static int usb_parse_interface(struct usb_interface *interface, unsigned char *buffer, int size) -{ - int i, len, numskipped, retval, parsed = 0; - struct usb_descriptor_header *header; - struct usb_host_interface *ifp; - unsigned char *begin; - - interface->act_altsetting = 0; - interface->num_altsetting = 0; - interface->max_altsetting = USB_ALTSETTINGALLOC; - device_initialize(&interface->dev); - - interface->altsetting = kmalloc(sizeof(*interface->altsetting) * interface->max_altsetting, - GFP_KERNEL); - - if (!interface->altsetting) { - err("couldn't kmalloc interface->altsetting"); - return -1; - } - - while (size > 0) { - struct usb_interface_descriptor *d; - - if (interface->num_altsetting >= interface->max_altsetting) { - struct usb_host_interface *ptr; - int oldmas; - - oldmas = interface->max_altsetting; - interface->max_altsetting += USB_ALTSETTINGALLOC; - if (interface->max_altsetting > USB_MAXALTSETTING) { - warn("too many alternate settings (incr %d max %d)\n", - USB_ALTSETTINGALLOC, USB_MAXALTSETTING); - return -1; - } - - ptr = kmalloc(sizeof(*ptr) * interface->max_altsetting, GFP_KERNEL); - if (ptr == NULL) { - err("couldn't kmalloc interface->altsetting"); - return -1; - } - memcpy(ptr, interface->altsetting, sizeof(*interface->altsetting) * oldmas); - kfree(interface->altsetting); - interface->altsetting = ptr; - } - - ifp = interface->altsetting + interface->num_altsetting; - ifp->endpoint = NULL; - ifp->extra = NULL; - ifp->extralen = 0; - interface->num_altsetting++; - - memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE); - - /* Skip over the interface */ - buffer += ifp->desc.bLength; - parsed += ifp->desc.bLength; - size -= ifp->desc.bLength; - - begin = buffer; - numskipped = 0; - - /* Skip over any interface, class or vendor descriptors */ - while (size >= sizeof(struct usb_descriptor_header)) { - header = (struct usb_descriptor_header *)buffer; - - if (header->bLength < 2) { - err("invalid descriptor length of %d", header->bLength); - return -1; - } - - /* If we find another "proper" descriptor then we're done */ - if ((header->bDescriptorType == USB_DT_INTERFACE) || - (header->bDescriptorType == USB_DT_ENDPOINT) || - (header->bDescriptorType == USB_DT_CONFIG) || - (header->bDescriptorType == USB_DT_DEVICE)) - break; - - numskipped++; - - buffer += header->bLength; - parsed += header->bLength; - size -= header->bLength; - } - - if (numskipped) - dbg("skipped %d class/vendor specific interface descriptors", numskipped); - - /* Copy any unknown descriptors into a storage area for */ - /* drivers to later parse */ - len = (int)(buffer - begin); - if (len) { - ifp->extra = kmalloc(len, GFP_KERNEL); - - if (!ifp->extra) { - err("couldn't allocate memory for interface extra descriptors"); - ifp->extralen = 0; - return -1; - } - memcpy(ifp->extra, begin, len); - ifp->extralen = len; - } - - /* Did we hit an unexpected descriptor? */ - header = (struct usb_descriptor_header *)buffer; - if ((size >= sizeof(struct usb_descriptor_header)) && - ((header->bDescriptorType == USB_DT_CONFIG) || - (header->bDescriptorType == USB_DT_DEVICE))) - return parsed; - - if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) { - warn("too many endpoints"); - return -1; - } - - ifp->endpoint = (struct usb_host_endpoint *) - kmalloc(ifp->desc.bNumEndpoints * - sizeof(struct usb_host_endpoint), GFP_KERNEL); - if (!ifp->endpoint) { - err("out of memory"); - return -1; - } - - memset(ifp->endpoint, 0, ifp->desc.bNumEndpoints * - sizeof(struct usb_host_endpoint)); - - for (i = 0; i < ifp->desc.bNumEndpoints; i++) { - header = (struct usb_descriptor_header *)buffer; - - if (header->bLength > size) { - err("ran out of descriptors parsing"); - return -1; - } - - retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size); - if (retval < 0) - return retval; - - buffer += retval; - parsed += retval; - size -= retval; - } - - /* We check to see if it's an alternate to this one */ - d = (struct usb_interface_descriptor *)buffer; - if (size < USB_DT_INTERFACE_SIZE - || d->bDescriptorType != USB_DT_INTERFACE - || !d->bAlternateSetting) - return parsed; - } - - return parsed; -} - -int usb_parse_configuration(struct usb_host_config *config, char *buffer) -{ - int i, retval, size; - struct usb_descriptor_header *header; - - memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); - le16_to_cpus(&config->desc.wTotalLength); - size = config->desc.wTotalLength; - - if (config->desc.bNumInterfaces > USB_MAXINTERFACES) { - warn("too many interfaces"); - return -1; - } - - config->interface = (struct usb_interface *) - kmalloc(config->desc.bNumInterfaces * - sizeof(struct usb_interface), GFP_KERNEL); - dbg("kmalloc IF %p, numif %i", config->interface, config->desc.bNumInterfaces); - if (!config->interface) { - err("out of memory"); - return -1; - } - - memset(config->interface, 0, - config->desc.bNumInterfaces * sizeof(struct usb_interface)); - - buffer += config->desc.bLength; - size -= config->desc.bLength; - - config->extra = NULL; - config->extralen = 0; - - for (i = 0; i < config->desc.bNumInterfaces; i++) { - int numskipped, len; - char *begin; - - /* Skip over the rest of the Class Specific or Vendor */ - /* Specific descriptors */ - begin = buffer; - numskipped = 0; - while (size >= sizeof(struct usb_descriptor_header)) { - header = (struct usb_descriptor_header *)buffer; - - if ((header->bLength > size) || (header->bLength < 2)) { - err("invalid descriptor length of %d", header->bLength); - return -1; - } - - /* If we find another "proper" descriptor then we're done */ - if ((header->bDescriptorType == USB_DT_ENDPOINT) || - (header->bDescriptorType == USB_DT_INTERFACE) || - (header->bDescriptorType == USB_DT_CONFIG) || - (header->bDescriptorType == USB_DT_DEVICE)) - break; - - dbg("skipping descriptor 0x%X", header->bDescriptorType); - numskipped++; - - buffer += header->bLength; - size -= header->bLength; - } - if (numskipped) - dbg("skipped %d class/vendor specific endpoint descriptors", numskipped); - - /* Copy any unknown descriptors into a storage area for */ - /* drivers to later parse */ - len = (int)(buffer - begin); - if (len) { - if (config->extralen) { - warn("extra config descriptor"); - } else { - config->extra = kmalloc(len, GFP_KERNEL); - if (!config->extra) { - err("couldn't allocate memory for config extra descriptors"); - config->extralen = 0; - return -1; - } - - memcpy(config->extra, begin, len); - config->extralen = len; - } - } - - retval = usb_parse_interface(config->interface + i, buffer, size); - if (retval < 0) - return retval; - - buffer += retval; - size -= retval; - } - - return size; -} - -// hub-only!! ... and only exported for reset/reinit path. -// otherwise used internally on disconnect/destroy path -void usb_destroy_configuration(struct usb_device *dev) -{ - int c, i, j, k; - - if (!dev->config) - return; - - if (dev->rawdescriptors) { - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) - kfree(dev->rawdescriptors[i]); - - kfree(dev->rawdescriptors); - } - - for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { - struct usb_host_config *cf = &dev->config[c]; - - if (!cf->interface) - break; - - for (i = 0; i < cf->desc.bNumInterfaces; i++) { - struct usb_interface *ifp = - &cf->interface[i]; - - if (!ifp->altsetting) - break; - - for (j = 0; j < ifp->num_altsetting; j++) { - struct usb_host_interface *as = - &ifp->altsetting[j]; - - if(as->extra) { - kfree(as->extra); - } - - if (!as->endpoint) - break; - - for(k = 0; k < as->desc.bNumEndpoints; k++) { - if(as->endpoint[k].extra) { - kfree(as->endpoint[k].extra); - } - } - kfree(as->endpoint); - } - - kfree(ifp->altsetting); - } - kfree(cf->interface); - } - kfree(dev->config); -} - - -// hub-only!! ... and only in reset path, or usb_new_device() -// (used by real hubs and virtual root hubs) -int usb_get_configuration(struct usb_device *dev) -{ - int result; - unsigned int cfgno, length; - unsigned char *buffer; - unsigned char *bigbuffer; - struct usb_config_descriptor *desc; - - if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) { - warn("too many configurations"); - return -EINVAL; - } - - if (dev->descriptor.bNumConfigurations < 1) { - warn("not enough configurations"); - return -EINVAL; - } - - dev->config = (struct usb_host_config *) - kmalloc(dev->descriptor.bNumConfigurations * - sizeof(struct usb_host_config), GFP_KERNEL); - if (!dev->config) { - err("out of memory"); - return -ENOMEM; - } - memset(dev->config, 0, dev->descriptor.bNumConfigurations * - sizeof(struct usb_host_config)); - - dev->rawdescriptors = (char **)kmalloc(sizeof(char *) * - dev->descriptor.bNumConfigurations, GFP_KERNEL); - if (!dev->rawdescriptors) { - err("out of memory"); - return -ENOMEM; - } - - buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - err("unable to allocate memory for configuration descriptors"); - return -ENOMEM; - } - desc = (struct usb_config_descriptor *)buffer; - - for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) { - /* We grab the first 8 bytes so we know how long the whole */ - /* configuration is */ - result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8); - if (result < 8) { - if (result < 0) - err("unable to get descriptor"); - else { - err("config descriptor too short (expected %i, got %i)", 8, result); - result = -EINVAL; - } - goto err; - } - - /* Get the full buffer */ - length = le16_to_cpu(desc->wTotalLength); - - bigbuffer = kmalloc(length, GFP_KERNEL); - if (!bigbuffer) { - err("unable to allocate memory for configuration descriptors"); - result = -ENOMEM; - goto err; - } - - /* Now that we know the length, get the whole thing */ - result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length); - if (result < 0) { - err("couldn't get all of config descriptors"); - kfree(bigbuffer); - goto err; - } - - if (result < length) { - err("config descriptor too short (expected %i, got %i)", length, result); - result = -EINVAL; - kfree(bigbuffer); - goto err; - } - - dev->rawdescriptors[cfgno] = bigbuffer; - - result = usb_parse_configuration(&dev->config[cfgno], bigbuffer); - if (result > 0) - dbg("descriptor data left"); - else if (result < 0) { - result = -EINVAL; - goto err; - } - } - - kfree(buffer); - return 0; -err: - kfree(buffer); - dev->descriptor.bNumConfigurations = cfgno; - return result; -} - +#if 0 +#include +#include +#include +#include +#include +#else +#include "../usb_wrapper.h" +#endif + +#define USB_MAXALTSETTING 128 /* Hard limit */ +#define USB_MAXENDPOINTS 30 /* Hard limit */ + +/* these maximums are arbitrary */ +#define USB_MAXCONFIG 8 +#define USB_ALTSETTINGALLOC 4 +#define USB_MAXINTERFACES 32 + +static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char *buffer, int size) +{ + struct usb_descriptor_header *header; + unsigned char *begin; + int parsed = 0, len, numskipped; + + header = (struct usb_descriptor_header *)buffer; + + /* Everything should be fine being passed into here, but we sanity */ + /* check JIC */ + if (header->bLength > size) { + err("ran out of descriptors parsing"); + return -1; + } + + if (header->bDescriptorType != USB_DT_ENDPOINT) { + warn("unexpected descriptor 0x%X, expecting endpoint, 0x%X", + header->bDescriptorType, USB_DT_ENDPOINT); + return parsed; + } + + if (header->bLength == USB_DT_ENDPOINT_AUDIO_SIZE) + memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_AUDIO_SIZE); + else + memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_SIZE); + + le16_to_cpus(&endpoint->desc.wMaxPacketSize); + + buffer += header->bLength; + size -= header->bLength; + parsed += header->bLength; + + /* Skip over the rest of the Class Specific or Vendor Specific */ + /* descriptors */ + begin = buffer; + numskipped = 0; + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength < 2) { + err("invalid descriptor length of %d", header->bLength); + return -1; + } + + /* If we find another "proper" descriptor then we're done */ + if ((header->bDescriptorType == USB_DT_ENDPOINT) || + (header->bDescriptorType == USB_DT_INTERFACE) || + (header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE)) + break; + + dbg("skipping descriptor 0x%X", + header->bDescriptorType); + numskipped++; + + buffer += header->bLength; + size -= header->bLength; + parsed += header->bLength; + } + if (numskipped) + dbg("skipped %d class/vendor specific endpoint descriptors", numskipped); + + /* Copy any unknown descriptors into a storage area for drivers */ + /* to later parse */ + len = (int)(buffer - begin); + if (!len) { + endpoint->extra = NULL; + endpoint->extralen = 0; + return parsed; + } + + endpoint->extra = kmalloc(len, GFP_KERNEL); + + if (!endpoint->extra) { + err("couldn't allocate memory for endpoint extra descriptors"); + endpoint->extralen = 0; + return parsed; + } + + memcpy(endpoint->extra, begin, len); + endpoint->extralen = len; + + return parsed; +} + +static int usb_parse_interface(struct usb_interface *interface, unsigned char *buffer, int size) +{ + int i, len, numskipped, retval, parsed = 0; + struct usb_descriptor_header *header; + struct usb_host_interface *ifp; + unsigned char *begin; + + interface->act_altsetting = 0; + interface->num_altsetting = 0; + interface->max_altsetting = USB_ALTSETTINGALLOC; + device_initialize(&interface->dev); + + interface->altsetting = kmalloc(sizeof(*interface->altsetting) * interface->max_altsetting, + GFP_KERNEL); + + if (!interface->altsetting) { + err("couldn't kmalloc interface->altsetting"); + return -1; + } + + while (size > 0) { + struct usb_interface_descriptor *d; + + if (interface->num_altsetting >= interface->max_altsetting) { + struct usb_host_interface *ptr; + int oldmas; + + oldmas = interface->max_altsetting; + interface->max_altsetting += USB_ALTSETTINGALLOC; + if (interface->max_altsetting > USB_MAXALTSETTING) { + warn("too many alternate settings (incr %d max %d)\n", + USB_ALTSETTINGALLOC, USB_MAXALTSETTING); + return -1; + } + + ptr = kmalloc(sizeof(*ptr) * interface->max_altsetting, GFP_KERNEL); + if (ptr == NULL) { + err("couldn't kmalloc interface->altsetting"); + return -1; + } + memcpy(ptr, interface->altsetting, sizeof(*interface->altsetting) * oldmas); + kfree(interface->altsetting); + interface->altsetting = ptr; + } + + ifp = interface->altsetting + interface->num_altsetting; + ifp->endpoint = NULL; + ifp->extra = NULL; + ifp->extralen = 0; + interface->num_altsetting++; + + memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE); + + /* Skip over the interface */ + buffer += ifp->desc.bLength; + parsed += ifp->desc.bLength; + size -= ifp->desc.bLength; + + begin = buffer; + numskipped = 0; + + /* Skip over any interface, class or vendor descriptors */ + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength < 2) { + err("invalid descriptor length of %d", header->bLength); + return -1; + } + + /* If we find another "proper" descriptor then we're done */ + if ((header->bDescriptorType == USB_DT_INTERFACE) || + (header->bDescriptorType == USB_DT_ENDPOINT) || + (header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE)) + break; + + numskipped++; + + buffer += header->bLength; + parsed += header->bLength; + size -= header->bLength; + } + + if (numskipped) + dbg("skipped %d class/vendor specific interface descriptors", numskipped); + + /* Copy any unknown descriptors into a storage area for */ + /* drivers to later parse */ + len = (int)(buffer - begin); + if (len) { + ifp->extra = kmalloc(len, GFP_KERNEL); + + if (!ifp->extra) { + err("couldn't allocate memory for interface extra descriptors"); + ifp->extralen = 0; + return -1; + } + memcpy(ifp->extra, begin, len); + ifp->extralen = len; + } + + /* Did we hit an unexpected descriptor? */ + header = (struct usb_descriptor_header *)buffer; + if ((size >= sizeof(struct usb_descriptor_header)) && + ((header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE))) + return parsed; + + if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) { + warn("too many endpoints"); + return -1; + } + + ifp->endpoint = (struct usb_host_endpoint *) + kmalloc(ifp->desc.bNumEndpoints * + sizeof(struct usb_host_endpoint), GFP_KERNEL); + if (!ifp->endpoint) { + err("out of memory"); + return -1; + } + + memset(ifp->endpoint, 0, ifp->desc.bNumEndpoints * + sizeof(struct usb_host_endpoint)); + + for (i = 0; i < ifp->desc.bNumEndpoints; i++) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength > size) { + err("ran out of descriptors parsing"); + return -1; + } + + retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size); + if (retval < 0) + return retval; + + buffer += retval; + parsed += retval; + size -= retval; + } + + /* We check to see if it's an alternate to this one */ + d = (struct usb_interface_descriptor *)buffer; + if (size < USB_DT_INTERFACE_SIZE + || d->bDescriptorType != USB_DT_INTERFACE + || !d->bAlternateSetting) + return parsed; + } + + return parsed; +} + +int usb_parse_configuration(struct usb_host_config *config, char *buffer) +{ + int i, retval, size; + struct usb_descriptor_header *header; + + memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); + le16_to_cpus(&config->desc.wTotalLength); + size = config->desc.wTotalLength; + + if (config->desc.bNumInterfaces > USB_MAXINTERFACES) { + warn("too many interfaces"); + return -1; + } + + config->interface = (struct usb_interface *) + kmalloc(config->desc.bNumInterfaces * + sizeof(struct usb_interface), GFP_KERNEL); + dbg("kmalloc IF %p, numif %i", config->interface, config->desc.bNumInterfaces); + if (!config->interface) { + err("out of memory"); + return -1; + } + + memset(config->interface, 0, + config->desc.bNumInterfaces * sizeof(struct usb_interface)); + + buffer += config->desc.bLength; + size -= config->desc.bLength; + + config->extra = NULL; + config->extralen = 0; + + for (i = 0; i < config->desc.bNumInterfaces; i++) { + int numskipped, len; + char *begin; + + /* Skip over the rest of the Class Specific or Vendor */ + /* Specific descriptors */ + begin = buffer; + numskipped = 0; + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; + + if ((header->bLength > size) || (header->bLength < 2)) { + err("invalid descriptor length of %d", header->bLength); + return -1; + } + + /* If we find another "proper" descriptor then we're done */ + if ((header->bDescriptorType == USB_DT_ENDPOINT) || + (header->bDescriptorType == USB_DT_INTERFACE) || + (header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE)) + break; + + dbg("skipping descriptor 0x%X", header->bDescriptorType); + numskipped++; + + buffer += header->bLength; + size -= header->bLength; + } + if (numskipped) + dbg("skipped %d class/vendor specific endpoint descriptors", numskipped); + + /* Copy any unknown descriptors into a storage area for */ + /* drivers to later parse */ + len = (int)(buffer - begin); + if (len) { + if (config->extralen) { + warn("extra config descriptor"); + } else { + config->extra = kmalloc(len, GFP_KERNEL); + if (!config->extra) { + err("couldn't allocate memory for config extra descriptors"); + config->extralen = 0; + return -1; + } + + memcpy(config->extra, begin, len); + config->extralen = len; + } + } + + retval = usb_parse_interface(config->interface + i, buffer, size); + if (retval < 0) + return retval; + + buffer += retval; + size -= retval; + } + + return size; +} + +// hub-only!! ... and only exported for reset/reinit path. +// otherwise used internally on disconnect/destroy path +void usb_destroy_configuration(struct usb_device *dev) +{ + int c, i, j, k; + + if (!dev->config) + return; + + if (dev->rawdescriptors) { + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) + kfree(dev->rawdescriptors[i]); + + kfree(dev->rawdescriptors); + } + + for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { + struct usb_host_config *cf = &dev->config[c]; + + if (!cf->interface) + break; + + for (i = 0; i < cf->desc.bNumInterfaces; i++) { + struct usb_interface *ifp = + &cf->interface[i]; + + if (!ifp->altsetting) + break; + + for (j = 0; j < ifp->num_altsetting; j++) { + struct usb_host_interface *as = + &ifp->altsetting[j]; + + if(as->extra) { + kfree(as->extra); + } + + if (!as->endpoint) + break; + + for(k = 0; k < as->desc.bNumEndpoints; k++) { + if(as->endpoint[k].extra) { + kfree(as->endpoint[k].extra); + } + } + kfree(as->endpoint); + } + + kfree(ifp->altsetting); + } + kfree(cf->interface); + } + kfree(dev->config); +} + + +// hub-only!! ... and only in reset path, or usb_new_device() +// (used by real hubs and virtual root hubs) +int usb_get_configuration(struct usb_device *dev) +{ + int result; + unsigned int cfgno, length; + unsigned char *buffer; + unsigned char *bigbuffer; + struct usb_config_descriptor *desc; + + if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) { + warn("too many configurations"); + return -EINVAL; + } + + if (dev->descriptor.bNumConfigurations < 1) { + warn("not enough configurations"); + return -EINVAL; + } + + dev->config = (struct usb_host_config *) + kmalloc(dev->descriptor.bNumConfigurations * + sizeof(struct usb_host_config), GFP_KERNEL); + if (!dev->config) { + err("out of memory"); + return -ENOMEM; + } + memset(dev->config, 0, dev->descriptor.bNumConfigurations * + sizeof(struct usb_host_config)); + + dev->rawdescriptors = (char **)kmalloc(sizeof(char *) * + dev->descriptor.bNumConfigurations, GFP_KERNEL); + if (!dev->rawdescriptors) { + err("out of memory"); + return -ENOMEM; + } + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + err("unable to allocate memory for configuration descriptors"); + return -ENOMEM; + } + desc = (struct usb_config_descriptor *)buffer; + + for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) { + /* We grab the first 8 bytes so we know how long the whole */ + /* configuration is */ + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8); + if (result < 8) { + if (result < 0) + err("unable to get descriptor"); + else { + err("config descriptor too short (expected %i, got %i)", 8, result); + result = -EINVAL; + } + goto err; + } + + /* Get the full buffer */ + length = le16_to_cpu(desc->wTotalLength); + + bigbuffer = kmalloc(length, GFP_KERNEL); + if (!bigbuffer) { + err("unable to allocate memory for configuration descriptors"); + result = -ENOMEM; + goto err; + } + + /* Now that we know the length, get the whole thing */ + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length); + if (result < 0) { + err("couldn't get all of config descriptors"); + kfree(bigbuffer); + goto err; + } + + if (result < length) { + err("config descriptor too short (expected %i, got %i)", length, result); + result = -EINVAL; + kfree(bigbuffer); + goto err; + } + + dev->rawdescriptors[cfgno] = bigbuffer; + + result = usb_parse_configuration(&dev->config[cfgno], bigbuffer); + if (result > 0) + dbg("descriptor data left"); + else if (result < 0) { + result = -EINVAL; + goto err; + } + } + + kfree(buffer); + return 0; +err: + kfree(buffer); + dev->descriptor.bNumConfigurations = cfgno; + return result; +} + diff --git a/reactos/drivers/usb/cromwell/core/hcd-pci.c b/reactos/drivers/usb/cromwell/core/hcd-pci.c index e65c436cced..e91b61dcf34 100644 --- a/reactos/drivers/usb/cromwell/core/hcd-pci.c +++ b/reactos/drivers/usb/cromwell/core/hcd-pci.c @@ -1,369 +1,370 @@ -/* - * (C) Copyright David Brownell 2000-2002 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if 0 -#include - -#ifdef CONFIG_USB_DEBUG - #define DEBUG -#else - #undef DEBUG -#endif - -#include -#include -#include -#include -#include -#include -#include "hcd.h" -#else -#define DEBUG -#include "../usb_wrapper.h" -#include "hcd.h" -#endif - - -/* PCI-based HCs are normal, but custom bus glue should be ok */ - - -/*-------------------------------------------------------------------------*/ - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - -/** - * usb_hcd_pci_probe - initialize PCI-based HCDs - * @dev: USB Host Controller being probed - * @id: pci hotplug id connecting controller to HCD framework - * Context: !in_interrupt() - * - * Allocates basic PCI resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - * - * Store this function in the HCD's struct pci_driver as probe(). - */ -int STDCALL usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) -{ - struct hc_driver *driver; - PHYSICAL_ADDRESS resource; - unsigned long len; - void *base; - struct usb_hcd *hcd; - int retval, region; - char buf [8]; - //char *bufp = buf; - - printk("usbcore: usb_hcd_pci_probe() called\n"); - - if (usb_disabled()) - return -ENODEV; - - if (!id || !(driver = (struct hc_driver *) id->driver_data)) - return -EINVAL; - - if (pci_enable_device (dev) < 0) - return -ENODEV; - - if (!dev->irq) { - err ("Found HC with no IRQ. Check BIOS/PCI %s setup!", - dev->slot_name); - return -ENODEV; - } - - if (driver->flags & HCD_MEMORY) { // EHCI, OHCI - region = 0; - resource = pci_resource_start (dev, 0); - len = pci_resource_len (dev, 0); - if (!request_mem_region (resource, len, driver->description)) { - dbg ("controller already in use"); - return -EBUSY; - } - base = ioremap_nocache (resource, len); - if (base == NULL) { - dbg ("error mapping memory"); - retval = -EFAULT; -clean_1: - release_mem_region (resource, len); - err ("init %s fail, %d", dev->slot_name, retval); - return retval; - } - - } else { // UHCI - //resource = 0; - len = 0; - for (region = 0; region < PCI_ROM_RESOURCE; region++) { - if (!(pci_resource_flags (dev, region) & IORESOURCE_IO)) - continue; - - resource = pci_resource_start (dev, region); - len = pci_resource_len (dev, region); - if (request_region (resource, len, - driver->description)) - break; - } - if (region == PCI_ROM_RESOURCE) { - dbg ("no i/o regions available"); - return -EBUSY; - } - base = NULL; //(void *) resource; // this isn't possible - } - - // driver->start(), later on, will transfer device from - // control by SMM/BIOS to control by Linux (if needed) - - pci_set_master (dev); - - hcd = driver->hcd_alloc (); - if (hcd == NULL){ - dbg ("hcd alloc fail"); - retval = -ENOMEM; -clean_2: - if (driver->flags & HCD_MEMORY) { - iounmap (base); - goto clean_1; - } else { - release_region (resource, len); - err ("init %s fail, %d", dev->slot_name, retval); - return retval; - } - } - pci_set_drvdata (dev, hcd); - hcd->driver = driver; - hcd->description = driver->description; - hcd->pdev = dev; - hcd->self.bus_name = dev->slot_name; - hcd->product_desc = dev->dev.name; - hcd->self.controller = &dev->dev; - hcd->controller = hcd->self.controller; - - if ((retval = hcd_buffer_create (hcd)) != 0) { -clean_3: - driver->hcd_free (hcd); - goto clean_2; - } - - dev_info (hcd->controller, "%s\n", hcd->product_desc); - -#ifndef __sparc__ - sprintf (buf, "%d", dev->irq); -#else - bufp = __irq_itoa(dev->irq); -#endif - if (request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ, hcd->description, hcd) - != 0) { - dev_err (hcd->controller, - "request interrupt %s failed\n", buf); - retval = -EBUSY; - goto clean_3; - } - hcd->irq = dev->irq; - - hcd->regs = base; - hcd->region = region; - dev_info (hcd->controller, "irq %s, %s %p\n", buf, - (driver->flags & HCD_MEMORY) ? "pci mem" : "io base", - base); - - usb_bus_init (&hcd->self); - hcd->self.op = &usb_hcd_operations; - hcd->self.hcpriv = (void *) hcd; - - INIT_LIST_HEAD (&hcd->dev_list); - - usb_register_bus (&hcd->self); - - if ((retval = driver->start (hcd)) < 0) - usb_hcd_pci_remove (dev); - - return retval; -} -EXPORT_SYMBOL (usb_hcd_pci_probe); - - -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_pci_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - * - * Store this function in the HCD's struct pci_driver as remove(). - */ -void STDCALL usb_hcd_pci_remove (struct pci_dev *dev) -{ - struct usb_hcd *hcd; - struct usb_device *hub; - - hcd = pci_get_drvdata(dev); - if (!hcd) - return; - dev_info (hcd->controller, "remove, state %x\n", hcd->state); - - if (in_interrupt ()) - BUG (); - - hub = hcd->self.root_hub; - hcd->state = USB_STATE_QUIESCING; - - dev_dbg (hcd->controller, "roothub graceful disconnect\n"); - usb_disconnect (&hub); - - hcd->driver->stop (hcd); - hcd_buffer_destroy (hcd); - hcd->state = USB_STATE_HALT; - pci_set_drvdata (dev, 0); - - free_irq (hcd->irq, hcd); - if (hcd->driver->flags & HCD_MEMORY) { - iounmap (hcd->regs); - release_mem_region (pci_resource_start (dev, 0), - pci_resource_len (dev, 0)); - } else { - release_region (pci_resource_start (dev, hcd->region), - pci_resource_len (dev, hcd->region)); - } - - usb_deregister_bus (&hcd->self); - if (atomic_read (&hcd->self.refcnt) != 1) { - dev_warn (hcd->controller, - "dangling refs (%d) to bus %d!\n", - atomic_read (&hcd->self.refcnt) - 1, - hcd->self.busnum); - } - hcd->driver->hcd_free (hcd); -} -EXPORT_SYMBOL (usb_hcd_pci_remove); - - -#ifdef CONFIG_PM - -/* - * Some "sleep" power levels imply updating struct usb_driver - * to include a callback asking hcds to do their bit by checking - * if all the drivers can suspend. Gets involved with remote wakeup. - * - * If there are pending urbs, then HCs will need to access memory, - * causing extra power drain. New sleep()/wakeup() PM calls might - * be needed, beyond PCI suspend()/resume(). The root hub timer - * still be accessing memory though ... - * - * FIXME: USB should have some power budgeting support working with - * all kinds of hubs. - * - * FIXME: This assumes only D0->D3 suspend and D3->D0 resume. - * D1 and D2 states should do something, yes? - * - * FIXME: Should provide generic enable_wake(), calling pci_enable_wake() - * for all supported states, so that USB remote wakeup can work for any - * devices that support it (and are connected via powered hubs). - * - * FIXME: resume doesn't seem to work right any more... - */ - - -// 2.4 kernels have issued concurrent resumes (w/APM) -// we defend against that error; PCI doesn't yet. - -/** - * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD - * @dev: USB Host Controller being suspended - * - * Store this function in the HCD's struct pci_driver as suspend(). - */ -int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) -{ - struct usb_hcd *hcd; - int retval; - - hcd = pci_get_drvdata(dev); - dev_info (hcd->controller, "suspend to state %d\n", state); - - pci_save_state (dev, hcd->pci_state); - - // FIXME for all connected devices, leaf-to-root: - // driver->suspend() - // proposed "new 2.5 driver model" will automate that - - /* driver may want to disable DMA etc */ - retval = hcd->driver->suspend (hcd, state); - hcd->state = USB_STATE_SUSPENDED; - - pci_set_power_state (dev, state); - return retval; -} -EXPORT_SYMBOL (usb_hcd_pci_suspend); - -/** - * usb_hcd_pci_resume - power management resume of a PCI-based HCD - * @dev: USB Host Controller being resumed - * - * Store this function in the HCD's struct pci_driver as resume(). - */ -int usb_hcd_pci_resume (struct pci_dev *dev) -{ - struct usb_hcd *hcd; - int retval; - - hcd = pci_get_drvdata(dev); - dev_info (hcd->controller, "resume\n"); - - /* guard against multiple resumes (APM bug?) */ - atomic_inc (&hcd->resume_count); - if (atomic_read (&hcd->resume_count) != 1) { - dev_err (hcd->controller, "concurrent PCI resumes\n"); - retval = 0; - goto done; - } - - retval = -EBUSY; - if (hcd->state != USB_STATE_SUSPENDED) { - dev_dbg (hcd->controller, "can't resume, not suspended!\n"); - goto done; - } - hcd->state = USB_STATE_RESUMING; - - pci_set_power_state (dev, 0); - pci_restore_state (dev, hcd->pci_state); - - retval = hcd->driver->resume (hcd); - if (!HCD_IS_RUNNING (hcd->state)) { - dev_dbg (hcd->controller, "resume fail, retval %d\n", retval); - usb_hc_died (hcd); -// FIXME: recover, reset etc. - } else { - // FIXME for all connected devices, root-to-leaf: - // driver->resume (); - // proposed "new 2.5 driver model" will automate that - } - -done: - atomic_dec (&hcd->resume_count); - return retval; -} -EXPORT_SYMBOL (usb_hcd_pci_resume); - -#endif /* CONFIG_PM */ - - +/* + * (C) Copyright David Brownell 2000-2002 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if 0 +#include + +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include "hcd.h" +#else +#define DEBUG +#include "../usb_wrapper.h" +#include "hcd.h" +#endif + + +/* PCI-based HCs are normal, but custom bus glue should be ok */ + + +/*-------------------------------------------------------------------------*/ + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + +/** + * usb_hcd_pci_probe - initialize PCI-based HCDs + * @dev: USB Host Controller being probed + * @id: pci hotplug id connecting controller to HCD framework + * Context: !in_interrupt() + * + * Allocates basic PCI resources for this USB host controller, and + * then invokes the start() method for the HCD associated with it + * through the hotplug entry's driver_data. + * + * Store this function in the HCD's struct pci_driver as probe(). + */ +int STDCALL +usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) +{ + struct hc_driver *driver; + PHYSICAL_ADDRESS resource; + unsigned long len; + void *base; + struct usb_hcd *hcd; + int retval, region; + char buf [8]; + //char *bufp = buf; + + printk("usbcore: usb_hcd_pci_probe() called\n"); + + if (usb_disabled()) + return -ENODEV; + + if (!id || !(driver = (struct hc_driver *) id->driver_data)) + return -EINVAL; + + if (pci_enable_device (dev) < 0) + return -ENODEV; + + if (!dev->irq) { + err ("Found HC with no IRQ. Check BIOS/PCI %s setup!", + dev->slot_name); + return -ENODEV; + } + + if (driver->flags & HCD_MEMORY) { // EHCI, OHCI + region = 0; + resource = pci_resource_start (dev, 0); + len = pci_resource_len (dev, 0); + if (!request_mem_region (resource, len, driver->description)) { + dbg ("controller already in use"); + return -EBUSY; + } + base = ioremap_nocache (resource, len); + if (base == NULL) { + dbg ("error mapping memory"); + retval = -EFAULT; +clean_1: + release_mem_region (resource, len); + err ("init %s fail, %d", dev->slot_name, retval); + return retval; + } + + } else { // UHCI + //resource = 0; + len = 0; + for (region = 0; region < PCI_ROM_RESOURCE; region++) { + if (!(pci_resource_flags (dev, region) & IORESOURCE_IO)) + continue; + + resource = pci_resource_start (dev, region); + len = pci_resource_len (dev, region); + if (request_region (resource, len, + driver->description)) + break; + } + if (region == PCI_ROM_RESOURCE) { + dbg ("no i/o regions available"); + return -EBUSY; + } + base = (void *) (ULONG_PTR)resource.u.LowPart; + } + + // driver->start(), later on, will transfer device from + // control by SMM/BIOS to control by Linux (if needed) + + pci_set_master (dev); + + hcd = driver->hcd_alloc (); + if (hcd == NULL){ + dbg ("hcd alloc fail"); + retval = -ENOMEM; +clean_2: + if (driver->flags & HCD_MEMORY) { + iounmap (base); + goto clean_1; + } else { + release_region (resource, len); + err ("init %s fail, %d", dev->slot_name, retval); + return retval; + } + } + pci_set_drvdata (dev, hcd); + hcd->driver = driver; + hcd->description = driver->description; + hcd->pdev = dev; + hcd->self.bus_name = dev->slot_name; + hcd->product_desc = dev->dev.name; + hcd->self.controller = &dev->dev; + hcd->controller = hcd->self.controller; + + if ((retval = hcd_buffer_create (hcd)) != 0) { +clean_3: + driver->hcd_free (hcd); + goto clean_2; + } + + dev_info (hcd->controller, "%s\n", hcd->product_desc); + +#ifndef __sparc__ + sprintf (buf, "%d", dev->irq); +#else + bufp = __irq_itoa(dev->irq); +#endif + if (request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ, hcd->description, hcd) + != 0) { + dev_err (hcd->controller, + "request interrupt %s failed\n", buf); + retval = -EBUSY; + goto clean_3; + } + hcd->irq = dev->irq; + + hcd->regs = base; + hcd->region = region; + dev_info (hcd->controller, "irq %s, %s %p\n", buf, + (driver->flags & HCD_MEMORY) ? "pci mem" : "io base", + base); + + usb_bus_init (&hcd->self); + hcd->self.op = &usb_hcd_operations; + hcd->self.hcpriv = (void *) hcd; + + INIT_LIST_HEAD (&hcd->dev_list); + + usb_register_bus (&hcd->self); + + if ((retval = driver->start (hcd)) < 0) + usb_hcd_pci_remove (dev); + + return retval; +} +EXPORT_SYMBOL (usb_hcd_pci_probe); + + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_hcd_pci_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + * + * Store this function in the HCD's struct pci_driver as remove(). + */ +void STDCALL usb_hcd_pci_remove (struct pci_dev *dev) +{ + struct usb_hcd *hcd; + struct usb_device *hub; + + hcd = pci_get_drvdata(dev); + if (!hcd) + return; + dev_info (hcd->controller, "remove, state %x\n", hcd->state); + + if (in_interrupt ()) + BUG (); + + hub = hcd->self.root_hub; + hcd->state = USB_STATE_QUIESCING; + + dev_dbg (hcd->controller, "roothub graceful disconnect\n"); + usb_disconnect (&hub); + + hcd->driver->stop (hcd); + hcd_buffer_destroy (hcd); + hcd->state = USB_STATE_HALT; + pci_set_drvdata (dev, 0); + + free_irq (hcd->irq, hcd); + if (hcd->driver->flags & HCD_MEMORY) { + iounmap (hcd->regs); + release_mem_region (pci_resource_start (dev, 0), + pci_resource_len (dev, 0)); + } else { + release_region (pci_resource_start (dev, hcd->region), + pci_resource_len (dev, hcd->region)); + } + + usb_deregister_bus (&hcd->self); + if (atomic_read (&hcd->self.refcnt) != 1) { + dev_warn (hcd->controller, + "dangling refs (%d) to bus %d!\n", + atomic_read (&hcd->self.refcnt) - 1, + hcd->self.busnum); + } + hcd->driver->hcd_free (hcd); +} +EXPORT_SYMBOL (usb_hcd_pci_remove); + + +#ifdef CONFIG_PM + +/* + * Some "sleep" power levels imply updating struct usb_driver + * to include a callback asking hcds to do their bit by checking + * if all the drivers can suspend. Gets involved with remote wakeup. + * + * If there are pending urbs, then HCs will need to access memory, + * causing extra power drain. New sleep()/wakeup() PM calls might + * be needed, beyond PCI suspend()/resume(). The root hub timer + * still be accessing memory though ... + * + * FIXME: USB should have some power budgeting support working with + * all kinds of hubs. + * + * FIXME: This assumes only D0->D3 suspend and D3->D0 resume. + * D1 and D2 states should do something, yes? + * + * FIXME: Should provide generic enable_wake(), calling pci_enable_wake() + * for all supported states, so that USB remote wakeup can work for any + * devices that support it (and are connected via powered hubs). + * + * FIXME: resume doesn't seem to work right any more... + */ + + +// 2.4 kernels have issued concurrent resumes (w/APM) +// we defend against that error; PCI doesn't yet. + +/** + * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD + * @dev: USB Host Controller being suspended + * + * Store this function in the HCD's struct pci_driver as suspend(). + */ +int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) +{ + struct usb_hcd *hcd; + int retval; + + hcd = pci_get_drvdata(dev); + dev_info (hcd->controller, "suspend to state %d\n", state); + + pci_save_state (dev, hcd->pci_state); + + // FIXME for all connected devices, leaf-to-root: + // driver->suspend() + // proposed "new 2.5 driver model" will automate that + + /* driver may want to disable DMA etc */ + retval = hcd->driver->suspend (hcd, state); + hcd->state = USB_STATE_SUSPENDED; + + pci_set_power_state (dev, state); + return retval; +} +EXPORT_SYMBOL (usb_hcd_pci_suspend); + +/** + * usb_hcd_pci_resume - power management resume of a PCI-based HCD + * @dev: USB Host Controller being resumed + * + * Store this function in the HCD's struct pci_driver as resume(). + */ +int usb_hcd_pci_resume (struct pci_dev *dev) +{ + struct usb_hcd *hcd; + int retval; + + hcd = pci_get_drvdata(dev); + dev_info (hcd->controller, "resume\n"); + + /* guard against multiple resumes (APM bug?) */ + atomic_inc (&hcd->resume_count); + if (atomic_read (&hcd->resume_count) != 1) { + dev_err (hcd->controller, "concurrent PCI resumes\n"); + retval = 0; + goto done; + } + + retval = -EBUSY; + if (hcd->state != USB_STATE_SUSPENDED) { + dev_dbg (hcd->controller, "can't resume, not suspended!\n"); + goto done; + } + hcd->state = USB_STATE_RESUMING; + + pci_set_power_state (dev, 0); + pci_restore_state (dev, hcd->pci_state); + + retval = hcd->driver->resume (hcd); + if (!HCD_IS_RUNNING (hcd->state)) { + dev_dbg (hcd->controller, "resume fail, retval %d\n", retval); + usb_hc_died (hcd); +// FIXME: recover, reset etc. + } else { + // FIXME for all connected devices, root-to-leaf: + // driver->resume (); + // proposed "new 2.5 driver model" will automate that + } + +done: + atomic_dec (&hcd->resume_count); + return retval; +} +EXPORT_SYMBOL (usb_hcd_pci_resume); + +#endif /* CONFIG_PM */ + + diff --git a/reactos/drivers/usb/cromwell/core/hcd.c b/reactos/drivers/usb/cromwell/core/hcd.c index a9efdf7a77f..e594362f341 100644 --- a/reactos/drivers/usb/cromwell/core/hcd.c +++ b/reactos/drivers/usb/cromwell/core/hcd.c @@ -1,1499 +1,1499 @@ -/* - * (C) Copyright Linus Torvalds 1999 - * (C) Copyright Johannes Erdfelt 1999-2001 - * (C) Copyright Andreas Gal 1999 - * (C) Copyright Gregory P. Smith 1999 - * (C) Copyright Deti Fliegl 1999 - * (C) Copyright Randy Dunlap 2000 - * (C) Copyright David Brownell 2000-2002 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if 0 -#include - -#ifdef CONFIG_USB_DEBUG -#define DEBUG -#endif - -#include -#include -#include -#include -#include -#include /* for UTS_SYSNAME */ -#include /* for hcd->pdev and dma addressing */ -#include -#include - -#include -#else -#include "../usb_wrapper.h" -//#define DEBUG -#endif - -#include "hcd.h" - -// #define USB_BANDWIDTH_MESSAGES - -/*-------------------------------------------------------------------------*/ - -/* - * USB Host Controller Driver framework - * - * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing - * HCD-specific behaviors/bugs. - * - * This does error checks, tracks devices and urbs, and delegates to a - * "hc_driver" only for code (and data) that really needs to know about - * hardware differences. That includes root hub registers, i/o queues, - * and so on ... but as little else as possible. - * - * Shared code includes most of the "root hub" code (these are emulated, - * though each HC's hardware works differently) and PCI glue, plus request - * tracking overhead. The HCD code should only block on spinlocks or on - * hardware handshaking; blocking on software events (such as other kernel - * threads releasing resources, or completing actions) is all generic. - * - * Happens the USB 2.0 spec says this would be invisible inside the "USBD", - * and includes mostly a "HCDI" (HCD Interface) along with some APIs used - * only by the hub driver ... and that neither should be seen or used by - * usb client device drivers. - * - * Contributors of ideas or unattributed patches include: David Brownell, - * Roman Weissgaerber, Rory Bolt, Greg Kroah-Hartman, ... - * - * HISTORY: - * 2002-02-21 Pull in most of the usb_bus support from usb.c; some - * associated cleanup. "usb_hcd" still != "usb_bus". - * 2001-12-12 Initial patch version for Linux 2.5.1 kernel. - */ - -/*-------------------------------------------------------------------------*/ - -/* host controllers we manage */ -LIST_HEAD (usb_bus_list); -EXPORT_SYMBOL_GPL (usb_bus_list); - -/* used when allocating bus numbers */ -#define USB_MAXBUS 64 -struct usb_busmap { - unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))]; -}; -static struct usb_busmap busmap; - -/* used when updating list of hcds */ -DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */ -EXPORT_SYMBOL_GPL (usb_bus_list_lock); - -/* used when updating hcd data */ -static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED; - -/*-------------------------------------------------------------------------*/ - -/* - * Sharable chunks of root hub code. - */ - -/*-------------------------------------------------------------------------*/ - -#define KERNEL_REL ((LINUX_VERSION_CODE >> 16) & 0x0ff) -#define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff) - -/* usb 2.0 root hub device descriptor */ -static const u8 usb2_rh_dev_descriptor [18] = { - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x00, 0x02, /* __u16 bcdUSB; v2.0 */ - - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - - 0x00, 0x00, /* __u16 idVendor; */ - 0x00, 0x00, /* __u16 idProduct; */ - KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */ - - 0x03, /* __u8 iManufacturer; */ - 0x02, /* __u8 iProduct; */ - 0x01, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - -/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */ - -/* usb 1.1 root hub device descriptor */ -static const u8 usb11_rh_dev_descriptor [18] = { - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x10, 0x01, /* __u16 bcdUSB; v1.1 */ - - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - - 0x00, 0x00, /* __u16 idVendor; */ - 0x00, 0x00, /* __u16 idProduct; */ - KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */ - - 0x03, /* __u8 iManufacturer; */ - 0x02, /* __u8 iProduct; */ - 0x01, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - - -/*-------------------------------------------------------------------------*/ - -/* Configuration descriptors for our root hubs */ - -static const u8 fs_rh_config_descriptor [] = { - - /* one configuration */ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, 0x00, /* __u16 wTotalLength; */ - 0x01, /* __u8 bNumInterfaces; (1) */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, - 6: Self-powered, - 5 Remote-wakwup, - 4..0: resvd */ - 0x00, /* __u8 MaxPower; */ - - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ - - /* one interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x00, /* __u8 if_iInterface; */ - - /* one endpoint (status change endpoint) */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ - 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */ -}; - -static const u8 hs_rh_config_descriptor [] = { - - /* one configuration */ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, 0x00, /* __u16 wTotalLength; */ - 0x01, /* __u8 bNumInterfaces; (1) */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, - 6: Self-powered, - 5 Remote-wakwup, - 4..0: resvd */ - 0x00, /* __u8 MaxPower; */ - - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ - - /* one interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x00, /* __u8 if_iInterface; */ - - /* one endpoint (status change endpoint) */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ - 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */ -}; - -/*-------------------------------------------------------------------------*/ - -/* - * helper routine for returning string descriptors in UTF-16LE - * input can actually be ISO-8859-1; ASCII is its 7-bit subset - */ -static int ascii2utf (char *s, u8 *utf, int utfmax) -{ - int retval; - - for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) { - *utf++ = *s++; - *utf++ = 0; - } - return retval; -} - -/* - * rh_string - provides manufacturer, product and serial strings for root hub - * @id: the string ID number (1: serial number, 2: product, 3: vendor) - * @hcd: the host controller for this root hub - * @type: string describing our driver - * @data: return packet in UTF-16 LE - * @len: length of the return packet - * - * Produces either a manufacturer, product or serial number string for the - * virtual root hub device. - */ -static int rh_string ( - int id, - struct usb_hcd *hcd, - u8 *data, - int len -) { - char buf [100]; - - // language ids - if (id == 0) { - *data++ = 4; *data++ = 3; /* 4 bytes string data */ - *data++ = 0x09; *data++ = 0x04; /* MSFT-speak for "en-us" */ - return 4; - - // serial number - } else if (id == 1) { - strcpy (buf, hcd->self.bus_name); - - // product description - } else if (id == 2) { - strcpy (buf, hcd->product_desc); - - // id 3 == vendor description - } else if (id == 3) { - sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE, - hcd->description); - - // unsupported IDs --> "protocol stall" - } else - return 0; - - data [0] = 2 * (strlen (buf) + 1); - data [1] = 3; /* type == string */ - return 2 + ascii2utf (buf, data + 2, len - 2); -} - - -/* Root hub control transfers execute synchronously */ -static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) -{ - struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet; - u16 typeReq, wValue, wIndex, wLength; - const u8 *bufp = 0; - u8 *ubuf = urb->transfer_buffer; - int len = 0; - //unsigned long flags; - - typeReq = (cmd->bRequestType << 8) | cmd->bRequest; - wValue = le16_to_cpu (cmd->wValue); - wIndex = le16_to_cpu (cmd->wIndex); - wLength = le16_to_cpu (cmd->wLength); - - if (wLength > urb->transfer_buffer_length) - goto error; - - /* set up for success */ - urb->status = 0; - urb->actual_length = wLength; - switch (typeReq) { - - /* DEVICE REQUESTS */ - - case DeviceRequest | USB_REQ_GET_STATUS: - // DEVICE_REMOTE_WAKEUP - ubuf [0] = 1; // selfpowered - ubuf [1] = 0; - /* FALLTHROUGH */ - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: - case DeviceOutRequest | USB_REQ_SET_FEATURE: - dev_dbg (hcd->controller, "no device features yet yet\n"); - break; - case DeviceRequest | USB_REQ_GET_CONFIGURATION: - ubuf [0] = 1; - /* FALLTHROUGH */ - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch (wValue & 0xff00) { - case USB_DT_DEVICE << 8: - if (hcd->driver->flags & HCD_USB2) - bufp = usb2_rh_dev_descriptor; - else if (hcd->driver->flags & HCD_USB11) - bufp = usb11_rh_dev_descriptor; - else - goto error; - len = 18; - break; - case USB_DT_CONFIG << 8: - if (hcd->driver->flags & HCD_USB2) { - bufp = hs_rh_config_descriptor; - len = sizeof hs_rh_config_descriptor; - } else { - bufp = fs_rh_config_descriptor; - len = sizeof fs_rh_config_descriptor; - } - break; - case USB_DT_STRING << 8: - urb->actual_length = rh_string ( - wValue & 0xff, hcd, - ubuf, wLength); - break; - default: - goto error; - } - break; - case DeviceRequest | USB_REQ_GET_INTERFACE: - ubuf [0] = 0; - /* FALLTHROUGH */ - case DeviceOutRequest | USB_REQ_SET_INTERFACE: - break; - case DeviceOutRequest | USB_REQ_SET_ADDRESS: - // wValue == urb->dev->devaddr - dev_dbg (hcd->controller, "root hub device address %d\n", - wValue); - break; - - /* INTERFACE REQUESTS (no defined feature/status flags) */ - - /* ENDPOINT REQUESTS */ - - case EndpointRequest | USB_REQ_GET_STATUS: - // ENDPOINT_HALT flag - ubuf [0] = 0; - ubuf [1] = 0; - /* FALLTHROUGH */ - case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: - case EndpointOutRequest | USB_REQ_SET_FEATURE: - dev_dbg (hcd->controller, "no endpoint features yet\n"); - break; - - /* CLASS REQUESTS (and errors) */ - - default: - /* non-generic request */ - urb->status = hcd->driver->hub_control (hcd, - typeReq, wValue, wIndex, - ubuf, wLength); - break; -error: - /* "protocol stall" on error */ - urb->status = -EPIPE; - dev_dbg (hcd->controller, "unsupported hub control message (maxchild %d)\n", - urb->dev->maxchild); - } - if (urb->status) { - urb->actual_length = 0; - dev_dbg (hcd->controller, "CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d\n", - typeReq, wValue, wIndex, wLength, urb->status); - } - if (bufp) { - if (urb->transfer_buffer_length < len) - len = urb->transfer_buffer_length; - urb->actual_length = len; - // always USB_DIR_IN, toward host - memcpy (ubuf, bufp, len); - } - - /* any errors get returned through the urb completion */ - local_irq_save (flags); - usb_hcd_giveback_urb (hcd, urb, NULL); - local_irq_restore (flags); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* - * Root Hub interrupt transfers are synthesized with a timer. - * Completions are called in_interrupt() but not in_irq(). - */ - -static void rh_report_status (unsigned long ptr); - -static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) -{ - int len = 1 + (urb->dev->maxchild / 8); - - /* rh_timer protected by hcd_data_lock */ - if (hcd->rh_timer.data - || urb->status != -EINPROGRESS - || urb->transfer_buffer_length < len) { - dev_dbg (hcd->controller, - "not queuing rh status urb, stat %d\n", - urb->status); - return -EINVAL; - } - - init_timer (&hcd->rh_timer); - - hcd->rh_timer.function = rh_report_status; - hcd->rh_timer.data = (unsigned long) urb; - /* USB 2.0 spec says 256msec; this is close enough */ - hcd->rh_timer.expires = jiffies + HZ/4; - add_timer (&hcd->rh_timer); - urb->hcpriv = hcd; /* nonzero to indicate it's queued */ - return 0; -} - -/* timer callback */ - -static void rh_report_status (unsigned long ptr) -{ - struct urb *urb; - struct usb_hcd *hcd; - int length; - //unsigned long flags; - - urb = (struct urb *) ptr; - local_irq_save (flags); - spin_lock (&urb->lock); - - /* do nothing if the hc is gone or the urb's been unlinked */ - if (!urb->dev - || urb->status != -EINPROGRESS - || (hcd = urb->dev->bus->hcpriv) == 0 - || !HCD_IS_RUNNING (hcd->state)) { - spin_unlock (&urb->lock); - local_irq_restore (flags); - return; - } - - length = hcd->driver->hub_status_data (hcd, urb->transfer_buffer); - - /* complete the status urb, or retrigger the timer */ - spin_lock (&hcd_data_lock); - if (length > 0) { - hcd->rh_timer.data = 0; - urb->actual_length = length; - urb->status = 0; - urb->hcpriv = 0; - } else - mod_timer (&hcd->rh_timer, jiffies + HZ/4); - spin_unlock (&hcd_data_lock); - spin_unlock (&urb->lock); - - /* local irqs are always blocked in completions */ - if (length > 0) - usb_hcd_giveback_urb (hcd, urb, NULL); - local_irq_restore (flags); -} - -/*-------------------------------------------------------------------------*/ - -static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) -{ - if (usb_pipeint (urb->pipe)) { - int retval; - unsigned long flags; - - spin_lock_irqsave (&hcd_data_lock, flags); - retval = rh_status_urb (hcd, urb); - spin_unlock_irqrestore (&hcd_data_lock, flags); - return retval; - } - if (usb_pipecontrol (urb->pipe)) - return rh_call_control (hcd, urb); - else - return -EINVAL; -} - -/*-------------------------------------------------------------------------*/ - -void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb) -{ - //unsigned long flags; - - /* note: always a synchronous unlink */ - del_timer_sync (&hcd->rh_timer); - hcd->rh_timer.data = 0; - - local_irq_save (flags); - urb->hcpriv = 0; - usb_hcd_giveback_urb (hcd, urb, NULL); - local_irq_restore (flags); -} - -/*-------------------------------------------------------------------------*/ - -/* exported only within usbcore */ -void usb_bus_get (struct usb_bus *bus) -{ - atomic_inc (&bus->refcnt); -} - -/* exported only within usbcore */ -void usb_bus_put (struct usb_bus *bus) -{ - if (atomic_dec_and_test (&bus->refcnt)) - kfree (bus); -} - -/*-------------------------------------------------------------------------*/ - -/** - * usb_bus_init - shared initialization code - * @bus: the bus structure being initialized - * - * This code is used to initialize a usb_bus structure, memory for which is - * separately managed. - */ -void STDCALL usb_bus_init (struct usb_bus *bus) -{ - memset (&bus->devmap, 0, sizeof(struct usb_devmap)); - - bus->devnum_next = 1; - - bus->root_hub = NULL; - bus->hcpriv = NULL; - bus->busnum = -1; - bus->bandwidth_allocated = 0; - bus->bandwidth_int_reqs = 0; - bus->bandwidth_isoc_reqs = 0; - - INIT_LIST_HEAD (&bus->bus_list); - - atomic_set (&bus->refcnt, 1); -} - -/** - * usb_alloc_bus - creates a new USB host controller structure - * @op: pointer to a struct usb_operations that this bus structure should use - * Context: !in_interrupt() - * - * Creates a USB host controller bus structure with the specified - * usb_operations and initializes all the necessary internal objects. - * - * If no memory is available, NULL is returned. - * - * The caller should call usb_free_bus() when it is finished with the structure. - */ -struct usb_bus STDCALL *usb_alloc_bus (struct usb_operations *op) -{ - struct usb_bus *bus; - - bus = kmalloc (sizeof *bus, GFP_KERNEL); - if (!bus) - return NULL; - usb_bus_init (bus); - bus->op = op; - return bus; -} - -/** - * usb_free_bus - frees the memory used by a bus structure - * @bus: pointer to the bus to free - * - * To be invoked by a HCD, only as the last step of decoupling from - * hardware. It is an error to call this if the reference count is - * anything but one. That would indicate that some system component - * did not correctly shut down, and thought the hardware was still - * accessible. - */ -void STDCALL usb_free_bus (struct usb_bus *bus) -{ - if (!bus) - return; - if (atomic_read (&bus->refcnt) != 1) - err ("usb_free_bus #%d, count != 1", bus->busnum); - usb_bus_put (bus); -} - -/*-------------------------------------------------------------------------*/ - -/** - * usb_register_bus - registers the USB host controller with the usb core - * @bus: pointer to the bus to register - * Context: !in_interrupt() - * - * Assigns a bus number, and links the controller into usbcore data - * structures so that it can be seen by scanning the bus list. - */ -void STDCALL usb_register_bus(struct usb_bus *bus) -{ - int busnum; - - down (&usb_bus_list_lock); - busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); - if (busnum < USB_MAXBUS) { - set_bit (busnum, busmap.busmap); - bus->busnum = busnum; - } else - warn ("too many buses"); - - usb_bus_get (bus); - - /* Add it to the list of buses */ - list_add (&bus->bus_list, &usb_bus_list); - up (&usb_bus_list_lock); - - usbfs_add_bus (bus); - - dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum); -} - -/** - * usb_deregister_bus - deregisters the USB host controller - * @bus: pointer to the bus to deregister - * Context: !in_interrupt() - * - * Recycles the bus number, and unlinks the controller from usbcore data - * structures so that it won't be seen by scanning the bus list. - */ -void STDCALL usb_deregister_bus (struct usb_bus *bus) -{ - dev_info (bus->controller, "USB bus %d deregistered\n", bus->busnum); - - /* - * NOTE: make sure that all the devices are removed by the - * controller code, as well as having it call this when cleaning - * itself up - */ - down (&usb_bus_list_lock); - list_del (&bus->bus_list); - up (&usb_bus_list_lock); - - usbfs_remove_bus (bus); - - clear_bit (bus->busnum, busmap.busmap); - - usb_bus_put (bus); -} - -/** - * usb_register_root_hub - called by HCD to register its root hub - * @usb_dev: the usb root hub device to be registered. - * @parent_dev: the parent device of this root hub. - * - * The USB host controller calls this function to register the root hub - * properly with the USB subsystem. It sets up the device properly in - * the driverfs tree, and then calls usb_new_device() to register the - * usb device. - */ -int STDCALL usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev) -{ - int retval; - - sprintf (&usb_dev->dev.bus_id[0], "usb%d", usb_dev->bus->busnum); - usb_dev->state = USB_STATE_DEFAULT; - retval = usb_new_device (usb_dev, parent_dev); - if (retval) - dev_err (parent_dev, "can't register root hub for %s, %d\n", - usb_dev->dev.bus_id, retval); - return retval; -} - - -/*-------------------------------------------------------------------------*/ - -/** - * usb_calc_bus_time - approximate periodic transaction time in nanoseconds - * @speed: from dev->speed; USB_SPEED_{LOW,FULL,HIGH} - * @is_input: true iff the transaction sends data to the host - * @isoc: true for isochronous transactions, false for interrupt ones - * @bytecount: how many bytes in the transaction. - * - * Returns approximate bus time in nanoseconds for a periodic transaction. - * See USB 2.0 spec section 5.11.3; only periodic transfers need to be - * scheduled in software, this function is only used for such scheduling. - */ -long STDCALL usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount) -{ - unsigned long tmp; - - switch (speed) { - case USB_SPEED_LOW: /* INTR only */ - if (is_input) { - tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); - } else { - tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); - } - case USB_SPEED_FULL: /* ISOC or INTR */ - if (isoc) { - tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); - } else { - tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (9107L + BW_HOST_DELAY + tmp); - } - case USB_SPEED_HIGH: /* ISOC or INTR */ - // FIXME adjust for input vs output - if (isoc) - tmp = HS_USECS (bytecount); - else - tmp = HS_USECS_ISO (bytecount); - return tmp; - default: - dbg ("bogus device speed!"); - return -1; - } -} - -/* - * usb_check_bandwidth(): - * - * old_alloc is from host_controller->bandwidth_allocated in microseconds; - * bustime is from calc_bus_time(), but converted to microseconds. - * - * returns if successful, - * or -ENOSPC if bandwidth request fails. - * - * FIXME: - * This initial implementation does not use Endpoint.bInterval - * in managing bandwidth allocation. - * It probably needs to be expanded to use Endpoint.bInterval. - * This can be done as a later enhancement (correction). - * - * This will also probably require some kind of - * frame allocation tracking...meaning, for example, - * that if multiple drivers request interrupts every 10 USB frames, - * they don't all have to be allocated at - * frame numbers N, N+10, N+20, etc. Some of them could be at - * N+11, N+21, N+31, etc., and others at - * N+12, N+22, N+32, etc. - * - * Similarly for isochronous transfers... - * - * Individual HCDs can schedule more directly ... this logic - * is not correct for high speed transfers. - */ -int STDCALL usb_check_bandwidth (struct usb_device *dev, struct urb *urb) -{ - unsigned int pipe = urb->pipe; - long bustime; - int is_in = usb_pipein (pipe); - int is_iso = usb_pipeisoc (pipe); - int old_alloc = dev->bus->bandwidth_allocated; - int new_alloc; - - - bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso, - usb_maxpacket (dev, pipe, !is_in))); - if (is_iso) - bustime /= urb->number_of_packets; - - new_alloc = old_alloc + (int) bustime; - if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) { -#ifdef DEBUG - char *mode = -#ifdef CONFIG_USB_BANDWIDTH - ""; -#else - "would have "; -#endif - dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n", - mode, old_alloc, bustime, new_alloc); -#endif -#ifdef CONFIG_USB_BANDWIDTH - bustime = -ENOSPC; /* report error */ -#endif - } - - return bustime; -} - - -/** - * usb_claim_bandwidth - records bandwidth for a periodic transfer - * @dev: source/target of request - * @urb: request (urb->dev == dev) - * @bustime: bandwidth consumed, in (average) microseconds per frame - * @isoc: true iff the request is isochronous - * - * Bus bandwidth reservations are recorded purely for diagnostic purposes. - * HCDs are expected not to overcommit periodic bandwidth, and to record such - * reservations whenever endpoints are added to the periodic schedule. - * - * FIXME averaging per-frame is suboptimal. Better to sum over the HCD's - * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable - * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how - * large its periodic schedule is. - */ -void STDCALL usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc) -{ - dev->bus->bandwidth_allocated += bustime; - if (isoc) - dev->bus->bandwidth_isoc_reqs++; - else - dev->bus->bandwidth_int_reqs++; - urb->bandwidth = bustime; - -#ifdef USB_BANDWIDTH_MESSAGES - dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n", - bustime, - isoc ? "ISOC" : "INTR", - dev->bus->bandwidth_allocated, - dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); -#endif -} - - -/** - * usb_release_bandwidth - reverses effect of usb_claim_bandwidth() - * @dev: source/target of request - * @urb: request (urb->dev == dev) - * @isoc: true iff the request is isochronous - * - * This records that previously allocated bandwidth has been released. - * Bandwidth is released when endpoints are removed from the host controller's - * periodic schedule. - */ -void STDCALL usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc) -{ - dev->bus->bandwidth_allocated -= urb->bandwidth; - if (isoc) - dev->bus->bandwidth_isoc_reqs--; - else - dev->bus->bandwidth_int_reqs--; - -#ifdef USB_BANDWIDTH_MESSAGES - dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n", - urb->bandwidth, - isoc ? "ISOC" : "INTR", - dev->bus->bandwidth_allocated, - dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); -#endif - urb->bandwidth = 0; -} - - -/*-------------------------------------------------------------------------*/ - -/* - * Generic HC operations. - */ - -/*-------------------------------------------------------------------------*/ - -/* called from khubd, or root hub init threads for hcd-private init */ -static int hcd_alloc_dev (struct usb_device *udev) -{ - struct hcd_dev *dev; - struct usb_hcd *hcd; - unsigned long flags; - - if (!udev || udev->hcpriv) - return -EINVAL; - if (!udev->bus || !udev->bus->hcpriv) - return -ENODEV; - hcd = udev->bus->hcpriv; - if (hcd->state == USB_STATE_QUIESCING) - return -ENOLINK; - - dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL); - if (dev == NULL) - return -ENOMEM; - memset (dev, 0, sizeof *dev); - - INIT_LIST_HEAD (&dev->dev_list); - INIT_LIST_HEAD (&dev->urb_list); - - spin_lock_irqsave (&hcd_data_lock, flags); - list_add (&dev->dev_list, &hcd->dev_list); - // refcount is implicit - udev->hcpriv = dev; - spin_unlock_irqrestore (&hcd_data_lock, flags); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static void urb_unlink (struct urb *urb) -{ - unsigned long flags; - struct usb_device *dev; - - /* Release any periodic transfer bandwidth */ - if (urb->bandwidth) - usb_release_bandwidth (urb->dev, urb, - usb_pipeisoc (urb->pipe)); - - /* clear all state linking urb to this dev (and hcd) */ - - spin_lock_irqsave (&hcd_data_lock, flags); - list_del_init (&urb->urb_list); - dev = urb->dev; - spin_unlock_irqrestore (&hcd_data_lock, flags); - usb_put_dev (dev); -} - - -/* may be called in any context with a valid urb->dev usecount - * caller surrenders "ownership" of urb - * expects usb_submit_urb() to have sanity checked and conditioned all - * inputs in the urb - */ -static int hcd_submit_urb (struct urb *urb, int mem_flags) -{ - int status; - struct usb_hcd *hcd = urb->dev->bus->hcpriv; - struct hcd_dev *dev = urb->dev->hcpriv; - unsigned long flags; - - - if (!hcd || !dev) - return -ENODEV; -// printk("submit_urb %p, # %i, t %i\n",urb,urb->dev->devnum,usb_pipetype(urb->pipe)); - /* - * FIXME: make urb timeouts be generic, keeping the HCD cores - * as simple as possible. - */ - - // NOTE: a generic device/urb monitoring hook would go here. - // hcd_monitor_hook(MONITOR_URB_SUBMIT, urb) - // It would catch submission paths for all urbs. - - /* - * Atomically queue the urb, first to our records, then to the HCD. - * Access to urb->status is controlled by urb->lock ... changes on - * i/o completion (normal or fault) or unlinking. - */ - - // FIXME: verify that quiescing hc works right (RH cleans up) - - spin_lock_irqsave (&hcd_data_lock, flags); - if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) { - usb_get_dev (urb->dev); - list_add_tail (&urb->urb_list, &dev->urb_list); - status = 0; - } else { - INIT_LIST_HEAD (&urb->urb_list); - status = -ESHUTDOWN; - } - spin_unlock_irqrestore (&hcd_data_lock, flags); - if (status) - return status; - - /* increment urb's reference count as part of giving it to the HCD - * (which now controls it). HCD guarantees that it either returns - * an error or calls giveback(), but not both. - */ - - urb = usb_get_urb (urb); - if (urb->dev == hcd->self.root_hub) { - /* NOTE: requirement on hub callers (usbfs and the hub - * driver, for now) that URBs' urb->transfer_buffer be - * valid and usb_buffer_{sync,unmap}() not be needed, since - * they could clobber root hub response data. - */ - urb->transfer_flags |= URB_NO_DMA_MAP; - status = rh_urb_enqueue (hcd, urb); - goto done; - } - - /* lower level hcd code should use *_dma exclusively, - * unless it uses pio or talks to another transport. - */ - if (!(urb->transfer_flags & URB_NO_DMA_MAP) - && hcd->controller->dma_mask) { - if (usb_pipecontrol (urb->pipe)) - urb->setup_dma = dma_map_single ( - hcd->controller, - urb->setup_packet, - sizeof (struct usb_ctrlrequest), - DMA_TO_DEVICE); - if (urb->transfer_buffer_length != 0) - urb->transfer_dma = dma_map_single ( - hcd->controller, - urb->transfer_buffer, - urb->transfer_buffer_length, - usb_pipein (urb->pipe) - ? DMA_FROM_DEVICE - : DMA_TO_DEVICE); - } - - status = hcd->driver->urb_enqueue (hcd, urb, mem_flags); -done: - if (status) { - usb_put_urb (urb); - urb_unlink (urb); - } - return status; -} - -/*-------------------------------------------------------------------------*/ - -/* called in any context */ -static int hcd_get_frame_number (struct usb_device *udev) -{ - struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv; - return hcd->driver->get_frame_number (hcd); -} - -/*-------------------------------------------------------------------------*/ - -/* this makes the hcd giveback() the urb more quickly, by kicking it - * off hardware queues (which may take a while) and returning it as - * soon as practical. we've already set up the urb's return status, - * but we can't know if the callback completed already. - */ -static void -unlink1 (struct usb_hcd *hcd, struct urb *urb) -{ - if (urb == (struct urb *) hcd->rh_timer.data) - usb_rh_status_dequeue (hcd, urb); - else { - int value; - - /* failures "should" be harmless */ - value = hcd->driver->urb_dequeue (hcd, urb); - if (value != 0) - dev_dbg (hcd->controller, - "dequeue %p --> %d\n", - urb, value); - } -} - -struct completion_splice { // modified urb context: - /* did we complete? */ - struct completion done; - - /* original urb data */ - usb_complete_t complete; - void *context; -}; - -static void unlink_complete (struct urb *urb, struct pt_regs *regs) -{ - struct completion_splice *splice; - - splice = (struct completion_splice *) urb->context; - - /* issue original completion call */ - urb->complete = splice->complete; - urb->context = splice->context; - urb->complete (urb, regs); - - /* then let the synchronous unlink call complete */ - complete (&splice->done); -} - -/* - * called in any context; note ASYNC_UNLINK restrictions - * - * caller guarantees urb won't be recycled till both unlink() - * and the urb's completion function return - */ -static int hcd_unlink_urb (struct urb *urb) -{ - struct hcd_dev *dev; - struct usb_hcd *hcd = 0; - struct device *sys = 0; - unsigned long flags; - struct completion_splice splice; - int retval; - - if (!urb) - return -EINVAL; - - /* - * we contend for urb->status with the hcd core, - * which changes it while returning the urb. - * - * Caller guaranteed that the urb pointer hasn't been freed, and - * that it was submitted. But as a rule it can't know whether or - * not it's already been unlinked ... so we respect the reversed - * lock sequence needed for the usb_hcd_giveback_urb() code paths - * (urb lock, then hcd_data_lock) in case some other CPU is now - * unlinking it. - */ - spin_lock_irqsave (&urb->lock, flags); - spin_lock (&hcd_data_lock); - - if (!urb->dev || !urb->dev->bus) { - retval = -ENODEV; - goto done; - } - - dev = urb->dev->hcpriv; - sys = &urb->dev->dev; - hcd = urb->dev->bus->hcpriv; - if (!dev || !hcd) { - retval = -ENODEV; - goto done; - } - - if (!urb->hcpriv) { - retval = -EINVAL; - goto done; - } - - /* Any status except -EINPROGRESS means something already started to - * unlink this URB from the hardware. So there's no more work to do. - * - * FIXME use better explicit urb state - */ - if (urb->status != -EINPROGRESS) { - retval = -EBUSY; - goto done; - } - - /* maybe set up to block until the urb's completion fires. the - * lower level hcd code is always async, locking on urb->status - * updates; an intercepted completion unblocks us. - */ - if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) { - if (in_interrupt ()) { - dev_dbg (hcd->controller, "non-async unlink in_interrupt"); - retval = -EWOULDBLOCK; - goto done; - } - /* synchronous unlink: block till we see the completion */ - init_completion (&splice.done); - splice.complete = urb->complete; - splice.context = urb->context; - urb->complete = unlink_complete; - urb->context = &splice; - urb->status = -ENOENT; - } else { - /* asynchronous unlink */ - urb->status = -ECONNRESET; - } - spin_unlock (&hcd_data_lock); - spin_unlock_irqrestore (&urb->lock, flags); - - // FIXME remove splicing, so this becomes unlink1 (hcd, urb); - if (urb == (struct urb *) hcd->rh_timer.data) { - usb_rh_status_dequeue (hcd, urb); - retval = 0; - } else { - retval = hcd->driver->urb_dequeue (hcd, urb); - - /* hcds shouldn't really fail these calls, but... */ - if (retval) { - dev_dbg (sys, "dequeue %p --> %d\n", urb, retval); - if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) { - spin_lock_irqsave (&urb->lock, flags); - urb->complete = splice.complete; - urb->context = splice.context; - spin_unlock_irqrestore (&urb->lock, flags); - } - goto bye; - } - } - - /* block till giveback, if needed */ - if (urb->transfer_flags & URB_ASYNC_UNLINK) - return -EINPROGRESS; - - wait_for_completion (&splice.done); - return 0; - -done: - spin_unlock (&hcd_data_lock); - spin_unlock_irqrestore (&urb->lock, flags); -bye: - if (retval && sys && sys->driver) - dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval); - return retval; -} - -/*-------------------------------------------------------------------------*/ - -/* disables the endpoint: cancels any pending urbs, then synchronizes with - * the hcd to make sure all endpoint state is gone from hardware. use for - * set_configuration, set_interface, driver removal, physical disconnect. - * - * example: a qh stored in hcd_dev.ep[], holding state related to endpoint - * type, maxpacket size, toggle, halt status, and scheduling. - */ -static void hcd_endpoint_disable (struct usb_device *udev, int endpoint) -{ - unsigned long flags; - struct hcd_dev *dev; - struct usb_hcd *hcd; - struct urb *urb; - unsigned epnum = endpoint & USB_ENDPOINT_NUMBER_MASK; - - dev = udev->hcpriv; - hcd = udev->bus->hcpriv; - -rescan: - /* (re)block new requests, as best we can */ - if (endpoint & USB_DIR_IN) { - usb_endpoint_halt (udev, epnum, 0); - udev->epmaxpacketin [epnum] = 0; - } else { - usb_endpoint_halt (udev, epnum, 1); - udev->epmaxpacketout [epnum] = 0; - } - - /* then kill any current requests */ - spin_lock_irqsave (&hcd_data_lock, flags); - list_for_each_entry (urb, &dev->urb_list, urb_list) { - int tmp = urb->pipe; - - /* ignore urbs for other endpoints */ - if (usb_pipeendpoint (tmp) != epnum) - continue; - if ((tmp ^ endpoint) & USB_DIR_IN) - continue; - - /* another cpu may be in hcd, spinning on hcd_data_lock - * to giveback() this urb. the races here should be - * small, but a full fix needs a new "can't submit" - * urb state. - */ - if (urb->status != -EINPROGRESS) - continue; - usb_get_urb (urb); - spin_unlock_irqrestore (&hcd_data_lock, flags); - - spin_lock_irqsave (&urb->lock, flags); - tmp = urb->status; - if (tmp == -EINPROGRESS) - urb->status = -ESHUTDOWN; - spin_unlock_irqrestore (&urb->lock, flags); - - /* kick hcd unless it's already returning this */ - if (tmp == -EINPROGRESS) { - tmp = urb->pipe; - unlink1 (hcd, urb); - dev_dbg (hcd->controller, - "shutdown urb %p pipe %08x ep%d%s%s\n", - urb, tmp, usb_pipeendpoint (tmp), - (tmp & USB_DIR_IN) ? "in" : "out", - ({ char *s; \ - switch (usb_pipetype (tmp)) { \ - case PIPE_CONTROL: s = ""; break; \ - case PIPE_BULK: s = "-bulk"; break; \ - case PIPE_INTERRUPT: s = "-intr"; break; \ - default: s = "-iso"; break; \ - }; s;})); - } - usb_put_urb (urb); - - /* list contents may have changed */ - goto rescan; - } - spin_unlock_irqrestore (&hcd_data_lock, flags); - - /* synchronize with the hardware, so old configuration state - * clears out immediately (and will be freed). - */ - might_sleep (); - if (hcd->driver->endpoint_disable) - hcd->driver->endpoint_disable (hcd, dev, endpoint); -} - -/*-------------------------------------------------------------------------*/ - -/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup. - * we're guaranteed that the device is fully quiesced. also, that each - * endpoint has been hcd_endpoint_disabled. - */ - -static int hcd_free_dev (struct usb_device *udev) -{ - struct hcd_dev *dev; - struct usb_hcd *hcd; - unsigned long flags; - - if (!udev || !udev->hcpriv) - return -EINVAL; - - if (!udev->bus || !udev->bus->hcpriv) - return -ENODEV; - - // should udev->devnum == -1 ?? - - dev = udev->hcpriv; - hcd = udev->bus->hcpriv; - - /* device driver problem with refcounts? */ - if (!list_empty (&dev->urb_list)) { - dev_dbg (hcd->controller, "free busy dev, %s devnum %d (bug!)\n", - hcd->self.bus_name, udev->devnum); - return -EINVAL; - } - - spin_lock_irqsave (&hcd_data_lock, flags); - list_del (&dev->dev_list); - udev->hcpriv = NULL; - spin_unlock_irqrestore (&hcd_data_lock, flags); - - kfree (dev); - return 0; -} - -/* - * usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue) - * - * When registering a USB bus through the HCD framework code, use this - * usb_operations vector. The PCI glue layer does so automatically; only - * bus glue for non-PCI system busses will need to use this. - */ -struct usb_operations usb_hcd_operations = { - .allocate = hcd_alloc_dev, - .get_frame_number = hcd_get_frame_number, - .submit_urb = hcd_submit_urb, - .unlink_urb = hcd_unlink_urb, - .deallocate = hcd_free_dev, - .buffer_alloc = hcd_buffer_alloc, - .buffer_free = hcd_buffer_free, - .disable = hcd_endpoint_disable, -}; -EXPORT_SYMBOL (usb_hcd_operations); - -/*-------------------------------------------------------------------------*/ - -/** - * usb_hcd_giveback_urb - return URB from HCD to device driver - * @hcd: host controller returning the URB - * @urb: urb being returned to the USB device driver. - * @regs: pt_regs, passed down to the URB completion handler - * Context: in_interrupt() - * - * This hands the URB from HCD to its USB device driver, using its - * completion function. The HCD has freed all per-urb resources - * (and is done using urb->hcpriv). It also released all HCD locks; - * the device driver won't cause problems if it frees, modifies, - * or resubmits this URB. - */ -void STDCALL usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) -{ - urb_unlink (urb); - - // NOTE: a generic device/urb monitoring hook would go here. - // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev) - // It would catch exit/unlink paths for all urbs. - - /* lower level hcd code should use *_dma exclusively */ - if (!(urb->transfer_flags & URB_NO_DMA_MAP)) { - if (usb_pipecontrol (urb->pipe)) - pci_unmap_single (hcd->pdev, urb->setup_dma, - sizeof (struct usb_ctrlrequest), - PCI_DMA_TODEVICE); - if (urb->transfer_buffer_length != 0) - pci_unmap_single (hcd->pdev, urb->transfer_dma, - urb->transfer_buffer_length, - usb_pipein (urb->pipe) - ? PCI_DMA_FROMDEVICE - : PCI_DMA_TODEVICE); - } - - /* pass ownership to the completion handler */ - urb->complete (urb, regs); - usb_put_urb (urb); -} - -/*-------------------------------------------------------------------------*/ - -/** - * usb_hcd_irq - hook IRQs to HCD framework (bus glue) - * @irq: the IRQ being raised - * @__hcd: pointer to the HCD whose IRQ is beinng signaled - * @r: saved hardware registers - * - * When registering a USB bus through the HCD framework code, use this - * to handle interrupts. The PCI glue layer does so automatically; only - * bus glue for non-PCI system busses will need to use this. - */ -irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) -{ - struct usb_hcd *hcd = __hcd; - int start = hcd->state; - - if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */ - return IRQ_NONE; - - hcd->driver->irq (hcd, r); - if (hcd->state != start && hcd->state == USB_STATE_HALT) - usb_hc_died (hcd); - return IRQ_HANDLED; -} - -/*-------------------------------------------------------------------------*/ - -static void hcd_panic (void *_hcd) -{ - struct usb_hcd *hcd = _hcd; - hcd->driver->stop (hcd); -} - -/** - * usb_hc_died - report abnormal shutdown of a host controller (bus glue) - * @hcd: pointer to the HCD representing the controller - * - * This is called by bus glue to report a USB host controller that died - * while operations may still have been pending. It's called automatically - * by the PCI glue, so only glue for non-PCI busses should need to call it. - */ -void STDCALL usb_hc_died (struct usb_hcd *hcd) -{ - struct list_head *devlist, *urblist; - struct hcd_dev *dev; - struct urb *urb; - unsigned long flags; - - /* flag every pending urb as done */ - spin_lock_irqsave (&hcd_data_lock, flags); - list_for_each (devlist, &hcd->dev_list) { - dev = list_entry (devlist, struct hcd_dev, dev_list); - list_for_each (urblist, &dev->urb_list) { - urb = list_entry (urblist, struct urb, urb_list); - dev_dbg (hcd->controller, "shutdown %s urb %p pipe %x, current status %d\n", - hcd->self.bus_name, urb, urb->pipe, urb->status); - if (urb->status == -EINPROGRESS) - urb->status = -ESHUTDOWN; - } - } - urb = (struct urb *) hcd->rh_timer.data; - if (urb) - urb->status = -ESHUTDOWN; - spin_unlock_irqrestore (&hcd_data_lock, flags); - - /* hcd->stop() needs a task context */ - INIT_WORK (&hcd->work, hcd_panic, hcd); - (void) schedule_work (&hcd->work); -} - +/* + * (C) Copyright Linus Torvalds 1999 + * (C) Copyright Johannes Erdfelt 1999-2001 + * (C) Copyright Andreas Gal 1999 + * (C) Copyright Gregory P. Smith 1999 + * (C) Copyright Deti Fliegl 1999 + * (C) Copyright Randy Dunlap 2000 + * (C) Copyright David Brownell 2000-2002 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if 0 +#include + +#ifdef CONFIG_USB_DEBUG +#define DEBUG +#endif + +#include +#include +#include +#include +#include +#include /* for UTS_SYSNAME */ +#include /* for hcd->pdev and dma addressing */ +#include +#include + +#include +#else +#include "../usb_wrapper.h" +//#define DEBUG +#endif + +#include "hcd.h" + +// #define USB_BANDWIDTH_MESSAGES + +/*-------------------------------------------------------------------------*/ + +/* + * USB Host Controller Driver framework + * + * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing + * HCD-specific behaviors/bugs. + * + * This does error checks, tracks devices and urbs, and delegates to a + * "hc_driver" only for code (and data) that really needs to know about + * hardware differences. That includes root hub registers, i/o queues, + * and so on ... but as little else as possible. + * + * Shared code includes most of the "root hub" code (these are emulated, + * though each HC's hardware works differently) and PCI glue, plus request + * tracking overhead. The HCD code should only block on spinlocks or on + * hardware handshaking; blocking on software events (such as other kernel + * threads releasing resources, or completing actions) is all generic. + * + * Happens the USB 2.0 spec says this would be invisible inside the "USBD", + * and includes mostly a "HCDI" (HCD Interface) along with some APIs used + * only by the hub driver ... and that neither should be seen or used by + * usb client device drivers. + * + * Contributors of ideas or unattributed patches include: David Brownell, + * Roman Weissgaerber, Rory Bolt, Greg Kroah-Hartman, ... + * + * HISTORY: + * 2002-02-21 Pull in most of the usb_bus support from usb.c; some + * associated cleanup. "usb_hcd" still != "usb_bus". + * 2001-12-12 Initial patch version for Linux 2.5.1 kernel. + */ + +/*-------------------------------------------------------------------------*/ + +/* host controllers we manage */ +LIST_HEAD (usb_bus_list); +EXPORT_SYMBOL_GPL (usb_bus_list); + +/* used when allocating bus numbers */ +#define USB_MAXBUS 64 +struct usb_busmap { + unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))]; +}; +static struct usb_busmap busmap; + +/* used when updating list of hcds */ +DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */ +EXPORT_SYMBOL_GPL (usb_bus_list_lock); + +/* used when updating hcd data */ +static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED; + +/*-------------------------------------------------------------------------*/ + +/* + * Sharable chunks of root hub code. + */ + +/*-------------------------------------------------------------------------*/ + +#define KERNEL_REL ((LINUX_VERSION_CODE >> 16) & 0x0ff) +#define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff) + +/* usb 2.0 root hub device descriptor */ +static const u8 usb2_rh_dev_descriptor [18] = { + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x00, 0x02, /* __u16 bcdUSB; v2.0 */ + + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + + 0x00, 0x00, /* __u16 idVendor; */ + 0x00, 0x00, /* __u16 idProduct; */ + KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */ + + 0x03, /* __u8 iManufacturer; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + +/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */ + +/* usb 1.1 root hub device descriptor */ +static const u8 usb11_rh_dev_descriptor [18] = { + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x10, 0x01, /* __u16 bcdUSB; v1.1 */ + + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + + 0x00, 0x00, /* __u16 idVendor; */ + 0x00, 0x00, /* __u16 idProduct; */ + KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */ + + 0x03, /* __u8 iManufacturer; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + + +/*-------------------------------------------------------------------------*/ + +/* Configuration descriptors for our root hubs */ + +static const u8 fs_rh_config_descriptor [] = { + + /* one configuration */ + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, 0x00, /* __u16 wTotalLength; */ + 0x01, /* __u8 bNumInterfaces; (1) */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; + Bit 7: Bus-powered, + 6: Self-powered, + 5 Remote-wakwup, + 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x00, /* __u8 if_iInterface; */ + + /* one endpoint (status change endpoint) */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */ +}; + +static const u8 hs_rh_config_descriptor [] = { + + /* one configuration */ + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, 0x00, /* __u16 wTotalLength; */ + 0x01, /* __u8 bNumInterfaces; (1) */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; + Bit 7: Bus-powered, + 6: Self-powered, + 5 Remote-wakwup, + 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x00, /* __u8 if_iInterface; */ + + /* one endpoint (status change endpoint) */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */ +}; + +/*-------------------------------------------------------------------------*/ + +/* + * helper routine for returning string descriptors in UTF-16LE + * input can actually be ISO-8859-1; ASCII is its 7-bit subset + */ +static int ascii2utf (char *s, u8 *utf, int utfmax) +{ + int retval; + + for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) { + *utf++ = *s++; + *utf++ = 0; + } + return retval; +} + +/* + * rh_string - provides manufacturer, product and serial strings for root hub + * @id: the string ID number (1: serial number, 2: product, 3: vendor) + * @hcd: the host controller for this root hub + * @type: string describing our driver + * @data: return packet in UTF-16 LE + * @len: length of the return packet + * + * Produces either a manufacturer, product or serial number string for the + * virtual root hub device. + */ +static int rh_string ( + int id, + struct usb_hcd *hcd, + u8 *data, + int len +) { + char buf [100]; + + // language ids + if (id == 0) { + *data++ = 4; *data++ = 3; /* 4 bytes string data */ + *data++ = 0x09; *data++ = 0x04; /* MSFT-speak for "en-us" */ + return 4; + + // serial number + } else if (id == 1) { + strcpy (buf, hcd->self.bus_name); + + // product description + } else if (id == 2) { + strcpy (buf, hcd->product_desc); + + // id 3 == vendor description + } else if (id == 3) { + sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE, + hcd->description); + + // unsupported IDs --> "protocol stall" + } else + return 0; + + data [0] = 2 * (strlen (buf) + 1); + data [1] = 3; /* type == string */ + return 2 + ascii2utf (buf, data + 2, len - 2); +} + + +/* Root hub control transfers execute synchronously */ +static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) +{ + struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet; + u16 typeReq, wValue, wIndex, wLength; + const u8 *bufp = 0; + u8 *ubuf = urb->transfer_buffer; + int len = 0; + //unsigned long flags; + + typeReq = (cmd->bRequestType << 8) | cmd->bRequest; + wValue = le16_to_cpu (cmd->wValue); + wIndex = le16_to_cpu (cmd->wIndex); + wLength = le16_to_cpu (cmd->wLength); + + if (wLength > urb->transfer_buffer_length) + goto error; + + /* set up for success */ + urb->status = 0; + urb->actual_length = wLength; + switch (typeReq) { + + /* DEVICE REQUESTS */ + + case DeviceRequest | USB_REQ_GET_STATUS: + // DEVICE_REMOTE_WAKEUP + ubuf [0] = 1; // selfpowered + ubuf [1] = 0; + /* FALLTHROUGH */ + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + case DeviceOutRequest | USB_REQ_SET_FEATURE: + dev_dbg (hcd->controller, "no device features yet yet\n"); + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + ubuf [0] = 1; + /* FALLTHROUGH */ + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch (wValue & 0xff00) { + case USB_DT_DEVICE << 8: + if (hcd->driver->flags & HCD_USB2) + bufp = usb2_rh_dev_descriptor; + else if (hcd->driver->flags & HCD_USB11) + bufp = usb11_rh_dev_descriptor; + else + goto error; + len = 18; + break; + case USB_DT_CONFIG << 8: + if (hcd->driver->flags & HCD_USB2) { + bufp = hs_rh_config_descriptor; + len = sizeof hs_rh_config_descriptor; + } else { + bufp = fs_rh_config_descriptor; + len = sizeof fs_rh_config_descriptor; + } + break; + case USB_DT_STRING << 8: + urb->actual_length = rh_string ( + wValue & 0xff, hcd, + ubuf, wLength); + break; + default: + goto error; + } + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + ubuf [0] = 0; + /* FALLTHROUGH */ + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + // wValue == urb->dev->devaddr + dev_dbg (hcd->controller, "root hub device address %d\n", + wValue); + break; + + /* INTERFACE REQUESTS (no defined feature/status flags) */ + + /* ENDPOINT REQUESTS */ + + case EndpointRequest | USB_REQ_GET_STATUS: + // ENDPOINT_HALT flag + ubuf [0] = 0; + ubuf [1] = 0; + /* FALLTHROUGH */ + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: + case EndpointOutRequest | USB_REQ_SET_FEATURE: + dev_dbg (hcd->controller, "no endpoint features yet\n"); + break; + + /* CLASS REQUESTS (and errors) */ + + default: + /* non-generic request */ + urb->status = hcd->driver->hub_control (hcd, + typeReq, wValue, wIndex, + ubuf, wLength); + break; +error: + /* "protocol stall" on error */ + urb->status = -EPIPE; + dev_dbg (hcd->controller, "unsupported hub control message (maxchild %d)\n", + urb->dev->maxchild); + } + if (urb->status) { + urb->actual_length = 0; + dev_dbg (hcd->controller, "CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d\n", + typeReq, wValue, wIndex, wLength, urb->status); + } + if (bufp) { + if (urb->transfer_buffer_length < len) + len = urb->transfer_buffer_length; + urb->actual_length = len; + // always USB_DIR_IN, toward host + memcpy (ubuf, bufp, len); + } + + /* any errors get returned through the urb completion */ + local_irq_save (flags); + usb_hcd_giveback_urb (hcd, urb, NULL); + local_irq_restore (flags); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* + * Root Hub interrupt transfers are synthesized with a timer. + * Completions are called in_interrupt() but not in_irq(). + */ + +static void rh_report_status (unsigned long ptr); + +static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) +{ + int len = 1 + (urb->dev->maxchild / 8); + + /* rh_timer protected by hcd_data_lock */ + if (hcd->rh_timer.data + || urb->status != -EINPROGRESS + || urb->transfer_buffer_length < len) { + dev_dbg (hcd->controller, + "not queuing rh status urb, stat %d\n", + urb->status); + return -EINVAL; + } + + init_timer (&hcd->rh_timer); + + hcd->rh_timer.function = rh_report_status; + hcd->rh_timer.data = (unsigned long) urb; + /* USB 2.0 spec says 256msec; this is close enough */ + hcd->rh_timer.expires = jiffies + HZ/4; + add_timer (&hcd->rh_timer); + urb->hcpriv = hcd; /* nonzero to indicate it's queued */ + return 0; +} + +/* timer callback */ + +static void rh_report_status (unsigned long ptr) +{ + struct urb *urb; + struct usb_hcd *hcd; + int length; + //unsigned long flags; + + urb = (struct urb *) ptr; + local_irq_save (flags); + spin_lock (&urb->lock); + + /* do nothing if the hc is gone or the urb's been unlinked */ + if (!urb->dev + || urb->status != -EINPROGRESS + || (hcd = urb->dev->bus->hcpriv) == 0 + || !HCD_IS_RUNNING (hcd->state)) { + spin_unlock (&urb->lock); + local_irq_restore (flags); + return; + } + + length = hcd->driver->hub_status_data (hcd, urb->transfer_buffer); + + /* complete the status urb, or retrigger the timer */ + spin_lock (&hcd_data_lock); + if (length > 0) { + hcd->rh_timer.data = 0; + urb->actual_length = length; + urb->status = 0; + urb->hcpriv = 0; + } else + mod_timer (&hcd->rh_timer, jiffies + HZ/4); + spin_unlock (&hcd_data_lock); + spin_unlock (&urb->lock); + + /* local irqs are always blocked in completions */ + if (length > 0) + usb_hcd_giveback_urb (hcd, urb, NULL); + local_irq_restore (flags); +} + +/*-------------------------------------------------------------------------*/ + +static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) +{ + if (usb_pipeint (urb->pipe)) { + int retval; + unsigned long flags; + + spin_lock_irqsave (&hcd_data_lock, flags); + retval = rh_status_urb (hcd, urb); + spin_unlock_irqrestore (&hcd_data_lock, flags); + return retval; + } + if (usb_pipecontrol (urb->pipe)) + return rh_call_control (hcd, urb); + else + return -EINVAL; +} + +/*-------------------------------------------------------------------------*/ + +void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb) +{ + //unsigned long flags; + + /* note: always a synchronous unlink */ + del_timer_sync (&hcd->rh_timer); + hcd->rh_timer.data = 0; + + local_irq_save (flags); + urb->hcpriv = 0; + usb_hcd_giveback_urb (hcd, urb, NULL); + local_irq_restore (flags); +} + +/*-------------------------------------------------------------------------*/ + +/* exported only within usbcore */ +void usb_bus_get (struct usb_bus *bus) +{ + atomic_inc (&bus->refcnt); +} + +/* exported only within usbcore */ +void usb_bus_put (struct usb_bus *bus) +{ + if (atomic_dec_and_test (&bus->refcnt)) + kfree (bus); +} + +/*-------------------------------------------------------------------------*/ + +/** + * usb_bus_init - shared initialization code + * @bus: the bus structure being initialized + * + * This code is used to initialize a usb_bus structure, memory for which is + * separately managed. + */ +void STDCALL usb_bus_init (struct usb_bus *bus) +{ + memset (&bus->devmap, 0, sizeof(struct usb_devmap)); + + bus->devnum_next = 1; + + bus->root_hub = NULL; + bus->hcpriv = NULL; + bus->busnum = -1; + bus->bandwidth_allocated = 0; + bus->bandwidth_int_reqs = 0; + bus->bandwidth_isoc_reqs = 0; + + INIT_LIST_HEAD (&bus->bus_list); + + atomic_set (&bus->refcnt, 1); +} + +/** + * usb_alloc_bus - creates a new USB host controller structure + * @op: pointer to a struct usb_operations that this bus structure should use + * Context: !in_interrupt() + * + * Creates a USB host controller bus structure with the specified + * usb_operations and initializes all the necessary internal objects. + * + * If no memory is available, NULL is returned. + * + * The caller should call usb_free_bus() when it is finished with the structure. + */ +struct usb_bus STDCALL *usb_alloc_bus (struct usb_operations *op) +{ + struct usb_bus *bus; + + bus = kmalloc (sizeof *bus, GFP_KERNEL); + if (!bus) + return NULL; + usb_bus_init (bus); + bus->op = op; + return bus; +} + +/** + * usb_free_bus - frees the memory used by a bus structure + * @bus: pointer to the bus to free + * + * To be invoked by a HCD, only as the last step of decoupling from + * hardware. It is an error to call this if the reference count is + * anything but one. That would indicate that some system component + * did not correctly shut down, and thought the hardware was still + * accessible. + */ +void STDCALL usb_free_bus (struct usb_bus *bus) +{ + if (!bus) + return; + if (atomic_read (&bus->refcnt) != 1) + err ("usb_free_bus #%d, count != 1", bus->busnum); + usb_bus_put (bus); +} + +/*-------------------------------------------------------------------------*/ + +/** + * usb_register_bus - registers the USB host controller with the usb core + * @bus: pointer to the bus to register + * Context: !in_interrupt() + * + * Assigns a bus number, and links the controller into usbcore data + * structures so that it can be seen by scanning the bus list. + */ +void STDCALL usb_register_bus(struct usb_bus *bus) +{ + int busnum; + + down (&usb_bus_list_lock); + busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); + if (busnum < USB_MAXBUS) { + set_bit (busnum, busmap.busmap); + bus->busnum = busnum; + } else + warn ("too many buses"); + + usb_bus_get (bus); + + /* Add it to the list of buses */ + list_add (&bus->bus_list, &usb_bus_list); + up (&usb_bus_list_lock); + + usbfs_add_bus (bus); + + dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum); +} + +/** + * usb_deregister_bus - deregisters the USB host controller + * @bus: pointer to the bus to deregister + * Context: !in_interrupt() + * + * Recycles the bus number, and unlinks the controller from usbcore data + * structures so that it won't be seen by scanning the bus list. + */ +void STDCALL usb_deregister_bus (struct usb_bus *bus) +{ + dev_info (bus->controller, "USB bus %d deregistered\n", bus->busnum); + + /* + * NOTE: make sure that all the devices are removed by the + * controller code, as well as having it call this when cleaning + * itself up + */ + down (&usb_bus_list_lock); + list_del (&bus->bus_list); + up (&usb_bus_list_lock); + + usbfs_remove_bus (bus); + + clear_bit (bus->busnum, busmap.busmap); + + usb_bus_put (bus); +} + +/** + * usb_register_root_hub - called by HCD to register its root hub + * @usb_dev: the usb root hub device to be registered. + * @parent_dev: the parent device of this root hub. + * + * The USB host controller calls this function to register the root hub + * properly with the USB subsystem. It sets up the device properly in + * the driverfs tree, and then calls usb_new_device() to register the + * usb device. + */ +int STDCALL usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev) +{ + int retval; + + sprintf (&usb_dev->dev.bus_id[0], "usb%d", usb_dev->bus->busnum); + usb_dev->state = USB_STATE_DEFAULT; + retval = usb_new_device (usb_dev, parent_dev); + if (retval) + dev_err (parent_dev, "can't register root hub for %s, %d\n", + usb_dev->dev.bus_id, retval); + return retval; +} + + +/*-------------------------------------------------------------------------*/ + +/** + * usb_calc_bus_time - approximate periodic transaction time in nanoseconds + * @speed: from dev->speed; USB_SPEED_{LOW,FULL,HIGH} + * @is_input: true iff the transaction sends data to the host + * @isoc: true for isochronous transactions, false for interrupt ones + * @bytecount: how many bytes in the transaction. + * + * Returns approximate bus time in nanoseconds for a periodic transaction. + * See USB 2.0 spec section 5.11.3; only periodic transfers need to be + * scheduled in software, this function is only used for such scheduling. + */ +long STDCALL usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount) +{ + unsigned long tmp; + + switch (speed) { + case USB_SPEED_LOW: /* INTR only */ + if (is_input) { + tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); + } else { + tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); + } + case USB_SPEED_FULL: /* ISOC or INTR */ + if (isoc) { + tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); + } else { + tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; + return (9107L + BW_HOST_DELAY + tmp); + } + case USB_SPEED_HIGH: /* ISOC or INTR */ + // FIXME adjust for input vs output + if (isoc) + tmp = HS_USECS (bytecount); + else + tmp = HS_USECS_ISO (bytecount); + return tmp; + default: + dbg ("bogus device speed!"); + return -1; + } +} + +/* + * usb_check_bandwidth(): + * + * old_alloc is from host_controller->bandwidth_allocated in microseconds; + * bustime is from calc_bus_time(), but converted to microseconds. + * + * returns if successful, + * or -ENOSPC if bandwidth request fails. + * + * FIXME: + * This initial implementation does not use Endpoint.bInterval + * in managing bandwidth allocation. + * It probably needs to be expanded to use Endpoint.bInterval. + * This can be done as a later enhancement (correction). + * + * This will also probably require some kind of + * frame allocation tracking...meaning, for example, + * that if multiple drivers request interrupts every 10 USB frames, + * they don't all have to be allocated at + * frame numbers N, N+10, N+20, etc. Some of them could be at + * N+11, N+21, N+31, etc., and others at + * N+12, N+22, N+32, etc. + * + * Similarly for isochronous transfers... + * + * Individual HCDs can schedule more directly ... this logic + * is not correct for high speed transfers. + */ +int STDCALL usb_check_bandwidth (struct usb_device *dev, struct urb *urb) +{ + unsigned int pipe = urb->pipe; + long bustime; + int is_in = usb_pipein (pipe); + int is_iso = usb_pipeisoc (pipe); + int old_alloc = dev->bus->bandwidth_allocated; + int new_alloc; + + + bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso, + usb_maxpacket (dev, pipe, !is_in))); + if (is_iso) + bustime /= urb->number_of_packets; + + new_alloc = old_alloc + (int) bustime; + if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) { +#ifdef DEBUG + char *mode = +#ifdef CONFIG_USB_BANDWIDTH + ""; +#else + "would have "; +#endif + dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n", + mode, old_alloc, bustime, new_alloc); +#endif +#ifdef CONFIG_USB_BANDWIDTH + bustime = -ENOSPC; /* report error */ +#endif + } + + return bustime; +} + + +/** + * usb_claim_bandwidth - records bandwidth for a periodic transfer + * @dev: source/target of request + * @urb: request (urb->dev == dev) + * @bustime: bandwidth consumed, in (average) microseconds per frame + * @isoc: true iff the request is isochronous + * + * Bus bandwidth reservations are recorded purely for diagnostic purposes. + * HCDs are expected not to overcommit periodic bandwidth, and to record such + * reservations whenever endpoints are added to the periodic schedule. + * + * FIXME averaging per-frame is suboptimal. Better to sum over the HCD's + * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable + * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how + * large its periodic schedule is. + */ +void STDCALL usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc) +{ + dev->bus->bandwidth_allocated += bustime; + if (isoc) + dev->bus->bandwidth_isoc_reqs++; + else + dev->bus->bandwidth_int_reqs++; + urb->bandwidth = bustime; + +#ifdef USB_BANDWIDTH_MESSAGES + dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n", + bustime, + isoc ? "ISOC" : "INTR", + dev->bus->bandwidth_allocated, + dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); +#endif +} + + +/** + * usb_release_bandwidth - reverses effect of usb_claim_bandwidth() + * @dev: source/target of request + * @urb: request (urb->dev == dev) + * @isoc: true iff the request is isochronous + * + * This records that previously allocated bandwidth has been released. + * Bandwidth is released when endpoints are removed from the host controller's + * periodic schedule. + */ +void STDCALL usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc) +{ + dev->bus->bandwidth_allocated -= urb->bandwidth; + if (isoc) + dev->bus->bandwidth_isoc_reqs--; + else + dev->bus->bandwidth_int_reqs--; + +#ifdef USB_BANDWIDTH_MESSAGES + dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n", + urb->bandwidth, + isoc ? "ISOC" : "INTR", + dev->bus->bandwidth_allocated, + dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); +#endif + urb->bandwidth = 0; +} + + +/*-------------------------------------------------------------------------*/ + +/* + * Generic HC operations. + */ + +/*-------------------------------------------------------------------------*/ + +/* called from khubd, or root hub init threads for hcd-private init */ +static int hcd_alloc_dev (struct usb_device *udev) +{ + struct hcd_dev *dev; + struct usb_hcd *hcd; + unsigned long flags; + + if (!udev || udev->hcpriv) + return -EINVAL; + if (!udev->bus || !udev->bus->hcpriv) + return -ENODEV; + hcd = udev->bus->hcpriv; + if (hcd->state == USB_STATE_QUIESCING) + return -ENOLINK; + + dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL); + if (dev == NULL) + return -ENOMEM; + memset (dev, 0, sizeof *dev); + + INIT_LIST_HEAD (&dev->dev_list); + INIT_LIST_HEAD (&dev->urb_list); + + spin_lock_irqsave (&hcd_data_lock, flags); + list_add (&dev->dev_list, &hcd->dev_list); + // refcount is implicit + udev->hcpriv = dev; + spin_unlock_irqrestore (&hcd_data_lock, flags); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static void urb_unlink (struct urb *urb) +{ + unsigned long flags; + struct usb_device *dev; + + /* Release any periodic transfer bandwidth */ + if (urb->bandwidth) + usb_release_bandwidth (urb->dev, urb, + usb_pipeisoc (urb->pipe)); + + /* clear all state linking urb to this dev (and hcd) */ + + spin_lock_irqsave (&hcd_data_lock, flags); + list_del_init (&urb->urb_list); + dev = urb->dev; + spin_unlock_irqrestore (&hcd_data_lock, flags); + usb_put_dev (dev); +} + + +/* may be called in any context with a valid urb->dev usecount + * caller surrenders "ownership" of urb + * expects usb_submit_urb() to have sanity checked and conditioned all + * inputs in the urb + */ +static int hcd_submit_urb (struct urb *urb, int mem_flags) +{ + int status; + struct usb_hcd *hcd = urb->dev->bus->hcpriv; + struct hcd_dev *dev = urb->dev->hcpriv; + unsigned long flags; + + + if (!hcd || !dev) + return -ENODEV; +// printk("submit_urb %p, # %i, t %i\n",urb,urb->dev->devnum,usb_pipetype(urb->pipe)); + /* + * FIXME: make urb timeouts be generic, keeping the HCD cores + * as simple as possible. + */ + + // NOTE: a generic device/urb monitoring hook would go here. + // hcd_monitor_hook(MONITOR_URB_SUBMIT, urb) + // It would catch submission paths for all urbs. + + /* + * Atomically queue the urb, first to our records, then to the HCD. + * Access to urb->status is controlled by urb->lock ... changes on + * i/o completion (normal or fault) or unlinking. + */ + + // FIXME: verify that quiescing hc works right (RH cleans up) + + spin_lock_irqsave (&hcd_data_lock, flags); + if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) { + usb_get_dev (urb->dev); + list_add_tail (&urb->urb_list, &dev->urb_list); + status = 0; + } else { + INIT_LIST_HEAD (&urb->urb_list); + status = -ESHUTDOWN; + } + spin_unlock_irqrestore (&hcd_data_lock, flags); + if (status) + return status; + + /* increment urb's reference count as part of giving it to the HCD + * (which now controls it). HCD guarantees that it either returns + * an error or calls giveback(), but not both. + */ + + urb = usb_get_urb (urb); + if (urb->dev == hcd->self.root_hub) { + /* NOTE: requirement on hub callers (usbfs and the hub + * driver, for now) that URBs' urb->transfer_buffer be + * valid and usb_buffer_{sync,unmap}() not be needed, since + * they could clobber root hub response data. + */ + urb->transfer_flags |= URB_NO_DMA_MAP; + status = rh_urb_enqueue (hcd, urb); + goto done; + } + + /* lower level hcd code should use *_dma exclusively, + * unless it uses pio or talks to another transport. + */ + if (!(urb->transfer_flags & URB_NO_DMA_MAP) + && hcd->controller->dma_mask) { + if (usb_pipecontrol (urb->pipe)) + urb->setup_dma = dma_map_single ( + hcd->controller, + urb->setup_packet, + sizeof (struct usb_ctrlrequest), + DMA_TO_DEVICE); + if (urb->transfer_buffer_length != 0) + urb->transfer_dma = dma_map_single ( + hcd->controller, + urb->transfer_buffer, + urb->transfer_buffer_length, + usb_pipein (urb->pipe) + ? DMA_FROM_DEVICE + : DMA_TO_DEVICE); + } + + status = hcd->driver->urb_enqueue (hcd, urb, mem_flags); +done: + if (status) { + usb_put_urb (urb); + urb_unlink (urb); + } + return status; +} + +/*-------------------------------------------------------------------------*/ + +/* called in any context */ +static int hcd_get_frame_number (struct usb_device *udev) +{ + struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv; + return hcd->driver->get_frame_number (hcd); +} + +/*-------------------------------------------------------------------------*/ + +/* this makes the hcd giveback() the urb more quickly, by kicking it + * off hardware queues (which may take a while) and returning it as + * soon as practical. we've already set up the urb's return status, + * but we can't know if the callback completed already. + */ +static void +unlink1 (struct usb_hcd *hcd, struct urb *urb) +{ + if (urb == (struct urb *) hcd->rh_timer.data) + usb_rh_status_dequeue (hcd, urb); + else { + int value; + + /* failures "should" be harmless */ + value = hcd->driver->urb_dequeue (hcd, urb); + if (value != 0) + dev_dbg (hcd->controller, + "dequeue %p --> %d\n", + urb, value); + } +} + +struct completion_splice { // modified urb context: + /* did we complete? */ + struct completion done; + + /* original urb data */ + usb_complete_t complete; + void *context; +}; + +static void unlink_complete (struct urb *urb, struct pt_regs *regs) +{ + struct completion_splice *splice; + + splice = (struct completion_splice *) urb->context; + + /* issue original completion call */ + urb->complete = splice->complete; + urb->context = splice->context; + urb->complete (urb, regs); + + /* then let the synchronous unlink call complete */ + complete (&splice->done); +} + +/* + * called in any context; note ASYNC_UNLINK restrictions + * + * caller guarantees urb won't be recycled till both unlink() + * and the urb's completion function return + */ +static int hcd_unlink_urb (struct urb *urb) +{ + struct hcd_dev *dev; + struct usb_hcd *hcd = 0; + struct device *sys = 0; + unsigned long flags; + struct completion_splice splice; + int retval; + + if (!urb) + return -EINVAL; + + /* + * we contend for urb->status with the hcd core, + * which changes it while returning the urb. + * + * Caller guaranteed that the urb pointer hasn't been freed, and + * that it was submitted. But as a rule it can't know whether or + * not it's already been unlinked ... so we respect the reversed + * lock sequence needed for the usb_hcd_giveback_urb() code paths + * (urb lock, then hcd_data_lock) in case some other CPU is now + * unlinking it. + */ + spin_lock_irqsave (&urb->lock, flags); + spin_lock (&hcd_data_lock); + + if (!urb->dev || !urb->dev->bus) { + retval = -ENODEV; + goto done; + } + + dev = urb->dev->hcpriv; + sys = &urb->dev->dev; + hcd = urb->dev->bus->hcpriv; + if (!dev || !hcd) { + retval = -ENODEV; + goto done; + } + + if (!urb->hcpriv) { + retval = -EINVAL; + goto done; + } + + /* Any status except -EINPROGRESS means something already started to + * unlink this URB from the hardware. So there's no more work to do. + * + * FIXME use better explicit urb state + */ + if (urb->status != -EINPROGRESS) { + retval = -EBUSY; + goto done; + } + + /* maybe set up to block until the urb's completion fires. the + * lower level hcd code is always async, locking on urb->status + * updates; an intercepted completion unblocks us. + */ + if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) { + if (in_interrupt ()) { + dev_dbg (hcd->controller, "non-async unlink in_interrupt"); + retval = -EWOULDBLOCK; + goto done; + } + /* synchronous unlink: block till we see the completion */ + init_completion (&splice.done); + splice.complete = urb->complete; + splice.context = urb->context; + urb->complete = unlink_complete; + urb->context = &splice; + urb->status = -ENOENT; + } else { + /* asynchronous unlink */ + urb->status = -ECONNRESET; + } + spin_unlock (&hcd_data_lock); + spin_unlock_irqrestore (&urb->lock, flags); + + // FIXME remove splicing, so this becomes unlink1 (hcd, urb); + if (urb == (struct urb *) hcd->rh_timer.data) { + usb_rh_status_dequeue (hcd, urb); + retval = 0; + } else { + retval = hcd->driver->urb_dequeue (hcd, urb); + + /* hcds shouldn't really fail these calls, but... */ + if (retval) { + dev_dbg (sys, "dequeue %p --> %d\n", urb, retval); + if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) { + spin_lock_irqsave (&urb->lock, flags); + urb->complete = splice.complete; + urb->context = splice.context; + spin_unlock_irqrestore (&urb->lock, flags); + } + goto bye; + } + } + + /* block till giveback, if needed */ + if (urb->transfer_flags & URB_ASYNC_UNLINK) + return -EINPROGRESS; + + wait_for_completion (&splice.done); + return 0; + +done: + spin_unlock (&hcd_data_lock); + spin_unlock_irqrestore (&urb->lock, flags); +bye: + if (retval && sys && sys->driver) + dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval); + return retval; +} + +/*-------------------------------------------------------------------------*/ + +/* disables the endpoint: cancels any pending urbs, then synchronizes with + * the hcd to make sure all endpoint state is gone from hardware. use for + * set_configuration, set_interface, driver removal, physical disconnect. + * + * example: a qh stored in hcd_dev.ep[], holding state related to endpoint + * type, maxpacket size, toggle, halt status, and scheduling. + */ +static void hcd_endpoint_disable (struct usb_device *udev, int endpoint) +{ + unsigned long flags; + struct hcd_dev *dev; + struct usb_hcd *hcd; + struct urb *urb; + unsigned epnum = endpoint & USB_ENDPOINT_NUMBER_MASK; + + dev = udev->hcpriv; + hcd = udev->bus->hcpriv; + +rescan: + /* (re)block new requests, as best we can */ + if (endpoint & USB_DIR_IN) { + usb_endpoint_halt (udev, epnum, 0); + udev->epmaxpacketin [epnum] = 0; + } else { + usb_endpoint_halt (udev, epnum, 1); + udev->epmaxpacketout [epnum] = 0; + } + + /* then kill any current requests */ + spin_lock_irqsave (&hcd_data_lock, flags); + list_for_each_entry (urb, &dev->urb_list, urb_list) { + int tmp = urb->pipe; + + /* ignore urbs for other endpoints */ + if (usb_pipeendpoint (tmp) != epnum) + continue; + if ((tmp ^ endpoint) & USB_DIR_IN) + continue; + + /* another cpu may be in hcd, spinning on hcd_data_lock + * to giveback() this urb. the races here should be + * small, but a full fix needs a new "can't submit" + * urb state. + */ + if (urb->status != -EINPROGRESS) + continue; + usb_get_urb (urb); + spin_unlock_irqrestore (&hcd_data_lock, flags); + + spin_lock_irqsave (&urb->lock, flags); + tmp = urb->status; + if (tmp == -EINPROGRESS) + urb->status = -ESHUTDOWN; + spin_unlock_irqrestore (&urb->lock, flags); + + /* kick hcd unless it's already returning this */ + if (tmp == -EINPROGRESS) { + tmp = urb->pipe; + unlink1 (hcd, urb); + dev_dbg (hcd->controller, + "shutdown urb %p pipe %08x ep%d%s%s\n", + urb, tmp, usb_pipeendpoint (tmp), + (tmp & USB_DIR_IN) ? "in" : "out", + ({ char *s; \ + switch (usb_pipetype (tmp)) { \ + case PIPE_CONTROL: s = ""; break; \ + case PIPE_BULK: s = "-bulk"; break; \ + case PIPE_INTERRUPT: s = "-intr"; break; \ + default: s = "-iso"; break; \ + }; s;})); + } + usb_put_urb (urb); + + /* list contents may have changed */ + goto rescan; + } + spin_unlock_irqrestore (&hcd_data_lock, flags); + + /* synchronize with the hardware, so old configuration state + * clears out immediately (and will be freed). + */ + might_sleep (); + if (hcd->driver->endpoint_disable) + hcd->driver->endpoint_disable (hcd, dev, endpoint); +} + +/*-------------------------------------------------------------------------*/ + +/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup. + * we're guaranteed that the device is fully quiesced. also, that each + * endpoint has been hcd_endpoint_disabled. + */ + +static int hcd_free_dev (struct usb_device *udev) +{ + struct hcd_dev *dev; + struct usb_hcd *hcd; + unsigned long flags; + + if (!udev || !udev->hcpriv) + return -EINVAL; + + if (!udev->bus || !udev->bus->hcpriv) + return -ENODEV; + + // should udev->devnum == -1 ?? + + dev = udev->hcpriv; + hcd = udev->bus->hcpriv; + + /* device driver problem with refcounts? */ + if (!list_empty (&dev->urb_list)) { + dev_dbg (hcd->controller, "free busy dev, %s devnum %d (bug!)\n", + hcd->self.bus_name, udev->devnum); + return -EINVAL; + } + + spin_lock_irqsave (&hcd_data_lock, flags); + list_del (&dev->dev_list); + udev->hcpriv = NULL; + spin_unlock_irqrestore (&hcd_data_lock, flags); + + kfree (dev); + return 0; +} + +/* + * usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue) + * + * When registering a USB bus through the HCD framework code, use this + * usb_operations vector. The PCI glue layer does so automatically; only + * bus glue for non-PCI system busses will need to use this. + */ +struct usb_operations usb_hcd_operations = { + .allocate = hcd_alloc_dev, + .get_frame_number = hcd_get_frame_number, + .submit_urb = hcd_submit_urb, + .unlink_urb = hcd_unlink_urb, + .deallocate = hcd_free_dev, + .buffer_alloc = hcd_buffer_alloc, + .buffer_free = hcd_buffer_free, + .disable = hcd_endpoint_disable, +}; +EXPORT_SYMBOL (usb_hcd_operations); + +/*-------------------------------------------------------------------------*/ + +/** + * usb_hcd_giveback_urb - return URB from HCD to device driver + * @hcd: host controller returning the URB + * @urb: urb being returned to the USB device driver. + * @regs: pt_regs, passed down to the URB completion handler + * Context: in_interrupt() + * + * This hands the URB from HCD to its USB device driver, using its + * completion function. The HCD has freed all per-urb resources + * (and is done using urb->hcpriv). It also released all HCD locks; + * the device driver won't cause problems if it frees, modifies, + * or resubmits this URB. + */ +void STDCALL usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) +{ + urb_unlink (urb); + + // NOTE: a generic device/urb monitoring hook would go here. + // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev) + // It would catch exit/unlink paths for all urbs. + + /* lower level hcd code should use *_dma exclusively */ + if (!(urb->transfer_flags & URB_NO_DMA_MAP)) { + if (usb_pipecontrol (urb->pipe)) + pci_unmap_single (hcd->pdev, urb->setup_dma, + sizeof (struct usb_ctrlrequest), + PCI_DMA_TODEVICE); + if (urb->transfer_buffer_length != 0) + pci_unmap_single (hcd->pdev, urb->transfer_dma, + urb->transfer_buffer_length, + usb_pipein (urb->pipe) + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE); + } + + /* pass ownership to the completion handler */ + urb->complete (urb, regs); + usb_put_urb (urb); +} + +/*-------------------------------------------------------------------------*/ + +/** + * usb_hcd_irq - hook IRQs to HCD framework (bus glue) + * @irq: the IRQ being raised + * @__hcd: pointer to the HCD whose IRQ is beinng signaled + * @r: saved hardware registers + * + * When registering a USB bus through the HCD framework code, use this + * to handle interrupts. The PCI glue layer does so automatically; only + * bus glue for non-PCI system busses will need to use this. + */ +irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) +{ + struct usb_hcd *hcd = __hcd; + int start = hcd->state; + + if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */ + return IRQ_NONE; + + hcd->driver->irq (hcd, r); + if (hcd->state != start && hcd->state == USB_STATE_HALT) + usb_hc_died (hcd); + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*/ + +static void hcd_panic (void *_hcd) +{ + struct usb_hcd *hcd = _hcd; + hcd->driver->stop (hcd); +} + +/** + * usb_hc_died - report abnormal shutdown of a host controller (bus glue) + * @hcd: pointer to the HCD representing the controller + * + * This is called by bus glue to report a USB host controller that died + * while operations may still have been pending. It's called automatically + * by the PCI glue, so only glue for non-PCI busses should need to call it. + */ +void STDCALL usb_hc_died (struct usb_hcd *hcd) +{ + struct list_head *devlist, *urblist; + struct hcd_dev *dev; + struct urb *urb; + unsigned long flags; + + /* flag every pending urb as done */ + spin_lock_irqsave (&hcd_data_lock, flags); + list_for_each (devlist, &hcd->dev_list) { + dev = list_entry (devlist, struct hcd_dev, dev_list); + list_for_each (urblist, &dev->urb_list) { + urb = list_entry (urblist, struct urb, urb_list); + dev_dbg (hcd->controller, "shutdown %s urb %p pipe %x, current status %d\n", + hcd->self.bus_name, urb, urb->pipe, urb->status); + if (urb->status == -EINPROGRESS) + urb->status = -ESHUTDOWN; + } + } + urb = (struct urb *) hcd->rh_timer.data; + if (urb) + urb->status = -ESHUTDOWN; + spin_unlock_irqrestore (&hcd_data_lock, flags); + + /* hcd->stop() needs a task context */ + INIT_WORK (&hcd->work, hcd_panic, hcd); + (void) schedule_work (&hcd->work); +} + diff --git a/reactos/drivers/usb/cromwell/core/hcd.h b/reactos/drivers/usb/cromwell/core/hcd.h index 266324d5d15..5b6a6a013f5 100644 --- a/reactos/drivers/usb/cromwell/core/hcd.h +++ b/reactos/drivers/usb/cromwell/core/hcd.h @@ -1,481 +1,481 @@ -/* - * Copyright (c) 2001-2002 by David Brownell - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#ifdef __KERNEL__ - -/* This file contains declarations of usbcore internals that are mostly - * used or exposed by Host Controller Drivers. - */ - -/* - * USB Packet IDs (PIDs) - */ -#define USB_PID_UNDEF_0 0xf0 -#define USB_PID_OUT 0xe1 -#define USB_PID_ACK 0xd2 -#define USB_PID_DATA0 0xc3 -#define USB_PID_PING 0xb4 /* USB 2.0 */ -#define USB_PID_SOF 0xa5 -#define USB_PID_NYET 0x96 /* USB 2.0 */ -#define USB_PID_DATA2 0x87 /* USB 2.0 */ -#define USB_PID_SPLIT 0x78 /* USB 2.0 */ -#define USB_PID_IN 0x69 -#define USB_PID_NAK 0x5a -#define USB_PID_DATA1 0x4b -#define USB_PID_PREAMBLE 0x3c /* Token mode */ -#define USB_PID_ERR 0x3c /* USB 2.0: handshake mode */ -#define USB_PID_SETUP 0x2d -#define USB_PID_STALL 0x1e -#define USB_PID_MDATA 0x0f /* USB 2.0 */ - -/*-------------------------------------------------------------------------*/ - -/* - * USB Host Controller Driver (usb_hcd) framework - * - * Since "struct usb_bus" is so thin, you can't share much code in it. - * This framework is a layer over that, and should be more sharable. - */ - -/*-------------------------------------------------------------------------*/ - -struct usb_hcd { /* usb_bus.hcpriv points to this */ - - /* - * housekeeping - */ - struct usb_bus self; /* hcd is-a bus */ - - const char *product_desc; /* product/vendor string */ - const char *description; /* "ehci-hcd" etc */ - - struct timer_list rh_timer; /* drives root hub */ - struct list_head dev_list; /* devices on this bus */ - struct work_struct work; - - /* - * hardware info/state - */ - struct hc_driver *driver; /* hw-specific hooks */ - int irq; /* irq allocated */ - void *regs; /* device memory/io */ - struct device *controller; /* handle to hardware */ - - /* a few non-PCI controllers exist, mostly for OHCI */ - struct pci_dev *pdev; /* pci is typical */ -#ifdef CONFIG_PCI - int region; /* pci region for regs */ - u32 pci_state [16]; /* for PM state save */ - atomic_t resume_count; /* multiple resumes issue */ -#endif - -#define HCD_BUFFER_POOLS 4 - struct pci_pool *pool [HCD_BUFFER_POOLS]; - - int state; -# define __ACTIVE 0x01 -# define __SLEEPY 0x02 -# define __SUSPEND 0x04 -# define __TRANSIENT 0x80 - -# define USB_STATE_HALT 0 -# define USB_STATE_RUNNING (__ACTIVE) -# define USB_STATE_READY (__ACTIVE|__SLEEPY) -# define USB_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE) -# define USB_STATE_RESUMING (__SUSPEND|__TRANSIENT) -# define USB_STATE_SUSPENDED (__SUSPEND) - -#define HCD_IS_RUNNING(state) ((state) & __ACTIVE) -#define HCD_IS_SUSPENDED(state) ((state) & __SUSPEND) - - /* more shared queuing code would be good; it should support - * smarter scheduling, handle transaction translators, etc; - * input size of periodic table to an interrupt scheduler. - * (ohci 32, uhci 1024, ehci 256/512/1024). - */ -}; - -/* 2.4 does this a bit differently ... */ -static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd) -{ - return &hcd->self; -} - - -struct hcd_dev { /* usb_device.hcpriv points to this */ - struct list_head dev_list; /* on this hcd */ - struct list_head urb_list; /* pending on this dev */ - - /* per-configuration HC/HCD state, such as QH or ED */ - void *ep[32]; -}; - -// urb.hcpriv is really hardware-specific - -struct hcd_timeout { /* timeouts we allocate */ - struct list_head timeout_list; - struct timer_list timer; -}; - -/*-------------------------------------------------------------------------*/ - -/* - * FIXME usb_operations should vanish or become hc_driver, - * when usb_bus and usb_hcd become the same thing. - */ - -struct usb_operations { - int (*allocate)(struct usb_device *); - int (*deallocate)(struct usb_device *); - int (*get_frame_number) (struct usb_device *usb_dev); - int (*submit_urb) (struct urb *urb, int mem_flags); - int (*unlink_urb) (struct urb *urb); - - /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */ - void *(*buffer_alloc)(struct usb_bus *bus, size_t size, - int mem_flags, - dma_addr_t *dma); - void (*buffer_free)(struct usb_bus *bus, size_t size, - void *addr, dma_addr_t dma); - - void (*disable)(struct usb_device *udev, int bEndpointAddress); -}; - -/* each driver provides one of these, and hardware init support */ - -struct pt_regs; - -// new struct from 2.6 -struct hc_driver { - const char *description; /* "ehci-hcd" etc */ - - /* irq handler */ - irqreturn_t (*irq) (struct usb_hcd *hcd, struct pt_regs *regs); - - int flags; -#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ -#define HCD_USB11 0x0010 /* USB 1.1 */ -#define HCD_USB2 0x0020 /* USB 2.0 */ - - /* called to init HCD and root hub */ - int (*reset) (struct usb_hcd *hcd); - int (*start) (struct usb_hcd *hcd); - - /* called after all devices were suspended */ - int (*suspend) (struct usb_hcd *hcd, u32 state); - - /* called before any devices get resumed */ - int (*resume) (struct usb_hcd *hcd); - - /* cleanly make HCD stop writing memory and doing I/O */ - void (*stop) (struct usb_hcd *hcd); - - /* return current frame number */ - int (*get_frame_number) (struct usb_hcd *hcd); - - /* memory lifecycle */ - struct usb_hcd *(*hcd_alloc) (void); - void (*hcd_free) (struct usb_hcd *hcd); - - /* manage i/o requests, device state */ - int (*urb_enqueue) (struct usb_hcd *hcd, struct urb *urb, - int mem_flags); - int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); - - /* hw synch, freeing endpoint resources that urb_dequeue can't */ - void (*endpoint_disable)(struct usb_hcd *hcd, - struct hcd_dev *dev, int bEndpointAddress); - - /* root hub support */ - int (*hub_status_data) (struct usb_hcd *hcd, char *buf); - int (*hub_control) (struct usb_hcd *hcd, - u16 typeReq, u16 wValue, u16 wIndex, - char *buf, u16 wLength); -}; - -// old version, "just in case" -#if 0 -struct hc_driver { - const char *description; /* "ehci-hcd" etc */ - - /* irq handler */ - void (*irq) (struct usb_hcd *hcd, struct pt_regs *regs); - - int flags; -#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ -#define HCD_USB11 0x0010 /* USB 1.1 */ -#define HCD_USB2 0x0020 /* USB 2.0 */ - - /* called to init HCD and root hub */ - int (*start) (struct usb_hcd *hcd); - - /* called after all devices were suspended */ - int (*suspend) (struct usb_hcd *hcd, u32 state); - - /* called before any devices get resumed */ - int (*resume) (struct usb_hcd *hcd); - - /* cleanly make HCD stop writing memory and doing I/O */ - void (*stop) (struct usb_hcd *hcd); - - /* return current frame number */ - int (*get_frame_number) (struct usb_hcd *hcd); - - /* memory lifecycle */ - struct usb_hcd *(*hcd_alloc) (void); - void (*hcd_free) (struct usb_hcd *hcd); - - /* manage i/o requests, device state */ - int (*urb_enqueue) (struct usb_hcd *hcd, struct urb *urb, - int mem_flags); - int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); - - /* hw synch, freeing endpoint resources that urb_dequeue can't */ - void (*endpoint_disable)(struct usb_hcd *hcd, - struct hcd_dev *dev, int bEndpointAddress); - - /* root hub support */ - int (*hub_status_data) (struct usb_hcd *hcd, char *buf); - int (*hub_control) (struct usb_hcd *hcd, - u16 typeReq, u16 wValue, u16 wIndex, - char *buf, u16 wLength); -}; -#endif - -extern void STDCALL usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs); -extern void STDCALL usb_bus_init (struct usb_bus *bus); -extern void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb); - -#ifdef CONFIG_PCI -struct pci_dev; -struct pci_device_id; -extern int STDCALL usb_hcd_pci_probe (struct pci_dev *dev, - const struct pci_device_id *id); -extern void STDCALL usb_hcd_pci_remove (struct pci_dev *dev); - -#ifdef CONFIG_PM -// FIXME: see Documentation/power/pci.txt (2.4.6 and later?) -// extern int usb_hcd_pci_save_state (struct pci_dev *dev, u32 state); -extern int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state); -extern int usb_hcd_pci_resume (struct pci_dev *dev); -// extern int usb_hcd_pci_enable_wake (struct pci_dev *dev, u32 state, int flg); -#endif /* CONFIG_PM */ - -#endif /* CONFIG_PCI */ - -/* pci-ish (pdev null is ok) buffer alloc/mapping support */ -int hcd_buffer_create (struct usb_hcd *hcd); -void hcd_buffer_destroy (struct usb_hcd *hcd); - -void *hcd_buffer_alloc (struct usb_bus *bus, size_t size, - int mem_flags, dma_addr_t *dma); -void hcd_buffer_free (struct usb_bus *bus, size_t size, - void *addr, dma_addr_t dma); - -/* generic bus glue, needed for host controllers that don't use PCI */ -extern struct usb_operations usb_hcd_operations; -extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r); -extern void STDCALL usb_hc_died (struct usb_hcd *hcd); - -/* -------------------------------------------------------------------------- */ - -/* Enumeration is only for the hub driver, or HCD virtual root hubs */ -extern int usb_new_device(struct usb_device *dev, struct device *parent); -extern void STDCALL usb_connect(struct usb_device *dev); -extern void usb_disconnect(struct usb_device **); - -/* exported to hub driver ONLY to support usb_reset_device () */ -extern int usb_get_configuration(struct usb_device *dev); -extern void usb_set_maxpacket(struct usb_device *dev); -extern void usb_destroy_configuration(struct usb_device *dev); -extern int usb_set_address(struct usb_device *dev); - -/* use these only before the device's address has been set */ -#define usb_snddefctrl(dev) ((PIPE_CONTROL << 30)) -#define usb_rcvdefctrl(dev) ((PIPE_CONTROL << 30) | USB_DIR_IN) - -/*-------------------------------------------------------------------------*/ - -/* - * HCD Root Hub support - */ - -#include "hub.h" - -/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */ -#define DeviceRequest \ - ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) -#define DeviceOutRequest \ - ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) - -#define InterfaceRequest \ - ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) - -#define EndpointRequest \ - ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) -#define EndpointOutRequest \ - ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) - -/* table 9.6 standard features */ -#define DEVICE_REMOTE_WAKEUP 1 -#define ENDPOINT_HALT 0 - -/* class requests from the USB 2.0 hub spec, table 11-15 */ -/* GetBusState and SetHubDescriptor are optional, omitted */ -#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) -#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) -#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) -#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) -#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) -#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) -#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) - - -/*-------------------------------------------------------------------------*/ - -/* - * Generic bandwidth allocation constants/support - */ -#define FRAME_TIME_USECS 1000L -#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */ - /* Trying not to use worst-case bit-stuffing - of (7/6 * 8 * bytecount) = 9.33 * bytecount */ - /* bytecount = data payload byte count */ - -#define NS_TO_US(ns) ((ns + 500L) / 1000L) - /* convert & round nanoseconds to microseconds */ - -extern void STDCALL usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, - int bustime, int isoc); -extern void STDCALL usb_release_bandwidth (struct usb_device *dev, struct urb *urb, - int isoc); - -/* - * Full/low speed bandwidth allocation constants/support. - */ -#define BW_HOST_DELAY 1000L /* nanoseconds */ -#define BW_HUB_LS_SETUP 333L /* nanoseconds */ - /* 4 full-speed bit times (est.) */ - -#define FRAME_TIME_BITS 12000L /* frame = 1 millisecond */ -#define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L) -#define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L) - -extern int STDCALL usb_check_bandwidth (struct usb_device *dev, struct urb *urb); - -/* - * Ceiling microseconds (typical) for that many bytes at high speed - * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed - * to preallocate bandwidth) - */ -#define USB2_HOST_DELAY 5 /* nsec, guess */ -#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \ - + ((2083UL * (3167 + BitTime (bytes)))/1000) \ - + USB2_HOST_DELAY) -#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \ - + ((2083UL * (3167 + BitTime (bytes)))/1000) \ - + USB2_HOST_DELAY) - -extern long STDCALL usb_calc_bus_time (int speed, int is_input, - int isoc, int bytecount); - -/*-------------------------------------------------------------------------*/ - -extern struct usb_bus STDCALL *usb_alloc_bus (struct usb_operations *); -extern void STDCALL usb_free_bus (struct usb_bus *); - -extern void STDCALL usb_register_bus (struct usb_bus *); -extern void STDCALL usb_deregister_bus (struct usb_bus *); - -extern int STDCALL usb_register_root_hub (struct usb_device *usb_dev, - struct device *parent_dev); - -/* for portability to 2.4, hcds should call this */ -static inline int hcd_register_root (struct usb_hcd *hcd) -{ - return usb_register_root_hub ( - hcd_to_bus (hcd)->root_hub, hcd->controller); -} - -/*-------------------------------------------------------------------------*/ - -/* exported only within usbcore */ - -extern struct list_head usb_bus_list; -extern struct semaphore usb_bus_list_lock; - -extern void usb_bus_get (struct usb_bus *bus); -extern void usb_bus_put (struct usb_bus *bus); - -extern int usb_find_interface_driver (struct usb_device *dev, - struct usb_interface *interface); - -#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep))) - -#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) - -/* - * USB device fs stuff - */ - -#ifdef CONFIG_USB_DEVICEFS - -/* - * these are expected to be called from the USB core/hub thread - * with the kernel lock held - */ -extern void usbfs_add_bus(struct usb_bus *bus); -extern void usbfs_remove_bus(struct usb_bus *bus); -extern void usbfs_add_device(struct usb_device *dev); -extern void usbfs_remove_device(struct usb_device *dev); -extern void usbfs_update_special (void); - -extern int usbfs_init(void); -extern void usbfs_cleanup(void); - -#else /* CONFIG_USB_DEVICEFS */ - -static inline void usbfs_add_bus(struct usb_bus *bus) {} -static inline void usbfs_remove_bus(struct usb_bus *bus) {} -static inline void usbfs_add_device(struct usb_device *dev) {} -static inline void usbfs_remove_device(struct usb_device *dev) {} -static inline void usbfs_update_special (void) {} - -static inline int usbfs_init(void) { return 0; } -static inline void usbfs_cleanup(void) { } - -#endif /* CONFIG_USB_DEVICEFS */ - -/*-------------------------------------------------------------------------*/ - -/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */ -// bleech -- resurfaced in 2.4.11 or 2.4.12 -#define bitmap DeviceRemovable - - -/*-------------------------------------------------------------------------*/ - -/* random stuff */ - -#define RUN_CONTEXT (in_irq () ? "in_irq" \ - : (in_interrupt () ? "in_interrupt" : "can sleep")) - - -#endif /* __KERNEL__ */ - +/* + * Copyright (c) 2001-2002 by David Brownell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifdef __KERNEL__ + +/* This file contains declarations of usbcore internals that are mostly + * used or exposed by Host Controller Drivers. + */ + +/* + * USB Packet IDs (PIDs) + */ +#define USB_PID_UNDEF_0 0xf0 +#define USB_PID_OUT 0xe1 +#define USB_PID_ACK 0xd2 +#define USB_PID_DATA0 0xc3 +#define USB_PID_PING 0xb4 /* USB 2.0 */ +#define USB_PID_SOF 0xa5 +#define USB_PID_NYET 0x96 /* USB 2.0 */ +#define USB_PID_DATA2 0x87 /* USB 2.0 */ +#define USB_PID_SPLIT 0x78 /* USB 2.0 */ +#define USB_PID_IN 0x69 +#define USB_PID_NAK 0x5a +#define USB_PID_DATA1 0x4b +#define USB_PID_PREAMBLE 0x3c /* Token mode */ +#define USB_PID_ERR 0x3c /* USB 2.0: handshake mode */ +#define USB_PID_SETUP 0x2d +#define USB_PID_STALL 0x1e +#define USB_PID_MDATA 0x0f /* USB 2.0 */ + +/*-------------------------------------------------------------------------*/ + +/* + * USB Host Controller Driver (usb_hcd) framework + * + * Since "struct usb_bus" is so thin, you can't share much code in it. + * This framework is a layer over that, and should be more sharable. + */ + +/*-------------------------------------------------------------------------*/ + +struct usb_hcd { /* usb_bus.hcpriv points to this */ + + /* + * housekeeping + */ + struct usb_bus self; /* hcd is-a bus */ + + const char *product_desc; /* product/vendor string */ + const char *description; /* "ehci-hcd" etc */ + + struct timer_list rh_timer; /* drives root hub */ + struct list_head dev_list; /* devices on this bus */ + struct work_struct work; + + /* + * hardware info/state + */ + struct hc_driver *driver; /* hw-specific hooks */ + int irq; /* irq allocated */ + void *regs; /* device memory/io */ + struct device *controller; /* handle to hardware */ + + /* a few non-PCI controllers exist, mostly for OHCI */ + struct pci_dev *pdev; /* pci is typical */ +#ifdef CONFIG_PCI + int region; /* pci region for regs */ + u32 pci_state [16]; /* for PM state save */ + atomic_t resume_count; /* multiple resumes issue */ +#endif + +#define HCD_BUFFER_POOLS 4 + struct pci_pool *pool [HCD_BUFFER_POOLS]; + + int state; +# define __ACTIVE 0x01 +# define __SLEEPY 0x02 +# define __SUSPEND 0x04 +# define __TRANSIENT 0x80 + +# define USB_STATE_HALT 0 +# define USB_STATE_RUNNING (__ACTIVE) +# define USB_STATE_READY (__ACTIVE|__SLEEPY) +# define USB_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE) +# define USB_STATE_RESUMING (__SUSPEND|__TRANSIENT) +# define USB_STATE_SUSPENDED (__SUSPEND) + +#define HCD_IS_RUNNING(state) ((state) & __ACTIVE) +#define HCD_IS_SUSPENDED(state) ((state) & __SUSPEND) + + /* more shared queuing code would be good; it should support + * smarter scheduling, handle transaction translators, etc; + * input size of periodic table to an interrupt scheduler. + * (ohci 32, uhci 1024, ehci 256/512/1024). + */ +}; + +/* 2.4 does this a bit differently ... */ +static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd) +{ + return &hcd->self; +} + + +struct hcd_dev { /* usb_device.hcpriv points to this */ + struct list_head dev_list; /* on this hcd */ + struct list_head urb_list; /* pending on this dev */ + + /* per-configuration HC/HCD state, such as QH or ED */ + void *ep[32]; +}; + +// urb.hcpriv is really hardware-specific + +struct hcd_timeout { /* timeouts we allocate */ + struct list_head timeout_list; + struct timer_list timer; +}; + +/*-------------------------------------------------------------------------*/ + +/* + * FIXME usb_operations should vanish or become hc_driver, + * when usb_bus and usb_hcd become the same thing. + */ + +struct usb_operations { + int (*allocate)(struct usb_device *); + int (*deallocate)(struct usb_device *); + int (*get_frame_number) (struct usb_device *usb_dev); + int (*submit_urb) (struct urb *urb, int mem_flags); + int (*unlink_urb) (struct urb *urb); + + /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */ + void *(*buffer_alloc)(struct usb_bus *bus, size_t size, + int mem_flags, + dma_addr_t *dma); + void (*buffer_free)(struct usb_bus *bus, size_t size, + void *addr, dma_addr_t dma); + + void (*disable)(struct usb_device *udev, int bEndpointAddress); +}; + +/* each driver provides one of these, and hardware init support */ + +struct pt_regs; + +// new struct from 2.6 +struct hc_driver { + const char *description; /* "ehci-hcd" etc */ + + /* irq handler */ + irqreturn_t (*irq) (struct usb_hcd *hcd, struct pt_regs *regs); + + int flags; +#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ +#define HCD_USB11 0x0010 /* USB 1.1 */ +#define HCD_USB2 0x0020 /* USB 2.0 */ + + /* called to init HCD and root hub */ + int (*reset) (struct usb_hcd *hcd); + int (*start) (struct usb_hcd *hcd); + + /* called after all devices were suspended */ + int (*suspend) (struct usb_hcd *hcd, u32 state); + + /* called before any devices get resumed */ + int (*resume) (struct usb_hcd *hcd); + + /* cleanly make HCD stop writing memory and doing I/O */ + void (*stop) (struct usb_hcd *hcd); + + /* return current frame number */ + int (*get_frame_number) (struct usb_hcd *hcd); + + /* memory lifecycle */ + struct usb_hcd *(*hcd_alloc) (void); + void (*hcd_free) (struct usb_hcd *hcd); + + /* manage i/o requests, device state */ + int (*urb_enqueue) (struct usb_hcd *hcd, struct urb *urb, + int mem_flags); + int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); + + /* hw synch, freeing endpoint resources that urb_dequeue can't */ + void (*endpoint_disable)(struct usb_hcd *hcd, + struct hcd_dev *dev, int bEndpointAddress); + + /* root hub support */ + int (*hub_status_data) (struct usb_hcd *hcd, char *buf); + int (*hub_control) (struct usb_hcd *hcd, + u16 typeReq, u16 wValue, u16 wIndex, + char *buf, u16 wLength); +}; + +// old version, "just in case" +#if 0 +struct hc_driver { + const char *description; /* "ehci-hcd" etc */ + + /* irq handler */ + int (*irq) (struct usb_hcd *hcd, struct pt_regs *regs); + + int flags; +#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ +#define HCD_USB11 0x0010 /* USB 1.1 */ +#define HCD_USB2 0x0020 /* USB 2.0 */ + + /* called to init HCD and root hub */ + int (*start) (struct usb_hcd *hcd); + + /* called after all devices were suspended */ + int (*suspend) (struct usb_hcd *hcd, u32 state); + + /* called before any devices get resumed */ + int (*resume) (struct usb_hcd *hcd); + + /* cleanly make HCD stop writing memory and doing I/O */ + void (*stop) (struct usb_hcd *hcd); + + /* return current frame number */ + int (*get_frame_number) (struct usb_hcd *hcd); + + /* memory lifecycle */ + struct usb_hcd *(*hcd_alloc) (void); + void (*hcd_free) (struct usb_hcd *hcd); + + /* manage i/o requests, device state */ + int (*urb_enqueue) (struct usb_hcd *hcd, struct urb *urb, + int mem_flags); + int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); + + /* hw synch, freeing endpoint resources that urb_dequeue can't */ + void (*endpoint_disable)(struct usb_hcd *hcd, + struct hcd_dev *dev, int bEndpointAddress); + + /* root hub support */ + int (*hub_status_data) (struct usb_hcd *hcd, char *buf); + int (*hub_control) (struct usb_hcd *hcd, + u16 typeReq, u16 wValue, u16 wIndex, + char *buf, u16 wLength); +}; +#endif + +extern void STDCALL usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs); +extern void STDCALL usb_bus_init (struct usb_bus *bus); +extern void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb); + +#ifdef CONFIG_PCI +struct pci_dev; +struct pci_device_id; +extern int STDCALL usb_hcd_pci_probe (struct pci_dev *dev, + const struct pci_device_id *id); +extern void STDCALL usb_hcd_pci_remove (struct pci_dev *dev); + +#ifdef CONFIG_PM +// FIXME: see Documentation/power/pci.txt (2.4.6 and later?) +// extern int usb_hcd_pci_save_state (struct pci_dev *dev, u32 state); +extern int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state); +extern int usb_hcd_pci_resume (struct pci_dev *dev); +// extern int usb_hcd_pci_enable_wake (struct pci_dev *dev, u32 state, int flg); +#endif /* CONFIG_PM */ + +#endif /* CONFIG_PCI */ + +/* pci-ish (pdev null is ok) buffer alloc/mapping support */ +int hcd_buffer_create (struct usb_hcd *hcd); +void hcd_buffer_destroy (struct usb_hcd *hcd); + +void *hcd_buffer_alloc (struct usb_bus *bus, size_t size, + int mem_flags, dma_addr_t *dma); +void hcd_buffer_free (struct usb_bus *bus, size_t size, + void *addr, dma_addr_t dma); + +/* generic bus glue, needed for host controllers that don't use PCI */ +extern struct usb_operations usb_hcd_operations; +extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r); +extern void STDCALL usb_hc_died (struct usb_hcd *hcd); + +/* -------------------------------------------------------------------------- */ + +/* Enumeration is only for the hub driver, or HCD virtual root hubs */ +extern int usb_new_device(struct usb_device *dev, struct device *parent); +extern void STDCALL usb_connect(struct usb_device *dev); +extern void usb_disconnect(struct usb_device **); + +/* exported to hub driver ONLY to support usb_reset_device () */ +extern int usb_get_configuration(struct usb_device *dev); +extern void usb_set_maxpacket(struct usb_device *dev); +extern void usb_destroy_configuration(struct usb_device *dev); +extern int usb_set_address(struct usb_device *dev); + +/* use these only before the device's address has been set */ +#define usb_snddefctrl(dev) ((PIPE_CONTROL << 30)) +#define usb_rcvdefctrl(dev) ((PIPE_CONTROL << 30) | USB_DIR_IN) + +/*-------------------------------------------------------------------------*/ + +/* + * HCD Root Hub support + */ + +#include "hub.h" + +/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */ +#define DeviceRequest \ + ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) +#define DeviceOutRequest \ + ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) + +#define InterfaceRequest \ + ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) + +#define EndpointRequest \ + ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) +#define EndpointOutRequest \ + ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) + +/* table 9.6 standard features */ +#define DEVICE_REMOTE_WAKEUP 1 +#define ENDPOINT_HALT 0 + +/* class requests from the USB 2.0 hub spec, table 11-15 */ +/* GetBusState and SetHubDescriptor are optional, omitted */ +#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) +#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) +#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) +#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) +#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) +#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) +#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) + + +/*-------------------------------------------------------------------------*/ + +/* + * Generic bandwidth allocation constants/support + */ +#define FRAME_TIME_USECS 1000L +#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */ + /* Trying not to use worst-case bit-stuffing + of (7/6 * 8 * bytecount) = 9.33 * bytecount */ + /* bytecount = data payload byte count */ + +#define NS_TO_US(ns) ((ns + 500L) / 1000L) + /* convert & round nanoseconds to microseconds */ + +extern void STDCALL usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, + int bustime, int isoc); +extern void STDCALL usb_release_bandwidth (struct usb_device *dev, struct urb *urb, + int isoc); + +/* + * Full/low speed bandwidth allocation constants/support. + */ +#define BW_HOST_DELAY 1000L /* nanoseconds */ +#define BW_HUB_LS_SETUP 333L /* nanoseconds */ + /* 4 full-speed bit times (est.) */ + +#define FRAME_TIME_BITS 12000L /* frame = 1 millisecond */ +#define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L) +#define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L) + +extern int STDCALL usb_check_bandwidth (struct usb_device *dev, struct urb *urb); + +/* + * Ceiling microseconds (typical) for that many bytes at high speed + * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed + * to preallocate bandwidth) + */ +#define USB2_HOST_DELAY 5 /* nsec, guess */ +#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \ + + ((2083UL * (3167 + BitTime (bytes)))/1000) \ + + USB2_HOST_DELAY) +#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \ + + ((2083UL * (3167 + BitTime (bytes)))/1000) \ + + USB2_HOST_DELAY) + +extern long STDCALL usb_calc_bus_time (int speed, int is_input, + int isoc, int bytecount); + +/*-------------------------------------------------------------------------*/ + +extern struct usb_bus STDCALL *usb_alloc_bus (struct usb_operations *); +extern void STDCALL usb_free_bus (struct usb_bus *); + +extern void STDCALL usb_register_bus (struct usb_bus *); +extern void STDCALL usb_deregister_bus (struct usb_bus *); + +extern int STDCALL usb_register_root_hub (struct usb_device *usb_dev, + struct device *parent_dev); + +/* for portability to 2.4, hcds should call this */ +static inline int hcd_register_root (struct usb_hcd *hcd) +{ + return usb_register_root_hub ( + hcd_to_bus (hcd)->root_hub, hcd->controller); +} + +/*-------------------------------------------------------------------------*/ + +/* exported only within usbcore */ + +extern struct list_head usb_bus_list; +extern struct semaphore usb_bus_list_lock; + +extern void usb_bus_get (struct usb_bus *bus); +extern void usb_bus_put (struct usb_bus *bus); + +extern int usb_find_interface_driver (struct usb_device *dev, + struct usb_interface *interface); + +#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep))) + +#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) + +/* + * USB device fs stuff + */ + +#ifdef CONFIG_USB_DEVICEFS + +/* + * these are expected to be called from the USB core/hub thread + * with the kernel lock held + */ +extern void usbfs_add_bus(struct usb_bus *bus); +extern void usbfs_remove_bus(struct usb_bus *bus); +extern void usbfs_add_device(struct usb_device *dev); +extern void usbfs_remove_device(struct usb_device *dev); +extern void usbfs_update_special (void); + +extern int usbfs_init(void); +extern void usbfs_cleanup(void); + +#else /* CONFIG_USB_DEVICEFS */ + +static inline void usbfs_add_bus(struct usb_bus *bus) {} +static inline void usbfs_remove_bus(struct usb_bus *bus) {} +static inline void usbfs_add_device(struct usb_device *dev) {} +static inline void usbfs_remove_device(struct usb_device *dev) {} +static inline void usbfs_update_special (void) {} + +static inline int usbfs_init(void) { return 0; } +static inline void usbfs_cleanup(void) { } + +#endif /* CONFIG_USB_DEVICEFS */ + +/*-------------------------------------------------------------------------*/ + +/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */ +// bleech -- resurfaced in 2.4.11 or 2.4.12 +#define bitmap DeviceRemovable + + +/*-------------------------------------------------------------------------*/ + +/* random stuff */ + +#define RUN_CONTEXT (in_irq () ? "in_irq" \ + : (in_interrupt () ? "in_interrupt" : "can sleep")) + + +#endif /* __KERNEL__ */ + diff --git a/reactos/drivers/usb/cromwell/core/hub.c b/reactos/drivers/usb/cromwell/core/hub.c index 1b7e8207f1f..ff4809f76a8 100644 --- a/reactos/drivers/usb/cromwell/core/hub.c +++ b/reactos/drivers/usb/cromwell/core/hub.c @@ -1,1392 +1,1392 @@ -/* - * USB hub driver. - * - * (C) Copyright 1999 Linus Torvalds - * (C) Copyright 1999 Johannes Erdfelt - * (C) Copyright 1999 Gregory P. Smith - * (C) Copyright 2001 Brad Hards (bhards@bigpond.net.au) - * - */ -#define DEBUG -#if 0 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_USB_DEBUG - #define DEBUG -#else - #undef DEBUG -#endif -#include -#include -#include - -#include -#include -#include - -#include "hcd.h" -#include "hub.h" -#else -#include "../usb_wrapper.h" -#include "hcd.h" -#include "hub.h" -#define DEBUG -#endif - -/* Wakes up khubd */ -static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED; -static DECLARE_MUTEX(usb_address0_sem); - -static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */ -static LIST_HEAD(hub_list); /* List of all hubs (for cleanup) */ - -static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); -static pid_t khubd_pid = 0; /* PID of khubd */ -static DECLARE_COMPLETION(khubd_exited); - -#ifdef DEBUG -static inline char *portspeed (int portstatus) -{ - if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED)) - return "480 Mb/s"; - else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED)) - return "1.5 Mb/s"; - else - return "12 Mb/s"; -} -#endif - -/* for dev_info, dev_dbg, etc */ -static inline struct device *hubdev (struct usb_device *dev) -{ - return &dev->actconfig->interface [0].dev; -} - -/* USB 2.0 spec Section 11.24.4.5 */ -static int get_hub_descriptor(struct usb_device *dev, void *data, int size) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, - USB_DT_HUB << 8, 0, data, size, HZ * USB_CTRL_GET_TIMEOUT); -} - -/* - * USB 2.0 spec Section 11.24.2.1 - */ -static int clear_hub_feature(struct usb_device *dev, int feature) -{ - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ); -} - -/* - * USB 2.0 spec Section 11.24.2.2 - * BUG: doesn't handle port indicator selector in high byte of wIndex - */ -static int clear_port_feature(struct usb_device *dev, int port, int feature) -{ - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ); -} - -/* - * USB 2.0 spec Section 11.24.2.13 - * BUG: doesn't handle port indicator selector in high byte of wIndex - */ -static int set_port_feature(struct usb_device *dev, int port, int feature) -{ - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ); -} - -/* - * USB 2.0 spec Section 11.24.2.6 - */ -static int get_hub_status(struct usb_device *dev, - struct usb_hub_status *data) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0, - data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT); -} - -/* - * USB 2.0 spec Section 11.24.2.7 - */ -static int get_port_status(struct usb_device *dev, int port, - struct usb_port_status *data) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, - data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT); -} - -/* completion function, fires on port status changes and various faults */ -static void hub_irq(struct urb *urb, struct pt_regs *regs) -{ - struct usb_hub *hub = (struct usb_hub *)urb->context; - unsigned long flags; - int status; - - switch (urb->status) { - case -ENOENT: /* synchronous unlink */ - case -ECONNRESET: /* async unlink */ - case -ESHUTDOWN: /* hardware going away */ - return; - - default: /* presumably an error */ - /* Cause a hub reset after 10 consecutive errors */ - dev_dbg (&hub->intf->dev, "transfer --> %d\n", urb->status); - if ((++hub->nerrors < 10) || hub->error) - goto resubmit; - hub->error = urb->status; - /* FALL THROUGH */ - - /* let khubd handle things */ - case 0: /* we got data: port status changed */ - break; - } - - hub->nerrors = 0; - - /* Something happened, let khubd figure it out */ - spin_lock_irqsave(&hub_event_lock, flags); - if (list_empty(&hub->event_list)) { - list_add(&hub->event_list, &hub_event_list); - wake_up(&khubd_wait); - } - spin_unlock_irqrestore(&hub_event_lock, flags); - -resubmit: - if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0 - /* ENODEV means we raced disconnect() */ - && status != -ENODEV) - dev_err (&hub->intf->dev, "resubmit --> %d\n", urb->status); -} - -/* USB 2.0 spec Section 11.24.2.3 */ -static inline int -hub_clear_tt_buffer (struct usb_device *hub, u16 devinfo, u16 tt) -{ - return usb_control_msg (hub, usb_rcvctrlpipe (hub, 0), - HUB_CLEAR_TT_BUFFER, USB_DIR_IN | USB_RECIP_OTHER, - devinfo, tt, 0, 0, HZ); -} - -/* - * enumeration blocks khubd for a long time. we use keventd instead, since - * long blocking there is the exception, not the rule. accordingly, HCDs - * talking to TTs must queue control transfers (not just bulk and iso), so - * both can talk to the same hub concurrently. - */ -static void hub_tt_kevent (void *arg) -{ - struct usb_hub *hub = arg; - unsigned long flags; - - spin_lock_irqsave (&hub->tt.lock, flags); - while (!list_empty (&hub->tt.clear_list)) { - struct list_head *temp; - struct usb_tt_clear *clear; - struct usb_device *dev; - int status; - - temp = hub->tt.clear_list.next; - clear = list_entry (temp, struct usb_tt_clear, clear_list); - list_del (&clear->clear_list); - - /* drop lock so HCD can concurrently report other TT errors */ - spin_unlock_irqrestore (&hub->tt.lock, flags); - dev = interface_to_usbdev (hub->intf); - status = hub_clear_tt_buffer (dev, clear->devinfo, clear->tt); - spin_lock_irqsave (&hub->tt.lock, flags); - - if (status) - err ("usb-%s-%s clear tt %d (%04x) error %d", - dev->bus->bus_name, dev->devpath, - clear->tt, clear->devinfo, status); - kfree (clear); - } - spin_unlock_irqrestore (&hub->tt.lock, flags); -} - -/** - * usb_hub_tt_clear_buffer - clear control/bulk TT state in high speed hub - * @dev: the device whose split transaction failed - * @pipe: identifies the endpoint of the failed transaction - * - * High speed HCDs use this to tell the hub driver that some split control or - * bulk transaction failed in a way that requires clearing internal state of - * a transaction translator. This is normally detected (and reported) from - * interrupt context. - * - * It may not be possible for that hub to handle additional full (or low) - * speed transactions until that state is fully cleared out. - */ -void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe) -{ - struct usb_tt *tt = dev->tt; - unsigned long flags; - struct usb_tt_clear *clear; - - /* we've got to cope with an arbitrary number of pending TT clears, - * since each TT has "at least two" buffers that can need it (and - * there can be many TTs per hub). even if they're uncommon. - */ - if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == 0) { - err ("can't save CLEAR_TT_BUFFER state for hub at usb-%s-%s", - dev->bus->bus_name, tt->hub->devpath); - /* FIXME recover somehow ... RESET_TT? */ - return; - } - - /* info that CLEAR_TT_BUFFER needs */ - clear->tt = tt->multi ? dev->ttport : 1; - clear->devinfo = usb_pipeendpoint (pipe); - clear->devinfo |= dev->devnum << 4; - clear->devinfo |= usb_pipecontrol (pipe) - ? (USB_ENDPOINT_XFER_CONTROL << 11) - : (USB_ENDPOINT_XFER_BULK << 11); - if (usb_pipein (pipe)) - clear->devinfo |= 1 << 15; - - /* tell keventd to clear state for this TT */ - spin_lock_irqsave (&tt->lock, flags); - list_add_tail (&clear->clear_list, &tt->clear_list); - schedule_work (&tt->kevent); - spin_unlock_irqrestore (&tt->lock, flags); -} - -static void hub_power_on(struct usb_hub *hub) -{ - struct usb_device *dev; - int i; - - /* Enable power to the ports */ - dev_dbg(hubdev(interface_to_usbdev(hub->intf)), - "enabling power on all ports\n"); - dev = interface_to_usbdev(hub->intf); - - for (i = 0; i < hub->descriptor->bNbrPorts; i++) - set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); - - /* Wait for power to be enabled */ - wait_ms(hub->descriptor->bPwrOn2PwrGood * 2); -} - -static int hub_hub_status(struct usb_hub *hub, - u16 *status, u16 *change) -{ - struct usb_device *dev = interface_to_usbdev (hub->intf); - int ret; - - ret = get_hub_status(dev, &hub->status->hub); - if (ret < 0) - dev_err (hubdev (dev), - "%s failed (err = %d)\n", __FUNCTION__, ret); - else { - *status = le16_to_cpu(hub->status->hub.wHubStatus); - *change = le16_to_cpu(hub->status->hub.wHubChange); - ret = 0; - } - return ret; -} - -static int hub_configure(struct usb_hub *hub, - struct usb_endpoint_descriptor *endpoint) -{ - struct usb_device *dev = interface_to_usbdev (hub->intf); - struct device *hub_dev; - u16 hubstatus, hubchange; - unsigned int pipe; - int maxp, ret; - char *message; - - hub->buffer = usb_buffer_alloc(dev, sizeof(*hub->buffer), GFP_KERNEL, - &hub->buffer_dma); - if (!hub->buffer) { - message = "can't allocate hub irq buffer"; - ret = -ENOMEM; - goto fail; - } - - hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL); - if (!hub->status) { - message = "can't kmalloc hub status buffer"; - ret = -ENOMEM; - goto fail; - } - - hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); - if (!hub->descriptor) { - message = "can't kmalloc hub descriptor"; - ret = -ENOMEM; - goto fail; - } - - /* Request the entire hub descriptor. - * hub->descriptor can handle USB_MAXCHILDREN ports, - * but the hub can/will return fewer bytes here. - */ - ret = get_hub_descriptor(dev, hub->descriptor, - sizeof(*hub->descriptor)); - if (ret < 0) { - message = "can't read hub descriptor"; - goto fail; - } else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) { - message = "hub has too many ports!"; - ret = -ENODEV; - goto fail; - } - - hub_dev = hubdev(dev); - dev->maxchild = hub->descriptor->bNbrPorts; - dev_info (hub_dev, "%d port%s detected\n", dev->maxchild, - (dev->maxchild == 1) ? "" : "s"); - - le16_to_cpus(&hub->descriptor->wHubCharacteristics); - - if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) { - int i; - char portstr [USB_MAXCHILDREN + 1]; - - for (i = 0; i < dev->maxchild; i++) - portstr[i] = hub->descriptor->DeviceRemovable - [((i + 1) / 8)] & (1 << ((i + 1) % 8)) - ? 'F' : 'R'; - portstr[dev->maxchild] = 0; - dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr); - } else - dev_dbg(hub_dev, "standalone hub\n"); - - switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) { - case 0x00: - dev_dbg(hub_dev, "ganged power switching\n"); - break; - case 0x01: - dev_dbg(hub_dev, "individual port power switching\n"); - break; - case 0x02: - case 0x03: - dev_dbg(hub_dev, "unknown reserved power switching mode\n"); - break; - } - - switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) { - case 0x00: - dev_dbg(hub_dev, "global over-current protection\n"); - break; - case 0x08: - dev_dbg(hub_dev, "individual port over-current protection\n"); - break; - case 0x10: - case 0x18: - dev_dbg(hub_dev, "no over-current protection\n"); - break; - } - - spin_lock_init (&hub->tt.lock); - INIT_LIST_HEAD (&hub->tt.clear_list); - INIT_WORK (&hub->tt.kevent, hub_tt_kevent, hub); - switch (dev->descriptor.bDeviceProtocol) { - case 0: - break; - case 1: - dev_dbg(hub_dev, "Single TT\n"); - hub->tt.hub = dev; - break; - case 2: - dev_dbg(hub_dev, "TT per port\n"); - hub->tt.hub = dev; - hub->tt.multi = 1; - break; - default: - dev_dbg(hub_dev, "Unrecognized hub protocol %d\n", - dev->descriptor.bDeviceProtocol); - break; - } - - switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) { - case 0x00: - if (dev->descriptor.bDeviceProtocol != 0) - dev_dbg(hub_dev, "TT requires at most 8 FS bit times\n"); - break; - case 0x20: - dev_dbg(hub_dev, "TT requires at most 16 FS bit times\n"); - break; - case 0x40: - dev_dbg(hub_dev, "TT requires at most 24 FS bit times\n"); - break; - case 0x60: - dev_dbg(hub_dev, "TT requires at most 32 FS bit times\n"); - break; - } - - dev_dbg(hub_dev, "Port indicators are %s supported\n", - (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) - ? "" : "not"); - - dev_dbg(hub_dev, "power on to power good time: %dms\n", - hub->descriptor->bPwrOn2PwrGood * 2); - dev_dbg(hub_dev, "hub controller current requirement: %dmA\n", - hub->descriptor->bHubContrCurrent); - - ret = hub_hub_status(hub, &hubstatus, &hubchange); - if (ret < 0) { - message = "can't get hub status"; - goto fail; - } - - dev_dbg(hub_dev, "local power source is %s\n", - (hubstatus & HUB_STATUS_LOCAL_POWER) - ? "lost (inactive)" : "good"); - - dev_dbg(hub_dev, "%sover-current condition exists\n", - (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); - - /* Start the interrupt endpoint */ - pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - - if (maxp > sizeof(*hub->buffer)) - maxp = sizeof(*hub->buffer); - - hub->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!hub->urb) { - message = "couldn't allocate interrupt urb"; - ret = -ENOMEM; - goto fail; - } - - usb_fill_int_urb(hub->urb, dev, pipe, *hub->buffer, maxp, hub_irq, - hub, endpoint->bInterval); - hub->urb->transfer_dma = hub->buffer_dma; - hub->urb->transfer_flags |= URB_NO_DMA_MAP; - ret = usb_submit_urb(hub->urb, GFP_KERNEL); - if (ret) { - message = "couldn't submit status urb"; - goto fail; - } - - /* Wake up khubd */ - wake_up(&khubd_wait); - - hub_power_on(hub); - - return 0; - -fail: - dev_err (&hub->intf->dev, "config failed, %s (err %d)\n", - message, ret); - /* hub_disconnect() frees urb and descriptor */ - return ret; -} - -static void hub_disconnect(struct usb_interface *intf) -{ - struct usb_hub *hub = usb_get_intfdata (intf); - unsigned long flags; - - if (!hub) - return; - - usb_set_intfdata (intf, NULL); - spin_lock_irqsave(&hub_event_lock, flags); - - /* Delete it and then reset it */ - list_del(&hub->event_list); - INIT_LIST_HEAD(&hub->event_list); - list_del(&hub->hub_list); - INIT_LIST_HEAD(&hub->hub_list); - - spin_unlock_irqrestore(&hub_event_lock, flags); - - down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */ - up(&hub->khubd_sem); - - /* assuming we used keventd, it must quiesce too */ - if (hub->tt.hub) - flush_scheduled_work (); - - if (hub->urb) { - usb_unlink_urb(hub->urb); - usb_free_urb(hub->urb); - hub->urb = NULL; - } - - if (hub->descriptor) { - kfree(hub->descriptor); - hub->descriptor = NULL; - } - - if (hub->status) { - kfree(hub->status); - hub->status = NULL; - } - - if (hub->buffer) { - usb_buffer_free(interface_to_usbdev(intf), - sizeof(*hub->buffer), hub->buffer, - hub->buffer_dma); - hub->buffer = NULL; - } - - /* Free the memory */ - kfree(hub); -} - -static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_host_interface *desc; - struct usb_endpoint_descriptor *endpoint; - struct usb_device *dev; - struct usb_hub *hub; - unsigned long flags; - - desc = intf->altsetting + intf->act_altsetting; - dev = interface_to_usbdev(intf); - - /* Some hubs have a subclass of 1, which AFAICT according to the */ - /* specs is not defined, but it works */ - if ((desc->desc.bInterfaceSubClass != 0) && - (desc->desc.bInterfaceSubClass != 1)) { -descriptor_error: - dev_err (&intf->dev, "bad descriptor, ignoring hub\n"); - return -EIO; - } - - /* Multiple endpoints? What kind of mutant ninja-hub is this? */ - if (desc->desc.bNumEndpoints != 1) { - goto descriptor_error; - } - - endpoint = &desc->endpoint[0].desc; - - /* Output endpoint? Curiouser and curiouser.. */ - if (!(endpoint->bEndpointAddress & USB_DIR_IN)) { - goto descriptor_error; - } - - /* If it's not an interrupt endpoint, we'd better punt! */ - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_INT) { - goto descriptor_error; - return -EIO; - } - - /* We found a hub */ - dev_info (hubdev (dev), "USB hub found\n"); - - hub = kmalloc(sizeof(*hub), GFP_KERNEL); - if (!hub) { - err("couldn't kmalloc hub struct"); - return -ENOMEM; - } - - memset(hub, 0, sizeof(*hub)); - - INIT_LIST_HEAD(&hub->event_list); - hub->intf = intf; - init_MUTEX(&hub->khubd_sem); - - /* Record the new hub's existence */ - spin_lock_irqsave(&hub_event_lock, flags); - INIT_LIST_HEAD(&hub->hub_list); - list_add(&hub->hub_list, &hub_list); - spin_unlock_irqrestore(&hub_event_lock, flags); - - usb_set_intfdata (intf, hub); - - if (hub_configure(hub, endpoint) >= 0) { - strcpy (intf->dev.name, "Hub"); - return 0; - } - - hub_disconnect (intf); - return -ENODEV; -} - -static int -hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) -{ - struct usb_device *hub = interface_to_usbdev (intf); - - /* assert ifno == 0 (part of hub spec) */ - switch (code) { - case USBDEVFS_HUB_PORTINFO: { - struct usbdevfs_hub_portinfo *info = user_data; - unsigned long flags; - int i; - - spin_lock_irqsave(&hub_event_lock, flags); - if (hub->devnum <= 0) - info->nports = 0; - else { - info->nports = hub->maxchild; - for (i = 0; i < info->nports; i++) { - if (hub->children[i] == NULL) - info->port[i] = 0; - else - info->port[i] = - hub->children[i]->devnum; - } - } - spin_unlock_irqrestore(&hub_event_lock, flags); - - return info->nports + 1; - } - - default: - return -ENOSYS; - } -} - -static int hub_reset(struct usb_hub *hub) -{ - struct usb_device *dev = interface_to_usbdev(hub->intf); - int i; - - /* Disconnect any attached devices */ - for (i = 0; i < hub->descriptor->bNbrPorts; i++) { - if (dev->children[i]) - usb_disconnect(&dev->children[i]); - } - - /* Attempt to reset the hub */ - if (hub->urb) - usb_unlink_urb(hub->urb); - else - return -1; - - if (usb_reset_device(dev)) - return -1; - - hub->urb->dev = dev; - if (usb_submit_urb(hub->urb, GFP_KERNEL)) - return -1; - - hub_power_on(hub); - - return 0; -} - -static void hub_start_disconnect(struct usb_device *dev) -{ - struct usb_device *parent = dev->parent; - int i; - - /* Find the device pointer to disconnect */ - if (parent) { - for (i = 0; i < parent->maxchild; i++) { - if (parent->children[i] == dev) { - usb_disconnect(&parent->children[i]); - return; - } - } - } - - err("cannot disconnect hub %s", dev->devpath); -} - -static int hub_port_status(struct usb_device *dev, int port, - u16 *status, u16 *change) -{ - struct usb_hub *hub = usb_get_intfdata (dev->actconfig->interface); - int ret; - - ret = get_port_status(dev, port + 1, &hub->status->port); - if (ret < 0) - dev_err (hubdev (dev), - "%s failed (err = %d)\n", __FUNCTION__, ret); - else { - *status = le16_to_cpu(hub->status->port.wPortStatus); - *change = le16_to_cpu(hub->status->port.wPortChange); - ret = 0; - } - return ret; -} - -#define HUB_RESET_TRIES 5 -#define HUB_PROBE_TRIES 2 -#define HUB_SHORT_RESET_TIME 10 -#define HUB_LONG_RESET_TIME 200 -#define HUB_RESET_TIMEOUT 500 - -/* return: -1 on error, 0 on success, 1 on disconnect. */ -static int hub_port_wait_reset(struct usb_device *hub, int port, - struct usb_device *dev, unsigned int delay) -{ - int delay_time, ret; - u16 portstatus; - u16 portchange; - - for (delay_time = 0; - delay_time < HUB_RESET_TIMEOUT; - delay_time += delay) { - /* wait to give the device a chance to reset */ - wait_ms(delay); - - /* read and decode port status */ - ret = hub_port_status(hub, port, &portstatus, &portchange); - if (ret < 0) { - return -1; - } - - /* Device went away? */ - if (!(portstatus & USB_PORT_STAT_CONNECTION)) - return 1; - - /* bomb out completely if something weird happened */ - if ((portchange & USB_PORT_STAT_C_CONNECTION)) - return -1; - - /* if we`ve finished resetting, then break out of the loop */ - if (!(portstatus & USB_PORT_STAT_RESET) && - (portstatus & USB_PORT_STAT_ENABLE)) { - if (portstatus & USB_PORT_STAT_HIGH_SPEED) - dev->speed = USB_SPEED_HIGH; - else if (portstatus & USB_PORT_STAT_LOW_SPEED) - dev->speed = USB_SPEED_LOW; - else - dev->speed = USB_SPEED_FULL; - return 0; - } - - /* switch to the long delay after two short delay failures */ - if (delay_time >= 2 * HUB_SHORT_RESET_TIME) - delay = HUB_LONG_RESET_TIME; - - dev_dbg (hubdev (hub), - "port %d not reset yet, waiting %dms\n", - port + 1, delay); - } - - return -1; -} - -/* return: -1 on error, 0 on success, 1 on disconnect. */ -static int hub_port_reset(struct usb_device *hub, int port, - struct usb_device *dev, unsigned int delay) -{ - int i, status; - - /* Reset the port */ - for (i = 0; i < HUB_RESET_TRIES; i++) { - set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET); - - /* return on disconnect or reset */ - status = hub_port_wait_reset(hub, port, dev, delay); - if (status != -1) { - clear_port_feature(hub, - port + 1, USB_PORT_FEAT_C_RESET); - dev->state = status - ? USB_STATE_NOTATTACHED - : USB_STATE_DEFAULT; - return status; - } - - dev_dbg (hubdev (hub), - "port %d not enabled, trying reset again...\n", - port + 1); - delay = HUB_LONG_RESET_TIME; - } - - dev_err (hubdev (hub), - "Cannot enable port %i. Maybe the USB cable is bad?\n", - port + 1); - - return -1; -} - -int hub_port_disable(struct usb_device *hub, int port) -{ - int ret; - - ret = clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE); - if (ret) - dev_err(hubdev(hub), "cannot disable port %d (err = %d)\n", - port + 1, ret); - - return ret; -} - -/* USB 2.0 spec, 7.1.7.3 / fig 7-29: - * - * Between connect detection and reset signaling there must be a delay - * of 100ms at least for debounce and power-settling. The corresponding - * timer shall restart whenever the downstream port detects a disconnect. - * - * Apparently there are some bluetooth and irda-dongles and a number - * of low-speed devices which require longer delays of about 200-400ms. - * Not covered by the spec - but easy to deal with. - * - * This implementation uses 400ms minimum debounce timeout and checks - * every 25ms for transient disconnects to restart the delay. - */ - -#define HUB_DEBOUNCE_TIMEOUT 400 -#define HUB_DEBOUNCE_STEP 25 -#define HUB_DEBOUNCE_STABLE 4 - -/* return: -1 on error, 0 on success, 1 on disconnect. */ -static int hub_port_debounce(struct usb_device *hub, int port) -{ - int ret; - int delay_time, stable_count; - u16 portchange, portstatus; - unsigned connection; - - connection = 0; - stable_count = 0; - for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) { - wait_ms(HUB_DEBOUNCE_STEP); - - ret = hub_port_status(hub, port, &portstatus, &portchange); - if (ret < 0) - return -1; - - if ((portstatus & USB_PORT_STAT_CONNECTION) == connection) { - if (connection) { - if (++stable_count == HUB_DEBOUNCE_STABLE) - break; - } - } else { - stable_count = 0; - } - connection = portstatus & USB_PORT_STAT_CONNECTION; - - if ((portchange & USB_PORT_STAT_C_CONNECTION)) { - clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION); - } - } - - /* XXX Replace this with dbg() when 2.6 is about to ship. */ - dev_dbg (hubdev (hub), - "debounce: port %d: delay %dms stable %d status 0x%x\n", - port + 1, delay_time, stable_count, portstatus); - - return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1; -} - -static void hub_port_connect_change(struct usb_hub *hubstate, int port, - u16 portstatus, u16 portchange) -{ - struct usb_device *hub = interface_to_usbdev(hubstate->intf); - struct usb_device *dev; - unsigned int delay = HUB_SHORT_RESET_TIME; - int i; - - dev_dbg (&hubstate->intf->dev, - "port %d, status %x, change %x, %s\n", - port + 1, portstatus, portchange, portspeed (portstatus)); - - /* Clear the connection change status */ - clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION); - - /* Disconnect any existing devices under this port */ - if (hub->children[port]) - usb_disconnect(&hub->children[port]); - - /* Return now if nothing is connected */ - if (!(portstatus & USB_PORT_STAT_CONNECTION)) { - if (portstatus & USB_PORT_STAT_ENABLE) - hub_port_disable(hub, port); - - return; - } - - if (hub_port_debounce(hub, port)) { - dev_err (&hubstate->intf->dev, - "connect-debounce failed, port %d disabled\n", - port+1); - hub_port_disable(hub, port); - return; - } - - /* Some low speed devices have problems with the quick delay, so */ - /* be a bit pessimistic with those devices. RHbug #23670 */ - if (portstatus & USB_PORT_STAT_LOW_SPEED) - delay = HUB_LONG_RESET_TIME; - - down(&usb_address0_sem); - - for (i = 0; i < HUB_PROBE_TRIES; i++) { - struct usb_device *pdev; - int len; - - /* Allocate a new device struct */ - dev = usb_alloc_dev(hub, hub->bus); - if (!dev) { - dev_err (&hubstate->intf->dev, - "couldn't allocate usb_device\n"); - break; - } - - hub->children[port] = dev; - dev->state = USB_STATE_POWERED; - - /* Reset the device, and detect its speed */ - if (hub_port_reset(hub, port, dev, delay)) { - usb_put_dev(dev); - break; - } - - /* Find a new address for it */ - usb_connect(dev); - - /* Set up TT records, if needed */ - if (hub->tt) { - dev->tt = hub->tt; - dev->ttport = hub->ttport; - } else if (dev->speed != USB_SPEED_HIGH - && hub->speed == USB_SPEED_HIGH) { - dev->tt = &hubstate->tt; - dev->ttport = port + 1; - } - - /* Save readable and stable topology id, distinguishing - * devices by location for diagnostics, tools, etc. The - * string is a path along hub ports, from the root. Each - * device's id will be stable until USB is re-cabled, and - * hubs are often labeled with these port numbers. - * - * Initial size: ".NN" times five hubs + NUL = 16 bytes max - * (quite rare, since most hubs have 4-6 ports). - */ - pdev = dev->parent; - if (pdev->devpath [0] != '0') /* parent not root? */ - len = snprintf (dev->devpath, sizeof dev->devpath, - "%s.%d", pdev->devpath, port + 1); - /* root == "0", root port 2 == "2", port 3 that hub "2.3" */ - else - len = snprintf (dev->devpath, sizeof dev->devpath, - "%d", port + 1); - if (len == sizeof dev->devpath) - dev_err (&hubstate->intf->dev, - "devpath size! usb/%03d/%03d path %s\n", - dev->bus->busnum, dev->devnum, dev->devpath); - dev_info (&hubstate->intf->dev, - "new USB device on port %d, assigned address %d\n", - port + 1, dev->devnum); - - /* put the device in the global device tree. the hub port - * is the "bus_id"; hubs show in hierarchy like bridges - */ - dev->dev.parent = dev->parent->dev.parent->parent; - - /* Run it through the hoops (find a driver, etc) */ - if (!usb_new_device(dev, &hub->dev)) - goto done; - - /* Free the configuration if there was an error */ - usb_put_dev(dev); - - /* Switch to a long reset time */ - delay = HUB_LONG_RESET_TIME; - } - - hub->children[port] = NULL; - hub_port_disable(hub, port); -done: - up(&usb_address0_sem); -} - -static void hub_events(void) -{ - unsigned long flags; - struct list_head *tmp; - struct usb_device *dev; - struct usb_hub *hub; - u16 hubstatus; - u16 hubchange; - u16 portstatus; - u16 portchange; - int i, ret; - int m=0; - /* - * We restart the list every time to avoid a deadlock with - * deleting hubs downstream from this one. This should be - * safe since we delete the hub from the event list. - * Not the most efficient, but avoids deadlocks. - */ - - while (m<5) { - m++; - spin_lock_irqsave(&hub_event_lock, flags); - - if (list_empty(&hub_event_list)) - break; - - /* Grab the next entry from the beginning of the list */ - tmp = hub_event_list.next; - - hub = list_entry(tmp, struct usb_hub, event_list); - dev = interface_to_usbdev(hub->intf); - - list_del_init(tmp); - - if (unlikely(down_trylock(&hub->khubd_sem))) - BUG(); /* never blocks, we were on list */ - - spin_unlock_irqrestore(&hub_event_lock, flags); - - if (hub->error) { - dev_dbg (&hub->intf->dev, "resetting for error %d\n", - hub->error); - - if (hub_reset(hub)) { - dev_dbg (&hub->intf->dev, - "can't reset; disconnecting\n"); - up(&hub->khubd_sem); - hub_start_disconnect(dev); - continue; - } - - hub->nerrors = 0; - hub->error = 0; - } - - for (i = 0; i < hub->descriptor->bNbrPorts; i++) { - ret = hub_port_status(dev, i, &portstatus, &portchange); - if (ret < 0) { - continue; - } - - if (portchange & USB_PORT_STAT_C_CONNECTION) { - hub_port_connect_change(hub, i, portstatus, portchange); - } else if (portchange & USB_PORT_STAT_C_ENABLE) { - dev_dbg (hubdev (dev), - "port %d enable change, status %x\n", - i + 1, portstatus); - clear_port_feature(dev, - i + 1, USB_PORT_FEAT_C_ENABLE); - - /* - * EM interference sometimes causes badly - * shielded USB devices to be shutdown by - * the hub, this hack enables them again. - * Works at least with mouse driver. - */ - if (!(portstatus & USB_PORT_STAT_ENABLE) - && (portstatus & USB_PORT_STAT_CONNECTION) - && (dev->children[i])) { - dev_err (&hub->intf->dev, - "port %i " - "disabled by hub (EMI?), " - "re-enabling...", - i + 1); - hub_port_connect_change(hub, - i, portstatus, portchange); - } - } - - if (portchange & USB_PORT_STAT_C_SUSPEND) { - dev_dbg (&hub->intf->dev, - "suspend change on port %d\n", - i + 1); - clear_port_feature(dev, - i + 1, USB_PORT_FEAT_C_SUSPEND); - } - - if (portchange & USB_PORT_STAT_C_OVERCURRENT) { - dev_err (&hub->intf->dev, - "over-current change on port %d\n", - i + 1); - clear_port_feature(dev, - i + 1, USB_PORT_FEAT_C_OVER_CURRENT); - hub_power_on(hub); - } - - if (portchange & USB_PORT_STAT_C_RESET) { - dev_dbg (&hub->intf->dev, - "reset change on port %d\n", - i + 1); - clear_port_feature(dev, - i + 1, USB_PORT_FEAT_C_RESET); - } - } /* end for i */ - - /* deal with hub status changes */ - if (hub_hub_status(hub, &hubstatus, &hubchange) < 0) - dev_err (&hub->intf->dev, "get_hub_status failed\n"); - else { - if (hubchange & HUB_CHANGE_LOCAL_POWER) { - dev_dbg (&hub->intf->dev, "power change\n"); - clear_hub_feature(dev, C_HUB_LOCAL_POWER); - } - if (hubchange & HUB_CHANGE_OVERCURRENT) { - dev_dbg (&hub->intf->dev, "overcurrent change\n"); - wait_ms(500); /* Cool down */ - clear_hub_feature(dev, C_HUB_OVER_CURRENT); - hub_power_on(hub); - } - } - up(&hub->khubd_sem); - } /* end while (1) */ - - spin_unlock_irqrestore(&hub_event_lock, flags); -} - -static int hub_thread(void *__hub) -{ - /* - * This thread doesn't need any user-level access, - * so get rid of all our resources - */ - - daemonize("khubd"); - allow_signal(SIGKILL); - /* Send me a signal to get me die (for debugging) */ - do { - - hub_events(); - - //FIXME: Correct this - //wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); // interruptable_sleep_on analog - below - while (!list_empty(&hub_event_list)) { - interruptible_sleep_on(&khubd_wait); - } - - if (current->flags & PF_FREEZE) - refrigerator(PF_IOTHREAD); - - } while (!signal_pending(current)); - -// dbg("hub_thread exiting"); - complete_and_exit(&khubd_exited, 0); -} - -static struct usb_device_id hub_id_table [] = { - { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, - .bDeviceClass = USB_CLASS_HUB}, - { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, - .bInterfaceClass = USB_CLASS_HUB}, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, hub_id_table); - -static struct usb_driver hub_driver = { - .owner = THIS_MODULE, - .name = "hub", - .probe = hub_probe, - .disconnect = hub_disconnect, - .ioctl = hub_ioctl, - .id_table = hub_id_table, -}; - -/* - * This should be a separate module. - */ -int usb_hub_init(void) -{ - pid_t pid; - - // ReactOS-specific - // Create Event object, initialize other sync events - KeInitializeEvent(&khubd_wait, NotificationEvent, TRUE); // signalled state - - if (usb_register(&hub_driver) < 0) { - err("Unable to register USB hub driver"); - return -1; - } - - pid = kernel_thread(hub_thread, NULL, - CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - if (pid >= 0) { - khubd_pid = pid; - return 0; - } - - /* Fall through if kernel_thread failed */ - usb_deregister(&hub_driver); - err("failed to start hub_thread"); - - return -1; -} - -void usb_hub_cleanup(void) -{ - int ret; - - /* Kill the thread */ - ret = kill_proc(khubd_pid, SIGKILL, 1); - - wait_for_completion(&khubd_exited); - - /* - * Hub resources are freed for us by usb_deregister. It calls - * usb_driver_purge on every device which in turn calls that - * devices disconnect function if it is using this driver. - * The hub_disconnect function takes care of releasing the - * individual hub resources. -greg - */ - usb_deregister(&hub_driver); -} /* usb_hub_cleanup() */ - -/* - * WARNING - If a driver calls usb_reset_device, you should simulate a - * disconnect() and probe() for other interfaces you doesn't claim. This - * is left up to the driver writer right now. This insures other drivers - * have a chance to re-setup their interface. - * - * Take a look at proc_resetdevice in devio.c for some sample code to - * do this. - * Use this only from within your probe function, otherwise use - * usb_reset_device() below, which ensure proper locking - */ -int usb_physical_reset_device(struct usb_device *dev) -{ - struct usb_device *parent = dev->parent; - struct usb_device_descriptor *descriptor; - int i, ret, port = -1; - - if (!parent) { - err("attempting to reset root hub!"); - return -EINVAL; - } - - for (i = 0; i < parent->maxchild; i++) - if (parent->children[i] == dev) { - port = i; - break; - } - - if (port < 0) - return -ENOENT; - - descriptor = kmalloc(sizeof *descriptor, GFP_NOIO); - if (!descriptor) { - return -ENOMEM; - } - - down(&usb_address0_sem); - - /* Send a reset to the device */ - if (hub_port_reset(parent, port, dev, HUB_SHORT_RESET_TIME)) { - hub_port_disable(parent, port); - up(&usb_address0_sem); - kfree(descriptor); - return(-ENODEV); - } - - /* Reprogram the Address */ - ret = usb_set_address(dev); - if (ret < 0) { - err("USB device not accepting new address (error=%d)", ret); - hub_port_disable(parent, port); - up(&usb_address0_sem); - kfree(descriptor); - return ret; - } - - /* Let the SET_ADDRESS settle */ - wait_ms(10); - - up(&usb_address0_sem); - - /* - * Now we fetch the configuration descriptors for the device and - * see if anything has changed. If it has, we dump the current - * parsed descriptors and reparse from scratch. Then we leave - * the device alone for the caller to finish setting up. - * - * If nothing changed, we reprogram the configuration and then - * the alternate settings. - */ - - ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor, - sizeof(*descriptor)); - if (ret < 0) { - kfree(descriptor); - return ret; - } - - le16_to_cpus(&descriptor->bcdUSB); - le16_to_cpus(&descriptor->idVendor); - le16_to_cpus(&descriptor->idProduct); - le16_to_cpus(&descriptor->bcdDevice); - - if (RtlCompareMemory(&dev->descriptor, descriptor, sizeof(*descriptor))) { - kfree(descriptor); - usb_destroy_configuration(dev); - - ret = usb_get_device_descriptor(dev); - if (ret < sizeof(dev->descriptor)) { - if (ret < 0) - err("unable to get device %s descriptor " - "(error=%d)", dev->devpath, ret); - else - err("USB device %s descriptor short read " - "(expected %Zi, got %i)", - dev->devpath, - sizeof(dev->descriptor), ret); - - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - dev->devnum = -1; - return -EIO; - } - - ret = usb_get_configuration(dev); - if (ret < 0) { - err("unable to get configuration (error=%d)", ret); - usb_destroy_configuration(dev); - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - dev->devnum = -1; - return 1; - } - - dev->actconfig = dev->config; - usb_set_maxpacket(dev); - - return 1; - } - - kfree(descriptor); - - ret = usb_set_configuration(dev, dev->actconfig->desc.bConfigurationValue); - if (ret < 0) { - err("failed to set dev %s active configuration (error=%d)", - dev->devpath, ret); - return ret; - } - - for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *intf = &dev->actconfig->interface[i]; - struct usb_interface_descriptor *as; - - as = &intf->altsetting[intf->act_altsetting].desc; - ret = usb_set_interface(dev, as->bInterfaceNumber, - as->bAlternateSetting); - if (ret < 0) { - err("failed to set active alternate setting " - "for dev %s interface %d (error=%d)", - dev->devpath, i, ret); - return ret; - } - } - - return 0; -} - -int usb_reset_device(struct usb_device *udev) -{ - //struct device *gdev = &udev->dev; - int r; - - down_read(&gdev->bus->subsys.rwsem); - r = usb_physical_reset_device(udev); - up_read(&gdev->bus->subsys.rwsem); - - return r; -} - - +/* + * USB hub driver. + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999 Johannes Erdfelt + * (C) Copyright 1999 Gregory P. Smith + * (C) Copyright 2001 Brad Hards (bhards@bigpond.net.au) + * + */ +#define DEBUG +#if 0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif +#include +#include +#include + +#include +#include +#include + +#include "hcd.h" +#include "hub.h" +#else +#include "../usb_wrapper.h" +#include "hcd.h" +#include "hub.h" +#define DEBUG +#endif + +/* Wakes up khubd */ +static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED; +static DECLARE_MUTEX(usb_address0_sem); + +static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */ +static LIST_HEAD(hub_list); /* List of all hubs (for cleanup) */ + +static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); +static pid_t khubd_pid = 0; /* PID of khubd */ +static DECLARE_COMPLETION(khubd_exited); + +#ifdef DEBUG +static inline char *portspeed (int portstatus) +{ + if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED)) + return "480 Mb/s"; + else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED)) + return "1.5 Mb/s"; + else + return "12 Mb/s"; +} +#endif + +/* for dev_info, dev_dbg, etc */ +static inline struct device *hubdev (struct usb_device *dev) +{ + return &dev->actconfig->interface [0].dev; +} + +/* USB 2.0 spec Section 11.24.4.5 */ +static int get_hub_descriptor(struct usb_device *dev, void *data, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, + USB_DT_HUB << 8, 0, data, size, HZ * USB_CTRL_GET_TIMEOUT); +} + +/* + * USB 2.0 spec Section 11.24.2.1 + */ +static int clear_hub_feature(struct usb_device *dev, int feature) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ); +} + +/* + * USB 2.0 spec Section 11.24.2.2 + * BUG: doesn't handle port indicator selector in high byte of wIndex + */ +static int clear_port_feature(struct usb_device *dev, int port, int feature) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ); +} + +/* + * USB 2.0 spec Section 11.24.2.13 + * BUG: doesn't handle port indicator selector in high byte of wIndex + */ +static int set_port_feature(struct usb_device *dev, int port, int feature) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ); +} + +/* + * USB 2.0 spec Section 11.24.2.6 + */ +static int get_hub_status(struct usb_device *dev, + struct usb_hub_status *data) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0, + data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT); +} + +/* + * USB 2.0 spec Section 11.24.2.7 + */ +static int get_port_status(struct usb_device *dev, int port, + struct usb_port_status *data) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, + data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT); +} + +/* completion function, fires on port status changes and various faults */ +static void hub_irq(struct urb *urb, struct pt_regs *regs) +{ + struct usb_hub *hub = (struct usb_hub *)urb->context; + unsigned long flags; + int status; + + switch (urb->status) { + case -ENOENT: /* synchronous unlink */ + case -ECONNRESET: /* async unlink */ + case -ESHUTDOWN: /* hardware going away */ + return; + + default: /* presumably an error */ + /* Cause a hub reset after 10 consecutive errors */ + dev_dbg (&hub->intf->dev, "transfer --> %d\n", urb->status); + if ((++hub->nerrors < 10) || hub->error) + goto resubmit; + hub->error = urb->status; + /* FALL THROUGH */ + + /* let khubd handle things */ + case 0: /* we got data: port status changed */ + break; + } + + hub->nerrors = 0; + + /* Something happened, let khubd figure it out */ + spin_lock_irqsave(&hub_event_lock, flags); + if (list_empty(&hub->event_list)) { + list_add(&hub->event_list, &hub_event_list); + wake_up(&khubd_wait); + } + spin_unlock_irqrestore(&hub_event_lock, flags); + +resubmit: + if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0 + /* ENODEV means we raced disconnect() */ + && status != -ENODEV) + dev_err (&hub->intf->dev, "resubmit --> %d\n", urb->status); +} + +/* USB 2.0 spec Section 11.24.2.3 */ +static inline int +hub_clear_tt_buffer (struct usb_device *hub, u16 devinfo, u16 tt) +{ + return usb_control_msg (hub, usb_rcvctrlpipe (hub, 0), + HUB_CLEAR_TT_BUFFER, USB_DIR_IN | USB_RECIP_OTHER, + devinfo, tt, 0, 0, HZ); +} + +/* + * enumeration blocks khubd for a long time. we use keventd instead, since + * long blocking there is the exception, not the rule. accordingly, HCDs + * talking to TTs must queue control transfers (not just bulk and iso), so + * both can talk to the same hub concurrently. + */ +static void hub_tt_kevent (void *arg) +{ + struct usb_hub *hub = arg; + unsigned long flags; + + spin_lock_irqsave (&hub->tt.lock, flags); + while (!list_empty (&hub->tt.clear_list)) { + struct list_head *temp; + struct usb_tt_clear *clear; + struct usb_device *dev; + int status; + + temp = hub->tt.clear_list.next; + clear = list_entry (temp, struct usb_tt_clear, clear_list); + list_del (&clear->clear_list); + + /* drop lock so HCD can concurrently report other TT errors */ + spin_unlock_irqrestore (&hub->tt.lock, flags); + dev = interface_to_usbdev (hub->intf); + status = hub_clear_tt_buffer (dev, clear->devinfo, clear->tt); + spin_lock_irqsave (&hub->tt.lock, flags); + + if (status) + err ("usb-%s-%s clear tt %d (%04x) error %d", + dev->bus->bus_name, dev->devpath, + clear->tt, clear->devinfo, status); + kfree (clear); + } + spin_unlock_irqrestore (&hub->tt.lock, flags); +} + +/** + * usb_hub_tt_clear_buffer - clear control/bulk TT state in high speed hub + * @dev: the device whose split transaction failed + * @pipe: identifies the endpoint of the failed transaction + * + * High speed HCDs use this to tell the hub driver that some split control or + * bulk transaction failed in a way that requires clearing internal state of + * a transaction translator. This is normally detected (and reported) from + * interrupt context. + * + * It may not be possible for that hub to handle additional full (or low) + * speed transactions until that state is fully cleared out. + */ +void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe) +{ + struct usb_tt *tt = dev->tt; + unsigned long flags; + struct usb_tt_clear *clear; + + /* we've got to cope with an arbitrary number of pending TT clears, + * since each TT has "at least two" buffers that can need it (and + * there can be many TTs per hub). even if they're uncommon. + */ + if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == 0) { + err ("can't save CLEAR_TT_BUFFER state for hub at usb-%s-%s", + dev->bus->bus_name, tt->hub->devpath); + /* FIXME recover somehow ... RESET_TT? */ + return; + } + + /* info that CLEAR_TT_BUFFER needs */ + clear->tt = tt->multi ? dev->ttport : 1; + clear->devinfo = usb_pipeendpoint (pipe); + clear->devinfo |= dev->devnum << 4; + clear->devinfo |= usb_pipecontrol (pipe) + ? (USB_ENDPOINT_XFER_CONTROL << 11) + : (USB_ENDPOINT_XFER_BULK << 11); + if (usb_pipein (pipe)) + clear->devinfo |= 1 << 15; + + /* tell keventd to clear state for this TT */ + spin_lock_irqsave (&tt->lock, flags); + list_add_tail (&clear->clear_list, &tt->clear_list); + schedule_work (&tt->kevent); + spin_unlock_irqrestore (&tt->lock, flags); +} + +static void hub_power_on(struct usb_hub *hub) +{ + struct usb_device *dev; + int i; + + /* Enable power to the ports */ + dev_dbg(hubdev(interface_to_usbdev(hub->intf)), + "enabling power on all ports\n"); + dev = interface_to_usbdev(hub->intf); + + for (i = 0; i < hub->descriptor->bNbrPorts; i++) + set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); + + /* Wait for power to be enabled */ + wait_ms(hub->descriptor->bPwrOn2PwrGood * 2); +} + +static int hub_hub_status(struct usb_hub *hub, + u16 *status, u16 *change) +{ + struct usb_device *dev = interface_to_usbdev (hub->intf); + int ret; + + ret = get_hub_status(dev, &hub->status->hub); + if (ret < 0) + dev_err (hubdev (dev), + "%s failed (err = %d)\n", __FUNCTION__, ret); + else { + *status = le16_to_cpu(hub->status->hub.wHubStatus); + *change = le16_to_cpu(hub->status->hub.wHubChange); + ret = 0; + } + return ret; +} + +static int hub_configure(struct usb_hub *hub, + struct usb_endpoint_descriptor *endpoint) +{ + struct usb_device *dev = interface_to_usbdev (hub->intf); + struct device *hub_dev; + u16 hubstatus, hubchange; + unsigned int pipe; + int maxp, ret; + char *message; + + hub->buffer = usb_buffer_alloc(dev, sizeof(*hub->buffer), GFP_KERNEL, + &hub->buffer_dma); + if (!hub->buffer) { + message = "can't allocate hub irq buffer"; + ret = -ENOMEM; + goto fail; + } + + hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL); + if (!hub->status) { + message = "can't kmalloc hub status buffer"; + ret = -ENOMEM; + goto fail; + } + + hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); + if (!hub->descriptor) { + message = "can't kmalloc hub descriptor"; + ret = -ENOMEM; + goto fail; + } + + /* Request the entire hub descriptor. + * hub->descriptor can handle USB_MAXCHILDREN ports, + * but the hub can/will return fewer bytes here. + */ + ret = get_hub_descriptor(dev, hub->descriptor, + sizeof(*hub->descriptor)); + if (ret < 0) { + message = "can't read hub descriptor"; + goto fail; + } else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) { + message = "hub has too many ports!"; + ret = -ENODEV; + goto fail; + } + + hub_dev = hubdev(dev); + dev->maxchild = hub->descriptor->bNbrPorts; + dev_info (hub_dev, "%d port%s detected\n", dev->maxchild, + (dev->maxchild == 1) ? "" : "s"); + + le16_to_cpus(&hub->descriptor->wHubCharacteristics); + + if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) { + int i; + char portstr [USB_MAXCHILDREN + 1]; + + for (i = 0; i < dev->maxchild; i++) + portstr[i] = hub->descriptor->DeviceRemovable + [((i + 1) / 8)] & (1 << ((i + 1) % 8)) + ? 'F' : 'R'; + portstr[dev->maxchild] = 0; + dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr); + } else + dev_dbg(hub_dev, "standalone hub\n"); + + switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) { + case 0x00: + dev_dbg(hub_dev, "ganged power switching\n"); + break; + case 0x01: + dev_dbg(hub_dev, "individual port power switching\n"); + break; + case 0x02: + case 0x03: + dev_dbg(hub_dev, "unknown reserved power switching mode\n"); + break; + } + + switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) { + case 0x00: + dev_dbg(hub_dev, "global over-current protection\n"); + break; + case 0x08: + dev_dbg(hub_dev, "individual port over-current protection\n"); + break; + case 0x10: + case 0x18: + dev_dbg(hub_dev, "no over-current protection\n"); + break; + } + + spin_lock_init (&hub->tt.lock); + INIT_LIST_HEAD (&hub->tt.clear_list); + INIT_WORK (&hub->tt.kevent, hub_tt_kevent, hub); + switch (dev->descriptor.bDeviceProtocol) { + case 0: + break; + case 1: + dev_dbg(hub_dev, "Single TT\n"); + hub->tt.hub = dev; + break; + case 2: + dev_dbg(hub_dev, "TT per port\n"); + hub->tt.hub = dev; + hub->tt.multi = 1; + break; + default: + dev_dbg(hub_dev, "Unrecognized hub protocol %d\n", + dev->descriptor.bDeviceProtocol); + break; + } + + switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) { + case 0x00: + if (dev->descriptor.bDeviceProtocol != 0) + dev_dbg(hub_dev, "TT requires at most 8 FS bit times\n"); + break; + case 0x20: + dev_dbg(hub_dev, "TT requires at most 16 FS bit times\n"); + break; + case 0x40: + dev_dbg(hub_dev, "TT requires at most 24 FS bit times\n"); + break; + case 0x60: + dev_dbg(hub_dev, "TT requires at most 32 FS bit times\n"); + break; + } + + dev_dbg(hub_dev, "Port indicators are %s supported\n", + (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) + ? "" : "not"); + + dev_dbg(hub_dev, "power on to power good time: %dms\n", + hub->descriptor->bPwrOn2PwrGood * 2); + dev_dbg(hub_dev, "hub controller current requirement: %dmA\n", + hub->descriptor->bHubContrCurrent); + + ret = hub_hub_status(hub, &hubstatus, &hubchange); + if (ret < 0) { + message = "can't get hub status"; + goto fail; + } + + dev_dbg(hub_dev, "local power source is %s\n", + (hubstatus & HUB_STATUS_LOCAL_POWER) + ? "lost (inactive)" : "good"); + + dev_dbg(hub_dev, "%sover-current condition exists\n", + (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); + + /* Start the interrupt endpoint */ + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + if (maxp > sizeof(*hub->buffer)) + maxp = sizeof(*hub->buffer); + + hub->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!hub->urb) { + message = "couldn't allocate interrupt urb"; + ret = -ENOMEM; + goto fail; + } + + usb_fill_int_urb(hub->urb, dev, pipe, *hub->buffer, maxp, hub_irq, + hub, endpoint->bInterval); + hub->urb->transfer_dma = hub->buffer_dma; + hub->urb->transfer_flags |= URB_NO_DMA_MAP; + ret = usb_submit_urb(hub->urb, GFP_KERNEL); + if (ret) { + message = "couldn't submit status urb"; + goto fail; + } + + /* Wake up khubd */ + wake_up(&khubd_wait); + + hub_power_on(hub); + + return 0; + +fail: + dev_err (&hub->intf->dev, "config failed, %s (err %d)\n", + message, ret); + /* hub_disconnect() frees urb and descriptor */ + return ret; +} + +static void hub_disconnect(struct usb_interface *intf) +{ + struct usb_hub *hub = usb_get_intfdata (intf); + unsigned long flags; + + if (!hub) + return; + + usb_set_intfdata (intf, NULL); + spin_lock_irqsave(&hub_event_lock, flags); + + /* Delete it and then reset it */ + list_del(&hub->event_list); + INIT_LIST_HEAD(&hub->event_list); + list_del(&hub->hub_list); + INIT_LIST_HEAD(&hub->hub_list); + + spin_unlock_irqrestore(&hub_event_lock, flags); + + down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */ + up(&hub->khubd_sem); + + /* assuming we used keventd, it must quiesce too */ + if (hub->tt.hub) + flush_scheduled_work (); + + if (hub->urb) { + usb_unlink_urb(hub->urb); + usb_free_urb(hub->urb); + hub->urb = NULL; + } + + if (hub->descriptor) { + kfree(hub->descriptor); + hub->descriptor = NULL; + } + + if (hub->status) { + kfree(hub->status); + hub->status = NULL; + } + + if (hub->buffer) { + usb_buffer_free(interface_to_usbdev(intf), + sizeof(*hub->buffer), hub->buffer, + hub->buffer_dma); + hub->buffer = NULL; + } + + /* Free the memory */ + kfree(hub); +} + +static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_host_interface *desc; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *dev; + struct usb_hub *hub; + unsigned long flags; + + desc = intf->altsetting + intf->act_altsetting; + dev = interface_to_usbdev(intf); + + /* Some hubs have a subclass of 1, which AFAICT according to the */ + /* specs is not defined, but it works */ + if ((desc->desc.bInterfaceSubClass != 0) && + (desc->desc.bInterfaceSubClass != 1)) { +descriptor_error: + dev_err (&intf->dev, "bad descriptor, ignoring hub\n"); + return -EIO; + } + + /* Multiple endpoints? What kind of mutant ninja-hub is this? */ + if (desc->desc.bNumEndpoints != 1) { + goto descriptor_error; + } + + endpoint = &desc->endpoint[0].desc; + + /* Output endpoint? Curiouser and curiouser.. */ + if (!(endpoint->bEndpointAddress & USB_DIR_IN)) { + goto descriptor_error; + } + + /* If it's not an interrupt endpoint, we'd better punt! */ + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + != USB_ENDPOINT_XFER_INT) { + goto descriptor_error; + return -EIO; + } + + /* We found a hub */ + dev_info (hubdev (dev), "USB hub found\n"); + + hub = kmalloc(sizeof(*hub), GFP_KERNEL); + if (!hub) { + err("couldn't kmalloc hub struct"); + return -ENOMEM; + } + + memset(hub, 0, sizeof(*hub)); + + INIT_LIST_HEAD(&hub->event_list); + hub->intf = intf; + init_MUTEX(&hub->khubd_sem); + + /* Record the new hub's existence */ + spin_lock_irqsave(&hub_event_lock, flags); + INIT_LIST_HEAD(&hub->hub_list); + list_add(&hub->hub_list, &hub_list); + spin_unlock_irqrestore(&hub_event_lock, flags); + + usb_set_intfdata (intf, hub); + + if (hub_configure(hub, endpoint) >= 0) { + strcpy (intf->dev.name, "Hub"); + return 0; + } + + hub_disconnect (intf); + return -ENODEV; +} + +static int +hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) +{ + struct usb_device *hub = interface_to_usbdev (intf); + + /* assert ifno == 0 (part of hub spec) */ + switch (code) { + case USBDEVFS_HUB_PORTINFO: { + struct usbdevfs_hub_portinfo *info = user_data; + unsigned long flags; + int i; + + spin_lock_irqsave(&hub_event_lock, flags); + if (hub->devnum <= 0) + info->nports = 0; + else { + info->nports = hub->maxchild; + for (i = 0; i < info->nports; i++) { + if (hub->children[i] == NULL) + info->port[i] = 0; + else + info->port[i] = + hub->children[i]->devnum; + } + } + spin_unlock_irqrestore(&hub_event_lock, flags); + + return info->nports + 1; + } + + default: + return -ENOSYS; + } +} + +static int hub_reset(struct usb_hub *hub) +{ + struct usb_device *dev = interface_to_usbdev(hub->intf); + int i; + + /* Disconnect any attached devices */ + for (i = 0; i < hub->descriptor->bNbrPorts; i++) { + if (dev->children[i]) + usb_disconnect(&dev->children[i]); + } + + /* Attempt to reset the hub */ + if (hub->urb) + usb_unlink_urb(hub->urb); + else + return -1; + + if (usb_reset_device(dev)) + return -1; + + hub->urb->dev = dev; + if (usb_submit_urb(hub->urb, GFP_KERNEL)) + return -1; + + hub_power_on(hub); + + return 0; +} + +static void hub_start_disconnect(struct usb_device *dev) +{ + struct usb_device *parent = dev->parent; + int i; + + /* Find the device pointer to disconnect */ + if (parent) { + for (i = 0; i < parent->maxchild; i++) { + if (parent->children[i] == dev) { + usb_disconnect(&parent->children[i]); + return; + } + } + } + + err("cannot disconnect hub %s", dev->devpath); +} + +static int hub_port_status(struct usb_device *dev, int port, + u16 *status, u16 *change) +{ + struct usb_hub *hub = usb_get_intfdata (dev->actconfig->interface); + int ret; + + ret = get_port_status(dev, port + 1, &hub->status->port); + if (ret < 0) + dev_err (hubdev (dev), + "%s failed (err = %d)\n", __FUNCTION__, ret); + else { + *status = le16_to_cpu(hub->status->port.wPortStatus); + *change = le16_to_cpu(hub->status->port.wPortChange); + ret = 0; + } + return ret; +} + +#define HUB_RESET_TRIES 5 +#define HUB_PROBE_TRIES 2 +#define HUB_SHORT_RESET_TIME 10 +#define HUB_LONG_RESET_TIME 200 +#define HUB_RESET_TIMEOUT 500 + +/* return: -1 on error, 0 on success, 1 on disconnect. */ +static int hub_port_wait_reset(struct usb_device *hub, int port, + struct usb_device *dev, unsigned int delay) +{ + int delay_time, ret; + u16 portstatus; + u16 portchange; + + for (delay_time = 0; + delay_time < HUB_RESET_TIMEOUT; + delay_time += delay) { + /* wait to give the device a chance to reset */ + wait_ms(delay); + + /* read and decode port status */ + ret = hub_port_status(hub, port, &portstatus, &portchange); + if (ret < 0) { + return -1; + } + + /* Device went away? */ + if (!(portstatus & USB_PORT_STAT_CONNECTION)) + return 1; + + /* bomb out completely if something weird happened */ + if ((portchange & USB_PORT_STAT_C_CONNECTION)) + return -1; + + /* if we`ve finished resetting, then break out of the loop */ + if (!(portstatus & USB_PORT_STAT_RESET) && + (portstatus & USB_PORT_STAT_ENABLE)) { + if (portstatus & USB_PORT_STAT_HIGH_SPEED) + dev->speed = USB_SPEED_HIGH; + else if (portstatus & USB_PORT_STAT_LOW_SPEED) + dev->speed = USB_SPEED_LOW; + else + dev->speed = USB_SPEED_FULL; + return 0; + } + + /* switch to the long delay after two short delay failures */ + if (delay_time >= 2 * HUB_SHORT_RESET_TIME) + delay = HUB_LONG_RESET_TIME; + + dev_dbg (hubdev (hub), + "port %d not reset yet, waiting %dms\n", + port + 1, delay); + } + + return -1; +} + +/* return: -1 on error, 0 on success, 1 on disconnect. */ +static int hub_port_reset(struct usb_device *hub, int port, + struct usb_device *dev, unsigned int delay) +{ + int i, status; + + /* Reset the port */ + for (i = 0; i < HUB_RESET_TRIES; i++) { + set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET); + + /* return on disconnect or reset */ + status = hub_port_wait_reset(hub, port, dev, delay); + if (status != -1) { + clear_port_feature(hub, + port + 1, USB_PORT_FEAT_C_RESET); + dev->state = status + ? USB_STATE_NOTATTACHED + : USB_STATE_DEFAULT; + return status; + } + + dev_dbg (hubdev (hub), + "port %d not enabled, trying reset again...\n", + port + 1); + delay = HUB_LONG_RESET_TIME; + } + + dev_err (hubdev (hub), + "Cannot enable port %i. Maybe the USB cable is bad?\n", + port + 1); + + return -1; +} + +int hub_port_disable(struct usb_device *hub, int port) +{ + int ret; + + ret = clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE); + if (ret) + dev_err(hubdev(hub), "cannot disable port %d (err = %d)\n", + port + 1, ret); + + return ret; +} + +/* USB 2.0 spec, 7.1.7.3 / fig 7-29: + * + * Between connect detection and reset signaling there must be a delay + * of 100ms at least for debounce and power-settling. The corresponding + * timer shall restart whenever the downstream port detects a disconnect. + * + * Apparently there are some bluetooth and irda-dongles and a number + * of low-speed devices which require longer delays of about 200-400ms. + * Not covered by the spec - but easy to deal with. + * + * This implementation uses 400ms minimum debounce timeout and checks + * every 25ms for transient disconnects to restart the delay. + */ + +#define HUB_DEBOUNCE_TIMEOUT 400 +#define HUB_DEBOUNCE_STEP 25 +#define HUB_DEBOUNCE_STABLE 4 + +/* return: -1 on error, 0 on success, 1 on disconnect. */ +static int hub_port_debounce(struct usb_device *hub, int port) +{ + int ret; + int delay_time, stable_count; + u16 portchange, portstatus; + unsigned connection; + + connection = 0; + stable_count = 0; + for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) { + wait_ms(HUB_DEBOUNCE_STEP); + + ret = hub_port_status(hub, port, &portstatus, &portchange); + if (ret < 0) + return -1; + + if ((portstatus & USB_PORT_STAT_CONNECTION) == connection) { + if (connection) { + if (++stable_count == HUB_DEBOUNCE_STABLE) + break; + } + } else { + stable_count = 0; + } + connection = portstatus & USB_PORT_STAT_CONNECTION; + + if ((portchange & USB_PORT_STAT_C_CONNECTION)) { + clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION); + } + } + + /* XXX Replace this with dbg() when 2.6 is about to ship. */ + dev_dbg (hubdev (hub), + "debounce: port %d: delay %dms stable %d status 0x%x\n", + port + 1, delay_time, stable_count, portstatus); + + return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1; +} + +static void hub_port_connect_change(struct usb_hub *hubstate, int port, + u16 portstatus, u16 portchange) +{ + struct usb_device *hub = interface_to_usbdev(hubstate->intf); + struct usb_device *dev; + unsigned int delay = HUB_SHORT_RESET_TIME; + int i; + + dev_dbg (&hubstate->intf->dev, + "port %d, status %x, change %x, %s\n", + port + 1, portstatus, portchange, portspeed (portstatus)); + + /* Clear the connection change status */ + clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION); + + /* Disconnect any existing devices under this port */ + if (hub->children[port]) + usb_disconnect(&hub->children[port]); + + /* Return now if nothing is connected */ + if (!(portstatus & USB_PORT_STAT_CONNECTION)) { + if (portstatus & USB_PORT_STAT_ENABLE) + hub_port_disable(hub, port); + + return; + } + + if (hub_port_debounce(hub, port)) { + dev_err (&hubstate->intf->dev, + "connect-debounce failed, port %d disabled\n", + port+1); + hub_port_disable(hub, port); + return; + } + + /* Some low speed devices have problems with the quick delay, so */ + /* be a bit pessimistic with those devices. RHbug #23670 */ + if (portstatus & USB_PORT_STAT_LOW_SPEED) + delay = HUB_LONG_RESET_TIME; + + down(&usb_address0_sem); + + for (i = 0; i < HUB_PROBE_TRIES; i++) { + struct usb_device *pdev; + int len; + + /* Allocate a new device struct */ + dev = usb_alloc_dev(hub, hub->bus); + if (!dev) { + dev_err (&hubstate->intf->dev, + "couldn't allocate usb_device\n"); + break; + } + + hub->children[port] = dev; + dev->state = USB_STATE_POWERED; + + /* Reset the device, and detect its speed */ + if (hub_port_reset(hub, port, dev, delay)) { + usb_put_dev(dev); + break; + } + + /* Find a new address for it */ + usb_connect(dev); + + /* Set up TT records, if needed */ + if (hub->tt) { + dev->tt = hub->tt; + dev->ttport = hub->ttport; + } else if (dev->speed != USB_SPEED_HIGH + && hub->speed == USB_SPEED_HIGH) { + dev->tt = &hubstate->tt; + dev->ttport = port + 1; + } + + /* Save readable and stable topology id, distinguishing + * devices by location for diagnostics, tools, etc. The + * string is a path along hub ports, from the root. Each + * device's id will be stable until USB is re-cabled, and + * hubs are often labeled with these port numbers. + * + * Initial size: ".NN" times five hubs + NUL = 16 bytes max + * (quite rare, since most hubs have 4-6 ports). + */ + pdev = dev->parent; + if (pdev->devpath [0] != '0') /* parent not root? */ + len = snprintf (dev->devpath, sizeof dev->devpath, + "%s.%d", pdev->devpath, port + 1); + /* root == "0", root port 2 == "2", port 3 that hub "2.3" */ + else + len = snprintf (dev->devpath, sizeof dev->devpath, + "%d", port + 1); + if (len == sizeof dev->devpath) + dev_err (&hubstate->intf->dev, + "devpath size! usb/%03d/%03d path %s\n", + dev->bus->busnum, dev->devnum, dev->devpath); + dev_info (&hubstate->intf->dev, + "new USB device on port %d, assigned address %d\n", + port + 1, dev->devnum); + + /* put the device in the global device tree. the hub port + * is the "bus_id"; hubs show in hierarchy like bridges + */ + dev->dev.parent = dev->parent->dev.parent->parent; + + /* Run it through the hoops (find a driver, etc) */ + if (!usb_new_device(dev, &hub->dev)) + goto done; + + /* Free the configuration if there was an error */ + usb_put_dev(dev); + + /* Switch to a long reset time */ + delay = HUB_LONG_RESET_TIME; + } + + hub->children[port] = NULL; + hub_port_disable(hub, port); +done: + up(&usb_address0_sem); +} + +static void hub_events(void) +{ + unsigned long flags; + struct list_head *tmp; + struct usb_device *dev; + struct usb_hub *hub; + u16 hubstatus; + u16 hubchange; + u16 portstatus; + u16 portchange; + int i, ret; + int m=0; + /* + * We restart the list every time to avoid a deadlock with + * deleting hubs downstream from this one. This should be + * safe since we delete the hub from the event list. + * Not the most efficient, but avoids deadlocks. + */ + + while (m<5) { + m++; + spin_lock_irqsave(&hub_event_lock, flags); + + if (list_empty(&hub_event_list)) + break; + + /* Grab the next entry from the beginning of the list */ + tmp = hub_event_list.next; + + hub = list_entry(tmp, struct usb_hub, event_list); + dev = interface_to_usbdev(hub->intf); + + list_del_init(tmp); + + if (unlikely(down_trylock(&hub->khubd_sem))) + BUG(); /* never blocks, we were on list */ + + spin_unlock_irqrestore(&hub_event_lock, flags); + + if (hub->error) { + dev_dbg (&hub->intf->dev, "resetting for error %d\n", + hub->error); + + if (hub_reset(hub)) { + dev_dbg (&hub->intf->dev, + "can't reset; disconnecting\n"); + up(&hub->khubd_sem); + hub_start_disconnect(dev); + continue; + } + + hub->nerrors = 0; + hub->error = 0; + } + + for (i = 0; i < hub->descriptor->bNbrPorts; i++) { + ret = hub_port_status(dev, i, &portstatus, &portchange); + if (ret < 0) { + continue; + } + + if (portchange & USB_PORT_STAT_C_CONNECTION) { + hub_port_connect_change(hub, i, portstatus, portchange); + } else if (portchange & USB_PORT_STAT_C_ENABLE) { + dev_dbg (hubdev (dev), + "port %d enable change, status %x\n", + i + 1, portstatus); + clear_port_feature(dev, + i + 1, USB_PORT_FEAT_C_ENABLE); + + /* + * EM interference sometimes causes badly + * shielded USB devices to be shutdown by + * the hub, this hack enables them again. + * Works at least with mouse driver. + */ + if (!(portstatus & USB_PORT_STAT_ENABLE) + && (portstatus & USB_PORT_STAT_CONNECTION) + && (dev->children[i])) { + dev_err (&hub->intf->dev, + "port %i " + "disabled by hub (EMI?), " + "re-enabling...", + i + 1); + hub_port_connect_change(hub, + i, portstatus, portchange); + } + } + + if (portchange & USB_PORT_STAT_C_SUSPEND) { + dev_dbg (&hub->intf->dev, + "suspend change on port %d\n", + i + 1); + clear_port_feature(dev, + i + 1, USB_PORT_FEAT_C_SUSPEND); + } + + if (portchange & USB_PORT_STAT_C_OVERCURRENT) { + dev_err (&hub->intf->dev, + "over-current change on port %d\n", + i + 1); + clear_port_feature(dev, + i + 1, USB_PORT_FEAT_C_OVER_CURRENT); + hub_power_on(hub); + } + + if (portchange & USB_PORT_STAT_C_RESET) { + dev_dbg (&hub->intf->dev, + "reset change on port %d\n", + i + 1); + clear_port_feature(dev, + i + 1, USB_PORT_FEAT_C_RESET); + } + } /* end for i */ + + /* deal with hub status changes */ + if (hub_hub_status(hub, &hubstatus, &hubchange) < 0) + dev_err (&hub->intf->dev, "get_hub_status failed\n"); + else { + if (hubchange & HUB_CHANGE_LOCAL_POWER) { + dev_dbg (&hub->intf->dev, "power change\n"); + clear_hub_feature(dev, C_HUB_LOCAL_POWER); + } + if (hubchange & HUB_CHANGE_OVERCURRENT) { + dev_dbg (&hub->intf->dev, "overcurrent change\n"); + wait_ms(500); /* Cool down */ + clear_hub_feature(dev, C_HUB_OVER_CURRENT); + hub_power_on(hub); + } + } + up(&hub->khubd_sem); + } /* end while (1) */ + + spin_unlock_irqrestore(&hub_event_lock, flags); +} + +static int hub_thread(void *__hub) +{ + /* + * This thread doesn't need any user-level access, + * so get rid of all our resources + */ + + daemonize("khubd"); + allow_signal(SIGKILL); + /* Send me a signal to get me die (for debugging) */ + do { + + hub_events(); + + //FIXME: Correct this + //wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); // interruptable_sleep_on analog - below + while (!list_empty(&hub_event_list)) { + interruptible_sleep_on(&khubd_wait); + } + + if (current->flags & PF_FREEZE) + refrigerator(PF_IOTHREAD); + + } while (!signal_pending(current)); + +// dbg("hub_thread exiting"); + complete_and_exit(&khubd_exited, 0); +} + +static struct usb_device_id hub_id_table [] = { + { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, + .bDeviceClass = USB_CLASS_HUB}, + { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, + .bInterfaceClass = USB_CLASS_HUB}, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, hub_id_table); + +static struct usb_driver hub_driver = { + .owner = THIS_MODULE, + .name = "hub", + .probe = hub_probe, + .disconnect = hub_disconnect, + .ioctl = hub_ioctl, + .id_table = hub_id_table, +}; + +/* + * This should be a separate module. + */ +int usb_hub_init(void) +{ + pid_t pid; + + // ReactOS-specific + // Create Event object, initialize other sync events + KeInitializeEvent(&khubd_wait, NotificationEvent, TRUE); // signalled state + + if (usb_register(&hub_driver) < 0) { + err("Unable to register USB hub driver"); + return -1; + } + + pid = kernel_thread((void*)hub_thread, NULL, + (CLONE_FS | CLONE_FILES | CLONE_SIGHAND)); + if (pid >= 0) { + khubd_pid = pid; + return 0; + } + + /* Fall through if kernel_thread failed */ + usb_deregister(&hub_driver); + err("failed to start hub_thread"); + + return -1; +} + +void usb_hub_cleanup(void) +{ + int ret; + + /* Kill the thread */ + ret = kill_proc(khubd_pid, SIGKILL, 1); + + wait_for_completion(&khubd_exited); + + /* + * Hub resources are freed for us by usb_deregister. It calls + * usb_driver_purge on every device which in turn calls that + * devices disconnect function if it is using this driver. + * The hub_disconnect function takes care of releasing the + * individual hub resources. -greg + */ + usb_deregister(&hub_driver); +} /* usb_hub_cleanup() */ + +/* + * WARNING - If a driver calls usb_reset_device, you should simulate a + * disconnect() and probe() for other interfaces you doesn't claim. This + * is left up to the driver writer right now. This insures other drivers + * have a chance to re-setup their interface. + * + * Take a look at proc_resetdevice in devio.c for some sample code to + * do this. + * Use this only from within your probe function, otherwise use + * usb_reset_device() below, which ensure proper locking + */ +int usb_physical_reset_device(struct usb_device *dev) +{ + struct usb_device *parent = dev->parent; + struct usb_device_descriptor *descriptor; + int i, ret, port = -1; + + if (!parent) { + err("attempting to reset root hub!"); + return -EINVAL; + } + + for (i = 0; i < parent->maxchild; i++) + if (parent->children[i] == dev) { + port = i; + break; + } + + if (port < 0) + return -ENOENT; + + descriptor = kmalloc(sizeof *descriptor, GFP_NOIO); + if (!descriptor) { + return -ENOMEM; + } + + down(&usb_address0_sem); + + /* Send a reset to the device */ + if (hub_port_reset(parent, port, dev, HUB_SHORT_RESET_TIME)) { + hub_port_disable(parent, port); + up(&usb_address0_sem); + kfree(descriptor); + return(-ENODEV); + } + + /* Reprogram the Address */ + ret = usb_set_address(dev); + if (ret < 0) { + err("USB device not accepting new address (error=%d)", ret); + hub_port_disable(parent, port); + up(&usb_address0_sem); + kfree(descriptor); + return ret; + } + + /* Let the SET_ADDRESS settle */ + wait_ms(10); + + up(&usb_address0_sem); + + /* + * Now we fetch the configuration descriptors for the device and + * see if anything has changed. If it has, we dump the current + * parsed descriptors and reparse from scratch. Then we leave + * the device alone for the caller to finish setting up. + * + * If nothing changed, we reprogram the configuration and then + * the alternate settings. + */ + + ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor, + sizeof(*descriptor)); + if (ret < 0) { + kfree(descriptor); + return ret; + } + + le16_to_cpus(&descriptor->bcdUSB); + le16_to_cpus(&descriptor->idVendor); + le16_to_cpus(&descriptor->idProduct); + le16_to_cpus(&descriptor->bcdDevice); + + if (RtlCompareMemory(&dev->descriptor, descriptor, sizeof(*descriptor))) { + kfree(descriptor); + usb_destroy_configuration(dev); + + ret = usb_get_device_descriptor(dev); + if (ret < sizeof(dev->descriptor)) { + if (ret < 0) + err("unable to get device %s descriptor " + "(error=%d)", dev->devpath, ret); + else + err("USB device %s descriptor short read " + "(expected %Zi, got %i)", + dev->devpath, + sizeof(dev->descriptor), ret); + + clear_bit(dev->devnum, dev->bus->devmap.devicemap); + dev->devnum = -1; + return -EIO; + } + + ret = usb_get_configuration(dev); + if (ret < 0) { + err("unable to get configuration (error=%d)", ret); + usb_destroy_configuration(dev); + clear_bit(dev->devnum, dev->bus->devmap.devicemap); + dev->devnum = -1; + return 1; + } + + dev->actconfig = dev->config; + usb_set_maxpacket(dev); + + return 1; + } + + kfree(descriptor); + + ret = usb_set_configuration(dev, dev->actconfig->desc.bConfigurationValue); + if (ret < 0) { + err("failed to set dev %s active configuration (error=%d)", + dev->devpath, ret); + return ret; + } + + for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *intf = &dev->actconfig->interface[i]; + struct usb_interface_descriptor *as; + + as = &intf->altsetting[intf->act_altsetting].desc; + ret = usb_set_interface(dev, as->bInterfaceNumber, + as->bAlternateSetting); + if (ret < 0) { + err("failed to set active alternate setting " + "for dev %s interface %d (error=%d)", + dev->devpath, i, ret); + return ret; + } + } + + return 0; +} + +int usb_reset_device(struct usb_device *udev) +{ + //struct device *gdev = &udev->dev; + int r; + + down_read(&gdev->bus->subsys.rwsem); + r = usb_physical_reset_device(udev); + up_read(&gdev->bus->subsys.rwsem); + + return r; +} + + diff --git a/reactos/drivers/usb/cromwell/core/hub.h b/reactos/drivers/usb/cromwell/core/hub.h index f51a9992cc6..1e250782061 100644 --- a/reactos/drivers/usb/cromwell/core/hub.h +++ b/reactos/drivers/usb/cromwell/core/hub.h @@ -1,195 +1,195 @@ -#ifndef __LINUX_HUB_H -#define __LINUX_HUB_H - -/* - * Hub protocol and driver data structures. - * - * Some of these are known to the "virtual root hub" code - * in host controller drivers. - */ -#if 0 -#include -#include -#include /* likely()/unlikely() */ -#endif -/* - * Hub request types - */ - -#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE) -#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER) - -/* - * Hub class requests - * See USB 2.0 spec Table 11-16 - */ -#define HUB_CLEAR_TT_BUFFER 8 -#define HUB_RESET_TT 9 -#define HUB_GET_TT_STATE 10 -#define HUB_STOP_TT 11 - -/* - * Hub Class feature numbers - * See USB 2.0 spec Table 11-17 - */ -#define C_HUB_LOCAL_POWER 0 -#define C_HUB_OVER_CURRENT 1 - -/* - * Port feature numbers - * See USB 2.0 spec Table 11-17 - */ -#define USB_PORT_FEAT_CONNECTION 0 -#define USB_PORT_FEAT_ENABLE 1 -#define USB_PORT_FEAT_SUSPEND 2 -#define USB_PORT_FEAT_OVER_CURRENT 3 -#define USB_PORT_FEAT_RESET 4 -#define USB_PORT_FEAT_POWER 8 -#define USB_PORT_FEAT_LOWSPEED 9 -#define USB_PORT_FEAT_HIGHSPEED 10 -#define USB_PORT_FEAT_C_CONNECTION 16 -#define USB_PORT_FEAT_C_ENABLE 17 -#define USB_PORT_FEAT_C_SUSPEND 18 -#define USB_PORT_FEAT_C_OVER_CURRENT 19 -#define USB_PORT_FEAT_C_RESET 20 -#define USB_PORT_FEAT_TEST 21 -#define USB_PORT_FEAT_INDICATOR 22 - -/* - * Hub Status and Hub Change results - * See USB 2.0 spec Table 11-19 and Table 11-20 - */ -struct usb_port_status { - __u16 wPortStatus; - __u16 wPortChange; -} __attribute__ ((packed)); - -/* - * wPortStatus bit field - * See USB 2.0 spec Table 11-21 - */ -#define USB_PORT_STAT_CONNECTION 0x0001 -#define USB_PORT_STAT_ENABLE 0x0002 -#define USB_PORT_STAT_SUSPEND 0x0004 -#define USB_PORT_STAT_OVERCURRENT 0x0008 -#define USB_PORT_STAT_RESET 0x0010 -/* bits 5 to 7 are reserved */ -#define USB_PORT_STAT_POWER 0x0100 -#define USB_PORT_STAT_LOW_SPEED 0x0200 -#define USB_PORT_STAT_HIGH_SPEED 0x0400 -#define USB_PORT_STAT_TEST 0x0800 -#define USB_PORT_STAT_INDICATOR 0x1000 -/* bits 13 to 15 are reserved */ - -/* - * wPortChange bit field - * See USB 2.0 spec Table 11-22 - * Bits 0 to 4 shown, bits 5 to 15 are reserved - */ -#define USB_PORT_STAT_C_CONNECTION 0x0001 -#define USB_PORT_STAT_C_ENABLE 0x0002 -#define USB_PORT_STAT_C_SUSPEND 0x0004 -#define USB_PORT_STAT_C_OVERCURRENT 0x0008 -#define USB_PORT_STAT_C_RESET 0x0010 - -/* - * wHubCharacteristics (masks) - * See USB 2.0 spec Table 11-13, offset 3 - */ -#define HUB_CHAR_LPSM 0x0003 /* D1 .. D0 */ -#define HUB_CHAR_COMPOUND 0x0004 /* D2 */ -#define HUB_CHAR_OCPM 0x0018 /* D4 .. D3 */ -#define HUB_CHAR_TTTT 0x0060 /* D6 .. D5 */ -#define HUB_CHAR_PORTIND 0x0080 /* D7 */ - -struct usb_hub_status { - __u16 wHubStatus; - __u16 wHubChange; -} __attribute__ ((packed)); - -/* - * Hub Status & Hub Change bit masks - * See USB 2.0 spec Table 11-19 and Table 11-20 - * Bits 0 and 1 for wHubStatus and wHubChange - * Bits 2 to 15 are reserved for both - */ -#define HUB_STATUS_LOCAL_POWER 0x0001 -#define HUB_STATUS_OVERCURRENT 0x0002 -#define HUB_CHANGE_LOCAL_POWER 0x0001 -#define HUB_CHANGE_OVERCURRENT 0x0002 - - -/* - * Hub descriptor - * See USB 2.0 spec Table 11-13 - */ - -#define USB_DT_HUB (USB_TYPE_CLASS | 0x09) -#define USB_DT_HUB_NONVAR_SIZE 7 - -struct usb_hub_descriptor { - __u8 bDescLength; - __u8 bDescriptorType; - __u8 bNbrPorts; - __u16 wHubCharacteristics; - __u8 bPwrOn2PwrGood; - __u8 bHubContrCurrent; - /* add 1 bit for hub status change; round to bytes */ - __u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8]; - __u8 PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8]; -} __attribute__ ((packed)); - -struct usb_device; - -/* - * As of USB 2.0, full/low speed devices are segregated into trees. - * One type grows from USB 1.1 host controllers (OHCI, UHCI etc). - * The other type grows from high speed hubs when they connect to - * full/low speed devices using "Transaction Translators" (TTs). - * - * TTs should only be known to the hub driver, and high speed bus - * drivers (only EHCI for now). They affect periodic scheduling and - * sometimes control/bulk error recovery. - */ -struct usb_tt { - struct usb_device *hub; /* upstream highspeed hub */ - int multi; /* true means one TT per port */ - - /* for control/bulk error recovery (CLEAR_TT_BUFFER) */ - spinlock_t lock; - struct list_head clear_list; /* of usb_tt_clear */ - struct work_struct kevent; -}; - -struct usb_tt_clear { - struct list_head clear_list; - unsigned tt; - u16 devinfo; -}; - -extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe); - -struct usb_hub { - struct usb_interface *intf; /* the "real" device */ - struct urb *urb; /* for interrupt polling pipe */ - - /* buffer for urb ... 1 bit each for hub and children, rounded up */ - char (*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8]; - dma_addr_t buffer_dma; /* DMA address for buffer */ - union { - struct usb_hub_status hub; - struct usb_port_status port; - } *status; /* buffer for status reports */ - - int error; /* last reported error */ - int nerrors; /* track consecutive errors */ - - struct list_head hub_list; /* all hubs */ - struct list_head event_list; /* hubs w/data or errs ready */ - - struct usb_hub_descriptor *descriptor; /* class descriptor */ - struct semaphore khubd_sem; - struct usb_tt tt; /* Transaction Translator */ -}; - -#endif /* __LINUX_HUB_H */ +#ifndef __LINUX_HUB_H +#define __LINUX_HUB_H + +/* + * Hub protocol and driver data structures. + * + * Some of these are known to the "virtual root hub" code + * in host controller drivers. + */ +#if 0 +#include +#include +#include /* likely()/unlikely() */ +#endif +/* + * Hub request types + */ + +#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE) +#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER) + +/* + * Hub class requests + * See USB 2.0 spec Table 11-16 + */ +#define HUB_CLEAR_TT_BUFFER 8 +#define HUB_RESET_TT 9 +#define HUB_GET_TT_STATE 10 +#define HUB_STOP_TT 11 + +/* + * Hub Class feature numbers + * See USB 2.0 spec Table 11-17 + */ +#define C_HUB_LOCAL_POWER 0 +#define C_HUB_OVER_CURRENT 1 + +/* + * Port feature numbers + * See USB 2.0 spec Table 11-17 + */ +#define USB_PORT_FEAT_CONNECTION 0 +#define USB_PORT_FEAT_ENABLE 1 +#define USB_PORT_FEAT_SUSPEND 2 +#define USB_PORT_FEAT_OVER_CURRENT 3 +#define USB_PORT_FEAT_RESET 4 +#define USB_PORT_FEAT_POWER 8 +#define USB_PORT_FEAT_LOWSPEED 9 +#define USB_PORT_FEAT_HIGHSPEED 10 +#define USB_PORT_FEAT_C_CONNECTION 16 +#define USB_PORT_FEAT_C_ENABLE 17 +#define USB_PORT_FEAT_C_SUSPEND 18 +#define USB_PORT_FEAT_C_OVER_CURRENT 19 +#define USB_PORT_FEAT_C_RESET 20 +#define USB_PORT_FEAT_TEST 21 +#define USB_PORT_FEAT_INDICATOR 22 + +/* + * Hub Status and Hub Change results + * See USB 2.0 spec Table 11-19 and Table 11-20 + */ +struct usb_port_status { + __u16 wPortStatus; + __u16 wPortChange; +} __attribute__ ((packed)); + +/* + * wPortStatus bit field + * See USB 2.0 spec Table 11-21 + */ +#define USB_PORT_STAT_CONNECTION 0x0001 +#define USB_PORT_STAT_ENABLE 0x0002 +#define USB_PORT_STAT_SUSPEND 0x0004 +#define USB_PORT_STAT_OVERCURRENT 0x0008 +#define USB_PORT_STAT_RESET 0x0010 +/* bits 5 to 7 are reserved */ +#define USB_PORT_STAT_POWER 0x0100 +#define USB_PORT_STAT_LOW_SPEED 0x0200 +#define USB_PORT_STAT_HIGH_SPEED 0x0400 +#define USB_PORT_STAT_TEST 0x0800 +#define USB_PORT_STAT_INDICATOR 0x1000 +/* bits 13 to 15 are reserved */ + +/* + * wPortChange bit field + * See USB 2.0 spec Table 11-22 + * Bits 0 to 4 shown, bits 5 to 15 are reserved + */ +#define USB_PORT_STAT_C_CONNECTION 0x0001 +#define USB_PORT_STAT_C_ENABLE 0x0002 +#define USB_PORT_STAT_C_SUSPEND 0x0004 +#define USB_PORT_STAT_C_OVERCURRENT 0x0008 +#define USB_PORT_STAT_C_RESET 0x0010 + +/* + * wHubCharacteristics (masks) + * See USB 2.0 spec Table 11-13, offset 3 + */ +#define HUB_CHAR_LPSM 0x0003 /* D1 .. D0 */ +#define HUB_CHAR_COMPOUND 0x0004 /* D2 */ +#define HUB_CHAR_OCPM 0x0018 /* D4 .. D3 */ +#define HUB_CHAR_TTTT 0x0060 /* D6 .. D5 */ +#define HUB_CHAR_PORTIND 0x0080 /* D7 */ + +struct usb_hub_status { + __u16 wHubStatus; + __u16 wHubChange; +} __attribute__ ((packed)); + +/* + * Hub Status & Hub Change bit masks + * See USB 2.0 spec Table 11-19 and Table 11-20 + * Bits 0 and 1 for wHubStatus and wHubChange + * Bits 2 to 15 are reserved for both + */ +#define HUB_STATUS_LOCAL_POWER 0x0001 +#define HUB_STATUS_OVERCURRENT 0x0002 +#define HUB_CHANGE_LOCAL_POWER 0x0001 +#define HUB_CHANGE_OVERCURRENT 0x0002 + + +/* + * Hub descriptor + * See USB 2.0 spec Table 11-13 + */ + +#define USB_DT_HUB (USB_TYPE_CLASS | 0x09) +#define USB_DT_HUB_NONVAR_SIZE 7 + +struct usb_hub_descriptor { + __u8 bDescLength; + __u8 bDescriptorType; + __u8 bNbrPorts; + __u16 wHubCharacteristics; + __u8 bPwrOn2PwrGood; + __u8 bHubContrCurrent; + /* add 1 bit for hub status change; round to bytes */ + __u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8]; + __u8 PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8]; +} __attribute__ ((packed)); + +struct usb_device; + +/* + * As of USB 2.0, full/low speed devices are segregated into trees. + * One type grows from USB 1.1 host controllers (OHCI, UHCI etc). + * The other type grows from high speed hubs when they connect to + * full/low speed devices using "Transaction Translators" (TTs). + * + * TTs should only be known to the hub driver, and high speed bus + * drivers (only EHCI for now). They affect periodic scheduling and + * sometimes control/bulk error recovery. + */ +struct usb_tt { + struct usb_device *hub; /* upstream highspeed hub */ + int multi; /* true means one TT per port */ + + /* for control/bulk error recovery (CLEAR_TT_BUFFER) */ + spinlock_t lock; + struct list_head clear_list; /* of usb_tt_clear */ + struct work_struct kevent; +}; + +struct usb_tt_clear { + struct list_head clear_list; + unsigned tt; + u16 devinfo; +}; + +extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe); + +struct usb_hub { + struct usb_interface *intf; /* the "real" device */ + struct urb *urb; /* for interrupt polling pipe */ + + /* buffer for urb ... 1 bit each for hub and children, rounded up */ + char (*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8]; + dma_addr_t buffer_dma; /* DMA address for buffer */ + union { + struct usb_hub_status hub; + struct usb_port_status port; + } *status; /* buffer for status reports */ + + int error; /* last reported error */ + int nerrors; /* track consecutive errors */ + + struct list_head hub_list; /* all hubs */ + struct list_head event_list; /* hubs w/data or errs ready */ + + struct usb_hub_descriptor *descriptor; /* class descriptor */ + struct semaphore khubd_sem; + struct usb_tt tt; /* Transaction Translator */ +}; + +#endif /* __LINUX_HUB_H */ diff --git a/reactos/drivers/usb/cromwell/core/makefile b/reactos/drivers/usb/cromwell/core/makefile index 5301aa379f9..2a229b5239b 100644 --- a/reactos/drivers/usb/cromwell/core/makefile +++ b/reactos/drivers/usb/cromwell/core/makefile @@ -1,22 +1,25 @@ -PATH_TO_TOP = ../../../.. - -TARGET_TYPE = export_driver - -TARGET_NAME = usbcore - -TARGET_DDKLIBS = ntoskrnl.a - -TARGET_CFLAGS = -Wall -I$(PATH_TO_TOP)/ntoskrnl/include -DDEBUG_MODE - -TARGET_OBJECTS = \ - message.o hcd.o hcd-pci.o hub.o usb.o config.o urb.o \ - buffer_simple.o usb-debug.o ../sys/ros_wrapper.o \ - ../sys/linuxwrapper.o usbcore.o - -include $(PATH_TO_TOP)/rules.mak - -include $(TOOLS_PATH)/helper.mk - -# Automatic dependency tracking -DEP_OBJECTS := $(TARGET_OBJECTS) -include $(PATH_TO_TOP)/tools/depend.mk +PATH_TO_TOP = ../../../.. + +TARGET_TYPE = export_driver + +TARGET_NAME = usbcore + +TARGET_DDKLIBS = ntoskrnl.a + +TARGET_CFLAGS = -Wall -I$(PATH_TO_TOP)/ntoskrnl/include -DDEBUG_MODE + +TARGET_OBJECTS = \ + message.o hcd.o hcd-pci.o hub.o usb.o config.o urb.o \ + buffer_simple.o usb-debug.o ../sys/ros_wrapper.o \ + ../sys/linuxwrapper.o usbcore.o + +TARGET_LIBS = \ + $(PATH_TO_TOP)/dk/nkm/lib/libusbcore.a + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk + +# Automatic dependency tracking +DEP_OBJECTS := $(TARGET_OBJECTS) +include $(PATH_TO_TOP)/tools/depend.mk diff --git a/reactos/drivers/usb/cromwell/core/makefile.crom b/reactos/drivers/usb/cromwell/core/makefile.crom index 489af5802be..dd6262ccaaa 100644 --- a/reactos/drivers/usb/cromwell/core/makefile.crom +++ b/reactos/drivers/usb/cromwell/core/makefile.crom @@ -1,6 +1,6 @@ - -O_TARGET := message.o hcd.o hcd-pci.o hub.o usb.o config.o urb.o buffer_simple.o urb.o usb-debug.o - -#O_TARGET := urb.o - -include $(TOPDIR)/Rules.make + +O_TARGET := message.o hcd.o hcd-pci.o hub.o usb.o config.o urb.o buffer_simple.o urb.o usb-debug.o + +#O_TARGET := urb.o + +include $(TOPDIR)/Rules.make diff --git a/reactos/drivers/usb/cromwell/core/message.c b/reactos/drivers/usb/cromwell/core/message.c index 749c76b8029..79d1065d2e9 100644 --- a/reactos/drivers/usb/cromwell/core/message.c +++ b/reactos/drivers/usb/cromwell/core/message.c @@ -1,1056 +1,1057 @@ -/* - * message.c - synchronous message handling - */ -#if 0 -#include /* for scatterlist macros */ -#include -#include -#include -#include -#include -#include -#else -#include "../usb_wrapper.h" -#endif - -#include "hcd.h" /* for usbcore internals */ - -// ReactOS specific: No WAITQUEUEs here -#define wake_up(a) do {} while(0) - -struct usb_api_data { - wait_queue_head_t wqh; - int done; -}; - -static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs) -{ - struct usb_api_data *awd = (struct usb_api_data *)urb->context; - - awd->done = 1; - wmb(); - wake_up(&awd->wqh); -} - -// Starts urb and waits for completion or timeout -static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) -{ - //DECLARE_WAITQUEUE(wait, current); // Fireball, 24Jan05 - silent gcc complaining about unused wait variable - struct usb_api_data awd; - int status; - - init_waitqueue_head(&awd.wqh); - awd.done = 0; - - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&awd.wqh, &wait); - - urb->context = &awd; - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - // something went wrong - usb_free_urb(urb); - set_current_state(TASK_RUNNING); - remove_wait_queue(&awd.wqh, &wait); - return status; - } - - while (timeout && !awd.done) - { - timeout = schedule_timeout(timeout); - set_current_state(TASK_UNINTERRUPTIBLE); - rmb(); - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&awd.wqh, &wait); - - if (!timeout && !awd.done) { - if (urb->status != -EINPROGRESS) { /* No callback?!! */ - printk(KERN_ERR "usb: raced timeout, " - "pipe 0x%x status %d time left %d\n", - urb->pipe, urb->status, timeout); - status = urb->status; - } else { - warn("usb_control/bulk_msg: timeout"); - usb_unlink_urb(urb); // remove urb safely - status = -ETIMEDOUT; - } - } else - status = urb->status; - - if (actual_length) - *actual_length = urb->actual_length; - - usb_free_urb(urb); - return status; -} - -/*-------------------------------------------------------------------*/ -// returns status (negative) or length (positive) -int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, - struct usb_ctrlrequest *cmd, void *data, int len, int timeout) -{ - struct urb *urb; - int retv; - int length; - - urb = usb_alloc_urb(0, GFP_NOIO); - if (!urb) - return -ENOMEM; - - usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data, len, - usb_api_blocking_completion, 0); - - retv = usb_start_wait_urb(urb, timeout, &length); - - if (retv < 0) - return retv; - else - return length; -} - -/** - * usb_control_msg - Builds a control urb, sends it off and waits for completion - * @dev: pointer to the usb device to send the message to - * @pipe: endpoint "pipe" to send the message to - * @request: USB message request value - * @requesttype: USB message request type value - * @value: USB message value - * @index: USB message index value - * @data: pointer to the data to send - * @size: length in bytes of the data to send - * @timeout: time in jiffies to wait for the message to complete before - * timing out (if 0 the wait is forever) - * Context: !in_interrupt () - * - * This function sends a simple control message to a specified endpoint - * and waits for the message to complete, or timeout. - * - * If successful, it returns the number of bytes transferred, otherwise a negative error number. - * - * Don't use this function from within an interrupt context, like a - * bottom half handler. If you need an asynchronous message, or need to send - * a message from within interrupt context, use usb_submit_urb() - * If a thread in your driver uses this call, make sure your disconnect() - * method can wait for it to complete. Since you don't have a handle on - * the URB used, you can't cancel the request. - */ -int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, - __u16 value, __u16 index, void *data, __u16 size, int timeout) -{ - struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); - int ret; - - if (!dr) - return -ENOMEM; - - dr->bRequestType= requesttype; - dr->bRequest = request; - dr->wValue = cpu_to_le16p(&value); - dr->wIndex = cpu_to_le16p(&index); - dr->wLength = cpu_to_le16p(&size); - - //dbg("usb_control_msg"); - - ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout); - - kfree(dr); - - return ret; -} - - -/** - * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion - * @usb_dev: pointer to the usb device to send the message to - * @pipe: endpoint "pipe" to send the message to - * @data: pointer to the data to send - * @len: length in bytes of the data to send - * @actual_length: pointer to a location to put the actual length transferred in bytes - * @timeout: time in jiffies to wait for the message to complete before - * timing out (if 0 the wait is forever) - * Context: !in_interrupt () - * - * This function sends a simple bulk message to a specified endpoint - * and waits for the message to complete, or timeout. - * - * If successful, it returns 0, otherwise a negative error number. - * The number of actual bytes transferred will be stored in the - * actual_length paramater. - * - * Don't use this function from within an interrupt context, like a - * bottom half handler. If you need an asynchronous message, or need to - * send a message from within interrupt context, use usb_submit_urb() - * If a thread in your driver uses this call, make sure your disconnect() - * method can wait for it to complete. Since you don't have a handle on - * the URB used, you can't cancel the request. - */ -int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, - void *data, int len, int *actual_length, int timeout) -{ - struct urb *urb; - - if (len < 0) - return -EINVAL; - - urb=usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - - usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, - usb_api_blocking_completion, 0); - - return usb_start_wait_urb(urb,timeout,actual_length); -} - -/*-------------------------------------------------------------------*/ -//#warning "Scatter-gather stuff disabled" -#if 0 -static void sg_clean (struct usb_sg_request *io) -{ - if (io->urbs) { - while (io->entries--) - usb_free_urb (io->urbs [io->entries]); - kfree (io->urbs); - io->urbs = 0; - } - if (io->dev->dev.dma_mask != 0) - usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents); - io->dev = 0; -} - -static void sg_complete (struct urb *urb, struct pt_regs *regs) -{ - struct usb_sg_request *io = (struct usb_sg_request *) urb->context; - unsigned long flags; - - spin_lock_irqsave (&io->lock, flags); - - /* In 2.5 we require hcds' endpoint queues not to progress after fault - * reports, until the completion callback (this!) returns. That lets - * device driver code (like this routine) unlink queued urbs first, - * if it needs to, since the HC won't work on them at all. So it's - * not possible for page N+1 to overwrite page N, and so on. - * - * That's only for "hard" faults; "soft" faults (unlinks) sometimes - * complete before the HCD can get requests away from hardware, - * though never during cleanup after a hard fault. - */ - if (io->status - && (io->status != -ECONNRESET - || urb->status != -ECONNRESET) - && urb->actual_length) { - dev_err (io->dev->bus->controller, - "dev %s ep%d%s scatterlist error %d/%d\n", - io->dev->devpath, - usb_pipeendpoint (urb->pipe), - usb_pipein (urb->pipe) ? "in" : "out", - urb->status, io->status); - // BUG (); - } - - if (urb->status && urb->status != -ECONNRESET) { - int i, found, status; - - io->status = urb->status; - - /* the previous urbs, and this one, completed already. - * unlink the later ones so they won't rx/tx bad data, - * - * FIXME don't bother unlinking urbs that haven't yet been - * submitted; those non-error cases shouldn't be syslogged - */ - for (i = 0, found = 0; i < io->entries; i++) { - if (found) { - status = usb_unlink_urb (io->urbs [i]); - if (status && status != -EINPROGRESS) - err ("sg_complete, unlink --> %d", - status); - } else if (urb == io->urbs [i]) - found = 1; - } - } - - /* on the last completion, signal usb_sg_wait() */ - io->bytes += urb->actual_length; - io->count--; - if (!io->count) - complete (&io->complete); - - spin_unlock_irqrestore (&io->lock, flags); -} - - -/** - * usb_sg_init - initializes scatterlist-based bulk/interrupt I/O request - * @io: request block being initialized. until usb_sg_wait() returns, - * treat this as a pointer to an opaque block of memory, - * @dev: the usb device that will send or receive the data - * @pipe: endpoint "pipe" used to transfer the data - * @period: polling rate for interrupt endpoints, in frames or - * (for high speed endpoints) microframes; ignored for bulk - * @sg: scatterlist entries - * @nents: how many entries in the scatterlist - * @length: how many bytes to send from the scatterlist, or zero to - * send every byte identified in the list. - * @mem_flags: SLAB_* flags affecting memory allocations in this call - * - * Returns zero for success, else a negative errno value. This initializes a - * scatter/gather request, allocating resources such as I/O mappings and urb - * memory (except maybe memory used by USB controller drivers). - * - * The request must be issued using usb_sg_wait(), which waits for the I/O to - * complete (or to be canceled) and then cleans up all resources allocated by - * usb_sg_init(). - * - * The request may be canceled with usb_sg_cancel(), either before or after - * usb_sg_wait() is called. - */ -int usb_sg_init ( - struct usb_sg_request *io, - struct usb_device *dev, - unsigned pipe, - unsigned period, - struct scatterlist *sg, - int nents, - size_t length, - int mem_flags -) -{ - int i; - int urb_flags; - int dma; - - if (!io || !dev || !sg - || usb_pipecontrol (pipe) - || usb_pipeisoc (pipe) - || nents <= 0) - return -EINVAL; - - spin_lock_init (&io->lock); - io->dev = dev; - io->pipe = pipe; - io->sg = sg; - io->nents = nents; - - /* not all host controllers use DMA (like the mainstream pci ones); - * they can use PIO (sl811) or be software over another transport. - */ - dma = (dev->dev.dma_mask != 0); - if (dma) - io->entries = usb_buffer_map_sg (dev, pipe, sg, nents); - else - io->entries = nents; - - /* initialize all the urbs we'll use */ - if (io->entries <= 0) - return io->entries; - - io->count = 0; - io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags); - if (!io->urbs) - goto nomem; - - urb_flags = URB_ASYNC_UNLINK | URB_NO_DMA_MAP | URB_NO_INTERRUPT; - if (usb_pipein (pipe)) - urb_flags |= URB_SHORT_NOT_OK; - - for (i = 0; i < io->entries; i++, io->count = i) { - unsigned len; - - io->urbs [i] = usb_alloc_urb (0, mem_flags); - if (!io->urbs [i]) { - io->entries = i; - goto nomem; - } - - io->urbs [i]->dev = dev; - io->urbs [i]->pipe = pipe; - io->urbs [i]->interval = period; - io->urbs [i]->transfer_flags = urb_flags; - - io->urbs [i]->complete = sg_complete; - io->urbs [i]->context = io; - io->urbs [i]->status = -EINPROGRESS; - io->urbs [i]->actual_length = 0; - - if (dma) { - /* hc may use _only_ transfer_dma */ - io->urbs [i]->transfer_dma = sg_dma_address (sg + i); - len = sg_dma_len (sg + i); - } else { - /* hc may use _only_ transfer_buffer */ - io->urbs [i]->transfer_buffer = - page_address (sg [i].page) + sg [i].offset; - len = sg [i].length; - } - - if (length) { - len = min_t (unsigned, len, length); - length -= len; - if (length == 0) - io->entries = i + 1; - } - io->urbs [i]->transfer_buffer_length = len; - } - io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT; - - /* transaction state */ - io->status = 0; - io->bytes = 0; - init_completion (&io->complete); - return 0; - -nomem: - sg_clean (io); - return -ENOMEM; -} - - -/** - * usb_sg_wait - synchronously execute scatter/gather request - * @io: request block handle, as initialized with usb_sg_init(). - * some fields become accessible when this call returns. - * Context: !in_interrupt () - * - * This function blocks until the specified I/O operation completes. It - * leverages the grouping of the related I/O requests to get good transfer - * rates, by queueing the requests. At higher speeds, such queuing can - * significantly improve USB throughput. - * - * There are three kinds of completion for this function. - * (1) success, where io->status is zero. The number of io->bytes - * transferred is as requested. - * (2) error, where io->status is a negative errno value. The number - * of io->bytes transferred before the error is usually less - * than requested, and can be nonzero. - * (3) cancelation, a type of error with status -ECONNRESET that - * is initiated by usb_sg_cancel(). - * - * When this function returns, all memory allocated through usb_sg_init() or - * this call will have been freed. The request block parameter may still be - * passed to usb_sg_cancel(), or it may be freed. It could also be - * reinitialized and then reused. - * - * Data Transfer Rates: - * - * Bulk transfers are valid for full or high speed endpoints. - * The best full speed data rate is 19 packets of 64 bytes each - * per frame, or 1216 bytes per millisecond. - * The best high speed data rate is 13 packets of 512 bytes each - * per microframe, or 52 KBytes per millisecond. - * - * The reason to use interrupt transfers through this API would most likely - * be to reserve high speed bandwidth, where up to 24 KBytes per millisecond - * could be transferred. That capability is less useful for low or full - * speed interrupt endpoints, which allow at most one packet per millisecond, - * of at most 8 or 64 bytes (respectively). - */ -void usb_sg_wait (struct usb_sg_request *io) -{ - int i; - unsigned long flags; - - /* queue the urbs. */ - spin_lock_irqsave (&io->lock, flags); - for (i = 0; i < io->entries && !io->status; i++) { - int retval; - - retval = usb_submit_urb (io->urbs [i], SLAB_ATOMIC); - - /* after we submit, let completions or cancelations fire; - * we handshake using io->status. - */ - spin_unlock_irqrestore (&io->lock, flags); - switch (retval) { - /* maybe we retrying will recover */ - case -ENXIO: // hc didn't queue this one - case -EAGAIN: - case -ENOMEM: - retval = 0; - i--; - // FIXME: should it usb_sg_cancel() on INTERRUPT? - yield (); - break; - - /* no error? continue immediately. - * - * NOTE: to work better with UHCI (4K I/O buffer may - * need 3K of TDs) it may be good to limit how many - * URBs are queued at once; N milliseconds? - */ - case 0: - cpu_relax (); - break; - - /* fail any uncompleted urbs */ - default: - io->urbs [i]->status = retval; - dbg ("usb_sg_msg, submit --> %d", retval); - usb_sg_cancel (io); - } - spin_lock_irqsave (&io->lock, flags); - if (retval && io->status == -ECONNRESET) - io->status = retval; - } - spin_unlock_irqrestore (&io->lock, flags); - - /* OK, yes, this could be packaged as non-blocking. - * So could the submit loop above ... but it's easier to - * solve neither problem than to solve both! - */ - wait_for_completion (&io->complete); - - sg_clean (io); -} - -/** - * usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait() - * @io: request block, initialized with usb_sg_init() - * - * This stops a request after it has been started by usb_sg_wait(). - * It can also prevents one initialized by usb_sg_init() from starting, - * so that call just frees resources allocated to the request. - */ -void usb_sg_cancel (struct usb_sg_request *io) -{ - unsigned long flags; - - spin_lock_irqsave (&io->lock, flags); - - /* shut everything down, if it didn't already */ - if (!io->status) { - int i; - - io->status = -ECONNRESET; - for (i = 0; i < io->entries; i++) { - int retval; - - if (!io->urbs [i]->dev) - continue; - retval = usb_unlink_urb (io->urbs [i]); - if (retval && retval != -EINPROGRESS) - warn ("usb_sg_cancel, unlink --> %d", retval); - // FIXME don't warn on "not yet submitted" error - } - } - spin_unlock_irqrestore (&io->lock, flags); -} -#endif -/*-------------------------------------------------------------------*/ - -/** - * usb_get_descriptor - issues a generic GET_DESCRIPTOR request - * @dev: the device whose descriptor is being retrieved - * @type: the descriptor type (USB_DT_*) - * @index: the number of the descriptor - * @buf: where to put the descriptor - * @size: how big is "buf"? - * Context: !in_interrupt () - * - * Gets a USB descriptor. Convenience functions exist to simplify - * getting some types of descriptors. Use - * usb_get_device_descriptor() for USB_DT_DEVICE, - * and usb_get_string() or usb_string() for USB_DT_STRING. - * Configuration descriptors (USB_DT_CONFIG) are part of the device - * structure, at least for the current configuration. - * In addition to a number of USB-standard descriptors, some - * devices also use class-specific or vendor-specific descriptors. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Returns the number of bytes received on success, or else the status code - * returned by the underlying usb_control_msg() call. - */ -int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) -{ - int i = 5; - int result; - - memset(buf,0,size); // Make sure we parse really received data - - while (i--) { - /* retries if the returned length was 0; flakey device */ - if ((result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, - (type << 8) + index, 0, buf, size, - HZ * USB_CTRL_GET_TIMEOUT)) > 0 - || result == -EPIPE) - break; - } - return result; -} - -/** - * usb_get_string - gets a string descriptor - * @dev: the device whose string descriptor is being retrieved - * @langid: code for language chosen (from string descriptor zero) - * @index: the number of the descriptor - * @buf: where to put the string - * @size: how big is "buf"? - * Context: !in_interrupt () - * - * Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character, - * in little-endian byte order). - * The usb_string() function will often be a convenient way to turn - * these strings into kernel-printable form. - * - * Strings may be referenced in device, configuration, interface, or other - * descriptors, and could also be used in vendor-specific ways. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Returns the number of bytes received on success, or else the status code - * returned by the underlying usb_control_msg() call. - */ -int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, - (USB_DT_STRING << 8) + index, langid, buf, size, - HZ * USB_CTRL_GET_TIMEOUT); -} - -/** - * usb_get_device_descriptor - (re)reads the device descriptor - * @dev: the device whose device descriptor is being updated - * Context: !in_interrupt () - * - * Updates the copy of the device descriptor stored in the device structure, - * which dedicates space for this purpose. Note that several fields are - * converted to the host CPU's byte order: the USB version (bcdUSB), and - * vendors product and version fields (idVendor, idProduct, and bcdDevice). - * That lets device drivers compare against non-byteswapped constants. - * - * There's normally no need to use this call, although some devices - * will change their descriptors after events like updating firmware. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Returns the number of bytes received on success, or else the status code - * returned by the underlying usb_control_msg() call. - */ -int usb_get_device_descriptor(struct usb_device *dev) -{ - int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, - sizeof(dev->descriptor)); - if (ret >= 0) { - le16_to_cpus(&dev->descriptor.bcdUSB); - le16_to_cpus(&dev->descriptor.idVendor); - le16_to_cpus(&dev->descriptor.idProduct); - le16_to_cpus(&dev->descriptor.bcdDevice); - } - return ret; -} - -/** - * usb_get_status - issues a GET_STATUS call - * @dev: the device whose status is being checked - * @type: USB_RECIP_*; for device, interface, or endpoint - * @target: zero (for device), else interface or endpoint number - * @data: pointer to two bytes of bitmap data - * Context: !in_interrupt () - * - * Returns device, interface, or endpoint status. Normally only of - * interest to see if the device is self powered, or has enabled the - * remote wakeup facility; or whether a bulk or interrupt endpoint - * is halted ("stalled"). - * - * Bits in these status bitmaps are set using the SET_FEATURE request, - * and cleared using the CLEAR_FEATURE request. The usb_clear_halt() - * function should be used to clear halt ("stall") status. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Returns the number of bytes received on success, or else the status code - * returned by the underlying usb_control_msg() call. - */ -int usb_get_status(struct usb_device *dev, int type, int target, void *data) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, data, 2, - HZ * USB_CTRL_GET_TIMEOUT); -} - - -// hub-only!! ... and only exported for reset/reinit path. -// otherwise used internally, when setting up a config -void usb_set_maxpacket(struct usb_device *dev) -{ - int i, b; - - /* NOTE: affects all endpoints _except_ ep0 */ - for (i=0; iactconfig->desc.bNumInterfaces; i++) { - struct usb_interface *ifp = dev->actconfig->interface + i; - struct usb_host_interface *as = ifp->altsetting + ifp->act_altsetting; - struct usb_host_endpoint *ep = as->endpoint; - int e; - - for (e=0; edesc.bNumEndpoints; e++) { - struct usb_endpoint_descriptor *d; - d = &ep [e].desc; - b = d->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - if ((d->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */ - dev->epmaxpacketout[b] = d->wMaxPacketSize; - dev->epmaxpacketin [b] = d->wMaxPacketSize; - } - else if (usb_endpoint_out(d->bEndpointAddress)) { - if (d->wMaxPacketSize > dev->epmaxpacketout[b]) - dev->epmaxpacketout[b] = d->wMaxPacketSize; - } - else { - if (d->wMaxPacketSize > dev->epmaxpacketin [b]) - dev->epmaxpacketin [b] = d->wMaxPacketSize; - } - } - } -} - -/** - * usb_clear_halt - tells device to clear endpoint halt/stall condition - * @dev: device whose endpoint is halted - * @pipe: endpoint "pipe" being cleared - * Context: !in_interrupt () - * - * This is used to clear halt conditions for bulk and interrupt endpoints, - * as reported by URB completion status. Endpoints that are halted are - * sometimes referred to as being "stalled". Such endpoints are unable - * to transmit or receive data until the halt status is cleared. Any URBs - * queued for such an endpoint should normally be unlinked by the driver - * before clearing the halt condition, as described in sections 5.7.5 - * and 5.8.5 of the USB 2.0 spec. - * - * Note that control and isochronous endpoints don't halt, although control - * endpoints report "protocol stall" (for unsupported requests) using the - * same status code used to report a true stall. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Returns zero on success, or else the status code returned by the - * underlying usb_control_msg() call. - */ -int usb_clear_halt(struct usb_device *dev, int pipe) -{ - int result; - int endp = usb_pipeendpoint(pipe); - - if (usb_pipein (pipe)) - endp |= USB_DIR_IN; - - /* we don't care if it wasn't halted first. in fact some devices - * (like some ibmcam model 1 units) seem to expect hosts to make - * this request for iso endpoints, which can't halt! - */ - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, - HZ * USB_CTRL_SET_TIMEOUT); - - /* don't un-halt or force to DATA0 except on success */ - if (result < 0) - return result; - - /* NOTE: seems like Microsoft and Apple don't bother verifying - * the clear "took", so some devices could lock up if you check... - * such as the Hagiwara FlashGate DUAL. So we won't bother. - * - * NOTE: make sure the logic here doesn't diverge much from - * the copy in usb-storage, for as long as we need two copies. - */ - - /* toggle was reset by the clear, then ep was reactivated */ - usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); - usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); - - return 0; -} - -/** - * usb_set_interface - Makes a particular alternate setting be current - * @dev: the device whose interface is being updated - * @interface: the interface being updated - * @alternate: the setting being chosen. - * Context: !in_interrupt () - * - * This is used to enable data transfers on interfaces that may not - * be enabled by default. Not all devices support such configurability. - * Only the driver bound to an interface may change its setting. - * - * Within any given configuration, each interface may have several - * alternative settings. These are often used to control levels of - * bandwidth consumption. For example, the default setting for a high - * speed interrupt endpoint may not send more than 64 bytes per microframe, - * while interrupt transfers of up to 3KBytes per microframe are legal. - * Also, isochronous endpoints may never be part of an - * interface's default setting. To access such bandwidth, alternate - * interface settings must be made current. - * - * Note that in the Linux USB subsystem, bandwidth associated with - * an endpoint in a given alternate setting is not reserved until an URB - * is submitted that needs that bandwidth. Some other operating systems - * allocate bandwidth early, when a configuration is chosen. - * - * This call is synchronous, and may not be used in an interrupt context. - * Also, drivers must not change altsettings while urbs are scheduled for - * endpoints in that interface; all such urbs must first be completed - * (perhaps forced by unlinking). - * - * Returns zero on success, or else the status code returned by the - * underlying usb_control_msg() call. - */ -int usb_set_interface(struct usb_device *dev, int interface, int alternate) -{ - struct usb_interface *iface; - struct usb_host_interface *iface_as; - int i, ret; - void (*disable)(struct usb_device *, int) = dev->bus->op->disable; - - iface = usb_ifnum_to_if(dev, interface); - if (!iface) { - warn("selecting invalid interface %d", interface); - return -EINVAL; - } - - /* 9.4.10 says devices don't need this, if the interface - only has one alternate setting */ - if (iface->num_altsetting == 1) { - dbg("ignoring set_interface for dev %d, iface %d, alt %d", - dev->devnum, interface, alternate); - return 0; - } - - if (alternate < 0 || alternate >= iface->num_altsetting) - return -EINVAL; - - if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, - iface->altsetting[alternate] - .desc.bAlternateSetting, - interface, NULL, 0, HZ * 5)) < 0) - return ret; - - /* FIXME drivers shouldn't need to replicate/bugfix the logic here - * when they implement async or easily-killable versions of this or - * other "should-be-internal" functions (like clear_halt). - * should hcd+usbcore postprocess control requests? - */ - - /* prevent submissions using previous endpoint settings */ - iface_as = iface->altsetting + iface->act_altsetting; - for (i = 0; i < iface_as->desc.bNumEndpoints; i++) { - u8 ep = iface_as->endpoint [i].desc.bEndpointAddress; - int out = !(ep & USB_DIR_IN); - - /* clear out hcd state, then usbcore state */ - if (disable) - disable (dev, ep); - ep &= USB_ENDPOINT_NUMBER_MASK; - (out ? dev->epmaxpacketout : dev->epmaxpacketin ) [ep] = 0; - } - iface->act_altsetting = alternate; - - /* 9.1.1.5: reset toggles for all endpoints affected by this iface-as - * - * Note: - * Despite EP0 is always present in all interfaces/AS, the list of - * endpoints from the descriptor does not contain EP0. Due to its - * omnipresence one might expect EP0 being considered "affected" by - * any SetInterface request and hence assume toggles need to be reset. - * However, EP0 toggles are re-synced for every individual transfer - * during the SETUP stage - hence EP0 toggles are "don't care" here. - * (Likewise, EP0 never "halts" on well designed devices.) - */ - - iface_as = &iface->altsetting[alternate]; - for (i = 0; i < iface_as->desc.bNumEndpoints; i++) { - u8 ep = iface_as->endpoint[i].desc.bEndpointAddress; - int out = !(ep & USB_DIR_IN); - - ep &= USB_ENDPOINT_NUMBER_MASK; - usb_settoggle (dev, ep, out, 0); - (out ? dev->epmaxpacketout : dev->epmaxpacketin) [ep] - = iface_as->endpoint [i].desc.wMaxPacketSize; - usb_endpoint_running (dev, ep, out); - } - - return 0; -} - -/** - * usb_set_configuration - Makes a particular device setting be current - * @dev: the device whose configuration is being updated - * @configuration: the configuration being chosen. - * Context: !in_interrupt () - * - * This is used to enable non-default device modes. Not all devices - * support this kind of configurability. By default, configuration - * zero is selected after enumeration; many devices only have a single - * configuration. - * - * USB devices may support one or more configurations, which affect - * power consumption and the functionality available. For example, - * the default configuration is limited to using 100mA of bus power, - * so that when certain device functionality requires more power, - * and the device is bus powered, that functionality will be in some - * non-default device configuration. Other device modes may also be - * reflected as configuration options, such as whether two ISDN - * channels are presented as independent 64Kb/s interfaces or as one - * bonded 128Kb/s interface. - * - * Note that USB has an additional level of device configurability, - * associated with interfaces. That configurability is accessed using - * usb_set_interface(). - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Returns zero on success, or else the status code returned by the - * underlying usb_control_msg() call. - */ -int usb_set_configuration(struct usb_device *dev, int configuration) -{ - int i, ret; - struct usb_host_config *cp = NULL; - void (*disable)(struct usb_device *, int) = dev->bus->op->disable; - - for (i=0; idescriptor.bNumConfigurations; i++) { - if (dev->config[i].desc.bConfigurationValue == configuration) { - cp = &dev->config[i]; - break; - } - } - if ((!cp && configuration != 0) || (cp && configuration == 0)) { - warn("selecting invalid configuration %d", configuration); - return -EINVAL; - } - - /* if it's already configured, clear out old state first. */ - if (dev->state != USB_STATE_ADDRESS && disable) { - for (i = 1 /* skip ep0 */; i < 15; i++) { - disable (dev, i); - disable (dev, USB_DIR_IN | i); - } - } - dev->toggle[0] = dev->toggle[1] = 0; - dev->halted[0] = dev->halted[1] = 0; - dev->state = USB_STATE_ADDRESS; - - if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_CONFIGURATION, 0, configuration, 0, - NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0) - return ret; - if (configuration) - dev->state = USB_STATE_CONFIGURED; - dev->actconfig = cp; - - /* reset more hc/hcd endpoint state */ - usb_set_maxpacket(dev); - - return 0; -} - - -/** - * usb_string - returns ISO 8859-1 version of a string descriptor - * @dev: the device whose string descriptor is being retrieved - * @index: the number of the descriptor - * @buf: where to put the string - * @size: how big is "buf"? - * Context: !in_interrupt () - * - * This converts the UTF-16LE encoded strings returned by devices, from - * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones - * that are more usable in most kernel contexts. Note that all characters - * in the chosen descriptor that can't be encoded using ISO-8859-1 - * are converted to the question mark ("?") character, and this function - * chooses strings in the first language supported by the device. - * - * The ASCII (or, redundantly, "US-ASCII") character set is the seven-bit - * subset of ISO 8859-1. ISO-8859-1 is the eight-bit subset of Unicode, - * and is appropriate for use many uses of English and several other - * Western European languages. (But it doesn't include the "Euro" symbol.) - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Returns length of the string (>= 0) or usb_control_msg status (< 0). - */ -int usb_string(struct usb_device *dev, int index, char *buf, size_t size) -{ - unsigned char *tbuf; - int err, len; - unsigned int u, idx; - - if (size <= 0 || !buf || !index) - return -EINVAL; - buf[0] = 0; - tbuf = kmalloc(256, GFP_KERNEL); - if (!tbuf) - return -ENOMEM; - - /* get langid for strings if it's not yet known */ - if (!dev->have_langid) { - err = usb_get_string(dev, 0, 0, tbuf, 4); - if (err < 0) { - err("error getting string descriptor 0 (error=%d)", err); - goto errout; - } else if (tbuf[0] < 4) { - err("string descriptor 0 too short"); - err = -EINVAL; - goto errout; - } else { - dev->have_langid = -1; - dev->string_langid = tbuf[2] | (tbuf[3]<< 8); - /* always use the first langid listed */ - dbg("USB device number %d default language ID 0x%x", - dev->devnum, dev->string_langid); - } - } - - /* - * ask for the length of the string - */ - - err = usb_get_string(dev, dev->string_langid, index, tbuf, 2); - if(err<2) - goto errout; - len=tbuf[0]; - - err = usb_get_string(dev, dev->string_langid, index, tbuf, len); - if (err < 0) - goto errout; - - size--; /* leave room for trailing NULL char in output buffer */ - for (idx = 0, u = 2; u < err; u += 2) { - if (idx >= size) - break; - if (tbuf[u+1]) /* high byte */ - buf[idx++] = '?'; /* non ISO-8859-1 character */ - else - buf[idx++] = tbuf[u]; - } - buf[idx] = 0; - err = idx; - - errout: - kfree(tbuf); - return err; -} - -// synchronous request completion model -EXPORT_SYMBOL(usb_control_msg); -EXPORT_SYMBOL(usb_bulk_msg); - -EXPORT_SYMBOL(usb_sg_init); -EXPORT_SYMBOL(usb_sg_cancel); -EXPORT_SYMBOL(usb_sg_wait); - -// synchronous control message convenience routines -EXPORT_SYMBOL(usb_get_descriptor); -EXPORT_SYMBOL(usb_get_device_descriptor); -EXPORT_SYMBOL(usb_get_status); -EXPORT_SYMBOL(usb_get_string); -EXPORT_SYMBOL(usb_string); -EXPORT_SYMBOL(usb_clear_halt); -EXPORT_SYMBOL(usb_set_configuration); -EXPORT_SYMBOL(usb_set_interface); - +/* + * message.c - synchronous message handling + */ +#if 0 +#include /* for scatterlist macros */ +#include +#include +#include +#include +#include +#include +#else +#include "../usb_wrapper.h" +#endif + +#include "hcd.h" /* for usbcore internals */ + +// ReactOS specific: No WAITQUEUEs here +#undef wake_up +#define wake_up(a) do {} while(0) + +struct usb_api_data { + wait_queue_head_t wqh; + int done; +}; + +static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs) +{ + struct usb_api_data *awd = (struct usb_api_data *)urb->context; + + awd->done = 1; + wmb(); + wake_up(&awd->wqh); +} + +// Starts urb and waits for completion or timeout +static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) +{ + //DECLARE_WAITQUEUE(wait, current); // Fireball, 24Jan05 - silent gcc complaining about unused wait variable + struct usb_api_data awd; + int status; + + init_waitqueue_head((PKEVENT)&awd.wqh); + awd.done = 0; + + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&awd.wqh, &wait); + + urb->context = &awd; + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status) { + // something went wrong + usb_free_urb(urb); + set_current_state(TASK_RUNNING); + remove_wait_queue(&awd.wqh, &wait); + return status; + } + + while (timeout && !awd.done) + { + timeout = schedule_timeout(timeout); + set_current_state(TASK_UNINTERRUPTIBLE); + rmb(); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&awd.wqh, &wait); + + if (!timeout && !awd.done) { + if (urb->status != -EINPROGRESS) { /* No callback?!! */ + printk(KERN_ERR "usb: raced timeout, " + "pipe 0x%x status %d time left %d\n", + urb->pipe, urb->status, timeout); + status = urb->status; + } else { + warn("usb_control/bulk_msg: timeout"); + usb_unlink_urb(urb); // remove urb safely + status = -ETIMEDOUT; + } + } else + status = urb->status; + + if (actual_length) + *actual_length = urb->actual_length; + + usb_free_urb(urb); + return status; +} + +/*-------------------------------------------------------------------*/ +// returns status (negative) or length (positive) +int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, + struct usb_ctrlrequest *cmd, void *data, int len, int timeout) +{ + struct urb *urb; + int retv; + int length; + + urb = usb_alloc_urb(0, GFP_NOIO); + if (!urb) + return -ENOMEM; + + usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data, len, + usb_api_blocking_completion, 0); + + retv = usb_start_wait_urb(urb, timeout, &length); + + if (retv < 0) + return retv; + else + return length; +} + +/** + * usb_control_msg - Builds a control urb, sends it off and waits for completion + * @dev: pointer to the usb device to send the message to + * @pipe: endpoint "pipe" to send the message to + * @request: USB message request value + * @requesttype: USB message request type value + * @value: USB message value + * @index: USB message index value + * @data: pointer to the data to send + * @size: length in bytes of the data to send + * @timeout: time in jiffies to wait for the message to complete before + * timing out (if 0 the wait is forever) + * Context: !in_interrupt () + * + * This function sends a simple control message to a specified endpoint + * and waits for the message to complete, or timeout. + * + * If successful, it returns the number of bytes transferred, otherwise a negative error number. + * + * Don't use this function from within an interrupt context, like a + * bottom half handler. If you need an asynchronous message, or need to send + * a message from within interrupt context, use usb_submit_urb() + * If a thread in your driver uses this call, make sure your disconnect() + * method can wait for it to complete. Since you don't have a handle on + * the URB used, you can't cancel the request. + */ +int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, + __u16 value, __u16 index, void *data, __u16 size, int timeout) +{ + struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); + int ret; + + if (!dr) + return -ENOMEM; + + dr->bRequestType= requesttype; + dr->bRequest = request; + dr->wValue = cpu_to_le16p(&value); + dr->wIndex = cpu_to_le16p(&index); + dr->wLength = cpu_to_le16p(&size); + + //dbg("usb_control_msg"); + + ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout); + + kfree(dr); + + return ret; +} + + +/** + * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion + * @usb_dev: pointer to the usb device to send the message to + * @pipe: endpoint "pipe" to send the message to + * @data: pointer to the data to send + * @len: length in bytes of the data to send + * @actual_length: pointer to a location to put the actual length transferred in bytes + * @timeout: time in jiffies to wait for the message to complete before + * timing out (if 0 the wait is forever) + * Context: !in_interrupt () + * + * This function sends a simple bulk message to a specified endpoint + * and waits for the message to complete, or timeout. + * + * If successful, it returns 0, otherwise a negative error number. + * The number of actual bytes transferred will be stored in the + * actual_length paramater. + * + * Don't use this function from within an interrupt context, like a + * bottom half handler. If you need an asynchronous message, or need to + * send a message from within interrupt context, use usb_submit_urb() + * If a thread in your driver uses this call, make sure your disconnect() + * method can wait for it to complete. Since you don't have a handle on + * the URB used, you can't cancel the request. + */ +int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, + void *data, int len, int *actual_length, int timeout) +{ + struct urb *urb; + + if (len < 0) + return -EINVAL; + + urb=usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return -ENOMEM; + + usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, + usb_api_blocking_completion, 0); + + return usb_start_wait_urb(urb,timeout,actual_length); +} + +/*-------------------------------------------------------------------*/ +//#warning "Scatter-gather stuff disabled" +#if 0 +static void sg_clean (struct usb_sg_request *io) +{ + if (io->urbs) { + while (io->entries--) + usb_free_urb (io->urbs [io->entries]); + kfree (io->urbs); + io->urbs = 0; + } + if (io->dev->dev.dma_mask != 0) + usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents); + io->dev = 0; +} + +static void sg_complete (struct urb *urb, struct pt_regs *regs) +{ + struct usb_sg_request *io = (struct usb_sg_request *) urb->context; + unsigned long flags; + + spin_lock_irqsave (&io->lock, flags); + + /* In 2.5 we require hcds' endpoint queues not to progress after fault + * reports, until the completion callback (this!) returns. That lets + * device driver code (like this routine) unlink queued urbs first, + * if it needs to, since the HC won't work on them at all. So it's + * not possible for page N+1 to overwrite page N, and so on. + * + * That's only for "hard" faults; "soft" faults (unlinks) sometimes + * complete before the HCD can get requests away from hardware, + * though never during cleanup after a hard fault. + */ + if (io->status + && (io->status != -ECONNRESET + || urb->status != -ECONNRESET) + && urb->actual_length) { + dev_err (io->dev->bus->controller, + "dev %s ep%d%s scatterlist error %d/%d\n", + io->dev->devpath, + usb_pipeendpoint (urb->pipe), + usb_pipein (urb->pipe) ? "in" : "out", + urb->status, io->status); + // BUG (); + } + + if (urb->status && urb->status != -ECONNRESET) { + int i, found, status; + + io->status = urb->status; + + /* the previous urbs, and this one, completed already. + * unlink the later ones so they won't rx/tx bad data, + * + * FIXME don't bother unlinking urbs that haven't yet been + * submitted; those non-error cases shouldn't be syslogged + */ + for (i = 0, found = 0; i < io->entries; i++) { + if (found) { + status = usb_unlink_urb (io->urbs [i]); + if (status && status != -EINPROGRESS) + err ("sg_complete, unlink --> %d", + status); + } else if (urb == io->urbs [i]) + found = 1; + } + } + + /* on the last completion, signal usb_sg_wait() */ + io->bytes += urb->actual_length; + io->count--; + if (!io->count) + complete (&io->complete); + + spin_unlock_irqrestore (&io->lock, flags); +} + + +/** + * usb_sg_init - initializes scatterlist-based bulk/interrupt I/O request + * @io: request block being initialized. until usb_sg_wait() returns, + * treat this as a pointer to an opaque block of memory, + * @dev: the usb device that will send or receive the data + * @pipe: endpoint "pipe" used to transfer the data + * @period: polling rate for interrupt endpoints, in frames or + * (for high speed endpoints) microframes; ignored for bulk + * @sg: scatterlist entries + * @nents: how many entries in the scatterlist + * @length: how many bytes to send from the scatterlist, or zero to + * send every byte identified in the list. + * @mem_flags: SLAB_* flags affecting memory allocations in this call + * + * Returns zero for success, else a negative errno value. This initializes a + * scatter/gather request, allocating resources such as I/O mappings and urb + * memory (except maybe memory used by USB controller drivers). + * + * The request must be issued using usb_sg_wait(), which waits for the I/O to + * complete (or to be canceled) and then cleans up all resources allocated by + * usb_sg_init(). + * + * The request may be canceled with usb_sg_cancel(), either before or after + * usb_sg_wait() is called. + */ +int usb_sg_init ( + struct usb_sg_request *io, + struct usb_device *dev, + unsigned pipe, + unsigned period, + struct scatterlist *sg, + int nents, + size_t length, + int mem_flags +) +{ + int i; + int urb_flags; + int dma; + + if (!io || !dev || !sg + || usb_pipecontrol (pipe) + || usb_pipeisoc (pipe) + || nents <= 0) + return -EINVAL; + + spin_lock_init (&io->lock); + io->dev = dev; + io->pipe = pipe; + io->sg = sg; + io->nents = nents; + + /* not all host controllers use DMA (like the mainstream pci ones); + * they can use PIO (sl811) or be software over another transport. + */ + dma = (dev->dev.dma_mask != 0); + if (dma) + io->entries = usb_buffer_map_sg (dev, pipe, sg, nents); + else + io->entries = nents; + + /* initialize all the urbs we'll use */ + if (io->entries <= 0) + return io->entries; + + io->count = 0; + io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags); + if (!io->urbs) + goto nomem; + + urb_flags = URB_ASYNC_UNLINK | URB_NO_DMA_MAP | URB_NO_INTERRUPT; + if (usb_pipein (pipe)) + urb_flags |= URB_SHORT_NOT_OK; + + for (i = 0; i < io->entries; i++, io->count = i) { + unsigned len; + + io->urbs [i] = usb_alloc_urb (0, mem_flags); + if (!io->urbs [i]) { + io->entries = i; + goto nomem; + } + + io->urbs [i]->dev = dev; + io->urbs [i]->pipe = pipe; + io->urbs [i]->interval = period; + io->urbs [i]->transfer_flags = urb_flags; + + io->urbs [i]->complete = sg_complete; + io->urbs [i]->context = io; + io->urbs [i]->status = -EINPROGRESS; + io->urbs [i]->actual_length = 0; + + if (dma) { + /* hc may use _only_ transfer_dma */ + io->urbs [i]->transfer_dma = sg_dma_address (sg + i); + len = sg_dma_len (sg + i); + } else { + /* hc may use _only_ transfer_buffer */ + io->urbs [i]->transfer_buffer = + page_address (sg [i].page) + sg [i].offset; + len = sg [i].length; + } + + if (length) { + len = min_t (unsigned, len, length); + length -= len; + if (length == 0) + io->entries = i + 1; + } + io->urbs [i]->transfer_buffer_length = len; + } + io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT; + + /* transaction state */ + io->status = 0; + io->bytes = 0; + init_completion (&io->complete); + return 0; + +nomem: + sg_clean (io); + return -ENOMEM; +} + + +/** + * usb_sg_wait - synchronously execute scatter/gather request + * @io: request block handle, as initialized with usb_sg_init(). + * some fields become accessible when this call returns. + * Context: !in_interrupt () + * + * This function blocks until the specified I/O operation completes. It + * leverages the grouping of the related I/O requests to get good transfer + * rates, by queueing the requests. At higher speeds, such queuing can + * significantly improve USB throughput. + * + * There are three kinds of completion for this function. + * (1) success, where io->status is zero. The number of io->bytes + * transferred is as requested. + * (2) error, where io->status is a negative errno value. The number + * of io->bytes transferred before the error is usually less + * than requested, and can be nonzero. + * (3) cancelation, a type of error with status -ECONNRESET that + * is initiated by usb_sg_cancel(). + * + * When this function returns, all memory allocated through usb_sg_init() or + * this call will have been freed. The request block parameter may still be + * passed to usb_sg_cancel(), or it may be freed. It could also be + * reinitialized and then reused. + * + * Data Transfer Rates: + * + * Bulk transfers are valid for full or high speed endpoints. + * The best full speed data rate is 19 packets of 64 bytes each + * per frame, or 1216 bytes per millisecond. + * The best high speed data rate is 13 packets of 512 bytes each + * per microframe, or 52 KBytes per millisecond. + * + * The reason to use interrupt transfers through this API would most likely + * be to reserve high speed bandwidth, where up to 24 KBytes per millisecond + * could be transferred. That capability is less useful for low or full + * speed interrupt endpoints, which allow at most one packet per millisecond, + * of at most 8 or 64 bytes (respectively). + */ +void usb_sg_wait (struct usb_sg_request *io) +{ + int i; + unsigned long flags; + + /* queue the urbs. */ + spin_lock_irqsave (&io->lock, flags); + for (i = 0; i < io->entries && !io->status; i++) { + int retval; + + retval = usb_submit_urb (io->urbs [i], SLAB_ATOMIC); + + /* after we submit, let completions or cancelations fire; + * we handshake using io->status. + */ + spin_unlock_irqrestore (&io->lock, flags); + switch (retval) { + /* maybe we retrying will recover */ + case -ENXIO: // hc didn't queue this one + case -EAGAIN: + case -ENOMEM: + retval = 0; + i--; + // FIXME: should it usb_sg_cancel() on INTERRUPT? + yield (); + break; + + /* no error? continue immediately. + * + * NOTE: to work better with UHCI (4K I/O buffer may + * need 3K of TDs) it may be good to limit how many + * URBs are queued at once; N milliseconds? + */ + case 0: + cpu_relax (); + break; + + /* fail any uncompleted urbs */ + default: + io->urbs [i]->status = retval; + dbg ("usb_sg_msg, submit --> %d", retval); + usb_sg_cancel (io); + } + spin_lock_irqsave (&io->lock, flags); + if (retval && io->status == -ECONNRESET) + io->status = retval; + } + spin_unlock_irqrestore (&io->lock, flags); + + /* OK, yes, this could be packaged as non-blocking. + * So could the submit loop above ... but it's easier to + * solve neither problem than to solve both! + */ + wait_for_completion (&io->complete); + + sg_clean (io); +} + +/** + * usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait() + * @io: request block, initialized with usb_sg_init() + * + * This stops a request after it has been started by usb_sg_wait(). + * It can also prevents one initialized by usb_sg_init() from starting, + * so that call just frees resources allocated to the request. + */ +void usb_sg_cancel (struct usb_sg_request *io) +{ + unsigned long flags; + + spin_lock_irqsave (&io->lock, flags); + + /* shut everything down, if it didn't already */ + if (!io->status) { + int i; + + io->status = -ECONNRESET; + for (i = 0; i < io->entries; i++) { + int retval; + + if (!io->urbs [i]->dev) + continue; + retval = usb_unlink_urb (io->urbs [i]); + if (retval && retval != -EINPROGRESS) + warn ("usb_sg_cancel, unlink --> %d", retval); + // FIXME don't warn on "not yet submitted" error + } + } + spin_unlock_irqrestore (&io->lock, flags); +} +#endif +/*-------------------------------------------------------------------*/ + +/** + * usb_get_descriptor - issues a generic GET_DESCRIPTOR request + * @dev: the device whose descriptor is being retrieved + * @type: the descriptor type (USB_DT_*) + * @index: the number of the descriptor + * @buf: where to put the descriptor + * @size: how big is "buf"? + * Context: !in_interrupt () + * + * Gets a USB descriptor. Convenience functions exist to simplify + * getting some types of descriptors. Use + * usb_get_device_descriptor() for USB_DT_DEVICE, + * and usb_get_string() or usb_string() for USB_DT_STRING. + * Configuration descriptors (USB_DT_CONFIG) are part of the device + * structure, at least for the current configuration. + * In addition to a number of USB-standard descriptors, some + * devices also use class-specific or vendor-specific descriptors. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Returns the number of bytes received on success, or else the status code + * returned by the underlying usb_control_msg() call. + */ +int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) +{ + int i = 5; + int result; + + memset(buf,0,size); // Make sure we parse really received data + + while (i--) { + /* retries if the returned length was 0; flakey device */ + if ((result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, + (type << 8) + index, 0, buf, size, + HZ * USB_CTRL_GET_TIMEOUT)) > 0 + || result == -EPIPE) + break; + } + return result; +} + +/** + * usb_get_string - gets a string descriptor + * @dev: the device whose string descriptor is being retrieved + * @langid: code for language chosen (from string descriptor zero) + * @index: the number of the descriptor + * @buf: where to put the string + * @size: how big is "buf"? + * Context: !in_interrupt () + * + * Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character, + * in little-endian byte order). + * The usb_string() function will often be a convenient way to turn + * these strings into kernel-printable form. + * + * Strings may be referenced in device, configuration, interface, or other + * descriptors, and could also be used in vendor-specific ways. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Returns the number of bytes received on success, or else the status code + * returned by the underlying usb_control_msg() call. + */ +int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, + (USB_DT_STRING << 8) + index, langid, buf, size, + HZ * USB_CTRL_GET_TIMEOUT); +} + +/** + * usb_get_device_descriptor - (re)reads the device descriptor + * @dev: the device whose device descriptor is being updated + * Context: !in_interrupt () + * + * Updates the copy of the device descriptor stored in the device structure, + * which dedicates space for this purpose. Note that several fields are + * converted to the host CPU's byte order: the USB version (bcdUSB), and + * vendors product and version fields (idVendor, idProduct, and bcdDevice). + * That lets device drivers compare against non-byteswapped constants. + * + * There's normally no need to use this call, although some devices + * will change their descriptors after events like updating firmware. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Returns the number of bytes received on success, or else the status code + * returned by the underlying usb_control_msg() call. + */ +int usb_get_device_descriptor(struct usb_device *dev) +{ + int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, + sizeof(dev->descriptor)); + if (ret >= 0) { + le16_to_cpus(&dev->descriptor.bcdUSB); + le16_to_cpus(&dev->descriptor.idVendor); + le16_to_cpus(&dev->descriptor.idProduct); + le16_to_cpus(&dev->descriptor.bcdDevice); + } + return ret; +} + +/** + * usb_get_status - issues a GET_STATUS call + * @dev: the device whose status is being checked + * @type: USB_RECIP_*; for device, interface, or endpoint + * @target: zero (for device), else interface or endpoint number + * @data: pointer to two bytes of bitmap data + * Context: !in_interrupt () + * + * Returns device, interface, or endpoint status. Normally only of + * interest to see if the device is self powered, or has enabled the + * remote wakeup facility; or whether a bulk or interrupt endpoint + * is halted ("stalled"). + * + * Bits in these status bitmaps are set using the SET_FEATURE request, + * and cleared using the CLEAR_FEATURE request. The usb_clear_halt() + * function should be used to clear halt ("stall") status. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Returns the number of bytes received on success, or else the status code + * returned by the underlying usb_control_msg() call. + */ +int usb_get_status(struct usb_device *dev, int type, int target, void *data) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, data, 2, + HZ * USB_CTRL_GET_TIMEOUT); +} + + +// hub-only!! ... and only exported for reset/reinit path. +// otherwise used internally, when setting up a config +void usb_set_maxpacket(struct usb_device *dev) +{ + int i, b; + + /* NOTE: affects all endpoints _except_ ep0 */ + for (i=0; iactconfig->desc.bNumInterfaces; i++) { + struct usb_interface *ifp = dev->actconfig->interface + i; + struct usb_host_interface *as = ifp->altsetting + ifp->act_altsetting; + struct usb_host_endpoint *ep = as->endpoint; + int e; + + for (e=0; edesc.bNumEndpoints; e++) { + struct usb_endpoint_descriptor *d; + d = &ep [e].desc; + b = d->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + if ((d->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */ + dev->epmaxpacketout[b] = d->wMaxPacketSize; + dev->epmaxpacketin [b] = d->wMaxPacketSize; + } + else if (usb_endpoint_out(d->bEndpointAddress)) { + if (d->wMaxPacketSize > dev->epmaxpacketout[b]) + dev->epmaxpacketout[b] = d->wMaxPacketSize; + } + else { + if (d->wMaxPacketSize > dev->epmaxpacketin [b]) + dev->epmaxpacketin [b] = d->wMaxPacketSize; + } + } + } +} + +/** + * usb_clear_halt - tells device to clear endpoint halt/stall condition + * @dev: device whose endpoint is halted + * @pipe: endpoint "pipe" being cleared + * Context: !in_interrupt () + * + * This is used to clear halt conditions for bulk and interrupt endpoints, + * as reported by URB completion status. Endpoints that are halted are + * sometimes referred to as being "stalled". Such endpoints are unable + * to transmit or receive data until the halt status is cleared. Any URBs + * queued for such an endpoint should normally be unlinked by the driver + * before clearing the halt condition, as described in sections 5.7.5 + * and 5.8.5 of the USB 2.0 spec. + * + * Note that control and isochronous endpoints don't halt, although control + * endpoints report "protocol stall" (for unsupported requests) using the + * same status code used to report a true stall. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Returns zero on success, or else the status code returned by the + * underlying usb_control_msg() call. + */ +int usb_clear_halt(struct usb_device *dev, int pipe) +{ + int result; + int endp = usb_pipeendpoint(pipe); + + if (usb_pipein (pipe)) + endp |= USB_DIR_IN; + + /* we don't care if it wasn't halted first. in fact some devices + * (like some ibmcam model 1 units) seem to expect hosts to make + * this request for iso endpoints, which can't halt! + */ + result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, + HZ * USB_CTRL_SET_TIMEOUT); + + /* don't un-halt or force to DATA0 except on success */ + if (result < 0) + return result; + + /* NOTE: seems like Microsoft and Apple don't bother verifying + * the clear "took", so some devices could lock up if you check... + * such as the Hagiwara FlashGate DUAL. So we won't bother. + * + * NOTE: make sure the logic here doesn't diverge much from + * the copy in usb-storage, for as long as we need two copies. + */ + + /* toggle was reset by the clear, then ep was reactivated */ + usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); + usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); + + return 0; +} + +/** + * usb_set_interface - Makes a particular alternate setting be current + * @dev: the device whose interface is being updated + * @interface: the interface being updated + * @alternate: the setting being chosen. + * Context: !in_interrupt () + * + * This is used to enable data transfers on interfaces that may not + * be enabled by default. Not all devices support such configurability. + * Only the driver bound to an interface may change its setting. + * + * Within any given configuration, each interface may have several + * alternative settings. These are often used to control levels of + * bandwidth consumption. For example, the default setting for a high + * speed interrupt endpoint may not send more than 64 bytes per microframe, + * while interrupt transfers of up to 3KBytes per microframe are legal. + * Also, isochronous endpoints may never be part of an + * interface's default setting. To access such bandwidth, alternate + * interface settings must be made current. + * + * Note that in the Linux USB subsystem, bandwidth associated with + * an endpoint in a given alternate setting is not reserved until an URB + * is submitted that needs that bandwidth. Some other operating systems + * allocate bandwidth early, when a configuration is chosen. + * + * This call is synchronous, and may not be used in an interrupt context. + * Also, drivers must not change altsettings while urbs are scheduled for + * endpoints in that interface; all such urbs must first be completed + * (perhaps forced by unlinking). + * + * Returns zero on success, or else the status code returned by the + * underlying usb_control_msg() call. + */ +int usb_set_interface(struct usb_device *dev, int interface, int alternate) +{ + struct usb_interface *iface; + struct usb_host_interface *iface_as; + int i, ret; + void (*disable)(struct usb_device *, int) = dev->bus->op->disable; + + iface = usb_ifnum_to_if(dev, interface); + if (!iface) { + warn("selecting invalid interface %d", interface); + return -EINVAL; + } + + /* 9.4.10 says devices don't need this, if the interface + only has one alternate setting */ + if (iface->num_altsetting == 1) { + dbg("ignoring set_interface for dev %d, iface %d, alt %d", + dev->devnum, interface, alternate); + return 0; + } + + if (alternate < 0 || alternate >= iface->num_altsetting) + return -EINVAL; + + if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, + iface->altsetting[alternate] + .desc.bAlternateSetting, + interface, NULL, 0, HZ * 5)) < 0) + return ret; + + /* FIXME drivers shouldn't need to replicate/bugfix the logic here + * when they implement async or easily-killable versions of this or + * other "should-be-internal" functions (like clear_halt). + * should hcd+usbcore postprocess control requests? + */ + + /* prevent submissions using previous endpoint settings */ + iface_as = iface->altsetting + iface->act_altsetting; + for (i = 0; i < iface_as->desc.bNumEndpoints; i++) { + u8 ep = iface_as->endpoint [i].desc.bEndpointAddress; + int out = !(ep & USB_DIR_IN); + + /* clear out hcd state, then usbcore state */ + if (disable) + disable (dev, ep); + ep &= USB_ENDPOINT_NUMBER_MASK; + (out ? dev->epmaxpacketout : dev->epmaxpacketin ) [ep] = 0; + } + iface->act_altsetting = alternate; + + /* 9.1.1.5: reset toggles for all endpoints affected by this iface-as + * + * Note: + * Despite EP0 is always present in all interfaces/AS, the list of + * endpoints from the descriptor does not contain EP0. Due to its + * omnipresence one might expect EP0 being considered "affected" by + * any SetInterface request and hence assume toggles need to be reset. + * However, EP0 toggles are re-synced for every individual transfer + * during the SETUP stage - hence EP0 toggles are "don't care" here. + * (Likewise, EP0 never "halts" on well designed devices.) + */ + + iface_as = &iface->altsetting[alternate]; + for (i = 0; i < iface_as->desc.bNumEndpoints; i++) { + u8 ep = iface_as->endpoint[i].desc.bEndpointAddress; + int out = !(ep & USB_DIR_IN); + + ep &= USB_ENDPOINT_NUMBER_MASK; + usb_settoggle (dev, ep, out, 0); + (out ? dev->epmaxpacketout : dev->epmaxpacketin) [ep] + = iface_as->endpoint [i].desc.wMaxPacketSize; + usb_endpoint_running (dev, ep, out); + } + + return 0; +} + +/** + * usb_set_configuration - Makes a particular device setting be current + * @dev: the device whose configuration is being updated + * @configuration: the configuration being chosen. + * Context: !in_interrupt () + * + * This is used to enable non-default device modes. Not all devices + * support this kind of configurability. By default, configuration + * zero is selected after enumeration; many devices only have a single + * configuration. + * + * USB devices may support one or more configurations, which affect + * power consumption and the functionality available. For example, + * the default configuration is limited to using 100mA of bus power, + * so that when certain device functionality requires more power, + * and the device is bus powered, that functionality will be in some + * non-default device configuration. Other device modes may also be + * reflected as configuration options, such as whether two ISDN + * channels are presented as independent 64Kb/s interfaces or as one + * bonded 128Kb/s interface. + * + * Note that USB has an additional level of device configurability, + * associated with interfaces. That configurability is accessed using + * usb_set_interface(). + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Returns zero on success, or else the status code returned by the + * underlying usb_control_msg() call. + */ +int usb_set_configuration(struct usb_device *dev, int configuration) +{ + int i, ret; + struct usb_host_config *cp = NULL; + void (*disable)(struct usb_device *, int) = dev->bus->op->disable; + + for (i=0; idescriptor.bNumConfigurations; i++) { + if (dev->config[i].desc.bConfigurationValue == configuration) { + cp = &dev->config[i]; + break; + } + } + if ((!cp && configuration != 0) || (cp && configuration == 0)) { + warn("selecting invalid configuration %d", configuration); + return -EINVAL; + } + + /* if it's already configured, clear out old state first. */ + if (dev->state != USB_STATE_ADDRESS && disable) { + for (i = 1 /* skip ep0 */; i < 15; i++) { + disable (dev, i); + disable (dev, USB_DIR_IN | i); + } + } + dev->toggle[0] = dev->toggle[1] = 0; + dev->halted[0] = dev->halted[1] = 0; + dev->state = USB_STATE_ADDRESS; + + if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_CONFIGURATION, 0, configuration, 0, + NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0) + return ret; + if (configuration) + dev->state = USB_STATE_CONFIGURED; + dev->actconfig = cp; + + /* reset more hc/hcd endpoint state */ + usb_set_maxpacket(dev); + + return 0; +} + + +/** + * usb_string - returns ISO 8859-1 version of a string descriptor + * @dev: the device whose string descriptor is being retrieved + * @index: the number of the descriptor + * @buf: where to put the string + * @size: how big is "buf"? + * Context: !in_interrupt () + * + * This converts the UTF-16LE encoded strings returned by devices, from + * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones + * that are more usable in most kernel contexts. Note that all characters + * in the chosen descriptor that can't be encoded using ISO-8859-1 + * are converted to the question mark ("?") character, and this function + * chooses strings in the first language supported by the device. + * + * The ASCII (or, redundantly, "US-ASCII") character set is the seven-bit + * subset of ISO 8859-1. ISO-8859-1 is the eight-bit subset of Unicode, + * and is appropriate for use many uses of English and several other + * Western European languages. (But it doesn't include the "Euro" symbol.) + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Returns length of the string (>= 0) or usb_control_msg status (< 0). + */ +int usb_string(struct usb_device *dev, int index, char *buf, size_t size) +{ + unsigned char *tbuf; + int err, len; + unsigned int u, idx; + + if (size <= 0 || !buf || !index) + return -EINVAL; + buf[0] = 0; + tbuf = kmalloc(256, GFP_KERNEL); + if (!tbuf) + return -ENOMEM; + + /* get langid for strings if it's not yet known */ + if (!dev->have_langid) { + err = usb_get_string(dev, 0, 0, tbuf, 4); + if (err < 0) { + err("error getting string descriptor 0 (error=%d)", err); + goto errout; + } else if (tbuf[0] < 4) { + err("string descriptor 0 too short"); + err = -EINVAL; + goto errout; + } else { + dev->have_langid = -1; + dev->string_langid = tbuf[2] | (tbuf[3]<< 8); + /* always use the first langid listed */ + dbg("USB device number %d default language ID 0x%x", + dev->devnum, dev->string_langid); + } + } + + /* + * ask for the length of the string + */ + + err = usb_get_string(dev, dev->string_langid, index, tbuf, 2); + if(err<2) + goto errout; + len=tbuf[0]; + + err = usb_get_string(dev, dev->string_langid, index, tbuf, len); + if (err < 0) + goto errout; + + size--; /* leave room for trailing NULL char in output buffer */ + for (idx = 0, u = 2; u < err; u += 2) { + if (idx >= size) + break; + if (tbuf[u+1]) /* high byte */ + buf[idx++] = '?'; /* non ISO-8859-1 character */ + else + buf[idx++] = tbuf[u]; + } + buf[idx] = 0; + err = idx; + + errout: + kfree(tbuf); + return err; +} + +// synchronous request completion model +EXPORT_SYMBOL(usb_control_msg); +EXPORT_SYMBOL(usb_bulk_msg); + +EXPORT_SYMBOL(usb_sg_init); +EXPORT_SYMBOL(usb_sg_cancel); +EXPORT_SYMBOL(usb_sg_wait); + +// synchronous control message convenience routines +EXPORT_SYMBOL(usb_get_descriptor); +EXPORT_SYMBOL(usb_get_device_descriptor); +EXPORT_SYMBOL(usb_get_status); +EXPORT_SYMBOL(usb_get_string); +EXPORT_SYMBOL(usb_string); +EXPORT_SYMBOL(usb_clear_halt); +EXPORT_SYMBOL(usb_set_configuration); +EXPORT_SYMBOL(usb_set_interface); + diff --git a/reactos/drivers/usb/cromwell/core/urb.c b/reactos/drivers/usb/cromwell/core/urb.c index 08b691fd1ff..4ba8cb4cc0b 100644 --- a/reactos/drivers/usb/cromwell/core/urb.c +++ b/reactos/drivers/usb/cromwell/core/urb.c @@ -1,398 +1,398 @@ -#include "../usb_wrapper.h" -#include "hcd.h" - -/** - * usb_init_urb - initializes a urb so that it can be used by a USB driver - * @urb: pointer to the urb to initialize - * - * Initializes a urb so that the USB subsystem can use it properly. - * - * If a urb is created with a call to usb_alloc_urb() it is not - * necessary to call this function. Only use this if you allocate the - * space for a struct urb on your own. If you call this function, be - * careful when freeing the memory for your urb that it is no longer in - * use by the USB core. - * - * Only use this function if you _really_ understand what you are doing. - */ -void STDCALL usb_init_urb(struct urb *urb) -{ - if (urb) { - memset(urb, 0, sizeof(*urb)); - urb->count = (atomic_t)ATOMIC_INIT(1); - spin_lock_init(&urb->lock); - } -} - -/** - * usb_alloc_urb - creates a new urb for a USB driver to use - * @iso_packets: number of iso packets for this urb - * @mem_flags: the type of memory to allocate, see kmalloc() for a list of - * valid options for this. - * - * Creates an urb for the USB driver to use, initializes a few internal - * structures, incrementes the usage counter, and returns a pointer to it. - * - * If no memory is available, NULL is returned. - * - * If the driver want to use this urb for interrupt, control, or bulk - * endpoints, pass '0' as the number of iso packets. - * - * The driver must call usb_free_urb() when it is finished with the urb. - */ -struct urb STDCALL *usb_alloc_urb(int iso_packets, int mem_flags) -{ - struct urb *urb; - - urb = (struct urb *)kmalloc(sizeof(struct urb) + - iso_packets * sizeof(struct usb_iso_packet_descriptor), - mem_flags); - if (!urb) { - err("alloc_urb: kmalloc failed"); - return NULL; - } - usb_init_urb(urb); - return urb; -} - -/** - * usb_free_urb - frees the memory used by a urb when all users of it are finished - * @urb: pointer to the urb to free - * - * Must be called when a user of a urb is finished with it. When the last user - * of the urb calls this function, the memory of the urb is freed. - * - * Note: The transfer buffer associated with the urb is not freed, that must be - * done elsewhere. - */ -void STDCALL usb_free_urb(struct urb *urb) -{ - if (urb) - if (atomic_dec_and_test(&urb->count)) - { - kfree(urb); - } -} - -/** - * usb_get_urb - increments the reference count of the urb - * @urb: pointer to the urb to modify - * - * This must be called whenever a urb is transferred from a device driver to a - * host controller driver. This allows proper reference counting to happen - * for urbs. - * - * A pointer to the urb with the incremented reference counter is returned. - */ -struct urb STDCALL * usb_get_urb(struct urb *urb) -{ - if (urb) { - atomic_inc(&urb->count); - return urb; - } else - return NULL; -} - - -/*-------------------------------------------------------------------*/ - -/** - * usb_submit_urb - issue an asynchronous transfer request for an endpoint - * @urb: pointer to the urb describing the request - * @mem_flags: the type of memory to allocate, see kmalloc() for a list - * of valid options for this. - * - * This submits a transfer request, and transfers control of the URB - * describing that request to the USB subsystem. Request completion will - * be indicated later, asynchronously, by calling the completion handler. - * The three types of completion are success, error, and unlink - * (also called "request cancellation"). - * URBs may be submitted in interrupt context. - * - * The caller must have correctly initialized the URB before submitting - * it. Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are - * available to ensure that most fields are correctly initialized, for - * the particular kind of transfer, although they will not initialize - * any transfer flags. - * - * Successful submissions return 0; otherwise this routine returns a - * negative error number. If the submission is successful, the complete() - * callback from the urb will be called exactly once, when the USB core and - * host controller driver are finished with the urb. When the completion - * function is called, control of the URB is returned to the device - * driver which issued the request. The completion handler may then - * immediately free or reuse that URB. - * - * For control endpoints, the synchronous usb_control_msg() call is - * often used (in non-interrupt context) instead of this call. - * That is often used through convenience wrappers, for the requests - * that are standardized in the USB 2.0 specification. For bulk - * endpoints, a synchronous usb_bulk_msg() call is available. - * - * Request Queuing: - * - * URBs may be submitted to endpoints before previous ones complete, to - * minimize the impact of interrupt latencies and system overhead on data - * throughput. This is required for continuous isochronous data streams, - * and may also be required for some kinds of interrupt transfers. Such - * queueing also maximizes bandwidth utilization by letting USB controllers - * start work on later requests before driver software has finished the - * completion processing for earlier requests. - * - * Bulk and Isochronous URBs may always be queued. At this writing, all - * mainstream host controller drivers support queueing for control and - * interrupt transfer requests. - * - * Reserved Bandwidth Transfers: - * - * Periodic transfers (interrupt or isochronous) are performed repeatedly, - * using the interval specified in the urb. Submitting the first urb to - * the endpoint reserves the bandwidth necessary to make those transfers. - * If the USB subsystem can't allocate sufficient bandwidth to perform - * the periodic request, submitting such a periodic request should fail. - * - * Device drivers must explicitly request that repetition, by ensuring that - * some URB is always on the endpoint's queue (except possibly for short - * periods during completion callacks). When there is no longer an urb - * queued, the endpoint's bandwidth reservation is canceled. This means - * drivers can use their completion handlers to ensure they keep bandwidth - * they need, by reinitializing and resubmitting the just-completed urb - * until the driver longer needs that periodic bandwidth. - * - * Memory Flags: - * - * The general rules for how to decide which mem_flags to use - * are the same as for kmalloc. There are four - * different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and - * GFP_ATOMIC. - * - * GFP_NOFS is not ever used, as it has not been implemented yet. - * - * GFP_ATOMIC is used when - * (a) you are inside a completion handler, an interrupt, bottom half, - * tasklet or timer, or - * (b) you are holding a spinlock or rwlock (does not apply to - * semaphores), or - * (c) current->state != TASK_RUNNING, this is the case only after - * you've changed it. - * - * GFP_NOIO is used in the block io path and error handling of storage - * devices. - * - * All other situations use GFP_KERNEL. - * - * Some more specific rules for mem_flags can be inferred, such as - * (1) start_xmit, timeout, and receive methods of network drivers must - * use GFP_ATOMIC (they are called with a spinlock held); - * (2) queuecommand methods of scsi drivers must use GFP_ATOMIC (also - * called with a spinlock held); - * (3) If you use a kernel thread with a network driver you must use - * GFP_NOIO, unless (b) or (c) apply; - * (4) after you have done a down() you can use GFP_KERNEL, unless (b) or (c) - * apply or your are in a storage driver's block io path; - * (5) USB probe and disconnect can use GFP_KERNEL unless (b) or (c) apply; and - * (6) changing firmware on a running storage or net device uses - * GFP_NOIO, unless b) or c) apply - * - */ -int STDCALL usb_submit_urb(struct urb *urb, int mem_flags) -{ - int pipe, temp, max; - struct usb_device *dev; - struct usb_operations *op; - int is_out; -// printk("sub dev %p bus %p num %i op %p sub %p\n", -// urb->dev, urb->dev->bus,urb->dev->devnum,urb->dev->bus->op, urb->dev->bus->op->submit_urb); - if (!urb || urb->hcpriv || !urb->complete) - return -EINVAL; - if (!(dev = urb->dev) || - (dev->state < USB_STATE_DEFAULT) || - (!dev->bus) || (dev->devnum <= 0)) - return -ENODEV; - if (!(op = dev->bus->op) || !op->submit_urb) - return -ENODEV; - - urb->status = -EINPROGRESS; - urb->actual_length = 0; - urb->bandwidth = 0; - - /* Lots of sanity checks, so HCDs can rely on clean data - * and don't need to duplicate tests - */ - pipe = urb->pipe; - temp = usb_pipetype (pipe); - is_out = usb_pipeout (pipe); - - if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED) - return -ENODEV; - - /* (actually HCDs may need to duplicate this, endpoint might yet - * stall due to queued bulk/intr transactions that complete after - * we check) - */ - if (usb_endpoint_halted (dev, usb_pipeendpoint (pipe), is_out)) - return -EPIPE; - - /* FIXME there should be a sharable lock protecting us against - * config/altsetting changes and disconnects, kicking in here. - * (here == before maxpacket, and eventually endpoint type, - * checks get made.) - */ - - max = usb_maxpacket (dev, pipe, is_out); - if (max <= 0) { - dbg ("%s: bogus endpoint %d-%s on usb-%s-%s (bad maxpacket %d)", - __FUNCTION__, - usb_pipeendpoint (pipe), is_out ? "OUT" : "IN", - dev->bus->bus_name, dev->devpath, - max); - return -EMSGSIZE; - } - - /* periodic transfers limit size per frame/uframe, - * but drivers only control those sizes for ISO. - * while we're checking, initialize return status. - */ - if (temp == PIPE_ISOCHRONOUS) { - int n, len; - - /* "high bandwidth" mode, 1-3 packets/uframe? */ - if (dev->speed == USB_SPEED_HIGH) { - int mult = 1 + ((max >> 11) & 0x03); - max &= 0x03ff; - max *= mult; - } - - if (urb->number_of_packets <= 0) - return -EINVAL; - for (n = 0; n < urb->number_of_packets; n++) { - len = urb->iso_frame_desc [n].length; - if (len < 0 || len > max) - return -EMSGSIZE; - urb->iso_frame_desc [n].status = -EXDEV; - urb->iso_frame_desc [n].actual_length = 0; - } - } - - /* the I/O buffer must be mapped/unmapped, except when length=0 */ - if (urb->transfer_buffer_length < 0) - return -EMSGSIZE; - -#ifdef DEBUG - /* stuff that drivers shouldn't do, but which shouldn't - * cause problems in HCDs if they get it wrong. - */ - { - unsigned int orig_flags = urb->transfer_flags; - unsigned int allowed; - - /* enforce simple/standard policy */ - allowed = URB_ASYNC_UNLINK; // affects later unlinks - allowed |= URB_NO_DMA_MAP; - allowed |= URB_NO_INTERRUPT; - switch (temp) { - case PIPE_BULK: - if (is_out) - allowed |= URB_ZERO_PACKET; - /* FALLTHROUGH */ - case PIPE_CONTROL: - allowed |= URB_NO_FSBR; /* only affects UHCI */ - /* FALLTHROUGH */ - default: /* all non-iso endpoints */ - if (!is_out) - allowed |= URB_SHORT_NOT_OK; - break; - case PIPE_ISOCHRONOUS: - allowed |= URB_ISO_ASAP; - break; - } - urb->transfer_flags &= allowed; - - /* fail if submitter gave bogus flags */ - if (urb->transfer_flags != orig_flags) { - err ("BOGUS urb flags, %x --> %x", - orig_flags, urb->transfer_flags); - return -EINVAL; - } - } -#endif - /* - * Force periodic transfer intervals to be legal values that are - * a power of two (so HCDs don't need to). - * - * FIXME want bus->{intr,iso}_sched_horizon values here. Each HC - * supports different values... this uses EHCI/UHCI defaults (and - * EHCI can use smaller non-default values). - */ - switch (temp) { - case PIPE_ISOCHRONOUS: - case PIPE_INTERRUPT: - /* too small? */ - if (urb->interval <= 0) - return -EINVAL; - /* too big? */ - switch (dev->speed) { - case USB_SPEED_HIGH: /* units are microframes */ - // NOTE usb handles 2^15 - if (urb->interval > (1024 * 8)) - urb->interval = 1024 * 8; - temp = 1024 * 8; - break; - case USB_SPEED_FULL: /* units are frames/msec */ - case USB_SPEED_LOW: - if (temp == PIPE_INTERRUPT) { - if (urb->interval > 255) - return -EINVAL; - // NOTE ohci only handles up to 32 - temp = 128; - } else { - if (urb->interval > 1024) - urb->interval = 1024; - // NOTE usb and ohci handle up to 2^15 - temp = 1024; - } - break; - default: - return -EINVAL; - } - /* power of two? */ - while (temp > urb->interval) - temp >>= 1; - urb->interval = temp; - } - - return op->submit_urb (urb, mem_flags); -} - -/*-------------------------------------------------------------------*/ - -/** - * usb_unlink_urb - abort/cancel a transfer request for an endpoint - * @urb: pointer to urb describing a previously submitted request - * - * This routine cancels an in-progress request. The requests's - * completion handler will be called with a status code indicating - * that the request has been canceled, and that control of the URB - * has been returned to that device driver. - * - * When the URB_ASYNC_UNLINK transfer flag for the URB is clear, this - * request is synchronous. Success is indicated by returning zero, - * at which time the urb will have been unlinked, - * and the completion function will see status -ENOENT. Failure is - * indicated by any other return value. This mode may not be used - * when unlinking an urb from an interrupt context, such as a bottom - * half or a completion handler, - * - * When the URB_ASYNC_UNLINK transfer flag for the URB is set, this - * request is asynchronous. Success is indicated by returning -EINPROGRESS, - * at which time the urb will normally not have been unlinked, - * and the completion function will see status -ECONNRESET. Failure is - * indicated by any other return value. - */ -int STDCALL usb_unlink_urb(struct urb *urb) -{ - if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op) - return urb->dev->bus->op->unlink_urb(urb); - else - return -ENODEV; -} +#include "../usb_wrapper.h" +#include "hcd.h" + +/** + * usb_init_urb - initializes a urb so that it can be used by a USB driver + * @urb: pointer to the urb to initialize + * + * Initializes a urb so that the USB subsystem can use it properly. + * + * If a urb is created with a call to usb_alloc_urb() it is not + * necessary to call this function. Only use this if you allocate the + * space for a struct urb on your own. If you call this function, be + * careful when freeing the memory for your urb that it is no longer in + * use by the USB core. + * + * Only use this function if you _really_ understand what you are doing. + */ +void STDCALL usb_init_urb(struct urb *urb) +{ + if (urb) { + memset(urb, 0, sizeof(*urb)); + urb->count = (atomic_t)ATOMIC_INIT(1); + spin_lock_init(&urb->lock); + } +} + +/** + * usb_alloc_urb - creates a new urb for a USB driver to use + * @iso_packets: number of iso packets for this urb + * @mem_flags: the type of memory to allocate, see kmalloc() for a list of + * valid options for this. + * + * Creates an urb for the USB driver to use, initializes a few internal + * structures, incrementes the usage counter, and returns a pointer to it. + * + * If no memory is available, NULL is returned. + * + * If the driver want to use this urb for interrupt, control, or bulk + * endpoints, pass '0' as the number of iso packets. + * + * The driver must call usb_free_urb() when it is finished with the urb. + */ +struct urb STDCALL *usb_alloc_urb(int iso_packets, int mem_flags) +{ + struct urb *urb; + + urb = (struct urb *)kmalloc(sizeof(struct urb) + + iso_packets * sizeof(struct usb_iso_packet_descriptor), + mem_flags); + if (!urb) { + err("alloc_urb: kmalloc failed"); + return NULL; + } + usb_init_urb(urb); + return urb; +} + +/** + * usb_free_urb - frees the memory used by a urb when all users of it are finished + * @urb: pointer to the urb to free + * + * Must be called when a user of a urb is finished with it. When the last user + * of the urb calls this function, the memory of the urb is freed. + * + * Note: The transfer buffer associated with the urb is not freed, that must be + * done elsewhere. + */ +void STDCALL usb_free_urb(struct urb *urb) +{ + if (urb) + if (atomic_dec_and_test(&urb->count)) + { + kfree(urb); + } +} + +/** + * usb_get_urb - increments the reference count of the urb + * @urb: pointer to the urb to modify + * + * This must be called whenever a urb is transferred from a device driver to a + * host controller driver. This allows proper reference counting to happen + * for urbs. + * + * A pointer to the urb with the incremented reference counter is returned. + */ +struct urb STDCALL * usb_get_urb(struct urb *urb) +{ + if (urb) { + atomic_inc(&urb->count); + return urb; + } else + return NULL; +} + + +/*-------------------------------------------------------------------*/ + +/** + * usb_submit_urb - issue an asynchronous transfer request for an endpoint + * @urb: pointer to the urb describing the request + * @mem_flags: the type of memory to allocate, see kmalloc() for a list + * of valid options for this. + * + * This submits a transfer request, and transfers control of the URB + * describing that request to the USB subsystem. Request completion will + * be indicated later, asynchronously, by calling the completion handler. + * The three types of completion are success, error, and unlink + * (also called "request cancellation"). + * URBs may be submitted in interrupt context. + * + * The caller must have correctly initialized the URB before submitting + * it. Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are + * available to ensure that most fields are correctly initialized, for + * the particular kind of transfer, although they will not initialize + * any transfer flags. + * + * Successful submissions return 0; otherwise this routine returns a + * negative error number. If the submission is successful, the complete() + * callback from the urb will be called exactly once, when the USB core and + * host controller driver are finished with the urb. When the completion + * function is called, control of the URB is returned to the device + * driver which issued the request. The completion handler may then + * immediately free or reuse that URB. + * + * For control endpoints, the synchronous usb_control_msg() call is + * often used (in non-interrupt context) instead of this call. + * That is often used through convenience wrappers, for the requests + * that are standardized in the USB 2.0 specification. For bulk + * endpoints, a synchronous usb_bulk_msg() call is available. + * + * Request Queuing: + * + * URBs may be submitted to endpoints before previous ones complete, to + * minimize the impact of interrupt latencies and system overhead on data + * throughput. This is required for continuous isochronous data streams, + * and may also be required for some kinds of interrupt transfers. Such + * queueing also maximizes bandwidth utilization by letting USB controllers + * start work on later requests before driver software has finished the + * completion processing for earlier requests. + * + * Bulk and Isochronous URBs may always be queued. At this writing, all + * mainstream host controller drivers support queueing for control and + * interrupt transfer requests. + * + * Reserved Bandwidth Transfers: + * + * Periodic transfers (interrupt or isochronous) are performed repeatedly, + * using the interval specified in the urb. Submitting the first urb to + * the endpoint reserves the bandwidth necessary to make those transfers. + * If the USB subsystem can't allocate sufficient bandwidth to perform + * the periodic request, submitting such a periodic request should fail. + * + * Device drivers must explicitly request that repetition, by ensuring that + * some URB is always on the endpoint's queue (except possibly for short + * periods during completion callacks). When there is no longer an urb + * queued, the endpoint's bandwidth reservation is canceled. This means + * drivers can use their completion handlers to ensure they keep bandwidth + * they need, by reinitializing and resubmitting the just-completed urb + * until the driver longer needs that periodic bandwidth. + * + * Memory Flags: + * + * The general rules for how to decide which mem_flags to use + * are the same as for kmalloc. There are four + * different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and + * GFP_ATOMIC. + * + * GFP_NOFS is not ever used, as it has not been implemented yet. + * + * GFP_ATOMIC is used when + * (a) you are inside a completion handler, an interrupt, bottom half, + * tasklet or timer, or + * (b) you are holding a spinlock or rwlock (does not apply to + * semaphores), or + * (c) current->state != TASK_RUNNING, this is the case only after + * you've changed it. + * + * GFP_NOIO is used in the block io path and error handling of storage + * devices. + * + * All other situations use GFP_KERNEL. + * + * Some more specific rules for mem_flags can be inferred, such as + * (1) start_xmit, timeout, and receive methods of network drivers must + * use GFP_ATOMIC (they are called with a spinlock held); + * (2) queuecommand methods of scsi drivers must use GFP_ATOMIC (also + * called with a spinlock held); + * (3) If you use a kernel thread with a network driver you must use + * GFP_NOIO, unless (b) or (c) apply; + * (4) after you have done a down() you can use GFP_KERNEL, unless (b) or (c) + * apply or your are in a storage driver's block io path; + * (5) USB probe and disconnect can use GFP_KERNEL unless (b) or (c) apply; and + * (6) changing firmware on a running storage or net device uses + * GFP_NOIO, unless b) or c) apply + * + */ +int STDCALL usb_submit_urb(struct urb *urb, int mem_flags) +{ + int pipe, temp, max; + struct usb_device *dev; + struct usb_operations *op; + int is_out; +// printk("sub dev %p bus %p num %i op %p sub %p\n", +// urb->dev, urb->dev->bus,urb->dev->devnum,urb->dev->bus->op, urb->dev->bus->op->submit_urb); + if (!urb || urb->hcpriv || !urb->complete) + return -EINVAL; + if (!(dev = urb->dev) || + (dev->state < USB_STATE_DEFAULT) || + (!dev->bus) || (dev->devnum <= 0)) + return -ENODEV; + if (!(op = dev->bus->op) || !op->submit_urb) + return -ENODEV; + + urb->status = -EINPROGRESS; + urb->actual_length = 0; + urb->bandwidth = 0; + + /* Lots of sanity checks, so HCDs can rely on clean data + * and don't need to duplicate tests + */ + pipe = urb->pipe; + temp = usb_pipetype (pipe); + is_out = usb_pipeout (pipe); + + if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED) + return -ENODEV; + + /* (actually HCDs may need to duplicate this, endpoint might yet + * stall due to queued bulk/intr transactions that complete after + * we check) + */ + if (usb_endpoint_halted (dev, usb_pipeendpoint (pipe), is_out)) + return -EPIPE; + + /* FIXME there should be a sharable lock protecting us against + * config/altsetting changes and disconnects, kicking in here. + * (here == before maxpacket, and eventually endpoint type, + * checks get made.) + */ + + max = usb_maxpacket (dev, pipe, is_out); + if (max <= 0) { + dbg ("%s: bogus endpoint %d-%s on usb-%s-%s (bad maxpacket %d)", + __FUNCTION__, + usb_pipeendpoint (pipe), is_out ? "OUT" : "IN", + dev->bus->bus_name, dev->devpath, + max); + return -EMSGSIZE; + } + + /* periodic transfers limit size per frame/uframe, + * but drivers only control those sizes for ISO. + * while we're checking, initialize return status. + */ + if (temp == PIPE_ISOCHRONOUS) { + int n, len; + + /* "high bandwidth" mode, 1-3 packets/uframe? */ + if (dev->speed == USB_SPEED_HIGH) { + int mult = 1 + ((max >> 11) & 0x03); + max &= 0x03ff; + max *= mult; + } + + if (urb->number_of_packets <= 0) + return -EINVAL; + for (n = 0; n < urb->number_of_packets; n++) { + len = urb->iso_frame_desc [n].length; + if (len < 0 || len > max) + return -EMSGSIZE; + urb->iso_frame_desc [n].status = -EXDEV; + urb->iso_frame_desc [n].actual_length = 0; + } + } + + /* the I/O buffer must be mapped/unmapped, except when length=0 */ + if (urb->transfer_buffer_length < 0) + return -EMSGSIZE; + +#ifdef DEBUG + /* stuff that drivers shouldn't do, but which shouldn't + * cause problems in HCDs if they get it wrong. + */ + { + unsigned int orig_flags = urb->transfer_flags; + unsigned int allowed; + + /* enforce simple/standard policy */ + allowed = URB_ASYNC_UNLINK; // affects later unlinks + allowed |= URB_NO_DMA_MAP; + allowed |= URB_NO_INTERRUPT; + switch (temp) { + case PIPE_BULK: + if (is_out) + allowed |= URB_ZERO_PACKET; + /* FALLTHROUGH */ + case PIPE_CONTROL: + allowed |= URB_NO_FSBR; /* only affects UHCI */ + /* FALLTHROUGH */ + default: /* all non-iso endpoints */ + if (!is_out) + allowed |= URB_SHORT_NOT_OK; + break; + case PIPE_ISOCHRONOUS: + allowed |= URB_ISO_ASAP; + break; + } + urb->transfer_flags &= allowed; + + /* fail if submitter gave bogus flags */ + if (urb->transfer_flags != orig_flags) { + err ("BOGUS urb flags, %x --> %x", + orig_flags, urb->transfer_flags); + return -EINVAL; + } + } +#endif + /* + * Force periodic transfer intervals to be legal values that are + * a power of two (so HCDs don't need to). + * + * FIXME want bus->{intr,iso}_sched_horizon values here. Each HC + * supports different values... this uses EHCI/UHCI defaults (and + * EHCI can use smaller non-default values). + */ + switch (temp) { + case PIPE_ISOCHRONOUS: + case PIPE_INTERRUPT: + /* too small? */ + if (urb->interval <= 0) + return -EINVAL; + /* too big? */ + switch (dev->speed) { + case USB_SPEED_HIGH: /* units are microframes */ + // NOTE usb handles 2^15 + if (urb->interval > (1024 * 8)) + urb->interval = 1024 * 8; + temp = 1024 * 8; + break; + case USB_SPEED_FULL: /* units are frames/msec */ + case USB_SPEED_LOW: + if (temp == PIPE_INTERRUPT) { + if (urb->interval > 255) + return -EINVAL; + // NOTE ohci only handles up to 32 + temp = 128; + } else { + if (urb->interval > 1024) + urb->interval = 1024; + // NOTE usb and ohci handle up to 2^15 + temp = 1024; + } + break; + default: + return -EINVAL; + } + /* power of two? */ + while (temp > urb->interval) + temp >>= 1; + urb->interval = temp; + } + + return op->submit_urb (urb, mem_flags); +} + +/*-------------------------------------------------------------------*/ + +/** + * usb_unlink_urb - abort/cancel a transfer request for an endpoint + * @urb: pointer to urb describing a previously submitted request + * + * This routine cancels an in-progress request. The requests's + * completion handler will be called with a status code indicating + * that the request has been canceled, and that control of the URB + * has been returned to that device driver. + * + * When the URB_ASYNC_UNLINK transfer flag for the URB is clear, this + * request is synchronous. Success is indicated by returning zero, + * at which time the urb will have been unlinked, + * and the completion function will see status -ENOENT. Failure is + * indicated by any other return value. This mode may not be used + * when unlinking an urb from an interrupt context, such as a bottom + * half or a completion handler, + * + * When the URB_ASYNC_UNLINK transfer flag for the URB is set, this + * request is asynchronous. Success is indicated by returning -EINPROGRESS, + * at which time the urb will normally not have been unlinked, + * and the completion function will see status -ECONNRESET. Failure is + * indicated by any other return value. + */ +int STDCALL usb_unlink_urb(struct urb *urb) +{ + if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op) + return urb->dev->bus->op->unlink_urb(urb); + else + return -ENODEV; +} diff --git a/reactos/drivers/usb/cromwell/core/usb-debug.c b/reactos/drivers/usb/cromwell/core/usb-debug.c index a2a3404f4c6..a6a6160e05a 100644 --- a/reactos/drivers/usb/cromwell/core/usb-debug.c +++ b/reactos/drivers/usb/cromwell/core/usb-debug.c @@ -1,206 +1,206 @@ -/* - * debug.c - USB debug helper routines. - * - * I just want these out of the way where they aren't in your - * face, but so that you can still use them.. - */ -#define CONFIG_USB_DEBUG -#if 0 -#include -#include -#include -#include -#ifdef CONFIG_USB_DEBUG - #define DEBUG -#else - #undef DEBUG -#endif -#include -#else -#include "../usb_wrapper.h" -#endif - -static void usb_show_endpoint(struct usb_host_endpoint *endpoint) -{ - usb_show_endpoint_descriptor(&endpoint->desc); -} - -static void usb_show_interface(struct usb_host_interface *altsetting) -{ - int i; - - usb_show_interface_descriptor(&altsetting->desc); - - for (i = 0; i < altsetting->desc.bNumEndpoints; i++) - usb_show_endpoint(altsetting->endpoint + i); -} - -static void usb_show_config(struct usb_host_config *config) -{ - int i, j; - struct usb_interface *ifp; - - usb_show_config_descriptor(&config->desc); - for (i = 0; i < config->desc.bNumInterfaces; i++) { - ifp = config->interface + i; - - if (!ifp) - break; - - printk("\n Interface: %d\n", i); - for (j = 0; j < ifp->num_altsetting; j++) - usb_show_interface(ifp->altsetting + j); - } -} - -void usb_show_device(struct usb_device *dev) -{ - int i; - - usb_show_device_descriptor(&dev->descriptor); - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) - usb_show_config(dev->config + i); -} - -/* - * Parse and show the different USB descriptors. - */ -void usb_show_device_descriptor(struct usb_device_descriptor *desc) -{ - if (!desc) - { - printk("Invalid USB device descriptor (NULL POINTER)\n"); - return; - } - printk(" Length = %2d%s\n", desc->bLength, - desc->bLength == USB_DT_DEVICE_SIZE ? "" : " (!!!)"); - printk(" DescriptorType = %02x\n", desc->bDescriptorType); - - printk(" USB version = %x.%02x\n", - desc->bcdUSB >> 8, desc->bcdUSB & 0xff); - printk(" Vendor:Product = %04x:%04x\n", - desc->idVendor, desc->idProduct); - printk(" MaxPacketSize0 = %d\n", desc->bMaxPacketSize0); - printk(" NumConfigurations = %d\n", desc->bNumConfigurations); - printk(" Device version = %x.%02x\n", - desc->bcdDevice >> 8, desc->bcdDevice & 0xff); - - printk(" Device Class:SubClass:Protocol = %02x:%02x:%02x\n", - desc->bDeviceClass, desc->bDeviceSubClass, desc->bDeviceProtocol); - switch (desc->bDeviceClass) { - case 0: - printk(" Per-interface classes\n"); - break; - case USB_CLASS_AUDIO: - printk(" Audio device class\n"); - break; - case USB_CLASS_COMM: - printk(" Communications class\n"); - break; - case USB_CLASS_HID: - printk(" Human Interface Devices class\n"); - break; - case USB_CLASS_PRINTER: - printk(" Printer device class\n"); - break; - case USB_CLASS_MASS_STORAGE: - printk(" Mass Storage device class\n"); - break; - case USB_CLASS_HUB: - printk(" Hub device class\n"); - break; - case USB_CLASS_VENDOR_SPEC: - printk(" Vendor class\n"); - break; - default: - printk(" Unknown class\n"); - } -} - -void usb_show_config_descriptor(struct usb_config_descriptor *desc) -{ - printk("Configuration:\n"); - printk(" bLength = %4d%s\n", desc->bLength, - desc->bLength == USB_DT_CONFIG_SIZE ? "" : " (!!!)"); - printk(" bDescriptorType = %02x\n", desc->bDescriptorType); - printk(" wTotalLength = %04x\n", desc->wTotalLength); - printk(" bNumInterfaces = %02x\n", desc->bNumInterfaces); - printk(" bConfigurationValue = %02x\n", desc->bConfigurationValue); - printk(" iConfiguration = %02x\n", desc->iConfiguration); - printk(" bmAttributes = %02x\n", desc->bmAttributes); - printk(" bMaxPower = %4dmA\n", desc->bMaxPower * 2); -} - -void usb_show_interface_descriptor(struct usb_interface_descriptor *desc) -{ - printk(" Alternate Setting: %2d\n", desc->bAlternateSetting); - printk(" bLength = %4d%s\n", desc->bLength, - desc->bLength == USB_DT_INTERFACE_SIZE ? "" : " (!!!)"); - printk(" bDescriptorType = %02x\n", desc->bDescriptorType); - printk(" bInterfaceNumber = %02x\n", desc->bInterfaceNumber); - printk(" bAlternateSetting = %02x\n", desc->bAlternateSetting); - printk(" bNumEndpoints = %02x\n", desc->bNumEndpoints); - printk(" bInterface Class:SubClass:Protocol = %02x:%02x:%02x\n", - desc->bInterfaceClass, desc->bInterfaceSubClass, desc->bInterfaceProtocol); - printk(" iInterface = %02x\n", desc->iInterface); -} - -void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *desc) -{ - char *LengthCommentString = (desc->bLength == - USB_DT_ENDPOINT_AUDIO_SIZE) ? " (Audio)" : (desc->bLength == - USB_DT_ENDPOINT_SIZE) ? "" : " (!!!)"; - char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" }; - - printk(" Endpoint:\n"); - printk(" bLength = %4d%s\n", - desc->bLength, LengthCommentString); - printk(" bDescriptorType = %02x\n", desc->bDescriptorType); - printk(" bEndpointAddress = %02x (%s)\n", desc->bEndpointAddress, - (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_CONTROL ? "i/o" : - (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? "in" : "out"); - printk(" bmAttributes = %02x (%s)\n", desc->bmAttributes, - EndpointType[USB_ENDPOINT_XFERTYPE_MASK & desc->bmAttributes]); - printk(" wMaxPacketSize = %04x\n", desc->wMaxPacketSize); - printk(" bInterval = %02x\n", desc->bInterval); - - /* Audio extensions to the endpoint descriptor */ - if (desc->bLength == USB_DT_ENDPOINT_AUDIO_SIZE) { - printk(" bRefresh = %02x\n", desc->bRefresh); - printk(" bSynchAddress = %02x\n", desc->bSynchAddress); - } -} - -void usb_show_string(struct usb_device *dev, char *id, int index) -{ - char *buf; - - if (!index) - return; - if (!(buf = kmalloc(256, GFP_KERNEL))) - return; - if (usb_string(dev, index, buf, 256) > 0) - dev_printk(KERN_INFO, &dev->dev, "%s: %s\n", id, buf); - kfree(buf); -} - -void usb_dump_urb (struct urb *urb) -{ - printk ("urb :%p\n", urb); - printk ("dev :%p\n", urb->dev); - printk ("pipe :%08X\n", urb->pipe); - printk ("status :%d\n", urb->status); - printk ("transfer_flags :%08X\n", urb->transfer_flags); - printk ("transfer_buffer :%p\n", urb->transfer_buffer); - printk ("transfer_buffer_length:%d\n", urb->transfer_buffer_length); - printk ("actual_length :%d\n", urb->actual_length); - printk ("setup_packet :%p\n", urb->setup_packet); - printk ("start_frame :%d\n", urb->start_frame); - printk ("number_of_packets :%d\n", urb->number_of_packets); - printk ("interval :%d\n", urb->interval); - printk ("error_count :%d\n", urb->error_count); - printk ("context :%p\n", urb->context); - printk ("complete :%p\n", urb->complete); -} - +/* + * debug.c - USB debug helper routines. + * + * I just want these out of the way where they aren't in your + * face, but so that you can still use them.. + */ +#define CONFIG_USB_DEBUG +#if 0 +#include +#include +#include +#include +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif +#include +#else +#include "../usb_wrapper.h" +#endif + +static void usb_show_endpoint(struct usb_host_endpoint *endpoint) +{ + usb_show_endpoint_descriptor(&endpoint->desc); +} + +static void usb_show_interface(struct usb_host_interface *altsetting) +{ + int i; + + usb_show_interface_descriptor(&altsetting->desc); + + for (i = 0; i < altsetting->desc.bNumEndpoints; i++) + usb_show_endpoint(altsetting->endpoint + i); +} + +static void usb_show_config(struct usb_host_config *config) +{ + int i, j; + struct usb_interface *ifp; + + usb_show_config_descriptor(&config->desc); + for (i = 0; i < config->desc.bNumInterfaces; i++) { + ifp = config->interface + i; + + if (!ifp) + break; + + printk("\n Interface: %d\n", i); + for (j = 0; j < ifp->num_altsetting; j++) + usb_show_interface(ifp->altsetting + j); + } +} + +void usb_show_device(struct usb_device *dev) +{ + int i; + + usb_show_device_descriptor(&dev->descriptor); + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) + usb_show_config(dev->config + i); +} + +/* + * Parse and show the different USB descriptors. + */ +void usb_show_device_descriptor(struct usb_device_descriptor *desc) +{ + if (!desc) + { + printk("Invalid USB device descriptor (NULL POINTER)\n"); + return; + } + printk(" Length = %2d%s\n", desc->bLength, + desc->bLength == USB_DT_DEVICE_SIZE ? "" : " (!!!)"); + printk(" DescriptorType = %02x\n", desc->bDescriptorType); + + printk(" USB version = %x.%02x\n", + desc->bcdUSB >> 8, desc->bcdUSB & 0xff); + printk(" Vendor:Product = %04x:%04x\n", + desc->idVendor, desc->idProduct); + printk(" MaxPacketSize0 = %d\n", desc->bMaxPacketSize0); + printk(" NumConfigurations = %d\n", desc->bNumConfigurations); + printk(" Device version = %x.%02x\n", + desc->bcdDevice >> 8, desc->bcdDevice & 0xff); + + printk(" Device Class:SubClass:Protocol = %02x:%02x:%02x\n", + desc->bDeviceClass, desc->bDeviceSubClass, desc->bDeviceProtocol); + switch (desc->bDeviceClass) { + case 0: + printk(" Per-interface classes\n"); + break; + case USB_CLASS_AUDIO: + printk(" Audio device class\n"); + break; + case USB_CLASS_COMM: + printk(" Communications class\n"); + break; + case USB_CLASS_HID: + printk(" Human Interface Devices class\n"); + break; + case USB_CLASS_PRINTER: + printk(" Printer device class\n"); + break; + case USB_CLASS_MASS_STORAGE: + printk(" Mass Storage device class\n"); + break; + case USB_CLASS_HUB: + printk(" Hub device class\n"); + break; + case USB_CLASS_VENDOR_SPEC: + printk(" Vendor class\n"); + break; + default: + printk(" Unknown class\n"); + } +} + +void usb_show_config_descriptor(struct usb_config_descriptor *desc) +{ + printk("Configuration:\n"); + printk(" bLength = %4d%s\n", desc->bLength, + desc->bLength == USB_DT_CONFIG_SIZE ? "" : " (!!!)"); + printk(" bDescriptorType = %02x\n", desc->bDescriptorType); + printk(" wTotalLength = %04x\n", desc->wTotalLength); + printk(" bNumInterfaces = %02x\n", desc->bNumInterfaces); + printk(" bConfigurationValue = %02x\n", desc->bConfigurationValue); + printk(" iConfiguration = %02x\n", desc->iConfiguration); + printk(" bmAttributes = %02x\n", desc->bmAttributes); + printk(" bMaxPower = %4dmA\n", desc->bMaxPower * 2); +} + +void usb_show_interface_descriptor(struct usb_interface_descriptor *desc) +{ + printk(" Alternate Setting: %2d\n", desc->bAlternateSetting); + printk(" bLength = %4d%s\n", desc->bLength, + desc->bLength == USB_DT_INTERFACE_SIZE ? "" : " (!!!)"); + printk(" bDescriptorType = %02x\n", desc->bDescriptorType); + printk(" bInterfaceNumber = %02x\n", desc->bInterfaceNumber); + printk(" bAlternateSetting = %02x\n", desc->bAlternateSetting); + printk(" bNumEndpoints = %02x\n", desc->bNumEndpoints); + printk(" bInterface Class:SubClass:Protocol = %02x:%02x:%02x\n", + desc->bInterfaceClass, desc->bInterfaceSubClass, desc->bInterfaceProtocol); + printk(" iInterface = %02x\n", desc->iInterface); +} + +void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *desc) +{ + char *LengthCommentString = (desc->bLength == + USB_DT_ENDPOINT_AUDIO_SIZE) ? " (Audio)" : (desc->bLength == + USB_DT_ENDPOINT_SIZE) ? "" : " (!!!)"; + char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" }; + + printk(" Endpoint:\n"); + printk(" bLength = %4d%s\n", + desc->bLength, LengthCommentString); + printk(" bDescriptorType = %02x\n", desc->bDescriptorType); + printk(" bEndpointAddress = %02x (%s)\n", desc->bEndpointAddress, + (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_CONTROL ? "i/o" : + (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? "in" : "out"); + printk(" bmAttributes = %02x (%s)\n", desc->bmAttributes, + EndpointType[USB_ENDPOINT_XFERTYPE_MASK & desc->bmAttributes]); + printk(" wMaxPacketSize = %04x\n", desc->wMaxPacketSize); + printk(" bInterval = %02x\n", desc->bInterval); + + /* Audio extensions to the endpoint descriptor */ + if (desc->bLength == USB_DT_ENDPOINT_AUDIO_SIZE) { + printk(" bRefresh = %02x\n", desc->bRefresh); + printk(" bSynchAddress = %02x\n", desc->bSynchAddress); + } +} + +void usb_show_string(struct usb_device *dev, char *id, int index) +{ + char *buf; + + if (!index) + return; + if (!(buf = kmalloc(256, GFP_KERNEL))) + return; + if (usb_string(dev, index, buf, 256) > 0) + dev_printk(KERN_INFO, &dev->dev, "%s: %s\n", id, buf); + kfree(buf); +} + +void usb_dump_urb (struct urb *urb) +{ + printk ("urb :%p\n", urb); + printk ("dev :%p\n", urb->dev); + printk ("pipe :%08X\n", urb->pipe); + printk ("status :%d\n", urb->status); + printk ("transfer_flags :%08X\n", urb->transfer_flags); + printk ("transfer_buffer :%p\n", urb->transfer_buffer); + printk ("transfer_buffer_length:%d\n", urb->transfer_buffer_length); + printk ("actual_length :%d\n", urb->actual_length); + printk ("setup_packet :%p\n", urb->setup_packet); + printk ("start_frame :%d\n", urb->start_frame); + printk ("number_of_packets :%d\n", urb->number_of_packets); + printk ("interval :%d\n", urb->interval); + printk ("error_count :%d\n", urb->error_count); + printk ("context :%p\n", urb->context); + printk ("complete :%p\n", urb->complete); +} + diff --git a/reactos/drivers/usb/cromwell/core/usb.c b/reactos/drivers/usb/cromwell/core/usb.c index a7726177e56..de3740e1ac1 100644 --- a/reactos/drivers/usb/cromwell/core/usb.c +++ b/reactos/drivers/usb/cromwell/core/usb.c @@ -1,1597 +1,1599 @@ -/* - * drivers/usb/usb.c - * - * (C) Copyright Linus Torvalds 1999 - * (C) Copyright Johannes Erdfelt 1999-2001 - * (C) Copyright Andreas Gal 1999 - * (C) Copyright Gregory P. Smith 1999 - * (C) Copyright Deti Fliegl 1999 (new USB architecture) - * (C) Copyright Randy Dunlap 2000 - * (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id, - more docs, etc) - * (C) Copyright Yggdrasil Computing, Inc. 2000 - * (usb_device_id matching changes by Adam J. Richter) - * (C) Copyright Greg Kroah-Hartman 2002-2003 - * - * NOTE! This is not actually a driver at all, rather this is - * just a collection of helper routines that implement the - * generic USB things that the real drivers can use.. - * - * Think of this as a "USB library" rather than anything else. - * It should be considered a slave, with no callbacks. Callbacks - * are evil. - */ - -#if 0 -#include - -#ifdef CONFIG_USB_DEBUG - #define DEBUG -#else - #undef DEBUG -#endif - -#include -#include -#include -#include -#include /* for in_interrupt() */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "hcd.h" -#include "usb.h" -#else -#include "../usb_wrapper.h" -#include "hcd.h" -#endif - - -extern int usb_hub_init(void); -extern void usb_hub_cleanup(void); -extern int usb_major_init(void); -extern void usb_major_cleanup(void); - - -int nousb; /* Disable USB when built into kernel image */ - /* Not honored on modular build */ - - -static int generic_probe (struct device *dev) -{ - return 0; -} -static int generic_remove (struct device *dev) -{ - return 0; -} - -static struct device_driver usb_generic_driver = { - .name = "usb", - .bus = &usb_bus_type, - .probe = generic_probe, - .remove = generic_remove, -}; - -static int usb_generic_driver_data; - -/* needs to be called with BKL held */ -int usb_device_probe(struct device *dev) -{ - struct usb_interface * intf = to_usb_interface(dev); - struct usb_driver * driver = to_usb_driver(dev->driver); - const struct usb_device_id *id; - int error = -ENODEV; - - dev_dbg(dev, "%s\n", __FUNCTION__); - - if (!driver->probe) - return error; - - id = usb_match_id (intf, driver->id_table); - if (id) { - dev_dbg (dev, "%s - got id\n", __FUNCTION__); - down (&driver->serialize); - error = driver->probe (intf, id); - up (&driver->serialize); - } - if (!error) - intf->driver = driver; - - return error; -} - -int usb_device_remove(struct device *dev) -{ - struct usb_interface *intf; - struct usb_driver *driver; - - intf = list_entry(dev,struct usb_interface,dev); - driver = to_usb_driver(dev->driver); - - down(&driver->serialize); - - if (intf->driver && intf->driver->disconnect) - intf->driver->disconnect(intf); - - /* if driver->disconnect didn't release the interface */ - if (intf->driver) - usb_driver_release_interface(driver, intf); - - up(&driver->serialize); - - return 0; -} - -/** - * usb_register - register a USB driver - * @new_driver: USB operations for the driver - * - * Registers a USB driver with the USB core. The list of unattached - * interfaces will be rescanned whenever a new driver is added, allowing - * the new driver to attach to any recognized devices. - * Returns a negative error code on failure and 0 on success. - * - * NOTE: if you want your driver to use the USB major number, you must call - * usb_register_dev() to enable that functionality. This function no longer - * takes care of that. - */ -int usb_register(struct usb_driver *new_driver) -{ - int retval = 0; - - if (nousb) - return -ENODEV; - - new_driver->driver.name = (char *)new_driver->name; - new_driver->driver.bus = &usb_bus_type; - new_driver->driver.probe = usb_device_probe; - new_driver->driver.remove = usb_device_remove; - - init_MUTEX(&new_driver->serialize); - - retval = driver_register(&new_driver->driver); - - if (!retval) { - info("registered new driver %s", new_driver->name); - usbfs_update_special(); - } else { - err("problem %d when registering driver %s", - retval, new_driver->name); - } - - return retval; -} - -/** - * usb_deregister - unregister a USB driver - * @driver: USB operations of the driver to unregister - * Context: !in_interrupt (), must be called with BKL held - * - * Unlinks the specified driver from the internal USB driver list. - * - * NOTE: If you called usb_register_dev(), you still need to call - * usb_deregister_dev() to clean up your driver's allocated minor numbers, - * this * call will no longer do it for you. - */ -void usb_deregister(struct usb_driver *driver) -{ - info("deregistering driver %s", driver->name); - - driver_unregister (&driver->driver); - - usbfs_update_special(); -} - -/** - * usb_ifnum_to_if - get the interface object with a given interface number (usbcore-internal) - * @dev: the device whose current configuration is considered - * @ifnum: the desired interface - * - * This walks the device descriptor for the currently active configuration - * and returns a pointer to the interface with that particular interface - * number, or null. - * - * Note that configuration descriptors are not required to assign interface - * numbers sequentially, so that it would be incorrect to assume that - * the first interface in that descriptor corresponds to interface zero. - * This routine helps device drivers avoid such mistakes. - * However, you should make sure that you do the right thing with any - * alternate settings available for this interfaces. - */ -struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) -{ - int i; - - for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) - if (dev->actconfig->interface[i].altsetting[0] - .desc.bInterfaceNumber == ifnum) - return &dev->actconfig->interface[i]; - - return NULL; -} - -/** - * usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number - * @dev: the device whose current configuration is considered - * @epnum: the desired endpoint - * - * This walks the device descriptor for the currently active configuration, - * and returns a pointer to the endpoint with that particular endpoint - * number, or null. - * - * Note that interface descriptors are not required to assign endpont - * numbers sequentially, so that it would be incorrect to assume that - * the first endpoint in that descriptor corresponds to interface zero. - * This routine helps device drivers avoid such mistakes. - */ -struct usb_endpoint_descriptor * -usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum) -{ - int i, j, k; - - for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) - for (j = 0; j < dev->actconfig->interface[i].num_altsetting; j++) - for (k = 0; k < dev->actconfig->interface[i] - .altsetting[j].desc.bNumEndpoints; k++) - if (epnum == dev->actconfig->interface[i] - .altsetting[j].endpoint[k] - .desc.bEndpointAddress) - return &dev->actconfig->interface[i] - .altsetting[j].endpoint[k] - .desc; - - return NULL; -} - -/** - * usb_driver_claim_interface - bind a driver to an interface - * @driver: the driver to be bound - * @iface: the interface to which it will be bound - * @priv: driver data associated with that interface - * - * This is used by usb device drivers that need to claim more than one - * interface on a device when probing (audio and acm are current examples). - * No device driver should directly modify internal usb_interface or - * usb_device structure members. - * - * Few drivers should need to use this routine, since the most natural - * way to bind to an interface is to return the private data from - * the driver's probe() method. Any driver that does use this must - * first be sure that no other driver has claimed the interface, by - * checking with usb_interface_claimed(). - */ -void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv) -{ - if (!iface || !driver) - return; - - // FIXME change API to report an error in this case - if (iface->driver) - err ("%s driver booted %s off interface %p", - driver->name, iface->driver->name, iface); - else - dbg("%s driver claimed interface %p", driver->name, iface); - - iface->driver = driver; - usb_set_intfdata(iface, priv); -} - -/** - * usb_interface_claimed - returns true iff an interface is claimed - * @iface: the interface being checked - * - * This should be used by drivers to check other interfaces to see if - * they are available or not. If another driver has claimed the interface, - * they may not claim it. Otherwise it's OK to claim it using - * usb_driver_claim_interface(). - * - * Returns true (nonzero) iff the interface is claimed, else false (zero). - */ -int usb_interface_claimed(struct usb_interface *iface) -{ - if (!iface) - return 0; - - return (iface->driver != NULL); -} /* usb_interface_claimed() */ - -/** - * usb_driver_release_interface - unbind a driver from an interface - * @driver: the driver to be unbound - * @iface: the interface from which it will be unbound - * - * This should be used by drivers to release their claimed interfaces. - * It is normally called in their disconnect() methods, and only for - * drivers that bound to more than one interface in their probe(). - * - * When the USB subsystem disconnect()s a driver from some interface, - * it automatically invokes this method for that interface. That - * means that even drivers that used usb_driver_claim_interface() - * usually won't need to call this. - */ -void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface) -{ - /* this should never happen, don't release something that's not ours */ - if (!iface || iface->driver != driver) - return; - - iface->driver = NULL; - usb_set_intfdata(iface, NULL); -} - -/** - * usb_match_id - find first usb_device_id matching device or interface - * @interface: the interface of interest - * @id: array of usb_device_id structures, terminated by zero entry - * - * usb_match_id searches an array of usb_device_id's and returns - * the first one matching the device or interface, or null. - * This is used when binding (or rebinding) a driver to an interface. - * Most USB device drivers will use this indirectly, through the usb core, - * but some layered driver frameworks use it directly. - * These device tables are exported with MODULE_DEVICE_TABLE, through - * modutils and "modules.usbmap", to support the driver loading - * functionality of USB hotplugging. - * - * What Matches: - * - * The "match_flags" element in a usb_device_id controls which - * members are used. If the corresponding bit is set, the - * value in the device_id must match its corresponding member - * in the device or interface descriptor, or else the device_id - * does not match. - * - * "driver_info" is normally used only by device drivers, - * but you can create a wildcard "matches anything" usb_device_id - * as a driver's "modules.usbmap" entry if you provide an id with - * only a nonzero "driver_info" field. If you do this, the USB device - * driver's probe() routine should use additional intelligence to - * decide whether to bind to the specified interface. - * - * What Makes Good usb_device_id Tables: - * - * The match algorithm is very simple, so that intelligence in - * driver selection must come from smart driver id records. - * Unless you have good reasons to use another selection policy, - * provide match elements only in related groups, and order match - * specifiers from specific to general. Use the macros provided - * for that purpose if you can. - * - * The most specific match specifiers use device descriptor - * data. These are commonly used with product-specific matches; - * the USB_DEVICE macro lets you provide vendor and product IDs, - * and you can also match against ranges of product revisions. - * These are widely used for devices with application or vendor - * specific bDeviceClass values. - * - * Matches based on device class/subclass/protocol specifications - * are slightly more general; use the USB_DEVICE_INFO macro, or - * its siblings. These are used with single-function devices - * where bDeviceClass doesn't specify that each interface has - * its own class. - * - * Matches based on interface class/subclass/protocol are the - * most general; they let drivers bind to any interface on a - * multiple-function device. Use the USB_INTERFACE_INFO - * macro, or its siblings, to match class-per-interface style - * devices (as recorded in bDeviceClass). - * - * Within those groups, remember that not all combinations are - * meaningful. For example, don't give a product version range - * without vendor and product IDs; or specify a protocol without - * its associated class and subclass. - */ -const struct usb_device_id * -usb_match_id(struct usb_interface *interface, const struct usb_device_id *id) -{ - struct usb_host_interface *intf; - struct usb_device *dev; - - /* proc_connectinfo in devio.c may call us with id == NULL. */ - if (id == NULL) - return NULL; - - intf = &interface->altsetting [interface->act_altsetting]; - dev = interface_to_usbdev(interface); - - /* It is important to check that id->driver_info is nonzero, - since an entry that is all zeroes except for a nonzero - id->driver_info is the way to create an entry that - indicates that the driver want to examine every - device and interface. */ - for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass || - id->driver_info; id++) { - - if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && - id->idVendor != dev->descriptor.idVendor) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && - id->idProduct != dev->descriptor.idProduct) - continue; - - /* No need to test id->bcdDevice_lo != 0, since 0 is never - greater than any unsigned number. */ - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) && - (id->bcdDevice_lo > dev->descriptor.bcdDevice)) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) && - (id->bcdDevice_hi < dev->descriptor.bcdDevice)) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) && - (id->bDeviceClass != dev->descriptor.bDeviceClass)) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && - (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass)) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && - (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) && - (id->bInterfaceClass != intf->desc.bInterfaceClass)) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) && - (id->bInterfaceSubClass != intf->desc.bInterfaceSubClass)) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) && - (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol)) - continue; - - return id; - } - - return NULL; -} - -/** - * usb_find_interface - find usb_interface pointer for driver and device - * @drv: the driver whose current configuration is considered - * @minor: the minor number of the desired device - * - * This walks the driver device list and returns a pointer to the interface - * with the matching minor. Note, this only works for devices that share the - * USB major number. - */ -struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) -{ - struct list_head *entry; - struct device *dev; - struct usb_interface *intf; - - list_for_each(entry, &drv->driver.devices) { - dev = container_of(entry, struct device, driver_list); - - /* can't look at usb devices, only interfaces */ - if (dev->driver == &usb_generic_driver) - continue; - - intf = to_usb_interface(dev); - if (intf->minor == -1) - continue; - if (intf->minor == minor) - return intf; - } - - /* no device found that matches */ - return NULL; -} - -static int usb_device_match (struct device *dev, struct device_driver *drv) -{ - struct usb_interface *intf; - struct usb_driver *usb_drv; - const struct usb_device_id *id; - - /* check for generic driver, which we don't match any device with */ - if (drv == &usb_generic_driver) - return 0; - - intf = to_usb_interface(dev); - - usb_drv = to_usb_driver(drv); - id = usb_drv->id_table; - - id = usb_match_id (intf, usb_drv->id_table); - if (id) - return 1; - - return 0; -} - - -#ifdef CONFIG_HOTPLUG - -/* - * USB hotplugging invokes what /proc/sys/kernel/hotplug says - * (normally /sbin/hotplug) when USB devices get added or removed. - * - * This invokes a user mode policy agent, typically helping to load driver - * or other modules, configure the device, and more. Drivers can provide - * a MODULE_DEVICE_TABLE to help with module loading subtasks. - * - * We're called either from khubd (the typical case) or from root hub - * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle - * delays in event delivery. Use sysfs (and DEVPATH) to make sure the - * device (and this configuration!) are still present. - */ -static int usb_hotplug (struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) -{ - struct usb_interface *intf; - struct usb_device *usb_dev; - char *scratch; - int i = 0; - int length = 0; - - dbg ("%s", __FUNCTION__); - - if (!dev) - return -ENODEV; - - /* Must check driver_data here, as on remove driver is always NULL */ - if ((dev->driver == &usb_generic_driver) || - (dev->driver_data == &usb_generic_driver_data)) - return 0; - - intf = to_usb_interface(dev); - usb_dev = interface_to_usbdev (intf); - - if (usb_dev->devnum < 0) { - dbg ("device already deleted ??"); - return -ENODEV; - } - if (!usb_dev->bus) { - dbg ("bus already removed?"); - return -ENODEV; - } - - scratch = buffer; - -#ifdef CONFIG_USB_DEVICEFS - /* If this is available, userspace programs can directly read - * all the device descriptors we don't tell them about. Or - * even act as usermode drivers. - * - * FIXME reduce hardwired intelligence here - */ - envp [i++] = scratch; - length += snprintf (scratch, buffer_size - length, - "DEVICE=/proc/bus/usb/%03d/%03d", - usb_dev->bus->busnum, usb_dev->devnum); - if ((buffer_size - length <= 0) || (i >= num_envp)) - return -ENOMEM; - ++length; - scratch += length; -#endif - - /* per-device configurations are common */ - envp [i++] = scratch; - length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x", - usb_dev->descriptor.idVendor, - usb_dev->descriptor.idProduct, - usb_dev->descriptor.bcdDevice); - if ((buffer_size - length <= 0) || (i >= num_envp)) - return -ENOMEM; - ++length; - scratch += length; - - /* class-based driver binding models */ - envp [i++] = scratch; - length += snprintf (scratch, buffer_size - length, "TYPE=%d/%d/%d", - usb_dev->descriptor.bDeviceClass, - usb_dev->descriptor.bDeviceSubClass, - usb_dev->descriptor.bDeviceProtocol); - if ((buffer_size - length <= 0) || (i >= num_envp)) - return -ENOMEM; - ++length; - scratch += length; - - if (usb_dev->descriptor.bDeviceClass == 0) { - int alt = intf->act_altsetting; - - /* 2.4 only exposed interface zero. in 2.5, hotplug - * agents are called for all interfaces, and can use - * $DEVPATH/bInterfaceNumber if necessary. - */ - envp [i++] = scratch; - length += snprintf (scratch, buffer_size - length, - "INTERFACE=%d/%d/%d", - intf->altsetting[alt].desc.bInterfaceClass, - intf->altsetting[alt].desc.bInterfaceSubClass, - intf->altsetting[alt].desc.bInterfaceProtocol); - if ((buffer_size - length <= 0) || (i >= num_envp)) - return -ENOMEM; - ++length; - scratch += length; - - } - envp [i++] = 0; - - return 0; -} - -#else - -static int usb_hotplug (struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) -{ - return -ENODEV; -} - -#endif /* CONFIG_HOTPLUG */ - -/** - * usb_alloc_dev - allocate a usb device structure (usbcore-internal) - * @parent: hub to which device is connected - * @bus: bus used to access the device - * Context: !in_interrupt () - * - * Only hub drivers (including virtual root hub drivers for host - * controllers) should ever call this. - * - * This call is synchronous, and may not be used in an interrupt context. - */ -struct usb_device STDCALL *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus) -{ - struct usb_device *dev; - - dev = kmalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; - - memset(dev, 0, sizeof(*dev)); - - device_initialize(&dev->dev); - dev->state = USB_STATE_ATTACHED; - - usb_bus_get(bus); - - if (!parent) - dev->devpath [0] = '0'; - dev->bus = bus; - dev->parent = parent; - INIT_LIST_HEAD(&dev->filelist); - - init_MUTEX(&dev->serialize); - - if (dev->bus->op->allocate) - dev->bus->op->allocate(dev); - - return dev; -} - -/** - * usb_get_dev - increments the reference count of the usb device structure - * @dev: the device being referenced - * - * Each live reference to a device should be refcounted. - * - * Drivers for USB interfaces should normally record such references in - * their probe() methods, when they bind to an interface, and release - * them by calling usb_put_dev(), in their disconnect() methods. - * - * A pointer to the device with the incremented reference counter is returned. - */ -struct usb_device STDCALL *usb_get_dev (struct usb_device *dev) -{ - struct device *tmp; - - if (!dev) - return NULL; - - tmp = get_device(&dev->dev); - if (tmp) - return to_usb_device(tmp); - else - return NULL; -} - -/** - * usb_put_dev - release a use of the usb device structure - * @dev: device that's been disconnected - * - * Must be called when a user of a device is finished with it. When the last - * user of the device calls this function, the memory of the device is freed. - */ -void STDCALL usb_put_dev(struct usb_device *dev) -{ - if (dev) - put_device(&dev->dev); -} - -/** - * usb_release_dev - free a usb device structure when all users of it are finished. - * @dev: device that's been disconnected - * - * Will be called only by the device core when all users of this usb device are - * done. - */ -static void usb_release_dev(struct device *dev) -{ - struct usb_device *udev; - - udev = to_usb_device(dev); - - if (udev->bus && udev->bus->op && udev->bus->op->deallocate) - udev->bus->op->deallocate(udev); - usb_destroy_configuration (udev); - usb_bus_put (udev->bus); - kfree (udev); -} - - -static struct usb_device *match_device(struct usb_device *dev, - u16 vendor_id, u16 product_id) -{ - struct usb_device *ret_dev = NULL; - int child; - - dbg("looking at vendor %d, product %d", - dev->descriptor.idVendor, - dev->descriptor.idProduct); - - /* see if this device matches */ - if ((dev->descriptor.idVendor == vendor_id) && - (dev->descriptor.idProduct == product_id)) { - dbg ("found the device!"); - ret_dev = usb_get_dev(dev); - goto exit; - } - - /* look through all of the children of this device */ - for (child = 0; child < dev->maxchild; ++child) { - if (dev->children[child]) { - ret_dev = match_device(dev->children[child], - vendor_id, product_id); - if (ret_dev) - goto exit; - } - } -exit: - return ret_dev; -} - -/** - * usb_find_device - find a specific usb device in the system - * @vendor_id: the vendor id of the device to find - * @product_id: the product id of the device to find - * - * Returns a pointer to a struct usb_device if such a specified usb - * device is present in the system currently. The usage count of the - * device will be incremented if a device is found. Make sure to call - * usb_put_dev() when the caller is finished with the device. - * - * If a device with the specified vendor and product id is not found, - * NULL is returned. - */ -struct usb_device *usb_find_device(u16 vendor_id, u16 product_id) -{ - struct list_head *buslist; - struct usb_bus *bus; - struct usb_device *dev = NULL; - - down(&usb_bus_list_lock); - for (buslist = usb_bus_list.next; - buslist != &usb_bus_list; - buslist = buslist->next) { - bus = container_of(buslist, struct usb_bus, bus_list); - dev = match_device(bus->root_hub, vendor_id, product_id); - if (dev) - goto exit; - } -exit: - up(&usb_bus_list_lock); - return dev; -} - -/** - * usb_get_current_frame_number - return current bus frame number - * @dev: the device whose bus is being queried - * - * Returns the current frame number for the USB host controller - * used with the given USB device. This can be used when scheduling - * isochronous requests. - * - * Note that different kinds of host controller have different - * "scheduling horizons". While one type might support scheduling only - * 32 frames into the future, others could support scheduling up to - * 1024 frames into the future. - */ -int usb_get_current_frame_number(struct usb_device *dev) -{ - return dev->bus->op->get_frame_number (dev); -} - -/*-------------------------------------------------------------------*/ -/* - * __usb_get_extra_descriptor() finds a descriptor of specific type in the - * extra field of the interface and endpoint descriptor structs. - */ - -int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr) -{ - struct usb_descriptor_header *header; - - while (size >= sizeof(struct usb_descriptor_header)) { - header = (struct usb_descriptor_header *)buffer; - - if (header->bLength < 2) { - err("invalid descriptor length of %d", header->bLength); - return -1; - } - - if (header->bDescriptorType == type) { - *ptr = header; - return 0; - } - - buffer += header->bLength; - size -= header->bLength; - } - return -1; -} - -/** - * usb_disconnect - disconnect a device (usbcore-internal) - * @pdev: pointer to device being disconnected - * Context: !in_interrupt () - * - * Something got disconnected. Get rid of it, and all of its children. - * - * Only hub drivers (including virtual root hub drivers for host - * controllers) should ever call this. - * - * This call is synchronous, and may not be used in an interrupt context. - */ -void usb_disconnect(struct usb_device **pdev) -{ - struct usb_device *dev = *pdev; - struct usb_bus *bus; - struct usb_operations *ops; - int i; - - might_sleep (); - - if (!dev) { - pr_debug ("%s nodev\n", __FUNCTION__); - return; - } - bus = dev->bus; - if (!bus) { - pr_debug ("%s nobus\n", __FUNCTION__); - return; - } - ops = bus->op; - - *pdev = NULL; - - /* mark the device as inactive, so any further urb submissions for - * this device will fail. - */ - dev->state = USB_STATE_NOTATTACHED; - - dev_info (&dev->dev, "USB disconnect, address %d\n", dev->devnum); - - /* Free up all the children before we remove this device */ - for (i = 0; i < USB_MAXCHILDREN; i++) { - struct usb_device **child = dev->children + i; - if (*child) - usb_disconnect(child); - } - - /* disconnect() drivers from interfaces (a key side effect) */ - dev_dbg (&dev->dev, "unregistering interfaces\n"); - if (dev->actconfig) { - for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *interface; - - /* remove this interface */ - interface = &dev->actconfig->interface[i]; - device_unregister(&interface->dev); - } - } - - /* deallocate hcd/hardware state */ - if (ops->disable) { - void (*disable)(struct usb_device *, int) = ops->disable; - - for (i = 0; i < 15; i++) { - disable (dev, i); - disable (dev, USB_DIR_IN | i); - } - } - - dev_dbg (&dev->dev, "unregistering device\n"); - /* Free the device number and remove the /proc/bus/usb entry */ - if (dev->devnum > 0) { - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - usbfs_remove_device(dev); - } - device_unregister(&dev->dev); - - /* Decrement the reference count, it'll auto free everything when */ - /* it hits 0 which could very well be now */ - usb_put_dev(dev); -} - -/** - * usb_connect - pick device address (usbcore-internal) - * @dev: newly detected device (in DEFAULT state) - * - * Picks a device address. It's up to the hub (or root hub) driver - * to handle and manage enumeration, starting from the DEFAULT state. - * Only hub drivers (including virtual root hub drivers for host - * controllers) should ever call this. - */ -void STDCALL usb_connect(struct usb_device *dev) -{ - int devnum; - // FIXME needs locking for SMP!! - /* why? this is called only from the hub thread, - * which hopefully doesn't run on multiple CPU's simultaneously 8-) - * ... it's also called from modprobe/rmmod/apmd threads as part - * of virtual root hub init/reinit. In the init case, the hub code - * won't have seen this, but not so for reinit ... - */ - dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */ - - /* Try to allocate the next devnum beginning at bus->devnum_next. */ - devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next); - if (devnum >= 128) - devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1); - - dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); - - if (devnum < 128) { - set_bit(devnum, dev->bus->devmap.devicemap); - dev->devnum = devnum; - } -} - - -// hub-only!! ... and only exported for reset/reinit path. -// otherwise used internally, for usb_new_device() -int usb_set_address(struct usb_device *dev) -{ - int retval; - - if (dev->devnum == 0) - return -EINVAL; - if (dev->state != USB_STATE_DEFAULT && dev->state != USB_STATE_ADDRESS) - return -EINVAL; - retval = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS, - 0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); - if (retval == 0) - dev->state = USB_STATE_ADDRESS; - return retval; -} - - -/* improve on the default device description, if we can ... and - * while we're at it, maybe show the vendor and product strings. - */ -static void set_device_description (struct usb_device *dev) -{ - void *buf; - int mfgr = dev->descriptor.iManufacturer; - int prod = dev->descriptor.iProduct; - int vendor_id = dev->descriptor.idVendor; - int product_id = dev->descriptor.idProduct; - char *mfgr_str, *prod_str; - - /* set default; keep it if there are no strings, or kmalloc fails */ - sprintf (dev->dev.name, "USB device %04x:%04x", - vendor_id, product_id); - - if (!(buf = kmalloc(256 * 2, GFP_KERNEL))) - return; - - prod_str = (char *) buf; - mfgr_str = (char *) buf + 256; - - if (prod && usb_string (dev, prod, prod_str, 256) > 0) { -#ifdef DEBUG - dev_printk (KERN_INFO, &dev->dev, "Product: %s\n", prod_str); -#endif - } else { - prod_str = 0; - } - - if (mfgr && usb_string (dev, mfgr, mfgr_str, 256) > 0) { -#ifdef DEBUG - dev_printk (KERN_INFO, &dev->dev, "Manufacturer: %s\n", mfgr_str); -#endif - } else { - mfgr_str = 0; - } - - /* much like pci ... describe as either: - * - both strings: 'product descr (vendor descr)' - * - product only: 'product descr (USB device vvvv:pppp)' - * - vendor only: 'USB device vvvv:pppp (vendor descr)' - * - neither string: 'USB device vvvv:pppp' - */ - - if (prod_str && mfgr_str) { - - snprintf(dev->dev.name, sizeof dev->dev.name, - "%s (%s)", prod_str, mfgr_str); - } else if (prod_str) { - snprintf(dev->dev.name, sizeof dev->dev.name, - "%s (USB device %04x:%04x)", - prod_str, vendor_id, product_id); - - } else if (mfgr_str) { - snprintf(dev->dev.name, sizeof dev->dev.name, - "USB device %04x:%04x (%s)", - vendor_id, product_id, mfgr_str); - } - usbprintk("USB connected: %s\n",dev->dev.name); - kfree(buf); -} - -/* - * By the time we get here, we chose a new device address - * and is in the default state. We need to identify the thing and - * get the ball rolling.. - * - * Returns 0 for success, != 0 for error. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Only hub drivers (including virtual root hub drivers for host - * controllers) should ever call this. - */ -#define NEW_DEVICE_RETRYS 2 -#define SET_ADDRESS_RETRYS 2 -int usb_new_device(struct usb_device *dev, struct device *parent) -{ - int err = 0; - int i; - int j; - - /* - * Set the driver for the usb device to point to the "generic" driver. - * This prevents the main usb device from being sent to the usb bus - * probe function. Yes, it's a hack, but a nice one :) - * - * Do it asap, so more driver model stuff (like the device.h message - * utilities) can be used in hcd submit/unlink code paths. - */ - usb_generic_driver.bus = &usb_bus_type; - dev->dev.parent = parent; - dev->dev.driver = &usb_generic_driver; - dev->dev.bus = &usb_bus_type; - dev->dev.release = usb_release_dev; - dev->dev.driver_data = &usb_generic_driver_data; - usb_get_dev(dev); - if (dev->dev.bus_id[0] == 0) - sprintf (&dev->dev.bus_id[0], "%d-%s", - dev->bus->busnum, dev->devpath); - - /* dma masks come from the controller; readonly, except to hcd */ - dev->dev.dma_mask = parent->dma_mask; - - /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... - * it's fixed size except for full speed devices. - */ - switch (dev->speed) { - case USB_SPEED_HIGH: /* fixed at 64 */ - i = 64; - break; - case USB_SPEED_FULL: /* 8, 16, 32, or 64 */ - /* to determine the ep0 maxpacket size, read the first 8 - * bytes from the device descriptor to get bMaxPacketSize0; - * then correct our initial (small) guess. - */ - // FALLTHROUGH - case USB_SPEED_LOW: /* fixed at 8 */ - i = 8; - break; - default: - return -EINVAL; - } - dev->epmaxpacketin [0] = i; - dev->epmaxpacketout[0] = i; - - for (i = 0; i < NEW_DEVICE_RETRYS; ++i) { - - for (j = 0; j < SET_ADDRESS_RETRYS; ++j) { - err = usb_set_address(dev); - if (err >= 0) - break; - wait_ms(200); - } - if (err < 0) { - dev_err(&dev->dev, "USB device not accepting new address=%d (error=%d)\n", - dev->devnum, err); - dev->state = USB_STATE_DEFAULT; - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - dev->devnum = -1; - return 1; - } - - wait_ms(10); /* Let the SET_ADDRESS settle */ - - /* high and low speed devices don't need this... */ - err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8); - if (err >= 8) - break; - wait_ms(100); - } - - if (err < 8) { - if (err < 0) - dev_err(&dev->dev, "USB device not responding, giving up (error=%d)\n", err); - else - dev_err(&dev->dev, "USB device descriptor short read (expected %i, got %i)\n", 8, err); - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - dev->devnum = -1; - return 1; - } - if (dev->speed == USB_SPEED_FULL) { - dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0; - dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; - } - - /* USB device state == addressed ... still not usable */ - - err = usb_get_device_descriptor(dev); - if (err < (signed)sizeof(dev->descriptor)) { - if (err < 0) - dev_err(&dev->dev, "unable to get device descriptor (error=%d)\n", err); - else - dev_err(&dev->dev, "USB device descriptor short read (expected %Zi, got %i)\n", - sizeof(dev->descriptor), err); - - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - dev->devnum = -1; - return 1; - } - - err = usb_get_configuration(dev); - if (err < 0) { - dev_err(&dev->dev, "unable to get device %d configuration (error=%d)\n", - dev->devnum, err); - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - dev->devnum = -1; - return 1; - } - - /* we set the default configuration here */ - err = usb_set_configuration(dev, dev->config[0].desc.bConfigurationValue); - if (err) { - dev_err(&dev->dev, "failed to set device %d default configuration (error=%d)\n", - dev->devnum, err); - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - dev->devnum = -1; - return 1; - } - - /* USB device state == configured ... tell the world! */ - - dev_dbg(&dev->dev, "new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n", - dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber); - set_device_description (dev); - -#ifdef DEBUG - if (dev->descriptor.iSerialNumber) - usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); -#endif - /* put into sysfs, with device and config specific files */ - err = device_add (&dev->dev); - if (err) - return err; - usb_create_driverfs_dev_files (dev); - - /* Register all of the interfaces for this device with the driver core. - * Remember, interfaces get bound to drivers, not devices. */ - for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *interface = &dev->actconfig->interface[i]; - struct usb_interface_descriptor *desc; - - desc = &interface->altsetting [interface->act_altsetting].desc; - interface->dev.parent = &dev->dev; - interface->dev.driver = NULL; - interface->dev.bus = &usb_bus_type; - interface->dev.dma_mask = parent->dma_mask; - sprintf (&interface->dev.bus_id[0], "%d-%s:%d", - dev->bus->busnum, dev->devpath, - desc->bInterfaceNumber); - if (!desc->iInterface - || usb_string (dev, desc->iInterface, - interface->dev.name, - sizeof interface->dev.name) <= 0) { - /* typically devices won't bother with interface - * descriptions; this is the normal case. an - * interface's driver might describe it better. - * (also: iInterface is per-altsetting ...) - */ - sprintf (&interface->dev.name[0], - "usb-%s-%s interface %d", - dev->bus->bus_name, dev->devpath, - desc->bInterfaceNumber); - DPRINT1("usb_new_device: %s\n", interface->dev.name); - } - dev_dbg (&dev->dev, "%s - registering interface %s\n", __FUNCTION__, interface->dev.bus_id); - device_add (&interface->dev); - usb_create_driverfs_intf_files (interface); - } - /* add a /proc/bus/usb entry */ - usbfs_add_device(dev); - - return 0; -} - -/** - * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_DMA_MAP - * @dev: device the buffer will be used with - * @size: requested buffer size - * @mem_flags: affect whether allocation may block - * @dma: used to return DMA address of buffer - * - * Return value is either null (indicating no buffer could be allocated), or - * the cpu-space pointer to a buffer that may be used to perform DMA to the - * specified device. Such cpu-space buffers are returned along with the DMA - * address (through the pointer provided). - * - * These buffers are used with URB_NO_DMA_MAP set in urb->transfer_flags to - * avoid behaviors like using "DMA bounce buffers", or tying down I/O mapping - * hardware for long idle periods. The implementation varies between - * platforms, depending on details of how DMA will work to this device. - * Using these buffers also helps prevent cacheline sharing problems on - * architectures where CPU caches are not DMA-coherent. - * - * When the buffer is no longer used, free it with usb_buffer_free(). - */ -void *usb_buffer_alloc ( - struct usb_device *dev, - size_t size, - int mem_flags, - dma_addr_t *dma -) -{ - if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc) - return 0; - return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma); -} - -/** - * usb_buffer_free - free memory allocated with usb_buffer_alloc() - * @dev: device the buffer was used with - * @size: requested buffer size - * @addr: CPU address of buffer - * @dma: DMA address of buffer - * - * This reclaims an I/O buffer, letting it be reused. The memory must have - * been allocated using usb_buffer_alloc(), and the parameters must match - * those provided in that allocation request. - */ -void usb_buffer_free ( - struct usb_device *dev, - size_t size, - void *addr, - dma_addr_t dma -) -{ - if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_free) - return; - dev->bus->op->buffer_free (dev->bus, size, addr, dma); -} - -/** - * usb_buffer_map - create DMA mapping(s) for an urb - * @urb: urb whose transfer_buffer will be mapped - * - * Return value is either null (indicating no buffer could be mapped), or - * the parameter. URB_NO_DMA_MAP is added to urb->transfer_flags if the - * operation succeeds. If the device is connected to this system through - * a non-DMA controller, this operation always succeeds. - * - * This call would normally be used for an urb which is reused, perhaps - * as the target of a large periodic transfer, with usb_buffer_dmasync() - * calls to synchronize memory and dma state. It may not be used for - * control requests. - * - * Reverse the effect of this call with usb_buffer_unmap(). - */ -struct urb *usb_buffer_map (struct urb *urb) -{ - struct usb_bus *bus; - struct device *controller; - - if (!urb - || usb_pipecontrol (urb->pipe) - || !urb->dev - || !(bus = urb->dev->bus) - || !(controller = bus->controller)) - return 0; - - if (controller->dma_mask) { - urb->transfer_dma = dma_map_single (controller, - urb->transfer_buffer, urb->transfer_buffer_length, - usb_pipein (urb->pipe) - ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - // FIXME generic api broken like pci, can't report errors - // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; - } else - urb->transfer_dma = ~0; - urb->transfer_flags |= URB_NO_DMA_MAP; - return urb; -} - -/** - * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s) - * @urb: urb whose transfer_buffer will be synchronized - */ -void usb_buffer_dmasync (struct urb *urb) -{ - struct usb_bus *bus; - struct device *controller; - - if (!urb - || !(urb->transfer_flags & URB_NO_DMA_MAP) - || !urb->dev - || !(bus = urb->dev->bus) - || !(controller = bus->controller)) - return; - - if (controller->dma_mask) - dma_sync_single (controller, - urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein (urb->pipe) - ? DMA_FROM_DEVICE : DMA_TO_DEVICE); -} - -/** - * usb_buffer_unmap - free DMA mapping(s) for an urb - * @urb: urb whose transfer_buffer will be unmapped - * - * Reverses the effect of usb_buffer_map(). - */ -void usb_buffer_unmap (struct urb *urb) -{ - struct usb_bus *bus; - struct device *controller; - - if (!urb - || !(urb->transfer_flags & URB_NO_DMA_MAP) - || !urb->dev - || !(bus = urb->dev->bus) - || !(controller = bus->controller)) - return; - - if (controller->dma_mask) - dma_unmap_single (controller, - urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein (urb->pipe) - ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - urb->transfer_flags &= ~URB_NO_DMA_MAP; -} - -/** - * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint - * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction - * @sg: the scatterlist to map - * @nents: the number of entries in the scatterlist - * - * Return value is either < 0 (indicating no buffers could be mapped), or - * the number of DMA mapping array entries in the scatterlist. - * - * The caller is responsible for placing the resulting DMA addresses from - * the scatterlist into URB transfer buffer pointers, and for setting the - * URB_NO_DMA_MAP transfer flag in each of those URBs. - * - * Top I/O rates come from queuing URBs, instead of waiting for each one - * to complete before starting the next I/O. This is particularly easy - * to do with scatterlists. Just allocate and submit one URB for each DMA - * mapping entry returned, stopping on the first error or when all succeed. - * Better yet, use the usb_sg_*() calls, which do that (and more) for you. - * - * This call would normally be used when translating scatterlist requests, - * rather than usb_buffer_map(), since on some hardware (with IOMMUs) it - * may be able to coalesce mappings for improved I/O efficiency. - * - * Reverse the effect of this call with usb_buffer_unmap_sg(). - */ -int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int nents) -{ - struct usb_bus *bus; - struct device *controller; - - if (!dev - || usb_pipecontrol (pipe) - || !(bus = dev->bus) - || !(controller = bus->controller) - || !controller->dma_mask) - return -1; - - // FIXME generic api broken like pci, can't report errors - return dma_map_sg (controller, sg, nents, - usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); -} - -/** - * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s) - * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction - * @sg: the scatterlist to synchronize - * @n_hw_ents: the positive return value from usb_buffer_map_sg - * - * Use this when you are re-using a scatterlist's data buffers for - * another USB request. - */ -void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int n_hw_ents) -{ - struct usb_bus *bus; - struct device *controller; - - if (!dev - || !(bus = dev->bus) - || !(controller = bus->controller) - || !controller->dma_mask) - return; - - dma_sync_sg (controller, sg, n_hw_ents, - usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); -} - -/** - * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist - * @dev: device to which the scatterlist will be mapped - * @pipe: endpoint defining the mapping direction - * @sg: the scatterlist to unmap - * @n_hw_ents: the positive return value from usb_buffer_map_sg - * - * Reverses the effect of usb_buffer_map_sg(). - */ -void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int n_hw_ents) -{ - struct usb_bus *bus; - struct device *controller; - - if (!dev - || !(bus = dev->bus) - || !(controller = bus->controller) - || !controller->dma_mask) - return; - - dma_unmap_sg (controller, sg, n_hw_ents, - usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); -} - - -struct bus_type usb_bus_type = { - .name = "usb", - .match = usb_device_match, - .hotplug = usb_hotplug, -}; - -#ifndef MODULE - -static int __init usb_setup_disable(char *str) -{ - nousb = 1; - return 1; -} - -/* format to disable USB on kernel command line is: nousb */ -__setup("nousb", usb_setup_disable); - -#endif - -/* - * for external read access to - */ -int STDCALL usb_disabled(void) -{ - return nousb; -} - -/* - * Init - */ -int STDCALL __init usb_init(void) -{ - if (nousb) { - info("USB support disabled\n"); - return 0; - } - - bus_register(&usb_bus_type); - usb_major_init(); - usbfs_init(); - usb_hub_init(); - - driver_register(&usb_generic_driver); - - return 0; -} - -/* - * Cleanup - */ -void STDCALL __exit usb_exit(void) -{ - /* This will matter if shutdown/reboot does exitcalls. */ - if (nousb) - return; - - driver_unregister(&usb_generic_driver); - usb_major_cleanup(); - usbfs_cleanup(); - usb_hub_cleanup(); - bus_unregister(&usb_bus_type); -} - -subsys_initcall(usb_init); -module_exit(usb_exit); - -/* - * USB may be built into the kernel or be built as modules. - * These symbols are exported for device (or host controller) - * driver modules to use. - */ -EXPORT_SYMBOL(usb_epnum_to_ep_desc); - -EXPORT_SYMBOL(usb_register); -EXPORT_SYMBOL(usb_deregister); -EXPORT_SYMBOL(usb_disabled); - -EXPORT_SYMBOL(usb_device_probe); -EXPORT_SYMBOL(usb_device_remove); - -EXPORT_SYMBOL(usb_alloc_dev); -EXPORT_SYMBOL(usb_put_dev); -EXPORT_SYMBOL(usb_get_dev); -EXPORT_SYMBOL(usb_hub_tt_clear_buffer); - -EXPORT_SYMBOL(usb_driver_claim_interface); -EXPORT_SYMBOL(usb_interface_claimed); -EXPORT_SYMBOL(usb_driver_release_interface); -EXPORT_SYMBOL(usb_match_id); -EXPORT_SYMBOL(usb_find_interface); -EXPORT_SYMBOL(usb_ifnum_to_if); - -EXPORT_SYMBOL(usb_new_device); -EXPORT_SYMBOL(usb_reset_device); -EXPORT_SYMBOL(usb_connect); -EXPORT_SYMBOL(usb_disconnect); - -EXPORT_SYMBOL(__usb_get_extra_descriptor); - -EXPORT_SYMBOL(usb_find_device); -EXPORT_SYMBOL(usb_get_current_frame_number); - -EXPORT_SYMBOL (usb_buffer_alloc); -EXPORT_SYMBOL (usb_buffer_free); - -EXPORT_SYMBOL (usb_buffer_map); -EXPORT_SYMBOL (usb_buffer_dmasync); -EXPORT_SYMBOL (usb_buffer_unmap); - -EXPORT_SYMBOL (usb_buffer_map_sg); -EXPORT_SYMBOL (usb_buffer_dmasync_sg); -EXPORT_SYMBOL (usb_buffer_unmap_sg); - -MODULE_LICENSE("GPL"); +/* + * drivers/usb/usb.c + * + * (C) Copyright Linus Torvalds 1999 + * (C) Copyright Johannes Erdfelt 1999-2001 + * (C) Copyright Andreas Gal 1999 + * (C) Copyright Gregory P. Smith 1999 + * (C) Copyright Deti Fliegl 1999 (new USB architecture) + * (C) Copyright Randy Dunlap 2000 + * (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id, + more docs, etc) + * (C) Copyright Yggdrasil Computing, Inc. 2000 + * (usb_device_id matching changes by Adam J. Richter) + * (C) Copyright Greg Kroah-Hartman 2002-2003 + * + * NOTE! This is not actually a driver at all, rather this is + * just a collection of helper routines that implement the + * generic USB things that the real drivers can use.. + * + * Think of this as a "USB library" rather than anything else. + * It should be considered a slave, with no callbacks. Callbacks + * are evil. + */ + +#if 0 +#include + +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif + +#include +#include +#include +#include +#include /* for in_interrupt() */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "hcd.h" +#include "usb.h" +#else +#include "../usb_wrapper.h" +#include "hcd.h" +#endif + + +extern int usb_hub_init(void); +extern void usb_hub_cleanup(void); +extern int usb_major_init(void); +extern void usb_major_cleanup(void); + + +int nousb; /* Disable USB when built into kernel image */ + /* Not honored on modular build */ + + +static int generic_probe (struct device *dev) +{ + return 0; +} +static int generic_remove (struct device *dev) +{ + return 0; +} + +static struct device_driver usb_generic_driver = { + .name = "usb", + .bus = &usb_bus_type, + .probe = generic_probe, + .remove = generic_remove, +}; + +static int usb_generic_driver_data; + +/* needs to be called with BKL held */ +int usb_device_probe(struct device *dev) +{ + struct usb_interface * intf = to_usb_interface(dev); + struct usb_driver * driver = to_usb_driver(dev->driver); + const struct usb_device_id *id; + int error = -ENODEV; + + dev_dbg(dev, "%s\n", __FUNCTION__); + + if (!driver->probe) + return error; + + id = usb_match_id (intf, driver->id_table); + if (id) { + dev_dbg (dev, "%s - got id\n", __FUNCTION__); + down (&driver->serialize); + error = driver->probe (intf, id); + up (&driver->serialize); + } + if (!error) + intf->driver = driver; + + return error; +} + +int usb_device_remove(struct device *dev) +{ + struct usb_interface *intf; + struct usb_driver *driver; + + intf = list_entry(dev,struct usb_interface,dev); + driver = to_usb_driver(dev->driver); + + down(&driver->serialize); + + if (intf->driver && intf->driver->disconnect) + intf->driver->disconnect(intf); + + /* if driver->disconnect didn't release the interface */ + if (intf->driver) + usb_driver_release_interface(driver, intf); + + up(&driver->serialize); + + return 0; +} + +/** + * usb_register - register a USB driver + * @new_driver: USB operations for the driver + * + * Registers a USB driver with the USB core. The list of unattached + * interfaces will be rescanned whenever a new driver is added, allowing + * the new driver to attach to any recognized devices. + * Returns a negative error code on failure and 0 on success. + * + * NOTE: if you want your driver to use the USB major number, you must call + * usb_register_dev() to enable that functionality. This function no longer + * takes care of that. + */ +int usb_register(struct usb_driver *new_driver) +{ + int retval = 0; + + if (nousb) + return -ENODEV; + + new_driver->driver.name = (char *)new_driver->name; + new_driver->driver.bus = &usb_bus_type; + new_driver->driver.probe = usb_device_probe; + new_driver->driver.remove = usb_device_remove; + + init_MUTEX(&new_driver->serialize); + + retval = driver_register(&new_driver->driver); + + if (!retval) { + info("registered new driver %s", new_driver->name); + usbfs_update_special(); + } else { + err("problem %d when registering driver %s", + retval, new_driver->name); + } + + return retval; +} + +/** + * usb_deregister - unregister a USB driver + * @driver: USB operations of the driver to unregister + * Context: !in_interrupt (), must be called with BKL held + * + * Unlinks the specified driver from the internal USB driver list. + * + * NOTE: If you called usb_register_dev(), you still need to call + * usb_deregister_dev() to clean up your driver's allocated minor numbers, + * this * call will no longer do it for you. + */ +void usb_deregister(struct usb_driver *driver) +{ + info("deregistering driver %s", driver->name); + + driver_unregister (&driver->driver); + + usbfs_update_special(); +} + +/** + * usb_ifnum_to_if - get the interface object with a given interface number (usbcore-internal) + * @dev: the device whose current configuration is considered + * @ifnum: the desired interface + * + * This walks the device descriptor for the currently active configuration + * and returns a pointer to the interface with that particular interface + * number, or null. + * + * Note that configuration descriptors are not required to assign interface + * numbers sequentially, so that it would be incorrect to assume that + * the first interface in that descriptor corresponds to interface zero. + * This routine helps device drivers avoid such mistakes. + * However, you should make sure that you do the right thing with any + * alternate settings available for this interfaces. + */ +struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) +{ + int i; + + for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) + if (dev->actconfig->interface[i].altsetting[0] + .desc.bInterfaceNumber == ifnum) + return &dev->actconfig->interface[i]; + + return NULL; +} + +/** + * usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number + * @dev: the device whose current configuration is considered + * @epnum: the desired endpoint + * + * This walks the device descriptor for the currently active configuration, + * and returns a pointer to the endpoint with that particular endpoint + * number, or null. + * + * Note that interface descriptors are not required to assign endpont + * numbers sequentially, so that it would be incorrect to assume that + * the first endpoint in that descriptor corresponds to interface zero. + * This routine helps device drivers avoid such mistakes. + */ +struct usb_endpoint_descriptor * +usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum) +{ + int i, j, k; + + for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) + for (j = 0; j < dev->actconfig->interface[i].num_altsetting; j++) + for (k = 0; k < dev->actconfig->interface[i] + .altsetting[j].desc.bNumEndpoints; k++) + if (epnum == dev->actconfig->interface[i] + .altsetting[j].endpoint[k] + .desc.bEndpointAddress) + return &dev->actconfig->interface[i] + .altsetting[j].endpoint[k] + .desc; + + return NULL; +} + +/** + * usb_driver_claim_interface - bind a driver to an interface + * @driver: the driver to be bound + * @iface: the interface to which it will be bound + * @priv: driver data associated with that interface + * + * This is used by usb device drivers that need to claim more than one + * interface on a device when probing (audio and acm are current examples). + * No device driver should directly modify internal usb_interface or + * usb_device structure members. + * + * Few drivers should need to use this routine, since the most natural + * way to bind to an interface is to return the private data from + * the driver's probe() method. Any driver that does use this must + * first be sure that no other driver has claimed the interface, by + * checking with usb_interface_claimed(). + */ +void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv) +{ + if (!iface || !driver) + return; + + // FIXME change API to report an error in this case + if (iface->driver) + err ("%s driver booted %s off interface %p", + driver->name, iface->driver->name, iface); + else + dbg("%s driver claimed interface %p", driver->name, iface); + + iface->driver = driver; + usb_set_intfdata(iface, priv); +} + +/** + * usb_interface_claimed - returns true iff an interface is claimed + * @iface: the interface being checked + * + * This should be used by drivers to check other interfaces to see if + * they are available or not. If another driver has claimed the interface, + * they may not claim it. Otherwise it's OK to claim it using + * usb_driver_claim_interface(). + * + * Returns true (nonzero) iff the interface is claimed, else false (zero). + */ +int usb_interface_claimed(struct usb_interface *iface) +{ + if (!iface) + return 0; + + return (iface->driver != NULL); +} /* usb_interface_claimed() */ + +/** + * usb_driver_release_interface - unbind a driver from an interface + * @driver: the driver to be unbound + * @iface: the interface from which it will be unbound + * + * This should be used by drivers to release their claimed interfaces. + * It is normally called in their disconnect() methods, and only for + * drivers that bound to more than one interface in their probe(). + * + * When the USB subsystem disconnect()s a driver from some interface, + * it automatically invokes this method for that interface. That + * means that even drivers that used usb_driver_claim_interface() + * usually won't need to call this. + */ +void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface) +{ + /* this should never happen, don't release something that's not ours */ + if (!iface || iface->driver != driver) + return; + + iface->driver = NULL; + usb_set_intfdata(iface, NULL); +} + +/** + * usb_match_id - find first usb_device_id matching device or interface + * @interface: the interface of interest + * @id: array of usb_device_id structures, terminated by zero entry + * + * usb_match_id searches an array of usb_device_id's and returns + * the first one matching the device or interface, or null. + * This is used when binding (or rebinding) a driver to an interface. + * Most USB device drivers will use this indirectly, through the usb core, + * but some layered driver frameworks use it directly. + * These device tables are exported with MODULE_DEVICE_TABLE, through + * modutils and "modules.usbmap", to support the driver loading + * functionality of USB hotplugging. + * + * What Matches: + * + * The "match_flags" element in a usb_device_id controls which + * members are used. If the corresponding bit is set, the + * value in the device_id must match its corresponding member + * in the device or interface descriptor, or else the device_id + * does not match. + * + * "driver_info" is normally used only by device drivers, + * but you can create a wildcard "matches anything" usb_device_id + * as a driver's "modules.usbmap" entry if you provide an id with + * only a nonzero "driver_info" field. If you do this, the USB device + * driver's probe() routine should use additional intelligence to + * decide whether to bind to the specified interface. + * + * What Makes Good usb_device_id Tables: + * + * The match algorithm is very simple, so that intelligence in + * driver selection must come from smart driver id records. + * Unless you have good reasons to use another selection policy, + * provide match elements only in related groups, and order match + * specifiers from specific to general. Use the macros provided + * for that purpose if you can. + * + * The most specific match specifiers use device descriptor + * data. These are commonly used with product-specific matches; + * the USB_DEVICE macro lets you provide vendor and product IDs, + * and you can also match against ranges of product revisions. + * These are widely used for devices with application or vendor + * specific bDeviceClass values. + * + * Matches based on device class/subclass/protocol specifications + * are slightly more general; use the USB_DEVICE_INFO macro, or + * its siblings. These are used with single-function devices + * where bDeviceClass doesn't specify that each interface has + * its own class. + * + * Matches based on interface class/subclass/protocol are the + * most general; they let drivers bind to any interface on a + * multiple-function device. Use the USB_INTERFACE_INFO + * macro, or its siblings, to match class-per-interface style + * devices (as recorded in bDeviceClass). + * + * Within those groups, remember that not all combinations are + * meaningful. For example, don't give a product version range + * without vendor and product IDs; or specify a protocol without + * its associated class and subclass. + */ +const struct usb_device_id * +usb_match_id(struct usb_interface *interface, const struct usb_device_id *id) +{ + struct usb_host_interface *intf; + struct usb_device *dev; + + /* proc_connectinfo in devio.c may call us with id == NULL. */ + if (id == NULL) + return NULL; + + intf = &interface->altsetting [interface->act_altsetting]; + dev = interface_to_usbdev(interface); + + /* It is important to check that id->driver_info is nonzero, + since an entry that is all zeroes except for a nonzero + id->driver_info is the way to create an entry that + indicates that the driver want to examine every + device and interface. */ + for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass || + id->driver_info; id++) { + + if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && + id->idVendor != dev->descriptor.idVendor) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && + id->idProduct != dev->descriptor.idProduct) + continue; + + /* No need to test id->bcdDevice_lo != 0, since 0 is never + greater than any unsigned number. */ + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) && + (id->bcdDevice_lo > dev->descriptor.bcdDevice)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) && + (id->bcdDevice_hi < dev->descriptor.bcdDevice)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) && + (id->bDeviceClass != dev->descriptor.bDeviceClass)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && + (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && + (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) && + (id->bInterfaceClass != intf->desc.bInterfaceClass)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) && + (id->bInterfaceSubClass != intf->desc.bInterfaceSubClass)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) && + (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol)) + continue; + + return id; + } + + return NULL; +} + +/** + * usb_find_interface - find usb_interface pointer for driver and device + * @drv: the driver whose current configuration is considered + * @minor: the minor number of the desired device + * + * This walks the driver device list and returns a pointer to the interface + * with the matching minor. Note, this only works for devices that share the + * USB major number. + */ +struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) +{ + struct list_head *entry; + struct device *dev; + struct usb_interface *intf; + + list_for_each(entry, &drv->driver.devices) { + dev = container_of(entry, struct device, driver_list); + + /* can't look at usb devices, only interfaces */ + if (dev->driver == &usb_generic_driver) + continue; + + intf = to_usb_interface(dev); + if (intf->minor == -1) + continue; + if (intf->minor == minor) + return intf; + } + + /* no device found that matches */ + return NULL; +} + +static int usb_device_match (struct device *dev, struct device_driver *drv) +{ + struct usb_interface *intf; + struct usb_driver *usb_drv; + const struct usb_device_id *id; + + /* check for generic driver, which we don't match any device with */ + if (drv == &usb_generic_driver) + return 0; + + intf = to_usb_interface(dev); + + usb_drv = to_usb_driver(drv); + id = usb_drv->id_table; + + id = usb_match_id (intf, usb_drv->id_table); + if (id) + return 1; + + return 0; +} + + +#ifdef CONFIG_HOTPLUG + +/* + * USB hotplugging invokes what /proc/sys/kernel/hotplug says + * (normally /sbin/hotplug) when USB devices get added or removed. + * + * This invokes a user mode policy agent, typically helping to load driver + * or other modules, configure the device, and more. Drivers can provide + * a MODULE_DEVICE_TABLE to help with module loading subtasks. + * + * We're called either from khubd (the typical case) or from root hub + * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle + * delays in event delivery. Use sysfs (and DEVPATH) to make sure the + * device (and this configuration!) are still present. + */ +static int usb_hotplug (struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct usb_interface *intf; + struct usb_device *usb_dev; + char *scratch; + int i = 0; + int length = 0; + + dbg ("%s", __FUNCTION__); + + if (!dev) + return -ENODEV; + + /* Must check driver_data here, as on remove driver is always NULL */ + if ((dev->driver == &usb_generic_driver) || + (dev->driver_data == &usb_generic_driver_data)) + return 0; + + intf = to_usb_interface(dev); + usb_dev = interface_to_usbdev (intf); + + if (usb_dev->devnum < 0) { + dbg ("device already deleted ??"); + return -ENODEV; + } + if (!usb_dev->bus) { + dbg ("bus already removed?"); + return -ENODEV; + } + + scratch = buffer; + +#ifdef CONFIG_USB_DEVICEFS + /* If this is available, userspace programs can directly read + * all the device descriptors we don't tell them about. Or + * even act as usermode drivers. + * + * FIXME reduce hardwired intelligence here + */ + envp [i++] = scratch; + length += snprintf (scratch, buffer_size - length, + "DEVICE=/proc/bus/usb/%03d/%03d", + usb_dev->bus->busnum, usb_dev->devnum); + if ((buffer_size - length <= 0) || (i >= num_envp)) + return -ENOMEM; + ++length; + scratch += length; +#endif + + /* per-device configurations are common */ + envp [i++] = scratch; + length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x", + usb_dev->descriptor.idVendor, + usb_dev->descriptor.idProduct, + usb_dev->descriptor.bcdDevice); + if ((buffer_size - length <= 0) || (i >= num_envp)) + return -ENOMEM; + ++length; + scratch += length; + + /* class-based driver binding models */ + envp [i++] = scratch; + length += snprintf (scratch, buffer_size - length, "TYPE=%d/%d/%d", + usb_dev->descriptor.bDeviceClass, + usb_dev->descriptor.bDeviceSubClass, + usb_dev->descriptor.bDeviceProtocol); + if ((buffer_size - length <= 0) || (i >= num_envp)) + return -ENOMEM; + ++length; + scratch += length; + + if (usb_dev->descriptor.bDeviceClass == 0) { + int alt = intf->act_altsetting; + + /* 2.4 only exposed interface zero. in 2.5, hotplug + * agents are called for all interfaces, and can use + * $DEVPATH/bInterfaceNumber if necessary. + */ + envp [i++] = scratch; + length += snprintf (scratch, buffer_size - length, + "INTERFACE=%d/%d/%d", + intf->altsetting[alt].desc.bInterfaceClass, + intf->altsetting[alt].desc.bInterfaceSubClass, + intf->altsetting[alt].desc.bInterfaceProtocol); + if ((buffer_size - length <= 0) || (i >= num_envp)) + return -ENOMEM; + ++length; + scratch += length; + + } + envp [i++] = 0; + + return 0; +} + +#else + +static int usb_hotplug (struct device *dev, char **envp, + int num_envp, char *buffer, int buffer_size) +{ + return -ENODEV; +} + +#endif /* CONFIG_HOTPLUG */ + +/** + * usb_alloc_dev - allocate a usb device structure (usbcore-internal) + * @parent: hub to which device is connected + * @bus: bus used to access the device + * Context: !in_interrupt () + * + * Only hub drivers (including virtual root hub drivers for host + * controllers) should ever call this. + * + * This call is synchronous, and may not be used in an interrupt context. + */ +struct usb_device STDCALL *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus) +{ + struct usb_device *dev; + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + memset(dev, 0, sizeof(*dev)); + + device_initialize(&dev->dev); + dev->state = USB_STATE_ATTACHED; + + usb_bus_get(bus); + + if (!parent) + dev->devpath [0] = '0'; + dev->bus = bus; + dev->parent = parent; + INIT_LIST_HEAD(&dev->filelist); + + init_MUTEX(&dev->serialize); + + if (dev->bus->op->allocate) + dev->bus->op->allocate(dev); + + return dev; +} + +/** + * usb_get_dev - increments the reference count of the usb device structure + * @dev: the device being referenced + * + * Each live reference to a device should be refcounted. + * + * Drivers for USB interfaces should normally record such references in + * their probe() methods, when they bind to an interface, and release + * them by calling usb_put_dev(), in their disconnect() methods. + * + * A pointer to the device with the incremented reference counter is returned. + */ +struct usb_device STDCALL *usb_get_dev (struct usb_device *dev) +{ + struct device *tmp; + + if (!dev) + return NULL; + + tmp = get_device(&dev->dev); + if (tmp) + return to_usb_device(tmp); + else + return NULL; +} + +/** + * usb_put_dev - release a use of the usb device structure + * @dev: device that's been disconnected + * + * Must be called when a user of a device is finished with it. When the last + * user of the device calls this function, the memory of the device is freed. + */ +void STDCALL usb_put_dev(struct usb_device *dev) +{ + if (dev) + put_device(&dev->dev); +} + +/** + * usb_release_dev - free a usb device structure when all users of it are finished. + * @dev: device that's been disconnected + * + * Will be called only by the device core when all users of this usb device are + * done. + */ +static void usb_release_dev(struct device *dev) +{ + struct usb_device *udev; + + udev = to_usb_device(dev); + + if (udev->bus && udev->bus->op && udev->bus->op->deallocate) + udev->bus->op->deallocate(udev); + usb_destroy_configuration (udev); + usb_bus_put (udev->bus); + kfree (udev); +} + + +static struct usb_device *match_device(struct usb_device *dev, + u16 vendor_id, u16 product_id) +{ + struct usb_device *ret_dev = NULL; + int child; + + dbg("looking at vendor %d, product %d", + dev->descriptor.idVendor, + dev->descriptor.idProduct); + + /* see if this device matches */ + if ((dev->descriptor.idVendor == vendor_id) && + (dev->descriptor.idProduct == product_id)) { + dbg ("found the device!"); + ret_dev = usb_get_dev(dev); + goto exit; + } + + /* look through all of the children of this device */ + for (child = 0; child < dev->maxchild; ++child) { + if (dev->children[child]) { + ret_dev = match_device(dev->children[child], + vendor_id, product_id); + if (ret_dev) + goto exit; + } + } +exit: + return ret_dev; +} + +/** + * usb_find_device - find a specific usb device in the system + * @vendor_id: the vendor id of the device to find + * @product_id: the product id of the device to find + * + * Returns a pointer to a struct usb_device if such a specified usb + * device is present in the system currently. The usage count of the + * device will be incremented if a device is found. Make sure to call + * usb_put_dev() when the caller is finished with the device. + * + * If a device with the specified vendor and product id is not found, + * NULL is returned. + */ +struct usb_device *usb_find_device(u16 vendor_id, u16 product_id) +{ + struct list_head *buslist; + struct usb_bus *bus; + struct usb_device *dev = NULL; + + down(&usb_bus_list_lock); + for (buslist = usb_bus_list.next; + buslist != &usb_bus_list; + buslist = buslist->next) { + bus = container_of(buslist, struct usb_bus, bus_list); + dev = match_device(bus->root_hub, vendor_id, product_id); + if (dev) + goto exit; + } +exit: + up(&usb_bus_list_lock); + return dev; +} + +/** + * usb_get_current_frame_number - return current bus frame number + * @dev: the device whose bus is being queried + * + * Returns the current frame number for the USB host controller + * used with the given USB device. This can be used when scheduling + * isochronous requests. + * + * Note that different kinds of host controller have different + * "scheduling horizons". While one type might support scheduling only + * 32 frames into the future, others could support scheduling up to + * 1024 frames into the future. + */ +int usb_get_current_frame_number(struct usb_device *dev) +{ + return dev->bus->op->get_frame_number (dev); +} + +/*-------------------------------------------------------------------*/ +/* + * __usb_get_extra_descriptor() finds a descriptor of specific type in the + * extra field of the interface and endpoint descriptor structs. + */ + +int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr) +{ + struct usb_descriptor_header *header; + + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength < 2) { + err("invalid descriptor length of %d", header->bLength); + return -1; + } + + if (header->bDescriptorType == type) { + *ptr = header; + return 0; + } + + buffer += header->bLength; + size -= header->bLength; + } + return -1; +} + +/** + * usb_disconnect - disconnect a device (usbcore-internal) + * @pdev: pointer to device being disconnected + * Context: !in_interrupt () + * + * Something got disconnected. Get rid of it, and all of its children. + * + * Only hub drivers (including virtual root hub drivers for host + * controllers) should ever call this. + * + * This call is synchronous, and may not be used in an interrupt context. + */ +void usb_disconnect(struct usb_device **pdev) +{ + struct usb_device *dev = *pdev; + struct usb_bus *bus; + struct usb_operations *ops; + int i; + + might_sleep (); + + if (!dev) { +// pr_debug ("%s nodev\n", __FUNCTION__); + DPRINT ("%s nodev\n", __FUNCTION__); + return; + } + bus = dev->bus; + if (!bus) { +// pr_debug ("%s nobus\n", __FUNCTION__); + DPRINT ("%s nobus\n", __FUNCTION__); + return; + } + ops = bus->op; + + *pdev = NULL; + + /* mark the device as inactive, so any further urb submissions for + * this device will fail. + */ + dev->state = USB_STATE_NOTATTACHED; + + dev_info (&dev->dev, "USB disconnect, address %d\n", dev->devnum); + + /* Free up all the children before we remove this device */ + for (i = 0; i < USB_MAXCHILDREN; i++) { + struct usb_device **child = dev->children + i; + if (*child) + usb_disconnect(child); + } + + /* disconnect() drivers from interfaces (a key side effect) */ + dev_dbg (&dev->dev, "unregistering interfaces\n"); + if (dev->actconfig) { + for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *interface; + + /* remove this interface */ + interface = &dev->actconfig->interface[i]; + device_unregister(&interface->dev); + } + } + + /* deallocate hcd/hardware state */ + if (ops->disable) { + void (*disable)(struct usb_device *, int) = ops->disable; + + for (i = 0; i < 15; i++) { + disable (dev, i); + disable (dev, USB_DIR_IN | i); + } + } + + dev_dbg (&dev->dev, "unregistering device\n"); + /* Free the device number and remove the /proc/bus/usb entry */ + if (dev->devnum > 0) { + clear_bit(dev->devnum, dev->bus->devmap.devicemap); + usbfs_remove_device(dev); + } + device_unregister(&dev->dev); + + /* Decrement the reference count, it'll auto free everything when */ + /* it hits 0 which could very well be now */ + usb_put_dev(dev); +} + +/** + * usb_connect - pick device address (usbcore-internal) + * @dev: newly detected device (in DEFAULT state) + * + * Picks a device address. It's up to the hub (or root hub) driver + * to handle and manage enumeration, starting from the DEFAULT state. + * Only hub drivers (including virtual root hub drivers for host + * controllers) should ever call this. + */ +void STDCALL usb_connect(struct usb_device *dev) +{ + int devnum; + // FIXME needs locking for SMP!! + /* why? this is called only from the hub thread, + * which hopefully doesn't run on multiple CPU's simultaneously 8-) + * ... it's also called from modprobe/rmmod/apmd threads as part + * of virtual root hub init/reinit. In the init case, the hub code + * won't have seen this, but not so for reinit ... + */ + dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */ + + /* Try to allocate the next devnum beginning at bus->devnum_next. */ + devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next); + if (devnum >= 128) + devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1); + + dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); + + if (devnum < 128) { + set_bit(devnum, dev->bus->devmap.devicemap); + dev->devnum = devnum; + } +} + + +// hub-only!! ... and only exported for reset/reinit path. +// otherwise used internally, for usb_new_device() +int usb_set_address(struct usb_device *dev) +{ + int retval; + + if (dev->devnum == 0) + return -EINVAL; + if (dev->state != USB_STATE_DEFAULT && dev->state != USB_STATE_ADDRESS) + return -EINVAL; + retval = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS, + 0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); + if (retval == 0) + dev->state = USB_STATE_ADDRESS; + return retval; +} + + +/* improve on the default device description, if we can ... and + * while we're at it, maybe show the vendor and product strings. + */ +static void set_device_description (struct usb_device *dev) +{ + void *buf; + int mfgr = dev->descriptor.iManufacturer; + int prod = dev->descriptor.iProduct; + int vendor_id = dev->descriptor.idVendor; + int product_id = dev->descriptor.idProduct; + char *mfgr_str, *prod_str; + + /* set default; keep it if there are no strings, or kmalloc fails */ + sprintf (dev->dev.name, "USB device %04x:%04x", + vendor_id, product_id); + + if (!(buf = kmalloc(256 * 2, GFP_KERNEL))) + return; + + prod_str = (char *) buf; + mfgr_str = (char *) buf + 256; + + if (prod && usb_string (dev, prod, prod_str, 256) > 0) { +#ifdef DEBUG + dev_printk (KERN_INFO, &dev->dev, "Product: %s\n", prod_str); +#endif + } else { + prod_str = 0; + } + + if (mfgr && usb_string (dev, mfgr, mfgr_str, 256) > 0) { +#ifdef DEBUG + dev_printk (KERN_INFO, &dev->dev, "Manufacturer: %s\n", mfgr_str); +#endif + } else { + mfgr_str = 0; + } + + /* much like pci ... describe as either: + * - both strings: 'product descr (vendor descr)' + * - product only: 'product descr (USB device vvvv:pppp)' + * - vendor only: 'USB device vvvv:pppp (vendor descr)' + * - neither string: 'USB device vvvv:pppp' + */ + + if (prod_str && mfgr_str) { + + snprintf(dev->dev.name, sizeof dev->dev.name, + "%s (%s)", prod_str, mfgr_str); + } else if (prod_str) { + snprintf(dev->dev.name, sizeof dev->dev.name, + "%s (USB device %04x:%04x)", + prod_str, vendor_id, product_id); + + } else if (mfgr_str) { + snprintf(dev->dev.name, sizeof dev->dev.name, + "USB device %04x:%04x (%s)", + vendor_id, product_id, mfgr_str); + } + usbprintk("USB connected: %s\n",dev->dev.name); + kfree(buf); +} + +/* + * By the time we get here, we chose a new device address + * and is in the default state. We need to identify the thing and + * get the ball rolling.. + * + * Returns 0 for success, != 0 for error. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Only hub drivers (including virtual root hub drivers for host + * controllers) should ever call this. + */ +#define NEW_DEVICE_RETRYS 2 +#define SET_ADDRESS_RETRYS 2 +int usb_new_device(struct usb_device *dev, struct device *parent) +{ + int err = 0; + int i; + int j; + + /* + * Set the driver for the usb device to point to the "generic" driver. + * This prevents the main usb device from being sent to the usb bus + * probe function. Yes, it's a hack, but a nice one :) + * + * Do it asap, so more driver model stuff (like the device.h message + * utilities) can be used in hcd submit/unlink code paths. + */ + usb_generic_driver.bus = &usb_bus_type; + dev->dev.parent = parent; + dev->dev.driver = &usb_generic_driver; + dev->dev.bus = &usb_bus_type; + dev->dev.release = usb_release_dev; + dev->dev.driver_data = &usb_generic_driver_data; + usb_get_dev(dev); + if (dev->dev.bus_id[0] == 0) + sprintf (&dev->dev.bus_id[0], "%d-%s", + dev->bus->busnum, dev->devpath); + + /* dma masks come from the controller; readonly, except to hcd */ + dev->dev.dma_mask = parent->dma_mask; + + /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... + * it's fixed size except for full speed devices. + */ + switch (dev->speed) { + case USB_SPEED_HIGH: /* fixed at 64 */ + i = 64; + break; + case USB_SPEED_FULL: /* 8, 16, 32, or 64 */ + /* to determine the ep0 maxpacket size, read the first 8 + * bytes from the device descriptor to get bMaxPacketSize0; + * then correct our initial (small) guess. + */ + // FALLTHROUGH + case USB_SPEED_LOW: /* fixed at 8 */ + i = 8; + break; + default: + return -EINVAL; + } + dev->epmaxpacketin [0] = i; + dev->epmaxpacketout[0] = i; + + for (i = 0; i < NEW_DEVICE_RETRYS; ++i) { + + for (j = 0; j < SET_ADDRESS_RETRYS; ++j) { + err = usb_set_address(dev); + if (err >= 0) + break; + wait_ms(200); + } + if (err < 0) { + dev_err(&dev->dev, "USB device not accepting new address=%d (error=%d)\n", + dev->devnum, err); + dev->state = USB_STATE_DEFAULT; + clear_bit(dev->devnum, dev->bus->devmap.devicemap); + dev->devnum = -1; + return 1; + } + + wait_ms(10); /* Let the SET_ADDRESS settle */ + + /* high and low speed devices don't need this... */ + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8); + if (err >= 8) + break; + wait_ms(100); + } + + if (err < 8) { + if (err < 0) + dev_err(&dev->dev, "USB device not responding, giving up (error=%d)\n", err); + else + dev_err(&dev->dev, "USB device descriptor short read (expected %i, got %i)\n", 8, err); + clear_bit(dev->devnum, dev->bus->devmap.devicemap); + dev->devnum = -1; + return 1; + } + if (dev->speed == USB_SPEED_FULL) { + dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0; + dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; + } + + /* USB device state == addressed ... still not usable */ + + err = usb_get_device_descriptor(dev); + if (err < (signed)sizeof(dev->descriptor)) { + if (err < 0) + dev_err(&dev->dev, "unable to get device descriptor (error=%d)\n", err); + else + dev_err(&dev->dev, "USB device descriptor short read (expected %Zi, got %i)\n", + sizeof(dev->descriptor), err); + + clear_bit(dev->devnum, dev->bus->devmap.devicemap); + dev->devnum = -1; + return 1; + } + + err = usb_get_configuration(dev); + if (err < 0) { + dev_err(&dev->dev, "unable to get device %d configuration (error=%d)\n", + dev->devnum, err); + clear_bit(dev->devnum, dev->bus->devmap.devicemap); + dev->devnum = -1; + return 1; + } + + /* we set the default configuration here */ + err = usb_set_configuration(dev, dev->config[0].desc.bConfigurationValue); + if (err) { + dev_err(&dev->dev, "failed to set device %d default configuration (error=%d)\n", + dev->devnum, err); + clear_bit(dev->devnum, dev->bus->devmap.devicemap); + dev->devnum = -1; + return 1; + } + + /* USB device state == configured ... tell the world! */ + + dev_dbg(&dev->dev, "new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n", + dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber); + set_device_description (dev); + +#ifdef DEBUG + if (dev->descriptor.iSerialNumber) + usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); +#endif + /* put into sysfs, with device and config specific files */ + err = device_add (&dev->dev); + if (err) + return err; + usb_create_driverfs_dev_files (dev); + + /* Register all of the interfaces for this device with the driver core. + * Remember, interfaces get bound to drivers, not devices. */ + for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *interface = &dev->actconfig->interface[i]; + struct usb_interface_descriptor *desc; + + desc = &interface->altsetting [interface->act_altsetting].desc; + interface->dev.parent = &dev->dev; + interface->dev.driver = NULL; + interface->dev.bus = &usb_bus_type; + interface->dev.dma_mask = parent->dma_mask; + sprintf (&interface->dev.bus_id[0], "%d-%s:%d", + dev->bus->busnum, dev->devpath, + desc->bInterfaceNumber); + if (!desc->iInterface + || usb_string (dev, desc->iInterface, + interface->dev.name, + sizeof interface->dev.name) <= 0) { + /* typically devices won't bother with interface + * descriptions; this is the normal case. an + * interface's driver might describe it better. + * (also: iInterface is per-altsetting ...) + */ + sprintf (&interface->dev.name[0], + "usb-%s-%s interface %d", + dev->bus->bus_name, dev->devpath, + desc->bInterfaceNumber); + DPRINT1("usb_new_device: %s\n", interface->dev.name); + } + dev_dbg (&dev->dev, "%s - registering interface %s\n", __FUNCTION__, interface->dev.bus_id); + device_add (&interface->dev); + usb_create_driverfs_intf_files (interface); + } + /* add a /proc/bus/usb entry */ + usbfs_add_device(dev); + + return 0; +} + +/** + * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_DMA_MAP + * @dev: device the buffer will be used with + * @size: requested buffer size + * @mem_flags: affect whether allocation may block + * @dma: used to return DMA address of buffer + * + * Return value is either null (indicating no buffer could be allocated), or + * the cpu-space pointer to a buffer that may be used to perform DMA to the + * specified device. Such cpu-space buffers are returned along with the DMA + * address (through the pointer provided). + * + * These buffers are used with URB_NO_DMA_MAP set in urb->transfer_flags to + * avoid behaviors like using "DMA bounce buffers", or tying down I/O mapping + * hardware for long idle periods. The implementation varies between + * platforms, depending on details of how DMA will work to this device. + * Using these buffers also helps prevent cacheline sharing problems on + * architectures where CPU caches are not DMA-coherent. + * + * When the buffer is no longer used, free it with usb_buffer_free(). + */ +void *usb_buffer_alloc ( + struct usb_device *dev, + size_t size, + int mem_flags, + dma_addr_t *dma +) +{ + if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc) + return 0; + return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma); +} + +/** + * usb_buffer_free - free memory allocated with usb_buffer_alloc() + * @dev: device the buffer was used with + * @size: requested buffer size + * @addr: CPU address of buffer + * @dma: DMA address of buffer + * + * This reclaims an I/O buffer, letting it be reused. The memory must have + * been allocated using usb_buffer_alloc(), and the parameters must match + * those provided in that allocation request. + */ +void usb_buffer_free ( + struct usb_device *dev, + size_t size, + void *addr, + dma_addr_t dma +) +{ + if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_free) + return; + dev->bus->op->buffer_free (dev->bus, size, addr, dma); +} + +/** + * usb_buffer_map - create DMA mapping(s) for an urb + * @urb: urb whose transfer_buffer will be mapped + * + * Return value is either null (indicating no buffer could be mapped), or + * the parameter. URB_NO_DMA_MAP is added to urb->transfer_flags if the + * operation succeeds. If the device is connected to this system through + * a non-DMA controller, this operation always succeeds. + * + * This call would normally be used for an urb which is reused, perhaps + * as the target of a large periodic transfer, with usb_buffer_dmasync() + * calls to synchronize memory and dma state. It may not be used for + * control requests. + * + * Reverse the effect of this call with usb_buffer_unmap(). + */ +struct urb *usb_buffer_map (struct urb *urb) +{ + struct usb_bus *bus; + struct device *controller; + + if (!urb + || usb_pipecontrol (urb->pipe) + || !urb->dev + || !(bus = urb->dev->bus) + || !(controller = bus->controller)) + return 0; + + if (controller->dma_mask) { + urb->transfer_dma = dma_map_single (controller, + urb->transfer_buffer, urb->transfer_buffer_length, + usb_pipein (urb->pipe) + ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + // FIXME generic api broken like pci, can't report errors + // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; + } else + urb->transfer_dma = ~0; + urb->transfer_flags |= URB_NO_DMA_MAP; + return urb; +} + +/** + * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s) + * @urb: urb whose transfer_buffer will be synchronized + */ +void usb_buffer_dmasync (struct urb *urb) +{ + struct usb_bus *bus; + struct device *controller; + + if (!urb + || !(urb->transfer_flags & URB_NO_DMA_MAP) + || !urb->dev + || !(bus = urb->dev->bus) + || !(controller = bus->controller)) + return; + + if (controller->dma_mask) + dma_sync_single (controller, + urb->transfer_dma, urb->transfer_buffer_length, + usb_pipein (urb->pipe) + ? DMA_FROM_DEVICE : DMA_TO_DEVICE); +} + +/** + * usb_buffer_unmap - free DMA mapping(s) for an urb + * @urb: urb whose transfer_buffer will be unmapped + * + * Reverses the effect of usb_buffer_map(). + */ +void usb_buffer_unmap (struct urb *urb) +{ + struct usb_bus *bus; + struct device *controller; + + if (!urb + || !(urb->transfer_flags & URB_NO_DMA_MAP) + || !urb->dev + || !(bus = urb->dev->bus) + || !(controller = bus->controller)) + return; + + if (controller->dma_mask) + dma_unmap_single (controller, + urb->transfer_dma, urb->transfer_buffer_length, + usb_pipein (urb->pipe) + ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + urb->transfer_flags &= ~URB_NO_DMA_MAP; +} + +/** + * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint + * @dev: device to which the scatterlist will be mapped + * @pipe: endpoint defining the mapping direction + * @sg: the scatterlist to map + * @nents: the number of entries in the scatterlist + * + * Return value is either < 0 (indicating no buffers could be mapped), or + * the number of DMA mapping array entries in the scatterlist. + * + * The caller is responsible for placing the resulting DMA addresses from + * the scatterlist into URB transfer buffer pointers, and for setting the + * URB_NO_DMA_MAP transfer flag in each of those URBs. + * + * Top I/O rates come from queuing URBs, instead of waiting for each one + * to complete before starting the next I/O. This is particularly easy + * to do with scatterlists. Just allocate and submit one URB for each DMA + * mapping entry returned, stopping on the first error or when all succeed. + * Better yet, use the usb_sg_*() calls, which do that (and more) for you. + * + * This call would normally be used when translating scatterlist requests, + * rather than usb_buffer_map(), since on some hardware (with IOMMUs) it + * may be able to coalesce mappings for improved I/O efficiency. + * + * Reverse the effect of this call with usb_buffer_unmap_sg(). + */ +int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int nents) +{ + struct usb_bus *bus; + struct device *controller; + + if (!dev + || usb_pipecontrol (pipe) + || !(bus = dev->bus) + || !(controller = bus->controller) + || !controller->dma_mask) + return -1; + + // FIXME generic api broken like pci, can't report errors + return dma_map_sg (controller, sg, nents, + usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); +} + +/** + * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s) + * @dev: device to which the scatterlist will be mapped + * @pipe: endpoint defining the mapping direction + * @sg: the scatterlist to synchronize + * @n_hw_ents: the positive return value from usb_buffer_map_sg + * + * Use this when you are re-using a scatterlist's data buffers for + * another USB request. + */ +void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents) +{ + struct usb_bus *bus; + struct device *controller; + + if (!dev + || !(bus = dev->bus) + || !(controller = bus->controller) + || !controller->dma_mask) + return; + + dma_sync_sg (controller, sg, n_hw_ents, + usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); +} + +/** + * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist + * @dev: device to which the scatterlist will be mapped + * @pipe: endpoint defining the mapping direction + * @sg: the scatterlist to unmap + * @n_hw_ents: the positive return value from usb_buffer_map_sg + * + * Reverses the effect of usb_buffer_map_sg(). + */ +void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents) +{ + struct usb_bus *bus; + struct device *controller; + + if (!dev + || !(bus = dev->bus) + || !(controller = bus->controller) + || !controller->dma_mask) + return; + + dma_unmap_sg (controller, sg, n_hw_ents, + usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); +} + + +struct bus_type usb_bus_type = { + .name = "usb", + .match = usb_device_match, + .hotplug = usb_hotplug, +}; + +#ifndef MODULE + +static int __init usb_setup_disable(char *str) +{ + nousb = 1; + return 1; +} + +/* format to disable USB on kernel command line is: nousb */ +__setup("nousb", usb_setup_disable); + +#endif + +/* + * for external read access to + */ +int STDCALL usb_disabled(void) +{ + return nousb; +} + +/* + * Init + */ +int STDCALL __init usb_init(void) +{ + if (nousb) { + info("USB support disabled\n"); + return 0; + } + + bus_register(&usb_bus_type); + usb_major_init(); + usbfs_init(); + usb_hub_init(); + + driver_register(&usb_generic_driver); + + return 0; +} + +/* + * Cleanup + */ +void STDCALL __exit usb_exit(void) +{ + /* This will matter if shutdown/reboot does exitcalls. */ + if (nousb) + return; + + driver_unregister(&usb_generic_driver); + usb_major_cleanup(); + usbfs_cleanup(); + usb_hub_cleanup(); + bus_unregister(&usb_bus_type); +} + +subsys_initcall(usb_init); +module_exit(usb_exit); + +/* + * USB may be built into the kernel or be built as modules. + * These symbols are exported for device (or host controller) + * driver modules to use. + */ +EXPORT_SYMBOL(usb_epnum_to_ep_desc); + +EXPORT_SYMBOL(usb_register); +EXPORT_SYMBOL(usb_deregister); +EXPORT_SYMBOL(usb_disabled); + +EXPORT_SYMBOL(usb_device_probe); +EXPORT_SYMBOL(usb_device_remove); + +EXPORT_SYMBOL(usb_alloc_dev); +EXPORT_SYMBOL(usb_put_dev); +EXPORT_SYMBOL(usb_get_dev); +EXPORT_SYMBOL(usb_hub_tt_clear_buffer); + +EXPORT_SYMBOL(usb_driver_claim_interface); +EXPORT_SYMBOL(usb_interface_claimed); +EXPORT_SYMBOL(usb_driver_release_interface); +EXPORT_SYMBOL(usb_match_id); +EXPORT_SYMBOL(usb_find_interface); +EXPORT_SYMBOL(usb_ifnum_to_if); + +EXPORT_SYMBOL(usb_new_device); +EXPORT_SYMBOL(usb_reset_device); +EXPORT_SYMBOL(usb_connect); +EXPORT_SYMBOL(usb_disconnect); + +EXPORT_SYMBOL(__usb_get_extra_descriptor); + +EXPORT_SYMBOL(usb_find_device); +EXPORT_SYMBOL(usb_get_current_frame_number); + +EXPORT_SYMBOL (usb_buffer_alloc); +EXPORT_SYMBOL (usb_buffer_free); + +EXPORT_SYMBOL (usb_buffer_map); +EXPORT_SYMBOL (usb_buffer_dmasync); +EXPORT_SYMBOL (usb_buffer_unmap); + +EXPORT_SYMBOL (usb_buffer_map_sg); +EXPORT_SYMBOL (usb_buffer_dmasync_sg); +EXPORT_SYMBOL (usb_buffer_unmap_sg); + +MODULE_LICENSE("GPL"); diff --git a/reactos/drivers/usb/cromwell/core/usb.h b/reactos/drivers/usb/cromwell/core/usb.h index 52210ef7fa6..09f459f67ac 100644 --- a/reactos/drivers/usb/cromwell/core/usb.h +++ b/reactos/drivers/usb/cromwell/core/usb.h @@ -1,5 +1,5 @@ -/* Functions local to drivers/usb/core/ */ - -extern void usb_create_driverfs_dev_files (struct usb_device *dev); -extern void usb_create_driverfs_intf_files (struct usb_interface *intf); - +/* Functions local to drivers/usb/core/ */ + +extern void usb_create_driverfs_dev_files (struct usb_device *dev); +extern void usb_create_driverfs_intf_files (struct usb_interface *intf); + diff --git a/reactos/drivers/usb/cromwell/core/usbcore.c b/reactos/drivers/usb/cromwell/core/usbcore.c index 34df7e4b021..e15755cd0a5 100644 --- a/reactos/drivers/usb/cromwell/core/usbcore.c +++ b/reactos/drivers/usb/cromwell/core/usbcore.c @@ -1,63 +1,67 @@ -/* - ReactOS specific functions for usbcore module - by Aleksey Bragin (aleksey@reactos.com) -*/ - -#include -#include - -NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo) -{ - DbgPrint("usbcore: AddDevice called\n"); - - /* we need to do kind of this stuff here (as usual) - PDEVICE_OBJECT fdo; - IoCreateDevice(..., &fdo); - pdx->LowerDeviceObject = - IoAttachDeviceToDeviceStack(fdo, pdo);*/ - - return STATUS_SUCCESS; -} - -VOID DriverUnload(PDRIVER_OBJECT DriverObject) -{ - // nothing to do here yet -} - -// Dispatch PNP -NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp) -{ - ULONG fcn; - PIO_STACK_LOCATION stack; - - stack = IoGetCurrentIrpStackLocation(Irp); - fcn = stack->MinorFunction; - DbgPrint("IRP_MJ_PNP, fcn=%d\n", fcn); - - if (fcn == IRP_MN_REMOVE_DEVICE) - { - IoDeleteDevice(fdo); - } - - return STATUS_SUCCESS; -} - -NTSTATUS DispatchPower(PDEVICE_OBJECT fido, PIRP Irp) -{ - DbgPrint("IRP_MJ_POWER dispatch\n"); - return STATUS_SUCCESS; -} - -/* - * Standard DriverEntry method. - */ -NTSTATUS STDCALL -DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegPath) -{ - DriverObject->DriverUnload = DriverUnload; - DriverObject->DriverExtension->AddDevice = AddDevice; - DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp; - DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower; - - return STATUS_SUCCESS; -} +/* + ReactOS specific functions for usbcore module + by Aleksey Bragin (aleksey@reactos.com) +*/ + +#include +#include + +NTSTATUS STDCALL +AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo) +{ + DbgPrint("usbcore: AddDevice called\n"); + + /* we need to do kind of this stuff here (as usual) + PDEVICE_OBJECT fdo; + IoCreateDevice(..., &fdo); + pdx->LowerDeviceObject = + IoAttachDeviceToDeviceStack(fdo, pdo);*/ + + return STATUS_SUCCESS; +} + +VOID STDCALL +DriverUnload(PDRIVER_OBJECT DriverObject) +{ + // nothing to do here yet +} + +// Dispatch PNP +NTSTATUS STDCALL +DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp) +{ + ULONG fcn; + PIO_STACK_LOCATION stack; + + stack = IoGetCurrentIrpStackLocation(Irp); + fcn = stack->MinorFunction; + DbgPrint("IRP_MJ_PNP, fcn=%d\n", fcn); + + if (fcn == IRP_MN_REMOVE_DEVICE) + { + IoDeleteDevice(fdo); + } + + return STATUS_SUCCESS; +} + +NTSTATUS STDCALL +DispatchPower(PDEVICE_OBJECT fido, PIRP Irp) +{ + DbgPrint("IRP_MJ_POWER dispatch\n"); + return STATUS_SUCCESS; +} + +/* + * Standard DriverEntry method. + */ +NTSTATUS STDCALL +DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegPath) +{ + DriverObject->DriverUnload = DriverUnload; + DriverObject->DriverExtension->AddDevice = AddDevice; + DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp; + DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower; + + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/usb/cromwell/core/usbcore.def b/reactos/drivers/usb/cromwell/core/usbcore.def index 25446cd4fff..cb675e2477d 100644 --- a/reactos/drivers/usb/cromwell/core/usbcore.def +++ b/reactos/drivers/usb/cromwell/core/usbcore.def @@ -1,32 +1,32 @@ -; -; Exports definition file for usbcore.sys -; -EXPORTS -usb_init@0 -usb_exit@0 -usb_init_urb@4 -usb_alloc_urb@8 -usb_free_urb@4 -usb_get_urb@4 -usb_get_dev@4 -usb_submit_urb@8 -usb_unlink_urb@4 -usb_bus_init@4 -usb_alloc_bus@4 -usb_free_bus@4 -usb_register_bus@4 -usb_deregister_bus@4 -usb_register_root_hub@8 -usb_calc_bus_time@16 -usb_check_bandwidth@8 -usb_claim_bandwidth@16 -usb_release_bandwidth@12 -usb_hcd_giveback_urb@12 -;usb_hcd_irq@12 -usb_hc_died@4 -usb_alloc_dev@8 -usb_connect@4 -usb_put_dev@4 -usb_disabled@0 -usb_hcd_pci_probe@8 +; +; Exports definition file for usbcore.sys +; +EXPORTS +usb_init@0 +usb_exit@0 +usb_init_urb@4 +usb_alloc_urb@8 +usb_free_urb@4 +usb_get_urb@4 +usb_get_dev@4 +usb_submit_urb@8 +usb_unlink_urb@4 +usb_bus_init@4 +usb_alloc_bus@4 +usb_free_bus@4 +usb_register_bus@4 +usb_deregister_bus@4 +usb_register_root_hub@8 +usb_calc_bus_time@16 +usb_check_bandwidth@8 +usb_claim_bandwidth@16 +usb_release_bandwidth@12 +usb_hcd_giveback_urb@12 +;usb_hcd_irq@12 +usb_hc_died@4 +usb_alloc_dev@8 +usb_connect@4 +usb_put_dev@4 +usb_disabled@0 +usb_hcd_pci_probe@8 usb_hcd_pci_remove@4 \ No newline at end of file diff --git a/reactos/drivers/usb/cromwell/core/usbcore.rc b/reactos/drivers/usb/cromwell/core/usbcore.rc index bccb64ac3d2..f12b4d6d391 100644 --- a/reactos/drivers/usb/cromwell/core/usbcore.rc +++ b/reactos/drivers/usb/cromwell/core/usbcore.rc @@ -1,5 +1,5 @@ -#define REACTOS_VERSION_DLL -#define REACTOS_STR_FILE_DESCRIPTION "USB Core Device Driver\0" -#define REACTOS_STR_INTERNAL_NAME "usbcore\0" -#define REACTOS_STR_ORIGINAL_FILENAME "usbcore.sys\0" -#include +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "USB Core Device Driver\0" +#define REACTOS_STR_INTERNAL_NAME "usbcore\0" +#define REACTOS_STR_ORIGINAL_FILENAME "usbcore.sys\0" +#include diff --git a/reactos/drivers/usb/cromwell/host/makefile b/reactos/drivers/usb/cromwell/host/makefile index e2e02edacfc..f81185fe1e7 100644 --- a/reactos/drivers/usb/cromwell/host/makefile +++ b/reactos/drivers/usb/cromwell/host/makefile @@ -1,20 +1,20 @@ -PATH_TO_TOP = ../../../.. - -TARGET_TYPE = export_driver - -TARGET_NAME = ohci - -TARGET_DDKLIBS = ntoskrnl.a usbcore.a - -TARGET_CFLAGS = -Wall -I$(PATH_TO_TOP)/ntoskrnl/include -DDEBUG_MODE - -TARGET_OBJECTS = \ - ohci-hcd.o ohci_main.o ../sys/ros_wrapper.o ../sys/linuxwrapper.o - -include $(PATH_TO_TOP)/rules.mak - -include $(TOOLS_PATH)/helper.mk - -# Automatic dependency tracking -DEP_OBJECTS := $(TARGET_OBJECTS) -include $(PATH_TO_TOP)/tools/depend.mk +PATH_TO_TOP = ../../../.. + +TARGET_TYPE = export_driver + +TARGET_NAME = ohci + +TARGET_DDKLIBS = ntoskrnl.a usbcore.a + +TARGET_CFLAGS = -Wall -I$(PATH_TO_TOP)/ntoskrnl/include -DDEBUG_MODE + +TARGET_OBJECTS = \ + ohci-hcd.o ohci_main.o ../sys/ros_wrapper.o ../sys/linuxwrapper.o + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk + +# Automatic dependency tracking +DEP_OBJECTS := $(TARGET_OBJECTS) +include $(PATH_TO_TOP)/tools/depend.mk diff --git a/reactos/drivers/usb/cromwell/host/makefile.crom b/reactos/drivers/usb/cromwell/host/makefile.crom index c23390585ae..d8bfc9a4c4f 100644 --- a/reactos/drivers/usb/cromwell/host/makefile.crom +++ b/reactos/drivers/usb/cromwell/host/makefile.crom @@ -1,3 +1,3 @@ -O_TARGET := ohci-hcd.o - -include $(TOPDIR)/Rules.make +O_TARGET := ohci-hcd.o + +include $(TOPDIR)/Rules.make diff --git a/reactos/drivers/usb/cromwell/host/ohci-dbg.c b/reactos/drivers/usb/cromwell/host/ohci-dbg.c index 6c9661b6738..0997ddfa28e 100644 --- a/reactos/drivers/usb/cromwell/host/ohci-dbg.c +++ b/reactos/drivers/usb/cromwell/host/ohci-dbg.c @@ -1,666 +1,666 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * - * This file is licenced under the GPL. - */ - -/*-------------------------------------------------------------------------*/ - -#ifdef DEBUG - -#define edstring(ed_type) ({ char *temp; \ - switch (ed_type) { \ - case PIPE_CONTROL: temp = "ctrl"; break; \ - case PIPE_BULK: temp = "bulk"; break; \ - case PIPE_INTERRUPT: temp = "intr"; break; \ - default: temp = "isoc"; break; \ - }; temp;}) -#define pipestring(pipe) edstring(usb_pipetype(pipe)) - -/* debug| print the main components of an URB - * small: 0) header + data packets 1) just header - */ -static void __attribute__((unused)) -urb_print (struct urb * urb, char * str, int small) -{ - unsigned int pipe= urb->pipe; - - if (!urb->dev || !urb->dev->bus) { - dbg("%s URB: no dev", str); - return; - } - -#ifndef OHCI_VERBOSE_DEBUG - if (urb->status != 0) -#endif - dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d", - str, - urb, - usb_pipedevice (pipe), - usb_pipeendpoint (pipe), - usb_pipeout (pipe)? "out" : "in", - pipestring (pipe), - urb->transfer_flags, - urb->actual_length, - urb->transfer_buffer_length, - urb->status); - -#ifdef OHCI_VERBOSE_DEBUG - if (!small) { - int i, len; - - if (usb_pipecontrol (pipe)) { - printk (KERN_DEBUG __FILE__ ": setup(8):"); - for (i = 0; i < 8 ; i++) - printk (" %02x", ((__u8 *) urb->setup_packet) [i]); - printk ("\n"); - } - if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) { - printk (KERN_DEBUG __FILE__ ": data(%d/%d):", - urb->actual_length, - urb->transfer_buffer_length); - len = usb_pipeout (pipe)? - urb->transfer_buffer_length: urb->actual_length; - for (i = 0; i < 16 && i < len; i++) - printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]); - printk ("%s stat:%d\n", i < len? "...": "", urb->status); - } - } -#endif -} - -#define ohci_dbg_sw(ohci, next, size, format, arg...) \ - do { \ - if (next) { \ - unsigned s_len; \ - s_len = snprintf (*next, *size, format, ## arg ); \ - *size -= s_len; *next += s_len; \ - } else \ - ohci_dbg(ohci,format, ## arg ); \ - } while (0); - - -static void ohci_dump_intr_mask ( - struct ohci_hcd *ohci, - char *label, - u32 mask, - char **next, - unsigned *size) -{ - ohci_dbg_sw (ohci, next, size, "%s 0x%08x%s%s%s%s%s%s%s%s%s\n", - label, - mask, - (mask & OHCI_INTR_MIE) ? " MIE" : "", - (mask & OHCI_INTR_OC) ? " OC" : "", - (mask & OHCI_INTR_RHSC) ? " RHSC" : "", - (mask & OHCI_INTR_FNO) ? " FNO" : "", - (mask & OHCI_INTR_UE) ? " UE" : "", - (mask & OHCI_INTR_RD) ? " RD" : "", - (mask & OHCI_INTR_SF) ? " SF" : "", - (mask & OHCI_INTR_WDH) ? " WDH" : "", - (mask & OHCI_INTR_SO) ? " SO" : "" - ); -} - -static void maybe_print_eds ( - struct ohci_hcd *ohci, - char *label, - u32 value, - char **next, - unsigned *size) -{ - if (value) - ohci_dbg_sw (ohci, next, size, "%s %08x\n", label, value); -} - -static char *hcfs2string (int state) -{ - switch (state) { - case OHCI_USB_RESET: return "reset"; - case OHCI_USB_RESUME: return "resume"; - case OHCI_USB_OPER: return "operational"; - case OHCI_USB_SUSPEND: return "suspend"; - } - return "?"; -} - -// dump control and status registers -static void -ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size) -{ - struct ohci_regs *regs = controller->regs; - u32 temp; - - temp = readl (®s->revision) & 0xff; - ohci_dbg_sw (controller, next, size, - "OHCI %d.%d, %s legacy support registers\n", - 0x03 & (temp >> 4), (temp & 0x0f), - (temp & 0x10) ? "with" : "NO"); - - temp = readl (®s->control); - ohci_dbg_sw (controller, next, size, - "control 0x%03x%s%s%s HCFS=%s%s%s%s%s CBSR=%d\n", - temp, - (temp & OHCI_CTRL_RWE) ? " RWE" : "", - (temp & OHCI_CTRL_RWC) ? " RWC" : "", - (temp & OHCI_CTRL_IR) ? " IR" : "", - hcfs2string (temp & OHCI_CTRL_HCFS), - (temp & OHCI_CTRL_BLE) ? " BLE" : "", - (temp & OHCI_CTRL_CLE) ? " CLE" : "", - (temp & OHCI_CTRL_IE) ? " IE" : "", - (temp & OHCI_CTRL_PLE) ? " PLE" : "", - temp & OHCI_CTRL_CBSR - ); - - temp = readl (®s->cmdstatus); - ohci_dbg_sw (controller, next, size, - "cmdstatus 0x%05x SOC=%d%s%s%s%s\n", temp, - (temp & OHCI_SOC) >> 16, - (temp & OHCI_OCR) ? " OCR" : "", - (temp & OHCI_BLF) ? " BLF" : "", - (temp & OHCI_CLF) ? " CLF" : "", - (temp & OHCI_HCR) ? " HCR" : "" - ); - - ohci_dump_intr_mask (controller, "intrstatus", - readl (®s->intrstatus), next, size); - ohci_dump_intr_mask (controller, "intrenable", - readl (®s->intrenable), next, size); - // intrdisable always same as intrenable - - maybe_print_eds (controller, "ed_periodcurrent", - readl (®s->ed_periodcurrent), next, size); - - maybe_print_eds (controller, "ed_controlhead", - readl (®s->ed_controlhead), next, size); - maybe_print_eds (controller, "ed_controlcurrent", - readl (®s->ed_controlcurrent), next, size); - - maybe_print_eds (controller, "ed_bulkhead", - readl (®s->ed_bulkhead), next, size); - maybe_print_eds (controller, "ed_bulkcurrent", - readl (®s->ed_bulkcurrent), next, size); - - maybe_print_eds (controller, "donehead", - readl (®s->donehead), next, size); -} - -#define dbg_port_sw(hc,num,value,next,size) \ - ohci_dbg_sw (hc, next, size, \ - "roothub.portstatus [%d] " \ - "0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \ - num, temp, \ - (temp & RH_PS_PRSC) ? " PRSC" : "", \ - (temp & RH_PS_OCIC) ? " OCIC" : "", \ - (temp & RH_PS_PSSC) ? " PSSC" : "", \ - (temp & RH_PS_PESC) ? " PESC" : "", \ - (temp & RH_PS_CSC) ? " CSC" : "", \ - \ - (temp & RH_PS_LSDA) ? " LSDA" : "", \ - (temp & RH_PS_PPS) ? " PPS" : "", \ - (temp & RH_PS_PRS) ? " PRS" : "", \ - (temp & RH_PS_POCI) ? " POCI" : "", \ - (temp & RH_PS_PSS) ? " PSS" : "", \ - \ - (temp & RH_PS_PES) ? " PES" : "", \ - (temp & RH_PS_CCS) ? " CCS" : "" \ - ); - - -static void -ohci_dump_roothub ( - struct ohci_hcd *controller, - int verbose, - char **next, - unsigned *size) -{ - u32 temp, ndp, i; - - temp = roothub_a (controller); - if (temp == ~(u32)0) - return; - ndp = (temp & RH_A_NDP); - - if (verbose) { - ohci_dbg_sw (controller, next, size, - "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d\n", temp, - ((temp & RH_A_POTPGT) >> 24) & 0xff, - (temp & RH_A_NOCP) ? " NOCP" : "", - (temp & RH_A_OCPM) ? " OCPM" : "", - (temp & RH_A_DT) ? " DT" : "", - (temp & RH_A_NPS) ? " NPS" : "", - (temp & RH_A_PSM) ? " PSM" : "", - ndp - ); - temp = roothub_b (controller); - ohci_dbg_sw (controller, next, size, - "roothub.b %08x PPCM=%04x DR=%04x\n", - temp, - (temp & RH_B_PPCM) >> 16, - (temp & RH_B_DR) - ); - temp = roothub_status (controller); - ohci_dbg_sw (controller, next, size, - "roothub.status %08x%s%s%s%s%s%s\n", - temp, - (temp & RH_HS_CRWE) ? " CRWE" : "", - (temp & RH_HS_OCIC) ? " OCIC" : "", - (temp & RH_HS_LPSC) ? " LPSC" : "", - (temp & RH_HS_DRWE) ? " DRWE" : "", - (temp & RH_HS_OCI) ? " OCI" : "", - (temp & RH_HS_LPS) ? " LPS" : "" - ); - } - - for (i = 0; i < ndp; i++) { - temp = roothub_portstatus (controller, i); - dbg_port_sw (controller, i, temp, next, size); - } -} - -static void ohci_dump (struct ohci_hcd *controller, int verbose) -{ - ohci_dbg (controller, "OHCI controller state\n"); - - // dumps some of the state we know about - ohci_dump_status (controller, NULL, 0); - if (controller->hcca) - ohci_dbg (controller, - "hcca frame #%04x\n", controller->hcca->frame_no); - ohci_dump_roothub (controller, 1, NULL, 0); -} - -static const char data0 [] = "DATA0"; -static const char data1 [] = "DATA1"; - -static void ohci_dump_td (struct ohci_hcd *ohci, char *label, struct td *td) -{ - u32 tmp = le32_to_cpup (&td->hwINFO); - - ohci_dbg (ohci, "%s td %p%s; urb %p index %d; hw next td %08x", - label, td, - (tmp & TD_DONE) ? " (DONE)" : "", - td->urb, td->index, - le32_to_cpup (&td->hwNextTD)); - if ((tmp & TD_ISO) == 0) { - const char *toggle, *pid; - u32 cbp, be; - - switch (tmp & TD_T) { - case TD_T_DATA0: toggle = data0; break; - case TD_T_DATA1: toggle = data1; break; - case TD_T_TOGGLE: toggle = "(CARRY)"; break; - default: toggle = "(?)"; break; - } - switch (tmp & TD_DP) { - case TD_DP_SETUP: pid = "SETUP"; break; - case TD_DP_IN: pid = "IN"; break; - case TD_DP_OUT: pid = "OUT"; break; - default: pid = "(bad pid)"; break; - } - ohci_dbg (ohci, " info %08x CC=%x %s DI=%d %s %s", tmp, - TD_CC_GET(tmp), /* EC, */ toggle, - (tmp & TD_DI) >> 21, pid, - (tmp & TD_R) ? "R" : ""); - cbp = le32_to_cpup (&td->hwCBP); - be = le32_to_cpup (&td->hwBE); - ohci_dbg (ohci, " cbp %08x be %08x (len %d)", cbp, be, - cbp ? (be + 1 - cbp) : 0); - } else { - unsigned i; - ohci_dbg (ohci, " info %08x CC=%x FC=%d DI=%d SF=%04x", tmp, - TD_CC_GET(tmp), - (tmp >> 24) & 0x07, - (tmp & TD_DI) >> 21, - tmp & 0x0000ffff); - ohci_dbg (ohci, " bp0 %08x be %08x", - le32_to_cpup (&td->hwCBP) & ~0x0fff, - le32_to_cpup (&td->hwBE)); - for (i = 0; i < MAXPSW; i++) { - u16 psw = le16_to_cpup (&td->hwPSW [i]); - int cc = (psw >> 12) & 0x0f; - ohci_dbg (ohci, " psw [%d] = %2x, CC=%x %s=%d", i, - psw, cc, - (cc >= 0x0e) ? "OFFSET" : "SIZE", - psw & 0x0fff); - } - } -} - -/* caller MUST own hcd spinlock if verbose is set! */ -static void __attribute__((unused)) -ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose) -{ - u32 tmp = ed->hwINFO; - char *type = ""; - - ohci_dbg (ohci, "%s, ed %p state 0x%x type %s; next ed %08x", - label, - ed, ed->state, edstring (ed->type), - le32_to_cpup (&ed->hwNextED)); - switch (tmp & (ED_IN|ED_OUT)) { - case ED_OUT: type = "-OUT"; break; - case ED_IN: type = "-IN"; break; - /* else from TDs ... control */ - } - ohci_dbg (ohci, - " info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d", le32_to_cpu (tmp), - 0x03ff & (le32_to_cpu (tmp) >> 16), - (tmp & ED_DEQUEUE) ? " DQ" : "", - (tmp & ED_ISO) ? " ISO" : "", - (tmp & ED_SKIP) ? " SKIP" : "", - (tmp & ED_LOWSPEED) ? " LOW" : "", - 0x000f & (le32_to_cpu (tmp) >> 7), - type, - 0x007f & le32_to_cpu (tmp)); - ohci_dbg (ohci, " tds: head %08x %s%s tail %08x%s", - tmp = le32_to_cpup (&ed->hwHeadP), - (ed->hwHeadP & ED_C) ? data1 : data0, - (ed->hwHeadP & ED_H) ? " HALT" : "", - le32_to_cpup (&ed->hwTailP), - verbose ? "" : " (not listing)"); - if (verbose) { - struct list_head *tmp; - - /* use ed->td_list because HC concurrently modifies - * hwNextTD as it accumulates ed_donelist. - */ - list_for_each (tmp, &ed->td_list) { - struct td *td; - td = list_entry (tmp, struct td, td_list); - ohci_dump_td (ohci, " ->", td); - } - } -} - -#else -static inline void ohci_dump (struct ohci_hcd *controller, int verbose) {} - -#undef OHCI_VERBOSE_DEBUG - -#endif /* DEBUG */ - -/*-------------------------------------------------------------------------*/ - -#ifdef STUB_DEBUG_FILES - -static inline void create_debug_files (struct ohci_hcd *bus) { } -static inline void remove_debug_files (struct ohci_hcd *bus) { } - -#else - -static inline struct ohci_hcd *dev_to_ohci (struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata (dev); - - return hcd_to_ohci (hcd); -} - -static ssize_t -show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed) -{ - unsigned temp, size = count; - - if (!ed) - return 0; - - /* print first --> last */ - while (ed->ed_prev) - ed = ed->ed_prev; - - /* dump a snapshot of the bulk or control schedule */ - while (ed) { - u32 info = ed->hwINFO; - u32 scratch = cpu_to_le32p (&ed->hwINFO); - struct list_head *entry; - struct td *td; - - temp = snprintf (buf, size, - "ed/%p %cs dev%d ep%d%s max %d %08x%s%s %s", - ed, - (info & ED_LOWSPEED) ? 'l' : 'f', - scratch & 0x7f, - (scratch >> 7) & 0xf, - (info & ED_IN) ? "in" : "out", - 0x03ff & (scratch >> 16), - scratch, - (info & ED_SKIP) ? " s" : "", - (ed->hwHeadP & ED_H) ? " H" : "", - (ed->hwHeadP & ED_C) ? data1 : data0); - size -= temp; - buf += temp; - - list_for_each (entry, &ed->td_list) { - u32 cbp, be; - - td = list_entry (entry, struct td, td_list); - scratch = cpu_to_le32p (&td->hwINFO); - cbp = le32_to_cpup (&td->hwCBP); - be = le32_to_cpup (&td->hwBE); - temp = snprintf (buf, size, - "\n\ttd %p %s %d cc=%x urb %p (%08x)", - td, - ({ char *pid; - switch (scratch & TD_DP) { - case TD_DP_SETUP: pid = "setup"; break; - case TD_DP_IN: pid = "in"; break; - case TD_DP_OUT: pid = "out"; break; - default: pid = "(?)"; break; - } pid;}), - cbp ? (be + 1 - cbp) : 0, - TD_CC_GET (scratch), td->urb, scratch); - size -= temp; - buf += temp; - } - - temp = snprintf (buf, size, "\n"); - size -= temp; - buf += temp; - - ed = ed->ed_next; - } - return count - size; -} - -static ssize_t -show_async (struct device *dev, char *buf) -{ - struct ohci_hcd *ohci; - size_t temp; - unsigned long flags; - - ohci = dev_to_ohci(dev); - - /* display control and bulk lists together, for simplicity */ - spin_lock_irqsave (&ohci->lock, flags); - temp = show_list (ohci, buf, PAGE_SIZE, ohci->ed_controltail); - temp += show_list (ohci, buf + temp, PAGE_SIZE - temp, ohci->ed_bulktail); - spin_unlock_irqrestore (&ohci->lock, flags); - - return temp; -} -static DEVICE_ATTR (async, S_IRUGO, show_async, NULL); - - -#define DBG_SCHED_LIMIT 64 - -static ssize_t -show_periodic (struct device *dev, char *buf) -{ - struct ohci_hcd *ohci; - struct ed **seen, *ed; - unsigned long flags; - unsigned temp, size, seen_count; - char *next; - unsigned i; - - if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC))) - return 0; - seen_count = 0; - - ohci = dev_to_ohci(dev); - next = buf; - size = PAGE_SIZE; - - temp = snprintf (next, size, "size = %d\n", NUM_INTS); - size -= temp; - next += temp; - - /* dump a snapshot of the periodic schedule (and load) */ - spin_lock_irqsave (&ohci->lock, flags); - for (i = 0; i < NUM_INTS; i++) { - if (!(ed = ohci->periodic [i])) - continue; - - temp = snprintf (next, size, "%2d [%3d]:", i, ohci->load [i]); - size -= temp; - next += temp; - - do { - temp = snprintf (next, size, " ed%d/%p", - ed->interval, ed); - size -= temp; - next += temp; - for (temp = 0; temp < seen_count; temp++) { - if (seen [temp] == ed) - break; - } - - /* show more info the first time around */ - if (temp == seen_count) { - u32 info = ed->hwINFO; - u32 scratch = cpu_to_le32p (&ed->hwINFO); - - temp = snprintf (next, size, - " (%cs dev%d%s ep%d%s" - " max %d %08x%s%s)", - (info & ED_LOWSPEED) ? 'l' : 'f', - scratch & 0x7f, - (info & ED_ISO) ? " iso" : "", - (scratch >> 7) & 0xf, - (info & ED_IN) ? "in" : "out", - 0x03ff & (scratch >> 16), - scratch, - (info & ED_SKIP) ? " s" : "", - (ed->hwHeadP & ED_H) ? " H" : ""); - size -= temp; - next += temp; - - // FIXME some TD info too - - if (seen_count < DBG_SCHED_LIMIT) - seen [seen_count++] = ed; - - ed = ed->ed_next; - - } else { - /* we've seen it and what's after */ - temp = 0; - ed = 0; - } - - } while (ed); - - temp = snprintf (next, size, "\n"); - size -= temp; - next += temp; - } - spin_unlock_irqrestore (&ohci->lock, flags); - kfree (seen); - - return PAGE_SIZE - size; -} -static DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL); - - -#undef DBG_SCHED_LIMIT - -static ssize_t -show_registers (struct device *dev, char *buf) -{ - struct ohci_hcd *ohci; - struct ohci_regs *regs; - unsigned long flags; - unsigned temp, size; - char *next; - u32 rdata; - - ohci = dev_to_ohci(dev); - regs = ohci->regs; - next = buf; - size = PAGE_SIZE; - - spin_lock_irqsave (&ohci->lock, flags); - - /* dump driver info, then registers in spec order */ - - ohci_dbg_sw (ohci, &next, &size, - "%s version " DRIVER_VERSION "\n", hcd_name); - - ohci_dump_status(ohci, &next, &size); - - /* hcca */ - if (ohci->hcca) - ohci_dbg_sw (ohci, &next, &size, - "hcca frame 0x%04x\n", ohci->hcca->frame_no); - - /* other registers mostly affect frame timings */ - rdata = readl (®s->fminterval); - temp = snprintf (next, size, - "fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n", - rdata, (rdata >> 31) ? " FIT" : "", - (rdata >> 16) & 0xefff, rdata & 0xffff); - size -= temp; - next += temp; - - rdata = readl (®s->fmremaining); - temp = snprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n", - rdata, (rdata >> 31) ? " FRT" : "", - rdata & 0x3fff); - size -= temp; - next += temp; - - rdata = readl (®s->periodicstart); - temp = snprintf (next, size, "periodicstart 0x%04x\n", - rdata & 0x3fff); - size -= temp; - next += temp; - - rdata = readl (®s->lsthresh); - temp = snprintf (next, size, "lsthresh 0x%04x\n", - rdata & 0x3fff); - size -= temp; - next += temp; - - /* roothub */ - ohci_dump_roothub (ohci, 1, &next, &size); - - spin_unlock_irqrestore (&ohci->lock, flags); - - return PAGE_SIZE - size; -} -static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL); - - -static inline void create_debug_files (struct ohci_hcd *bus) -{ - device_create_file (bus->hcd.controller, &dev_attr_async); - device_create_file (bus->hcd.controller, &dev_attr_periodic); - device_create_file (bus->hcd.controller, &dev_attr_registers); - ohci_dbg (bus, "created debug files\n"); -} - -static inline void remove_debug_files (struct ohci_hcd *bus) -{ - device_remove_file (bus->hcd.controller, &dev_attr_async); - device_remove_file (bus->hcd.controller, &dev_attr_periodic); - device_remove_file (bus->hcd.controller, &dev_attr_registers); -} - -#endif - -/*-------------------------------------------------------------------------*/ - +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * + * This file is licenced under the GPL. + */ + +/*-------------------------------------------------------------------------*/ + +#ifdef DEBUG + +#define edstring(ed_type) ({ char *temp; \ + switch (ed_type) { \ + case PIPE_CONTROL: temp = "ctrl"; break; \ + case PIPE_BULK: temp = "bulk"; break; \ + case PIPE_INTERRUPT: temp = "intr"; break; \ + default: temp = "isoc"; break; \ + }; temp;}) +#define pipestring(pipe) edstring(usb_pipetype(pipe)) + +/* debug| print the main components of an URB + * small: 0) header + data packets 1) just header + */ +static void __attribute__((unused)) +urb_print (struct urb * urb, char * str, int small) +{ + unsigned int pipe= urb->pipe; + + if (!urb->dev || !urb->dev->bus) { + dbg("%s URB: no dev", str); + return; + } + +#ifndef OHCI_VERBOSE_DEBUG + if (urb->status != 0) +#endif + dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d", + str, + urb, + usb_pipedevice (pipe), + usb_pipeendpoint (pipe), + usb_pipeout (pipe)? "out" : "in", + pipestring (pipe), + urb->transfer_flags, + urb->actual_length, + urb->transfer_buffer_length, + urb->status); + +#ifdef OHCI_VERBOSE_DEBUG + if (!small) { + int i, len; + + if (usb_pipecontrol (pipe)) { + printk (KERN_DEBUG __FILE__ ": setup(8):"); + for (i = 0; i < 8 ; i++) + printk (" %02x", ((__u8 *) urb->setup_packet) [i]); + printk ("\n"); + } + if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) { + printk (KERN_DEBUG __FILE__ ": data(%d/%d):", + urb->actual_length, + urb->transfer_buffer_length); + len = usb_pipeout (pipe)? + urb->transfer_buffer_length: urb->actual_length; + for (i = 0; i < 16 && i < len; i++) + printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]); + printk ("%s stat:%d\n", i < len? "...": "", urb->status); + } + } +#endif +} + +#define ohci_dbg_sw(ohci, next, size, format, arg...) \ + do { \ + if (next) { \ + unsigned s_len; \ + s_len = snprintf (*next, *size, format, ## arg ); \ + *size -= s_len; *next += s_len; \ + } else \ + ohci_dbg(ohci,format, ## arg ); \ + } while (0); + + +static void ohci_dump_intr_mask ( + struct ohci_hcd *ohci, + char *label, + u32 mask, + char **next, + unsigned *size) +{ + ohci_dbg_sw (ohci, next, size, "%s 0x%08x%s%s%s%s%s%s%s%s%s\n", + label, + mask, + (mask & OHCI_INTR_MIE) ? " MIE" : "", + (mask & OHCI_INTR_OC) ? " OC" : "", + (mask & OHCI_INTR_RHSC) ? " RHSC" : "", + (mask & OHCI_INTR_FNO) ? " FNO" : "", + (mask & OHCI_INTR_UE) ? " UE" : "", + (mask & OHCI_INTR_RD) ? " RD" : "", + (mask & OHCI_INTR_SF) ? " SF" : "", + (mask & OHCI_INTR_WDH) ? " WDH" : "", + (mask & OHCI_INTR_SO) ? " SO" : "" + ); +} + +static void maybe_print_eds ( + struct ohci_hcd *ohci, + char *label, + u32 value, + char **next, + unsigned *size) +{ + if (value) + ohci_dbg_sw (ohci, next, size, "%s %08x\n", label, value); +} + +static char *hcfs2string (int state) +{ + switch (state) { + case OHCI_USB_RESET: return "reset"; + case OHCI_USB_RESUME: return "resume"; + case OHCI_USB_OPER: return "operational"; + case OHCI_USB_SUSPEND: return "suspend"; + } + return "?"; +} + +// dump control and status registers +static void +ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size) +{ + struct ohci_regs *regs = controller->regs; + u32 temp; + + temp = readl (®s->revision) & 0xff; + ohci_dbg_sw (controller, next, size, + "OHCI %d.%d, %s legacy support registers\n", + 0x03 & (temp >> 4), (temp & 0x0f), + (temp & 0x10) ? "with" : "NO"); + + temp = readl (®s->control); + ohci_dbg_sw (controller, next, size, + "control 0x%03x%s%s%s HCFS=%s%s%s%s%s CBSR=%d\n", + temp, + (temp & OHCI_CTRL_RWE) ? " RWE" : "", + (temp & OHCI_CTRL_RWC) ? " RWC" : "", + (temp & OHCI_CTRL_IR) ? " IR" : "", + hcfs2string (temp & OHCI_CTRL_HCFS), + (temp & OHCI_CTRL_BLE) ? " BLE" : "", + (temp & OHCI_CTRL_CLE) ? " CLE" : "", + (temp & OHCI_CTRL_IE) ? " IE" : "", + (temp & OHCI_CTRL_PLE) ? " PLE" : "", + temp & OHCI_CTRL_CBSR + ); + + temp = readl (®s->cmdstatus); + ohci_dbg_sw (controller, next, size, + "cmdstatus 0x%05x SOC=%d%s%s%s%s\n", temp, + (temp & OHCI_SOC) >> 16, + (temp & OHCI_OCR) ? " OCR" : "", + (temp & OHCI_BLF) ? " BLF" : "", + (temp & OHCI_CLF) ? " CLF" : "", + (temp & OHCI_HCR) ? " HCR" : "" + ); + + ohci_dump_intr_mask (controller, "intrstatus", + readl (®s->intrstatus), next, size); + ohci_dump_intr_mask (controller, "intrenable", + readl (®s->intrenable), next, size); + // intrdisable always same as intrenable + + maybe_print_eds (controller, "ed_periodcurrent", + readl (®s->ed_periodcurrent), next, size); + + maybe_print_eds (controller, "ed_controlhead", + readl (®s->ed_controlhead), next, size); + maybe_print_eds (controller, "ed_controlcurrent", + readl (®s->ed_controlcurrent), next, size); + + maybe_print_eds (controller, "ed_bulkhead", + readl (®s->ed_bulkhead), next, size); + maybe_print_eds (controller, "ed_bulkcurrent", + readl (®s->ed_bulkcurrent), next, size); + + maybe_print_eds (controller, "donehead", + readl (®s->donehead), next, size); +} + +#define dbg_port_sw(hc,num,value,next,size) \ + ohci_dbg_sw (hc, next, size, \ + "roothub.portstatus [%d] " \ + "0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \ + num, temp, \ + (temp & RH_PS_PRSC) ? " PRSC" : "", \ + (temp & RH_PS_OCIC) ? " OCIC" : "", \ + (temp & RH_PS_PSSC) ? " PSSC" : "", \ + (temp & RH_PS_PESC) ? " PESC" : "", \ + (temp & RH_PS_CSC) ? " CSC" : "", \ + \ + (temp & RH_PS_LSDA) ? " LSDA" : "", \ + (temp & RH_PS_PPS) ? " PPS" : "", \ + (temp & RH_PS_PRS) ? " PRS" : "", \ + (temp & RH_PS_POCI) ? " POCI" : "", \ + (temp & RH_PS_PSS) ? " PSS" : "", \ + \ + (temp & RH_PS_PES) ? " PES" : "", \ + (temp & RH_PS_CCS) ? " CCS" : "" \ + ); + + +static void +ohci_dump_roothub ( + struct ohci_hcd *controller, + int verbose, + char **next, + unsigned *size) +{ + u32 temp, ndp, i; + + temp = roothub_a (controller); + if (temp == ~(u32)0) + return; + ndp = (temp & RH_A_NDP); + + if (verbose) { + ohci_dbg_sw (controller, next, size, + "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d\n", temp, + ((temp & RH_A_POTPGT) >> 24) & 0xff, + (temp & RH_A_NOCP) ? " NOCP" : "", + (temp & RH_A_OCPM) ? " OCPM" : "", + (temp & RH_A_DT) ? " DT" : "", + (temp & RH_A_NPS) ? " NPS" : "", + (temp & RH_A_PSM) ? " PSM" : "", + ndp + ); + temp = roothub_b (controller); + ohci_dbg_sw (controller, next, size, + "roothub.b %08x PPCM=%04x DR=%04x\n", + temp, + (temp & RH_B_PPCM) >> 16, + (temp & RH_B_DR) + ); + temp = roothub_status (controller); + ohci_dbg_sw (controller, next, size, + "roothub.status %08x%s%s%s%s%s%s\n", + temp, + (temp & RH_HS_CRWE) ? " CRWE" : "", + (temp & RH_HS_OCIC) ? " OCIC" : "", + (temp & RH_HS_LPSC) ? " LPSC" : "", + (temp & RH_HS_DRWE) ? " DRWE" : "", + (temp & RH_HS_OCI) ? " OCI" : "", + (temp & RH_HS_LPS) ? " LPS" : "" + ); + } + + for (i = 0; i < ndp; i++) { + temp = roothub_portstatus (controller, i); + dbg_port_sw (controller, i, temp, next, size); + } +} + +static void ohci_dump (struct ohci_hcd *controller, int verbose) +{ + ohci_dbg (controller, "OHCI controller state\n"); + + // dumps some of the state we know about + ohci_dump_status (controller, NULL, 0); + if (controller->hcca) + ohci_dbg (controller, + "hcca frame #%04x\n", controller->hcca->frame_no); + ohci_dump_roothub (controller, 1, NULL, 0); +} + +static const char data0 [] = "DATA0"; +static const char data1 [] = "DATA1"; + +static void ohci_dump_td (struct ohci_hcd *ohci, char *label, struct td *td) +{ + u32 tmp = le32_to_cpup (&td->hwINFO); + + ohci_dbg (ohci, "%s td %p%s; urb %p index %d; hw next td %08x", + label, td, + (tmp & TD_DONE) ? " (DONE)" : "", + td->urb, td->index, + le32_to_cpup (&td->hwNextTD)); + if ((tmp & TD_ISO) == 0) { + const char *toggle, *pid; + u32 cbp, be; + + switch (tmp & TD_T) { + case TD_T_DATA0: toggle = data0; break; + case TD_T_DATA1: toggle = data1; break; + case TD_T_TOGGLE: toggle = "(CARRY)"; break; + default: toggle = "(?)"; break; + } + switch (tmp & TD_DP) { + case TD_DP_SETUP: pid = "SETUP"; break; + case TD_DP_IN: pid = "IN"; break; + case TD_DP_OUT: pid = "OUT"; break; + default: pid = "(bad pid)"; break; + } + ohci_dbg (ohci, " info %08x CC=%x %s DI=%d %s %s", tmp, + TD_CC_GET(tmp), /* EC, */ toggle, + (tmp & TD_DI) >> 21, pid, + (tmp & TD_R) ? "R" : ""); + cbp = le32_to_cpup (&td->hwCBP); + be = le32_to_cpup (&td->hwBE); + ohci_dbg (ohci, " cbp %08x be %08x (len %d)", cbp, be, + cbp ? (be + 1 - cbp) : 0); + } else { + unsigned i; + ohci_dbg (ohci, " info %08x CC=%x FC=%d DI=%d SF=%04x", tmp, + TD_CC_GET(tmp), + (tmp >> 24) & 0x07, + (tmp & TD_DI) >> 21, + tmp & 0x0000ffff); + ohci_dbg (ohci, " bp0 %08x be %08x", + le32_to_cpup (&td->hwCBP) & ~0x0fff, + le32_to_cpup (&td->hwBE)); + for (i = 0; i < MAXPSW; i++) { + u16 psw = le16_to_cpup (&td->hwPSW [i]); + int cc = (psw >> 12) & 0x0f; + ohci_dbg (ohci, " psw [%d] = %2x, CC=%x %s=%d", i, + psw, cc, + (cc >= 0x0e) ? "OFFSET" : "SIZE", + psw & 0x0fff); + } + } +} + +/* caller MUST own hcd spinlock if verbose is set! */ +static void __attribute__((unused)) +ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose) +{ + u32 tmp = ed->hwINFO; + char *type = ""; + + ohci_dbg (ohci, "%s, ed %p state 0x%x type %s; next ed %08x", + label, + ed, ed->state, edstring (ed->type), + le32_to_cpup (&ed->hwNextED)); + switch (tmp & (ED_IN|ED_OUT)) { + case ED_OUT: type = "-OUT"; break; + case ED_IN: type = "-IN"; break; + /* else from TDs ... control */ + } + ohci_dbg (ohci, + " info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d", le32_to_cpu (tmp), + 0x03ff & (le32_to_cpu (tmp) >> 16), + (tmp & ED_DEQUEUE) ? " DQ" : "", + (tmp & ED_ISO) ? " ISO" : "", + (tmp & ED_SKIP) ? " SKIP" : "", + (tmp & ED_LOWSPEED) ? " LOW" : "", + 0x000f & (le32_to_cpu (tmp) >> 7), + type, + 0x007f & le32_to_cpu (tmp)); + ohci_dbg (ohci, " tds: head %08x %s%s tail %08x%s", + tmp = le32_to_cpup (&ed->hwHeadP), + (ed->hwHeadP & ED_C) ? data1 : data0, + (ed->hwHeadP & ED_H) ? " HALT" : "", + le32_to_cpup (&ed->hwTailP), + verbose ? "" : " (not listing)"); + if (verbose) { + struct list_head *tmp; + + /* use ed->td_list because HC concurrently modifies + * hwNextTD as it accumulates ed_donelist. + */ + list_for_each (tmp, &ed->td_list) { + struct td *td; + td = list_entry (tmp, struct td, td_list); + ohci_dump_td (ohci, " ->", td); + } + } +} + +#else +static inline void ohci_dump (struct ohci_hcd *controller, int verbose) {} + +#undef OHCI_VERBOSE_DEBUG + +#endif /* DEBUG */ + +/*-------------------------------------------------------------------------*/ + +#ifdef STUB_DEBUG_FILES + +static inline void create_debug_files (struct ohci_hcd *bus) { } +static inline void remove_debug_files (struct ohci_hcd *bus) { } + +#else + +static inline struct ohci_hcd *dev_to_ohci (struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata (dev); + + return hcd_to_ohci (hcd); +} + +static ssize_t +show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed) +{ + unsigned temp, size = count; + + if (!ed) + return 0; + + /* print first --> last */ + while (ed->ed_prev) + ed = ed->ed_prev; + + /* dump a snapshot of the bulk or control schedule */ + while (ed) { + u32 info = ed->hwINFO; + u32 scratch = cpu_to_le32p (&ed->hwINFO); + struct list_head *entry; + struct td *td; + + temp = snprintf (buf, size, + "ed/%p %cs dev%d ep%d%s max %d %08x%s%s %s", + ed, + (info & ED_LOWSPEED) ? 'l' : 'f', + scratch & 0x7f, + (scratch >> 7) & 0xf, + (info & ED_IN) ? "in" : "out", + 0x03ff & (scratch >> 16), + scratch, + (info & ED_SKIP) ? " s" : "", + (ed->hwHeadP & ED_H) ? " H" : "", + (ed->hwHeadP & ED_C) ? data1 : data0); + size -= temp; + buf += temp; + + list_for_each (entry, &ed->td_list) { + u32 cbp, be; + + td = list_entry (entry, struct td, td_list); + scratch = cpu_to_le32p (&td->hwINFO); + cbp = le32_to_cpup (&td->hwCBP); + be = le32_to_cpup (&td->hwBE); + temp = snprintf (buf, size, + "\n\ttd %p %s %d cc=%x urb %p (%08x)", + td, + ({ char *pid; + switch (scratch & TD_DP) { + case TD_DP_SETUP: pid = "setup"; break; + case TD_DP_IN: pid = "in"; break; + case TD_DP_OUT: pid = "out"; break; + default: pid = "(?)"; break; + } pid;}), + cbp ? (be + 1 - cbp) : 0, + TD_CC_GET (scratch), td->urb, scratch); + size -= temp; + buf += temp; + } + + temp = snprintf (buf, size, "\n"); + size -= temp; + buf += temp; + + ed = ed->ed_next; + } + return count - size; +} + +static ssize_t +show_async (struct device *dev, char *buf) +{ + struct ohci_hcd *ohci; + size_t temp; + unsigned long flags; + + ohci = dev_to_ohci(dev); + + /* display control and bulk lists together, for simplicity */ + spin_lock_irqsave (&ohci->lock, flags); + temp = show_list (ohci, buf, PAGE_SIZE, ohci->ed_controltail); + temp += show_list (ohci, buf + temp, PAGE_SIZE - temp, ohci->ed_bulktail); + spin_unlock_irqrestore (&ohci->lock, flags); + + return temp; +} +static DEVICE_ATTR (async, S_IRUGO, show_async, NULL); + + +#define DBG_SCHED_LIMIT 64 + +static ssize_t +show_periodic (struct device *dev, char *buf) +{ + struct ohci_hcd *ohci; + struct ed **seen, *ed; + unsigned long flags; + unsigned temp, size, seen_count; + char *next; + unsigned i; + + if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC))) + return 0; + seen_count = 0; + + ohci = dev_to_ohci(dev); + next = buf; + size = PAGE_SIZE; + + temp = snprintf (next, size, "size = %d\n", NUM_INTS); + size -= temp; + next += temp; + + /* dump a snapshot of the periodic schedule (and load) */ + spin_lock_irqsave (&ohci->lock, flags); + for (i = 0; i < NUM_INTS; i++) { + if (!(ed = ohci->periodic [i])) + continue; + + temp = snprintf (next, size, "%2d [%3d]:", i, ohci->load [i]); + size -= temp; + next += temp; + + do { + temp = snprintf (next, size, " ed%d/%p", + ed->interval, ed); + size -= temp; + next += temp; + for (temp = 0; temp < seen_count; temp++) { + if (seen [temp] == ed) + break; + } + + /* show more info the first time around */ + if (temp == seen_count) { + u32 info = ed->hwINFO; + u32 scratch = cpu_to_le32p (&ed->hwINFO); + + temp = snprintf (next, size, + " (%cs dev%d%s ep%d%s" + " max %d %08x%s%s)", + (info & ED_LOWSPEED) ? 'l' : 'f', + scratch & 0x7f, + (info & ED_ISO) ? " iso" : "", + (scratch >> 7) & 0xf, + (info & ED_IN) ? "in" : "out", + 0x03ff & (scratch >> 16), + scratch, + (info & ED_SKIP) ? " s" : "", + (ed->hwHeadP & ED_H) ? " H" : ""); + size -= temp; + next += temp; + + // FIXME some TD info too + + if (seen_count < DBG_SCHED_LIMIT) + seen [seen_count++] = ed; + + ed = ed->ed_next; + + } else { + /* we've seen it and what's after */ + temp = 0; + ed = 0; + } + + } while (ed); + + temp = snprintf (next, size, "\n"); + size -= temp; + next += temp; + } + spin_unlock_irqrestore (&ohci->lock, flags); + kfree (seen); + + return PAGE_SIZE - size; +} +static DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL); + + +#undef DBG_SCHED_LIMIT + +static ssize_t +show_registers (struct device *dev, char *buf) +{ + struct ohci_hcd *ohci; + struct ohci_regs *regs; + unsigned long flags; + unsigned temp, size; + char *next; + u32 rdata; + + ohci = dev_to_ohci(dev); + regs = ohci->regs; + next = buf; + size = PAGE_SIZE; + + spin_lock_irqsave (&ohci->lock, flags); + + /* dump driver info, then registers in spec order */ + + ohci_dbg_sw (ohci, &next, &size, + "%s version " DRIVER_VERSION "\n", hcd_name); + + ohci_dump_status(ohci, &next, &size); + + /* hcca */ + if (ohci->hcca) + ohci_dbg_sw (ohci, &next, &size, + "hcca frame 0x%04x\n", ohci->hcca->frame_no); + + /* other registers mostly affect frame timings */ + rdata = readl (®s->fminterval); + temp = snprintf (next, size, + "fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n", + rdata, (rdata >> 31) ? " FIT" : "", + (rdata >> 16) & 0xefff, rdata & 0xffff); + size -= temp; + next += temp; + + rdata = readl (®s->fmremaining); + temp = snprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n", + rdata, (rdata >> 31) ? " FRT" : "", + rdata & 0x3fff); + size -= temp; + next += temp; + + rdata = readl (®s->periodicstart); + temp = snprintf (next, size, "periodicstart 0x%04x\n", + rdata & 0x3fff); + size -= temp; + next += temp; + + rdata = readl (®s->lsthresh); + temp = snprintf (next, size, "lsthresh 0x%04x\n", + rdata & 0x3fff); + size -= temp; + next += temp; + + /* roothub */ + ohci_dump_roothub (ohci, 1, &next, &size); + + spin_unlock_irqrestore (&ohci->lock, flags); + + return PAGE_SIZE - size; +} +static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL); + + +static inline void create_debug_files (struct ohci_hcd *bus) +{ + device_create_file (bus->hcd.controller, &dev_attr_async); + device_create_file (bus->hcd.controller, &dev_attr_periodic); + device_create_file (bus->hcd.controller, &dev_attr_registers); + ohci_dbg (bus, "created debug files\n"); +} + +static inline void remove_debug_files (struct ohci_hcd *bus) +{ + device_remove_file (bus->hcd.controller, &dev_attr_async); + device_remove_file (bus->hcd.controller, &dev_attr_periodic); + device_remove_file (bus->hcd.controller, &dev_attr_registers); +} + +#endif + +/*-------------------------------------------------------------------------*/ + diff --git a/reactos/drivers/usb/cromwell/host/ohci-hcd.c b/reactos/drivers/usb/cromwell/host/ohci-hcd.c index 3470fa9e825..ecaacddc653 100644 --- a/reactos/drivers/usb/cromwell/host/ohci-hcd.c +++ b/reactos/drivers/usb/cromwell/host/ohci-hcd.c @@ -1,703 +1,705 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * - * [ Initialisation is based on Linus' ] - * [ uhci code and gregs ohci fragments ] - * [ (C) Copyright 1999 Linus Torvalds ] - * [ (C) Copyright 1999 Gregory P. Smith] - * - * - * OHCI is the main "non-Intel/VIA" standard for USB 1.1 host controller - * interfaces (though some non-x86 Intel chips use it). It supports - * smarter hardware than UHCI. A download link for the spec available - * through the http://www.usb.org website. - * - * History: - * - * 2003/02/24 show registers in sysfs (Kevin Brosius) - * - * 2002/09/03 get rid of ed hashtables, rework periodic scheduling and - * bandwidth accounting; if debugging, show schedules in driverfs - * 2002/07/19 fixes to management of ED and schedule state. - * 2002/06/09 SA-1111 support (Christopher Hoover) - * 2002/06/01 remember frame when HC won't see EDs any more; use that info - * to fix urb unlink races caused by interrupt latency assumptions; - * minor ED field and function naming updates - * 2002/01/18 package as a patch for 2.5.3; this should match the - * 2.4.17 kernel modulo some bugs being fixed. - * - * 2001/10/18 merge pmac cleanup (Benjamin Herrenschmidt) and bugfixes - * from post-2.4.5 patches. - * 2001/09/20 URB_ZERO_PACKET support; hcca_dma portability, OPTi warning - * 2001/09/07 match PCI PM changes, errnos from Linus' tree - * 2001/05/05 fork 2.4.5 version into "hcd" framework, cleanup, simplify; - * pbook pci quirks gone (please fix pbook pci sw!) (db) - * - * 2001/04/08 Identify version on module load (gb) - * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam); - pci_map_single (db) - * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db) - * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam) - * - * 2000/09/26 fixed races in removing the private portion of the urb - * 2000/09/07 disable bulk and control lists when unlinking the last - * endpoint descriptor in order to avoid unrecoverable errors on - * the Lucent chips. (rwc@sgi) - * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some - * urb unlink probs, indentation fixes - * 2000/08/11 various oops fixes mostly affecting iso and cleanup from - * device unplugs. - * 2000/06/28 use PCI hotplug framework, for better power management - * and for Cardbus support (David Brownell) - * 2000/earlier: fixes for NEC/Lucent chips; suspend/resume handling - * when the controller loses power; handle UE; cleanup; ... - * - * v5.2 1999/12/07 URB 3rd preview, - * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi) - * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume - * i386: HUB, Keyboard, Mouse, Printer - * - * v4.3 1999/10/27 multiple HCs, bulk_request - * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes - * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl. - * v4.0 1999/08/18 - * v3.0 1999/06/25 - * v2.1 1999/05/09 code clean up - * v2.0 1999/05/04 - * v1.0 1999/04/27 initial release - * - * This file is licenced under the GPL. - */ - -#if 0 -#include - -#ifdef CONFIG_USB_DEBUG -# define DEBUG -#else -# undef DEBUG -#endif - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for in_interrupt () */ -#include -#include "../core/hcd.h" - -#include -#include -#include -#include -#include -#else -#include "ohci_config.h" - -#include "../usb_wrapper.h" -#include "../core/hcd.h" - -//#define OHCI_VERBOSE_DEBUG -#endif - -/* - * TO DO: - * - * - "disabled" and "sleeping" should be in hcd->state - * - lots more testing!! - */ - -#define DRIVER_VERSION "2003 Feb 24" -#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell" -#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" - -/*-------------------------------------------------------------------------*/ - -// #define OHCI_VERBOSE_DEBUG /* not always helpful */ - -/* For initializing controller (mask in an HCFS mode too) */ -#define OHCI_CONTROL_INIT \ - (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE - -#define OHCI_UNLINK_TIMEOUT (HZ / 10) - -/*-------------------------------------------------------------------------*/ - -static const char hcd_name [] = "ohci-hcd"; - -#include "ohci.h" - -static inline void disable (struct ohci_hcd *ohci) -{ - ohci->disabled = 1; - ohci->hcd.state = USB_STATE_HALT; -} - -#include "ohci-hub.c" -#include "ohci-dbg.c" -#include "ohci-mem.c" -#include "ohci-q.c" - -/*-------------------------------------------------------------------------*/ - -/* - * queue up an urb for anything except the root hub - */ -static int ohci_urb_enqueue ( - struct usb_hcd *hcd, - struct urb *urb, - int mem_flags -) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - struct ed *ed; - urb_priv_t *urb_priv; - unsigned int pipe = urb->pipe; - int i, size = 0; - unsigned long flags; - int retval = 0; - -#ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "SUB", usb_pipein (pipe)); -#endif - - /* every endpoint has a ed, locate and maybe (re)initialize it */ - if (! (ed = ed_get (ohci, urb->dev, pipe, urb->interval))) - return -ENOMEM; - - /* for the private part of the URB we need the number of TDs (size) */ - switch (ed->type) { - case PIPE_CONTROL: - /* td_submit_urb() doesn't yet handle these */ - if (urb->transfer_buffer_length > 4096) - return -EMSGSIZE; - - /* 1 TD for setup, 1 for ACK, plus ... */ - size = 2; - /* FALLTHROUGH */ - // case PIPE_INTERRUPT: - // case PIPE_BULK: - default: - /* one TD for every 4096 Bytes (can be upto 8K) */ - size += urb->transfer_buffer_length / 4096; - /* ... and for any remaining bytes ... */ - if ((urb->transfer_buffer_length % 4096) != 0) - size++; - /* ... and maybe a zero length packet to wrap it up */ - if (size == 0) - size++; - else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0 - && (urb->transfer_buffer_length - % usb_maxpacket (urb->dev, pipe, - usb_pipeout (pipe))) == 0) - size++; - break; - case PIPE_ISOCHRONOUS: /* number of packets from URB */ - size = urb->number_of_packets; - break; - } - - /* allocate the private part of the URB */ - urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *), - mem_flags); - if (!urb_priv) - return -ENOMEM; - memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *)); - - /* fill the private part of the URB */ - urb_priv->length = size; - urb_priv->ed = ed; - - /* allocate the TDs (deferring hash chain updates) */ - for (i = 0; i < size; i++) { - urb_priv->td [i] = td_alloc (ohci, mem_flags); - if (!urb_priv->td [i]) { - urb_priv->length = i; - urb_free_priv (ohci, urb_priv); - return -ENOMEM; - } - } - - spin_lock_irqsave (&ohci->lock, flags); - - /* don't submit to a dead HC */ - if (ohci->disabled || ohci->sleeping) { - retval = -ENODEV; - goto fail; - } - - /* schedule the ed if needed */ - if (ed->state == ED_IDLE) { - retval = ed_schedule (ohci, ed); - if (retval < 0) - goto fail; - if (ed->type == PIPE_ISOCHRONOUS) { - u16 frame = le16_to_cpu (ohci->hcca->frame_no); - - /* delay a few frames before the first TD */ - frame += max_t (u16, 8, ed->interval); - frame &= ~(ed->interval - 1); - frame |= ed->branch; - urb->start_frame = frame; - - /* yes, only URB_ISO_ASAP is supported, and - * urb->start_frame is never used as input. - */ - } - } else if (ed->type == PIPE_ISOCHRONOUS) - urb->start_frame = ed->last_iso + ed->interval; - - /* fill the TDs and link them to the ed; and - * enable that part of the schedule, if needed - * and update count of queued periodic urbs - */ - urb->hcpriv = urb_priv; - td_submit_urb (ohci, urb); - -fail: - if (retval) - urb_free_priv (ohci, urb_priv); - spin_unlock_irqrestore (&ohci->lock, flags); - return retval; -} - -/* - * decouple the URB from the HC queues (TDs, urb_priv); it's - * already marked using urb->status. reporting is always done - * asynchronously, and we might be dealing with an urb that's - * partially transferred, or an ED with other urbs being unlinked. - */ -static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - unsigned long flags; - -#ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "UNLINK", 1); -#endif - - spin_lock_irqsave (&ohci->lock, flags); - if (!ohci->disabled) { - urb_priv_t *urb_priv; - - /* Unless an IRQ completed the unlink while it was being - * handed to us, flag it for unlink and giveback, and force - * some upcoming INTR_SF to call finish_unlinks() - */ - urb_priv = urb->hcpriv; - if (urb_priv) { - urb_priv->state = URB_DEL; - if (urb_priv->ed->state == ED_OPER) - start_urb_unlink (ohci, urb_priv->ed); - } - } else { - /* - * with HC dead, we won't respect hc queue pointers - * any more ... just clean up every urb's memory. - */ - if (urb->hcpriv) { - spin_unlock (&ohci->lock); - finish_urb (ohci, urb, NULL); - spin_lock (&ohci->lock); - } - } - spin_unlock_irqrestore (&ohci->lock, flags); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* frees config/altsetting state for endpoints, - * including ED memory, dummy TD, and bulk/intr data toggle - */ - -static void -ohci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int epnum = ep & USB_ENDPOINT_NUMBER_MASK; - unsigned long flags; - struct ed *ed; - - /* ASSERT: any requests/urbs are being unlinked */ - /* ASSERT: nobody can be submitting urbs for this any more */ - - epnum <<= 1; - if (epnum != 0 && !(ep & USB_DIR_IN)) - epnum |= 1; - -rescan: - spin_lock_irqsave (&ohci->lock, flags); - ed = dev->ep [epnum]; - if (!ed) - goto done; - - if (!HCD_IS_RUNNING (ohci->hcd.state) || ohci->disabled) - ed->state = ED_IDLE; - switch (ed->state) { - case ED_UNLINK: /* wait for hw to finish? */ - spin_unlock_irqrestore (&ohci->lock, flags); - set_current_state (TASK_UNINTERRUPTIBLE); - schedule_timeout (1); - goto rescan; - case ED_IDLE: /* fully unlinked */ - if (list_empty (&ed->td_list)) { - td_free (ohci, ed->dummy); - ed_free (ohci, ed); - break; - } - /* else FALL THROUGH */ - default: - /* caller was supposed to have unlinked any requests; - * that's not our job. can't recover; must leak ed. - */ - ohci_err (ohci, "ed %p (#%d) state %d%s\n", - ed, epnum, ed->state, - list_empty (&ed->td_list) ? "" : "(has tds)"); - td_free (ohci, ed->dummy); - break; - } - dev->ep [epnum] = 0; -done: - spin_unlock_irqrestore (&ohci->lock, flags); - return; -} - -static int ohci_get_frame (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - - return le16_to_cpu (ohci->hcca->frame_no); -} - -/*-------------------------------------------------------------------------* - * HC functions - *-------------------------------------------------------------------------*/ - -/* reset the HC and BUS */ - -static int hc_reset (struct ohci_hcd *ohci) -{ - u32 temp; - u32 ints; - u32 control; - - /* Disable HC interrupts */ - writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); - // acknowledge all pending interrupts - ints = readl(&ohci->regs->intrstatus); - writel (ints, &ohci->regs->intrstatus); - - if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { - // takeover without negotiation - there is noone to negotiate with - control = readl (&ohci->regs->control) & ~OHCI_CTRL_IR; - writel (control, &ohci->regs->control); - } - - ohci_dbg (ohci, "USB HC reset_hc %s: ctrl = 0x%x ;\n", - hcd_to_bus (&ohci->hcd)->bus_name, - readl (&ohci->regs->control)); - - /* Reset USB (needed by some controllers); RemoteWakeupConnected - * saved if boot firmware (BIOS/SMM/...) told us it's connected - */ - ohci->hc_control = readl (&ohci->regs->control); - ohci->hc_control &= OHCI_CTRL_RWC; /* hcfs 0 = RESET */ - writel (ohci->hc_control, &ohci->regs->control); - // flush those pci writes - (void) readl (&ohci->regs->control); - wait_ms (50); - - /* HC Reset requires max 10 us delay */ - writel (OHCI_HCR, &ohci->regs->cmdstatus); - temp = 30; /* ... allow extra time */ - while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) { - if (--temp == 0) { - ohci_err (ohci, "USB HC reset timed out!\n"); - return -1; - } - udelay (1); - } - - /* now we're in the SUSPEND state ... must go OPERATIONAL - * within 2msec else HC enters RESUME - * - * ... but some hardware won't init fmInterval "by the book" - * (SiS, OPTi ...), so reset again instead. SiS doesn't need - * this if we write fmInterval after we're OPERATIONAL. - */ - writel (ohci->hc_control, &ohci->regs->control); - // flush those pci writes - (void) readl (&ohci->regs->control); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -#define FI 0x2edf /* 12000 bits per frame (-1) */ -#define LSTHRESH 0x628 /* lowspeed bit threshold */ - -/* Start an OHCI controller, set the BUS operational - * enable interrupts - * connect the virtual root hub - */ -static int hc_start (struct ohci_hcd *ohci) -{ - u32 mask, tmp; - struct usb_device *udev; - struct usb_bus *bus; - - spin_lock_init (&ohci->lock); - ohci->disabled = 1; - ohci->sleeping = 0; - - /* Tell the controller where the control and bulk lists are - * The lists are empty now. */ - writel (0, &ohci->regs->ed_controlhead); - writel (0, &ohci->regs->ed_bulkhead); - - /* a reset clears this */ - writel ((u32) ohci->hcca_dma, &ohci->regs->hcca); - usbprintk("HCCA: %p \n",ohci->regs->hcca); - - /* force default fmInterval (we won't adjust it); init thresholds - * for last FS and LS packets, reserve 90% for periodic. - */ - writel ((((6 * (FI - 210)) / 7) << 16) | FI, &ohci->regs->fminterval); - writel (((9 * FI) / 10) & 0x3fff, &ohci->regs->periodicstart); - writel (LSTHRESH, &ohci->regs->lsthresh); - - /* some OHCI implementations are finicky about how they init. - * bogus values here mean not even enumeration could work. - */ - if ((readl (&ohci->regs->fminterval) & 0x3fff0000) == 0 - || !readl (&ohci->regs->periodicstart)) { - ohci_err (ohci, "init err\n"); - return -EOVERFLOW; - } - - /* start controller operations */ - ohci->hc_control &= OHCI_CTRL_RWC; - ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; - ohci->disabled = 0; - writel (ohci->hc_control, &ohci->regs->control); - - /* Choose the interrupts we care about now, others later on demand */ - mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH; - writel (mask, &ohci->regs->intrstatus); - writel (mask, &ohci->regs->intrenable); - - /* handle root hub init quirks ... */ - tmp = roothub_a (ohci); - tmp &= ~(RH_A_PSM | RH_A_OCPM); - if (ohci->flags & OHCI_QUIRK_SUPERIO) { - /* NSC 87560 and maybe others */ - tmp |= RH_A_NOCP; - tmp &= ~(RH_A_POTPGT | RH_A_NPS); - } else { - /* hub power always on; required for AMD-756 and some - * Mac platforms, use this mode everywhere by default - */ - tmp |= RH_A_NPS; - } - writel (tmp, &ohci->regs->roothub.a); - writel (RH_HS_LPSC, &ohci->regs->roothub.status); - writel (0, &ohci->regs->roothub.b); - // flush those pci writes - (void) readl (&ohci->regs->control); - - // POTPGT delay is bits 24-31, in 2 ms units. - mdelay ((roothub_a (ohci) >> 23) & 0x1fe); - - /* connect the virtual root hub */ - bus = hcd_to_bus (&ohci->hcd); - bus->root_hub = udev = usb_alloc_dev (NULL, bus); - ohci->hcd.state = USB_STATE_READY; - if (!udev) { - disable (ohci); - ohci->hc_control &= ~OHCI_CTRL_HCFS; - writel (ohci->hc_control, &ohci->regs->control); - ohci_err(ohci,"out of mem"); - return -ENOMEM; - } - - usb_connect (udev); - udev->speed = USB_SPEED_FULL; - if (hcd_register_root (&ohci->hcd) != 0) { - usb_put_dev (udev); - bus->root_hub = NULL; - disable (ohci); - ohci->hc_control &= ~OHCI_CTRL_HCFS; - writel (ohci->hc_control, &ohci->regs->control); - return -ENODEV; - } - create_debug_files (ohci); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* an interrupt happens */ - -static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - struct ohci_regs *regs = ohci->regs; - int ints; - - /* we can eliminate a (slow) readl() if _only_ WDH caused this irq */ - if ((ohci->hcca->done_head != 0) - && ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) { - ints = OHCI_INTR_WDH; - - /* cardbus/... hardware gone before remove() */ - } else if ((ints = readl (®s->intrstatus)) == ~(u32)0) { - disable (ohci); - ohci_dbg (ohci, "device removed!\n"); - return; - - /* interrupt for some other device? */ - } else if ((ints &= readl (®s->intrenable)) == 0) { - return; - } - - if (ints & OHCI_INTR_UE) { - disable (ohci); - ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n"); - // e.g. due to PCI Master/Target Abort - - ohci_dump (ohci, 1); - hc_reset (ohci); - } - - if (ints & OHCI_INTR_WDH) { - writel (OHCI_INTR_WDH, ®s->intrdisable); - dl_done_list (ohci, dl_reverse_done_list (ohci), ptregs); - writel (OHCI_INTR_WDH, ®s->intrenable); - } - - /* could track INTR_SO to reduce available PCI/... bandwidth */ - - /* handle any pending URB/ED unlinks, leaving INTR_SF enabled - * when there's still unlinking to be done (next frame). - */ - spin_lock (&ohci->lock); - if (ohci->ed_rm_list) - finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no), - ptregs); - if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list) - writel (OHCI_INTR_SF, ®s->intrdisable); - spin_unlock (&ohci->lock); - - writel (ints, ®s->intrstatus); - writel (OHCI_INTR_MIE, ®s->intrenable); - // flush those pci writes - (void) readl (&ohci->regs->control); -} - -/*-------------------------------------------------------------------------*/ - -static void ohci_stop (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - struct ohci_regs *regs = ohci->regs; - int ints; - - ohci_dbg (ohci, "stop %s controller%s\n", - hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), - ohci->disabled ? " (disabled)" : "" - ); - ohci_dump (ohci, 1); - - if (!ohci->disabled) - hc_reset (ohci); - - // Disable all interrupts - writel (OHCI_INTR_MIE, ®s->intrdisable); - // acknowledge all pending interrupts - ints = readl(®s->intrstatus); - writel (ints, ®s->intrstatus); - // flush register writes - (void) readl (&ohci->regs->control); - - remove_debug_files (ohci); - ohci_mem_cleanup (ohci); - if (ohci->hcca) { - pci_free_consistent (ohci->hcd.pdev, sizeof *ohci->hcca, - ohci->hcca, ohci->hcca_dma); - ohci->hcca = NULL; - ohci->hcca_dma = 0; - } -} - -/*-------------------------------------------------------------------------*/ - -// FIXME: this restart logic should be generic, -// and handle full hcd state cleanup - -/* controller died; cleanup debris, then restart */ -/* must not be called from interrupt context */ - -#ifdef CONFIG_PM -static int hc_restart (struct ohci_hcd *ohci) -{ - int temp; - int i; - - ohci->disabled = 1; - ohci->sleeping = 0; - if (hcd_to_bus (&ohci->hcd)->root_hub) - usb_disconnect (&hcd_to_bus (&ohci->hcd)->root_hub); - - /* empty the interrupt branches */ - for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0; - for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0; - - /* no EDs to remove */ - ohci->ed_rm_list = NULL; - - /* empty control and bulk lists */ - ohci->ed_controltail = NULL; - ohci->ed_bulktail = NULL; - - if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) { - ohci_err (ohci, "can't restart, %d\n", temp); - return temp; - } else - ohci_dbg (ohci, "restart complete\n"); - return 0; -} -#endif - -/*-------------------------------------------------------------------------*/ - -#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC - -MODULE_AUTHOR (DRIVER_AUTHOR); -MODULE_DESCRIPTION (DRIVER_INFO); -MODULE_LICENSE ("GPL"); - -#ifdef CONFIG_PCI -#include "ohci-pci.c" -#endif - -#ifdef CONFIG_SA1111 -#include "ohci-sa1111.c" -#endif - -#if !(defined(CONFIG_PCI) || defined(CONFIG_SA1111)) -#error "missing bus glue for ohci-hcd" -#endif +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * + * [ Initialisation is based on Linus' ] + * [ uhci code and gregs ohci fragments ] + * [ (C) Copyright 1999 Linus Torvalds ] + * [ (C) Copyright 1999 Gregory P. Smith] + * + * + * OHCI is the main "non-Intel/VIA" standard for USB 1.1 host controller + * interfaces (though some non-x86 Intel chips use it). It supports + * smarter hardware than UHCI. A download link for the spec available + * through the http://www.usb.org website. + * + * History: + * + * 2003/02/24 show registers in sysfs (Kevin Brosius) + * + * 2002/09/03 get rid of ed hashtables, rework periodic scheduling and + * bandwidth accounting; if debugging, show schedules in driverfs + * 2002/07/19 fixes to management of ED and schedule state. + * 2002/06/09 SA-1111 support (Christopher Hoover) + * 2002/06/01 remember frame when HC won't see EDs any more; use that info + * to fix urb unlink races caused by interrupt latency assumptions; + * minor ED field and function naming updates + * 2002/01/18 package as a patch for 2.5.3; this should match the + * 2.4.17 kernel modulo some bugs being fixed. + * + * 2001/10/18 merge pmac cleanup (Benjamin Herrenschmidt) and bugfixes + * from post-2.4.5 patches. + * 2001/09/20 URB_ZERO_PACKET support; hcca_dma portability, OPTi warning + * 2001/09/07 match PCI PM changes, errnos from Linus' tree + * 2001/05/05 fork 2.4.5 version into "hcd" framework, cleanup, simplify; + * pbook pci quirks gone (please fix pbook pci sw!) (db) + * + * 2001/04/08 Identify version on module load (gb) + * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam); + pci_map_single (db) + * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db) + * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam) + * + * 2000/09/26 fixed races in removing the private portion of the urb + * 2000/09/07 disable bulk and control lists when unlinking the last + * endpoint descriptor in order to avoid unrecoverable errors on + * the Lucent chips. (rwc@sgi) + * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some + * urb unlink probs, indentation fixes + * 2000/08/11 various oops fixes mostly affecting iso and cleanup from + * device unplugs. + * 2000/06/28 use PCI hotplug framework, for better power management + * and for Cardbus support (David Brownell) + * 2000/earlier: fixes for NEC/Lucent chips; suspend/resume handling + * when the controller loses power; handle UE; cleanup; ... + * + * v5.2 1999/12/07 URB 3rd preview, + * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi) + * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume + * i386: HUB, Keyboard, Mouse, Printer + * + * v4.3 1999/10/27 multiple HCs, bulk_request + * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes + * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl. + * v4.0 1999/08/18 + * v3.0 1999/06/25 + * v2.1 1999/05/09 code clean up + * v2.0 1999/05/04 + * v1.0 1999/04/27 initial release + * + * This file is licenced under the GPL. + */ + +#if 0 +#include + +#ifdef CONFIG_USB_DEBUG +# define DEBUG +#else +# undef DEBUG +#endif + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for in_interrupt () */ +#include +#include "../core/hcd.h" + +#include +#include +#include +#include +#include +#else +#include "ohci_config.h" + +#include "../usb_wrapper.h" +#include "../core/hcd.h" + +//#define OHCI_VERBOSE_DEBUG +#endif + +/* + * TO DO: + * + * - "disabled" and "sleeping" should be in hcd->state + * - lots more testing!! + */ + +#define DRIVER_VERSION "2003 Feb 24" +#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell" +#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" + +/*-------------------------------------------------------------------------*/ + +// #define OHCI_VERBOSE_DEBUG /* not always helpful */ + +/* For initializing controller (mask in an HCFS mode too) */ +#define OHCI_CONTROL_INIT \ + (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE + +#define OHCI_UNLINK_TIMEOUT (HZ / 10) + +/*-------------------------------------------------------------------------*/ + +static const char hcd_name [] = "ohci-hcd"; + +#include "ohci.h" + +static inline void disable (struct ohci_hcd *ohci) +{ + ohci->disabled = 1; + ohci->hcd.state = USB_STATE_HALT; +} + +#include "ohci-hub.c" +#include "ohci-dbg.c" +#include "ohci-mem.c" +#include "ohci-q.c" + +/*-------------------------------------------------------------------------*/ + +/* + * queue up an urb for anything except the root hub + */ +static int ohci_urb_enqueue ( + struct usb_hcd *hcd, + struct urb *urb, + int mem_flags +) { + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + struct ed *ed; + urb_priv_t *urb_priv; + unsigned int pipe = urb->pipe; + int i, size = 0; + unsigned long flags; + int retval = 0; + +#ifdef OHCI_VERBOSE_DEBUG + urb_print (urb, "SUB", usb_pipein (pipe)); +#endif + + /* every endpoint has a ed, locate and maybe (re)initialize it */ + if (! (ed = ed_get (ohci, urb->dev, pipe, urb->interval))) + return -ENOMEM; + + /* for the private part of the URB we need the number of TDs (size) */ + switch (ed->type) { + case PIPE_CONTROL: + /* td_submit_urb() doesn't yet handle these */ + if (urb->transfer_buffer_length > 4096) + return -EMSGSIZE; + + /* 1 TD for setup, 1 for ACK, plus ... */ + size = 2; + /* FALLTHROUGH */ + // case PIPE_INTERRUPT: + // case PIPE_BULK: + default: + /* one TD for every 4096 Bytes (can be upto 8K) */ + size += urb->transfer_buffer_length / 4096; + /* ... and for any remaining bytes ... */ + if ((urb->transfer_buffer_length % 4096) != 0) + size++; + /* ... and maybe a zero length packet to wrap it up */ + if (size == 0) + size++; + else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0 + && (urb->transfer_buffer_length + % usb_maxpacket (urb->dev, pipe, + usb_pipeout (pipe))) == 0) + size++; + break; + case PIPE_ISOCHRONOUS: /* number of packets from URB */ + size = urb->number_of_packets; + break; + } + + /* allocate the private part of the URB */ + urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *), + mem_flags); + if (!urb_priv) + return -ENOMEM; + memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *)); + + /* fill the private part of the URB */ + urb_priv->length = size; + urb_priv->ed = ed; + + /* allocate the TDs (deferring hash chain updates) */ + for (i = 0; i < size; i++) { + urb_priv->td [i] = td_alloc (ohci, mem_flags); + if (!urb_priv->td [i]) { + urb_priv->length = i; + urb_free_priv (ohci, urb_priv); + return -ENOMEM; + } + } + + spin_lock_irqsave (&ohci->lock, flags); + + /* don't submit to a dead HC */ + if (ohci->disabled || ohci->sleeping) { + retval = -ENODEV; + goto fail; + } + + /* schedule the ed if needed */ + if (ed->state == ED_IDLE) { + retval = ed_schedule (ohci, ed); + if (retval < 0) + goto fail; + if (ed->type == PIPE_ISOCHRONOUS) { + u16 frame = le16_to_cpu (ohci->hcca->frame_no); + + /* delay a few frames before the first TD */ + frame += max_t (u16, 8, ed->interval); + frame &= ~(ed->interval - 1); + frame |= ed->branch; + urb->start_frame = frame; + + /* yes, only URB_ISO_ASAP is supported, and + * urb->start_frame is never used as input. + */ + } + } else if (ed->type == PIPE_ISOCHRONOUS) + urb->start_frame = ed->last_iso + ed->interval; + + /* fill the TDs and link them to the ed; and + * enable that part of the schedule, if needed + * and update count of queued periodic urbs + */ + urb->hcpriv = urb_priv; + td_submit_urb (ohci, urb); + +fail: + if (retval) + urb_free_priv (ohci, urb_priv); + spin_unlock_irqrestore (&ohci->lock, flags); + return retval; +} + +/* + * decouple the URB from the HC queues (TDs, urb_priv); it's + * already marked using urb->status. reporting is always done + * asynchronously, and we might be dealing with an urb that's + * partially transferred, or an ED with other urbs being unlinked. + */ +static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + unsigned long flags; + +#ifdef OHCI_VERBOSE_DEBUG + urb_print (urb, "UNLINK", 1); +#endif + + spin_lock_irqsave (&ohci->lock, flags); + if (!ohci->disabled) { + urb_priv_t *urb_priv; + + /* Unless an IRQ completed the unlink while it was being + * handed to us, flag it for unlink and giveback, and force + * some upcoming INTR_SF to call finish_unlinks() + */ + urb_priv = urb->hcpriv; + if (urb_priv) { + urb_priv->state = URB_DEL; + if (urb_priv->ed->state == ED_OPER) + start_urb_unlink (ohci, urb_priv->ed); + } + } else { + /* + * with HC dead, we won't respect hc queue pointers + * any more ... just clean up every urb's memory. + */ + if (urb->hcpriv) { + spin_unlock (&ohci->lock); + finish_urb (ohci, urb, NULL); + spin_lock (&ohci->lock); + } + } + spin_unlock_irqrestore (&ohci->lock, flags); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* frees config/altsetting state for endpoints, + * including ED memory, dummy TD, and bulk/intr data toggle + */ + +static void +ohci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int epnum = ep & USB_ENDPOINT_NUMBER_MASK; + unsigned long flags; + struct ed *ed; + + /* ASSERT: any requests/urbs are being unlinked */ + /* ASSERT: nobody can be submitting urbs for this any more */ + + epnum <<= 1; + if (epnum != 0 && !(ep & USB_DIR_IN)) + epnum |= 1; + +rescan: + spin_lock_irqsave (&ohci->lock, flags); + ed = dev->ep [epnum]; + if (!ed) + goto done; + + if (!HCD_IS_RUNNING (ohci->hcd.state) || ohci->disabled) + ed->state = ED_IDLE; + switch (ed->state) { + case ED_UNLINK: /* wait for hw to finish? */ + spin_unlock_irqrestore (&ohci->lock, flags); + set_current_state (TASK_UNINTERRUPTIBLE); + schedule_timeout (1); + goto rescan; + case ED_IDLE: /* fully unlinked */ + if (list_empty (&ed->td_list)) { + td_free (ohci, ed->dummy); + ed_free (ohci, ed); + break; + } + /* else FALL THROUGH */ + default: + /* caller was supposed to have unlinked any requests; + * that's not our job. can't recover; must leak ed. + */ + ohci_err (ohci, "ed %p (#%d) state %d%s\n", + ed, epnum, ed->state, + list_empty (&ed->td_list) ? "" : "(has tds)"); + td_free (ohci, ed->dummy); + break; + } + dev->ep [epnum] = 0; +done: + spin_unlock_irqrestore (&ohci->lock, flags); + return; +} + +static int ohci_get_frame (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + + return le16_to_cpu (ohci->hcca->frame_no); +} + +/*-------------------------------------------------------------------------* + * HC functions + *-------------------------------------------------------------------------*/ + +/* reset the HC and BUS */ + +static int hc_reset (struct ohci_hcd *ohci) +{ + u32 temp; + u32 ints; + u32 control; + + /* Disable HC interrupts */ + writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); + // acknowledge all pending interrupts + ints = readl(&ohci->regs->intrstatus); + writel (ints, &ohci->regs->intrstatus); + + if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { + // takeover without negotiation - there is noone to negotiate with + control = readl (&ohci->regs->control) & ~OHCI_CTRL_IR; + writel (control, &ohci->regs->control); + } + + ohci_dbg (ohci, "USB HC reset_hc %s: ctrl = 0x%x ;\n", + hcd_to_bus (&ohci->hcd)->bus_name, + readl (&ohci->regs->control)); + + /* Reset USB (needed by some controllers); RemoteWakeupConnected + * saved if boot firmware (BIOS/SMM/...) told us it's connected + */ + ohci->hc_control = readl (&ohci->regs->control); + ohci->hc_control &= OHCI_CTRL_RWC; /* hcfs 0 = RESET */ + writel (ohci->hc_control, &ohci->regs->control); + // flush those pci writes + (void) readl (&ohci->regs->control); + wait_ms (50); + + /* HC Reset requires max 10 us delay */ + writel (OHCI_HCR, &ohci->regs->cmdstatus); + temp = 30; /* ... allow extra time */ + while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) { + if (--temp == 0) { + ohci_err (ohci, "USB HC reset timed out!\n"); + return -1; + } + udelay (1); + } + + /* now we're in the SUSPEND state ... must go OPERATIONAL + * within 2msec else HC enters RESUME + * + * ... but some hardware won't init fmInterval "by the book" + * (SiS, OPTi ...), so reset again instead. SiS doesn't need + * this if we write fmInterval after we're OPERATIONAL. + */ + writel (ohci->hc_control, &ohci->regs->control); + // flush those pci writes + (void) readl (&ohci->regs->control); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +#define FI 0x2edf /* 12000 bits per frame (-1) */ +#define LSTHRESH 0x628 /* lowspeed bit threshold */ + +/* Start an OHCI controller, set the BUS operational + * enable interrupts + * connect the virtual root hub + */ +static int hc_start (struct ohci_hcd *ohci) +{ + u32 mask, tmp; + struct usb_device *udev; + struct usb_bus *bus; + + spin_lock_init (&ohci->lock); + ohci->disabled = 1; + ohci->sleeping = 0; + + /* Tell the controller where the control and bulk lists are + * The lists are empty now. */ + writel (0, &ohci->regs->ed_controlhead); + writel (0, &ohci->regs->ed_bulkhead); + + /* a reset clears this */ + writel ((u32) ohci->hcca_dma, &ohci->regs->hcca); + usbprintk("HCCA: %p \n",ohci->regs->hcca); + + /* force default fmInterval (we won't adjust it); init thresholds + * for last FS and LS packets, reserve 90% for periodic. + */ + writel ((((6 * (FI - 210)) / 7) << 16) | FI, &ohci->regs->fminterval); + writel (((9 * FI) / 10) & 0x3fff, &ohci->regs->periodicstart); + writel (LSTHRESH, &ohci->regs->lsthresh); + + /* some OHCI implementations are finicky about how they init. + * bogus values here mean not even enumeration could work. + */ + if ((readl (&ohci->regs->fminterval) & 0x3fff0000) == 0 + || !readl (&ohci->regs->periodicstart)) { + ohci_err (ohci, "init err\n"); + return -EOVERFLOW; + } + + /* start controller operations */ + ohci->hc_control &= OHCI_CTRL_RWC; + ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; + ohci->disabled = 0; + writel (ohci->hc_control, &ohci->regs->control); + + /* Choose the interrupts we care about now, others later on demand */ + mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH; + writel (mask, &ohci->regs->intrstatus); + writel (mask, &ohci->regs->intrenable); + + /* handle root hub init quirks ... */ + tmp = roothub_a (ohci); + tmp &= ~(RH_A_PSM | RH_A_OCPM); + if (ohci->flags & OHCI_QUIRK_SUPERIO) { + /* NSC 87560 and maybe others */ + tmp |= RH_A_NOCP; + tmp &= ~(RH_A_POTPGT | RH_A_NPS); + } else { + /* hub power always on; required for AMD-756 and some + * Mac platforms, use this mode everywhere by default + */ + tmp |= RH_A_NPS; + } + writel (tmp, &ohci->regs->roothub.a); + writel (RH_HS_LPSC, &ohci->regs->roothub.status); + writel (0, &ohci->regs->roothub.b); + // flush those pci writes + (void) readl (&ohci->regs->control); + + // POTPGT delay is bits 24-31, in 2 ms units. + mdelay (((int)(roothub_a (ohci) >> 23) & 0x1fe)); + + /* connect the virtual root hub */ + bus = hcd_to_bus (&ohci->hcd); + bus->root_hub = udev = usb_alloc_dev (NULL, bus); + ohci->hcd.state = USB_STATE_READY; + if (!udev) { + disable (ohci); + ohci->hc_control &= ~OHCI_CTRL_HCFS; + writel (ohci->hc_control, &ohci->regs->control); + ohci_err(ohci,"out of mem"); + return -ENOMEM; + } + + usb_connect (udev); + udev->speed = USB_SPEED_FULL; + if (hcd_register_root (&ohci->hcd) != 0) { + usb_put_dev (udev); + bus->root_hub = NULL; + disable (ohci); + ohci->hc_control &= ~OHCI_CTRL_HCFS; + writel (ohci->hc_control, &ohci->regs->control); + return -ENODEV; + } + create_debug_files (ohci); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* an interrupt happens */ + +static +int ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + struct ohci_regs *regs = ohci->regs; + int ints; + + /* we can eliminate a (slow) readl() if _only_ WDH caused this irq */ + if ((ohci->hcca->done_head != 0) + && ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) { + ints = OHCI_INTR_WDH; + + /* cardbus/... hardware gone before remove() */ + } else if ((ints = readl (®s->intrstatus)) == ~(u32)0) { + disable (ohci); + ohci_dbg (ohci, "device removed!\n"); + return 0; + + /* interrupt for some other device? */ + } else if ((ints &= readl (®s->intrenable)) == 0) { + return 0; + } + + if (ints & OHCI_INTR_UE) { + disable (ohci); + ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n"); + // e.g. due to PCI Master/Target Abort + + ohci_dump (ohci, 1); + hc_reset (ohci); + } + + if (ints & OHCI_INTR_WDH) { + writel (OHCI_INTR_WDH, ®s->intrdisable); + dl_done_list (ohci, dl_reverse_done_list (ohci), ptregs); + writel (OHCI_INTR_WDH, ®s->intrenable); + } + + /* could track INTR_SO to reduce available PCI/... bandwidth */ + + /* handle any pending URB/ED unlinks, leaving INTR_SF enabled + * when there's still unlinking to be done (next frame). + */ + spin_lock (&ohci->lock); + if (ohci->ed_rm_list) + finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no), + ptregs); + if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list) + writel (OHCI_INTR_SF, ®s->intrdisable); + spin_unlock (&ohci->lock); + + writel (ints, ®s->intrstatus); + writel (OHCI_INTR_MIE, ®s->intrenable); + // flush those pci writes + (void) readl (&ohci->regs->control); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static void ohci_stop (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + struct ohci_regs *regs = ohci->regs; + int ints; + + ohci_dbg (ohci, "stop %s controller%s\n", + hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), + ohci->disabled ? " (disabled)" : "" + ); + ohci_dump (ohci, 1); + + if (!ohci->disabled) + hc_reset (ohci); + + // Disable all interrupts + writel (OHCI_INTR_MIE, ®s->intrdisable); + // acknowledge all pending interrupts + ints = readl(®s->intrstatus); + writel (ints, ®s->intrstatus); + // flush register writes + (void) readl (&ohci->regs->control); + + remove_debug_files (ohci); + ohci_mem_cleanup (ohci); + if (ohci->hcca) { + pci_free_consistent (ohci->hcd.pdev, sizeof *ohci->hcca, + ohci->hcca, ohci->hcca_dma); + ohci->hcca = NULL; + ohci->hcca_dma = 0; + } +} + +/*-------------------------------------------------------------------------*/ + +// FIXME: this restart logic should be generic, +// and handle full hcd state cleanup + +/* controller died; cleanup debris, then restart */ +/* must not be called from interrupt context */ + +#ifdef CONFIG_PM +static int hc_restart (struct ohci_hcd *ohci) +{ + int temp; + int i; + + ohci->disabled = 1; + ohci->sleeping = 0; + if (hcd_to_bus (&ohci->hcd)->root_hub) + usb_disconnect (&hcd_to_bus (&ohci->hcd)->root_hub); + + /* empty the interrupt branches */ + for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0; + for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0; + + /* no EDs to remove */ + ohci->ed_rm_list = NULL; + + /* empty control and bulk lists */ + ohci->ed_controltail = NULL; + ohci->ed_bulktail = NULL; + + if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) { + ohci_err (ohci, "can't restart, %d\n", temp); + return temp; + } else + ohci_dbg (ohci, "restart complete\n"); + return 0; +} +#endif + +/*-------------------------------------------------------------------------*/ + +#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC + +MODULE_AUTHOR (DRIVER_AUTHOR); +MODULE_DESCRIPTION (DRIVER_INFO); +MODULE_LICENSE ("GPL"); + +#ifdef CONFIG_PCI +#include "ohci-pci.c" +#endif + +#ifdef CONFIG_SA1111 +#include "ohci-sa1111.c" +#endif + +#if !(defined(CONFIG_PCI) || defined(CONFIG_SA1111)) +#error "missing bus glue for ohci-hcd" +#endif diff --git a/reactos/drivers/usb/cromwell/host/ohci-hub.c b/reactos/drivers/usb/cromwell/host/ohci-hub.c index 03be82741e0..a7584a499af 100644 --- a/reactos/drivers/usb/cromwell/host/ohci-hub.c +++ b/reactos/drivers/usb/cromwell/host/ohci-hub.c @@ -1,271 +1,271 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * - * This file is licenced under GPL - */ - -/*-------------------------------------------------------------------------*/ - -/* - * OHCI Root Hub ... the nonsharable stuff - * - * Registers don't need cpu_to_le32, that happens transparently - */ - -/* AMD-756 (D2 rev) reports corrupt register contents in some cases. - * The erratum (#4) description is incorrect. AMD's workaround waits - * till some bits (mostly reserved) are clear; ok for all revs. - */ -#define read_roothub(hc, register, mask) ({ \ - u32 temp = readl (&hc->regs->roothub.register); \ - if (temp == -1) \ - disable (hc); \ - else if (hc->flags & OHCI_QUIRK_AMD756) \ - while (temp & mask) \ - temp = readl (&hc->regs->roothub.register); \ - temp; }) - -static u32 roothub_a (struct ohci_hcd *hc) - { return read_roothub (hc, a, 0xfc0fe000); } -static inline u32 roothub_b (struct ohci_hcd *hc) - { return readl (&hc->regs->roothub.b); } -static inline u32 roothub_status (struct ohci_hcd *hc) - { return readl (&hc->regs->roothub.status); } -static u32 roothub_portstatus (struct ohci_hcd *hc, int i) - { return read_roothub (hc, portstatus [i], 0xffe0fce0); } - -/*-------------------------------------------------------------------------*/ - -#define dbg_port(hc,label,num,value) \ - ohci_dbg (hc, \ - "%s roothub.portstatus [%d] " \ - "= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \ - label, num, temp, \ - (temp & RH_PS_PRSC) ? " PRSC" : "", \ - (temp & RH_PS_OCIC) ? " OCIC" : "", \ - (temp & RH_PS_PSSC) ? " PSSC" : "", \ - (temp & RH_PS_PESC) ? " PESC" : "", \ - (temp & RH_PS_CSC) ? " CSC" : "", \ - \ - (temp & RH_PS_LSDA) ? " LSDA" : "", \ - (temp & RH_PS_PPS) ? " PPS" : "", \ - (temp & RH_PS_PRS) ? " PRS" : "", \ - (temp & RH_PS_POCI) ? " POCI" : "", \ - (temp & RH_PS_PSS) ? " PSS" : "", \ - \ - (temp & RH_PS_PES) ? " PES" : "", \ - (temp & RH_PS_CCS) ? " CCS" : "" \ - ); - - -/*-------------------------------------------------------------------------*/ - -/* build "status change" packet (one or two bytes) from HC registers */ - -static int -ohci_hub_status_data (struct usb_hcd *hcd, char *buf) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ports, i, changed = 0, length = 1; - - ports = roothub_a (ohci) & RH_A_NDP; - if (ports > MAX_ROOT_PORTS) { - if (ohci->disabled) - return -ESHUTDOWN; - ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", - ports, readl (&ohci->regs->roothub.a) & RH_A_NDP); - /* retry later; "should not happen" */ - return 0; - } - - /* init status */ - if (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC)) - buf [0] = changed = 1; - else - buf [0] = 0; - if (ports > 7) { - buf [1] = 0; - length++; - } - - /* look at each port */ - for (i = 0; i < ports; i++) { - u32 status = roothub_portstatus (ohci, i); - - status &= RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC - | RH_PS_OCIC | RH_PS_PRSC; - if (status) { - changed = 1; - if (i < 7) - buf [0] |= 1 << (i + 1); - else - buf [1] |= 1 << (i - 7); - } - } - return changed ? length : 0; -} - -/*-------------------------------------------------------------------------*/ - -static void -ohci_hub_descriptor ( - struct ohci_hcd *ohci, - struct usb_hub_descriptor *desc -) { - u32 rh = roothub_a (ohci); - int ports = rh & RH_A_NDP; - u16 temp; - - desc->bDescriptorType = 0x29; - desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24; - desc->bHubContrCurrent = 0; - - desc->bNbrPorts = ports; - temp = 1 + (ports / 8); - desc->bDescLength = 7 + 2 * temp; - - temp = 0; - if (rh & RH_A_PSM) /* per-port power switching? */ - temp |= 0x0001; - if (rh & RH_A_NOCP) /* no overcurrent reporting? */ - temp |= 0x0010; - else if (rh & RH_A_OCPM) /* per-port overcurrent reporting? */ - temp |= 0x0008; - desc->wHubCharacteristics = cpu_to_le16 (temp); - - /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ - rh = roothub_b (ohci); - desc->bitmap [0] = rh & RH_B_DR; - if (ports > 7) { - desc->bitmap [1] = (rh & RH_B_DR) >> 8; - desc->bitmap [2] = desc->bitmap [3] = 0xff; - } else - desc->bitmap [1] = 0xff; -} - -/*-------------------------------------------------------------------------*/ - -static int ohci_hub_control ( - struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, - u16 wIndex, - char *buf, - u16 wLength -) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ports = hcd_to_bus (hcd)->root_hub->maxchild; - u32 temp; - int retval = 0; - - switch (typeReq) { - case ClearHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - writel (RH_HS_OCIC, &ohci->regs->roothub.status); - case C_HUB_LOCAL_POWER: - break; - default: - goto error; - } - break; - case ClearPortFeature: - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - temp = RH_PS_CCS; - break; - case USB_PORT_FEAT_C_ENABLE: - temp = RH_PS_PESC; - break; - case USB_PORT_FEAT_SUSPEND: - temp = RH_PS_POCI; - break; - case USB_PORT_FEAT_C_SUSPEND: - temp = RH_PS_PSSC; - break; - case USB_PORT_FEAT_POWER: - temp = RH_PS_LSDA; - break; - case USB_PORT_FEAT_C_CONNECTION: - temp = RH_PS_CSC; - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - temp = RH_PS_OCIC; - break; - case USB_PORT_FEAT_C_RESET: - temp = RH_PS_PRSC; - break; - default: - goto error; - } - writel (temp, &ohci->regs->roothub.portstatus [wIndex]); - // readl (&ohci->regs->roothub.portstatus [wIndex]); - break; - case GetHubDescriptor: - ohci_hub_descriptor (ohci, (struct usb_hub_descriptor *) buf); - break; - case GetHubStatus: - temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE); - *(u32 *) buf = cpu_to_le32 (temp); - break; - case GetPortStatus: - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - temp = roothub_portstatus (ohci, wIndex); - *(u32 *) buf = cpu_to_le32 (temp); - -#ifndef OHCI_VERBOSE_DEBUG - if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ -#endif - dbg_port (ohci, "GetStatus", wIndex + 1, temp); - break; - case SetHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - // FIXME: this can be cleared, yes? - case C_HUB_LOCAL_POWER: - break; - default: - goto error; - } - break; - case SetPortFeature: - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - writel (RH_PS_PSS, - &ohci->regs->roothub.portstatus [wIndex]); - break; - case USB_PORT_FEAT_POWER: - writel (RH_PS_PPS, - &ohci->regs->roothub.portstatus [wIndex]); - break; - case USB_PORT_FEAT_RESET: - temp = readl (&ohci->regs->roothub.portstatus [wIndex]); - if (temp & RH_PS_CCS) - writel (RH_PS_PRS, - &ohci->regs->roothub.portstatus [wIndex]); - break; - default: - goto error; - } - break; - - default: -error: - /* "protocol stall" on error */ - retval = -EPIPE; - } - return retval; -} - +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * + * This file is licenced under GPL + */ + +/*-------------------------------------------------------------------------*/ + +/* + * OHCI Root Hub ... the nonsharable stuff + * + * Registers don't need cpu_to_le32, that happens transparently + */ + +/* AMD-756 (D2 rev) reports corrupt register contents in some cases. + * The erratum (#4) description is incorrect. AMD's workaround waits + * till some bits (mostly reserved) are clear; ok for all revs. + */ +#define read_roothub(hc, register, mask) ({ \ + u32 temp = readl (&hc->regs->roothub.register); \ + if (temp == -1) \ + disable (hc); \ + else if (hc->flags & OHCI_QUIRK_AMD756) \ + while (temp & mask) \ + temp = readl (&hc->regs->roothub.register); \ + temp; }) + +static u32 roothub_a (struct ohci_hcd *hc) + { return read_roothub (hc, a, 0xfc0fe000); } +static inline u32 roothub_b (struct ohci_hcd *hc) + { return readl (&hc->regs->roothub.b); } +static inline u32 roothub_status (struct ohci_hcd *hc) + { return readl (&hc->regs->roothub.status); } +static u32 roothub_portstatus (struct ohci_hcd *hc, int i) + { return read_roothub (hc, portstatus [i], 0xffe0fce0); } + +/*-------------------------------------------------------------------------*/ + +#define dbg_port(hc,label,num,value) \ + ohci_dbg (hc, \ + "%s roothub.portstatus [%d] " \ + "= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \ + label, num, temp, \ + (temp & RH_PS_PRSC) ? " PRSC" : "", \ + (temp & RH_PS_OCIC) ? " OCIC" : "", \ + (temp & RH_PS_PSSC) ? " PSSC" : "", \ + (temp & RH_PS_PESC) ? " PESC" : "", \ + (temp & RH_PS_CSC) ? " CSC" : "", \ + \ + (temp & RH_PS_LSDA) ? " LSDA" : "", \ + (temp & RH_PS_PPS) ? " PPS" : "", \ + (temp & RH_PS_PRS) ? " PRS" : "", \ + (temp & RH_PS_POCI) ? " POCI" : "", \ + (temp & RH_PS_PSS) ? " PSS" : "", \ + \ + (temp & RH_PS_PES) ? " PES" : "", \ + (temp & RH_PS_CCS) ? " CCS" : "" \ + ); + + +/*-------------------------------------------------------------------------*/ + +/* build "status change" packet (one or two bytes) from HC registers */ + +static int +ohci_hub_status_data (struct usb_hcd *hcd, char *buf) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ports, i, changed = 0, length = 1; + + ports = roothub_a (ohci) & RH_A_NDP; + if (ports > MAX_ROOT_PORTS) { + if (ohci->disabled) + return -ESHUTDOWN; + ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", + ports, readl (&ohci->regs->roothub.a) & RH_A_NDP); + /* retry later; "should not happen" */ + return 0; + } + + /* init status */ + if (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC)) + buf [0] = changed = 1; + else + buf [0] = 0; + if (ports > 7) { + buf [1] = 0; + length++; + } + + /* look at each port */ + for (i = 0; i < ports; i++) { + u32 status = roothub_portstatus (ohci, i); + + status &= RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC + | RH_PS_OCIC | RH_PS_PRSC; + if (status) { + changed = 1; + if (i < 7) + buf [0] |= 1 << (i + 1); + else + buf [1] |= 1 << (i - 7); + } + } + return changed ? length : 0; +} + +/*-------------------------------------------------------------------------*/ + +static void +ohci_hub_descriptor ( + struct ohci_hcd *ohci, + struct usb_hub_descriptor *desc +) { + u32 rh = roothub_a (ohci); + int ports = rh & RH_A_NDP; + u16 temp; + + desc->bDescriptorType = 0x29; + desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24; + desc->bHubContrCurrent = 0; + + desc->bNbrPorts = ports; + temp = 1 + (ports / 8); + desc->bDescLength = 7 + 2 * temp; + + temp = 0; + if (rh & RH_A_PSM) /* per-port power switching? */ + temp |= 0x0001; + if (rh & RH_A_NOCP) /* no overcurrent reporting? */ + temp |= 0x0010; + else if (rh & RH_A_OCPM) /* per-port overcurrent reporting? */ + temp |= 0x0008; + desc->wHubCharacteristics = cpu_to_le16 (temp); + + /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ + rh = roothub_b (ohci); + desc->bitmap [0] = rh & RH_B_DR; + if (ports > 7) { + desc->bitmap [1] = (rh & RH_B_DR) >> 8; + desc->bitmap [2] = desc->bitmap [3] = 0xff; + } else + desc->bitmap [1] = 0xff; +} + +/*-------------------------------------------------------------------------*/ + +static int ohci_hub_control ( + struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, + u16 wIndex, + char *buf, + u16 wLength +) { + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ports = hcd_to_bus (hcd)->root_hub->maxchild; + u32 temp; + int retval = 0; + + switch (typeReq) { + case ClearHubFeature: + switch (wValue) { + case C_HUB_OVER_CURRENT: + writel (RH_HS_OCIC, &ohci->regs->roothub.status); + case C_HUB_LOCAL_POWER: + break; + default: + goto error; + } + break; + case ClearPortFeature: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + temp = RH_PS_CCS; + break; + case USB_PORT_FEAT_C_ENABLE: + temp = RH_PS_PESC; + break; + case USB_PORT_FEAT_SUSPEND: + temp = RH_PS_POCI; + break; + case USB_PORT_FEAT_C_SUSPEND: + temp = RH_PS_PSSC; + break; + case USB_PORT_FEAT_POWER: + temp = RH_PS_LSDA; + break; + case USB_PORT_FEAT_C_CONNECTION: + temp = RH_PS_CSC; + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + temp = RH_PS_OCIC; + break; + case USB_PORT_FEAT_C_RESET: + temp = RH_PS_PRSC; + break; + default: + goto error; + } + writel (temp, &ohci->regs->roothub.portstatus [wIndex]); + // readl (&ohci->regs->roothub.portstatus [wIndex]); + break; + case GetHubDescriptor: + ohci_hub_descriptor (ohci, (struct usb_hub_descriptor *) buf); + break; + case GetHubStatus: + temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE); + *(u32 *) buf = cpu_to_le32 (temp); + break; + case GetPortStatus: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = roothub_portstatus (ohci, wIndex); + *(u32 *) buf = cpu_to_le32 (temp); + +#ifndef OHCI_VERBOSE_DEBUG + if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ +#endif + dbg_port (ohci, "GetStatus", wIndex + 1, temp); + break; + case SetHubFeature: + switch (wValue) { + case C_HUB_OVER_CURRENT: + // FIXME: this can be cleared, yes? + case C_HUB_LOCAL_POWER: + break; + default: + goto error; + } + break; + case SetPortFeature: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + switch (wValue) { + case USB_PORT_FEAT_SUSPEND: + writel (RH_PS_PSS, + &ohci->regs->roothub.portstatus [wIndex]); + break; + case USB_PORT_FEAT_POWER: + writel (RH_PS_PPS, + &ohci->regs->roothub.portstatus [wIndex]); + break; + case USB_PORT_FEAT_RESET: + temp = readl (&ohci->regs->roothub.portstatus [wIndex]); + if (temp & RH_PS_CCS) + writel (RH_PS_PRS, + &ohci->regs->roothub.portstatus [wIndex]); + break; + default: + goto error; + } + break; + + default: +error: + /* "protocol stall" on error */ + retval = -EPIPE; + } + return retval; +} + diff --git a/reactos/drivers/usb/cromwell/host/ohci-mem.c b/reactos/drivers/usb/cromwell/host/ohci-mem.c index 85371e9756a..4fc839304ce 100644 --- a/reactos/drivers/usb/cromwell/host/ohci-mem.c +++ b/reactos/drivers/usb/cromwell/host/ohci-mem.c @@ -1,146 +1,146 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * - * This file is licenced under the GPL. - */ - -/*-------------------------------------------------------------------------*/ - -/* - * There's basically three types of memory: - * - data used only by the HCD ... kmalloc is fine - * - async and periodic schedules, shared by HC and HCD ... these - * need to use pci_pool or pci_alloc_consistent - * - driver buffers, read/written by HC ... the hcd glue or the - * device driver provides us with dma addresses - * - * There's also PCI "register" data, which is memory mapped. - * No memory seen by this driver is pagable. - */ - -/*-------------------------------------------------------------------------*/ - -static struct usb_hcd *ohci_hcd_alloc (void) -{ - struct ohci_hcd *ohci; - - ohci = (struct ohci_hcd *) kmalloc (sizeof *ohci, GFP_KERNEL); - if (ohci != 0) { - memset (ohci, 0, sizeof (struct ohci_hcd)); - return &ohci->hcd; - } - return 0; -} - -static void ohci_hcd_free (struct usb_hcd *hcd) -{ - kfree (hcd_to_ohci (hcd)); -} - -/*-------------------------------------------------------------------------*/ - -static int ohci_mem_init (struct ohci_hcd *ohci) -{ - ohci->td_cache = pci_pool_create ("ohci_td", ohci->hcd.pdev, - sizeof (struct td), - 32 /* byte alignment */, - 0 /* no page-crossing issues */); - if (!ohci->td_cache) - return -ENOMEM; - ohci->ed_cache = pci_pool_create ("ohci_ed", ohci->hcd.pdev, - sizeof (struct ed), - 16 /* byte alignment */, - 0 /* no page-crossing issues */); - if (!ohci->ed_cache) { - pci_pool_destroy (ohci->td_cache); - return -ENOMEM; - } - return 0; -} - -static void ohci_mem_cleanup (struct ohci_hcd *ohci) -{ - if (ohci->td_cache) { - pci_pool_destroy (ohci->td_cache); - ohci->td_cache = 0; - } - if (ohci->ed_cache) { - pci_pool_destroy (ohci->ed_cache); - ohci->ed_cache = 0; - } -} - -/*-------------------------------------------------------------------------*/ - -/* ohci "done list" processing needs this mapping */ -static inline struct td * -dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) -{ - struct td *td; - - td_dma &= TD_MASK; - td = hc->td_hash [TD_HASH_FUNC(td_dma)]; - while (td && td->td_dma != td_dma) - td = td->td_hash; - return td; -} - -/* TDs ... */ -static struct td * -td_alloc (struct ohci_hcd *hc, int mem_flags) -{ - dma_addr_t dma; - struct td *td; - - td = pci_pool_alloc (hc->td_cache, mem_flags, &dma); - if (td) { - /* in case hc fetches it, make it look dead */ - memset (td, 0, sizeof *td); - td->hwNextTD = cpu_to_le32 (dma); - td->td_dma = dma; - /* hashed in td_fill */ - } - return td; -} - -static void -td_free (struct ohci_hcd *hc, struct td *td) -{ - struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)]; - - while (*prev && *prev != td) - prev = &(*prev)->td_hash; - if (*prev) - *prev = td->td_hash; - else if ((td->hwINFO & TD_DONE) != 0) - ohci_dbg (hc, "no hash for td %p\n", td); - pci_pool_free (hc->td_cache, td, td->td_dma); -} - -/*-------------------------------------------------------------------------*/ - -/* EDs ... */ -static struct ed * -ed_alloc (struct ohci_hcd *hc, int mem_flags) -{ - dma_addr_t dma; - struct ed *ed; - - ed = pci_pool_alloc (hc->ed_cache, mem_flags, &dma); - if (ed) { - memset (ed, 0, sizeof (*ed)); - INIT_LIST_HEAD (&ed->td_list); - ed->dma = dma; - } - return ed; -} - -static void -ed_free (struct ohci_hcd *hc, struct ed *ed) -{ - pci_pool_free (hc->ed_cache, ed, ed->dma); -} - +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * + * This file is licenced under the GPL. + */ + +/*-------------------------------------------------------------------------*/ + +/* + * There's basically three types of memory: + * - data used only by the HCD ... kmalloc is fine + * - async and periodic schedules, shared by HC and HCD ... these + * need to use pci_pool or pci_alloc_consistent + * - driver buffers, read/written by HC ... the hcd glue or the + * device driver provides us with dma addresses + * + * There's also PCI "register" data, which is memory mapped. + * No memory seen by this driver is pagable. + */ + +/*-------------------------------------------------------------------------*/ + +static struct usb_hcd *ohci_hcd_alloc (void) +{ + struct ohci_hcd *ohci; + + ohci = (struct ohci_hcd *) kmalloc (sizeof *ohci, GFP_KERNEL); + if (ohci != 0) { + memset (ohci, 0, sizeof (struct ohci_hcd)); + return &ohci->hcd; + } + return 0; +} + +static void ohci_hcd_free (struct usb_hcd *hcd) +{ + kfree (hcd_to_ohci (hcd)); +} + +/*-------------------------------------------------------------------------*/ + +static int ohci_mem_init (struct ohci_hcd *ohci) +{ + ohci->td_cache = pci_pool_create ("ohci_td", ohci->hcd.pdev, + sizeof (struct td), + 32 /* byte alignment */, + 0 /* no page-crossing issues */); + if (!ohci->td_cache) + return -ENOMEM; + ohci->ed_cache = pci_pool_create ("ohci_ed", ohci->hcd.pdev, + sizeof (struct ed), + 16 /* byte alignment */, + 0 /* no page-crossing issues */); + if (!ohci->ed_cache) { + pci_pool_destroy (ohci->td_cache); + return -ENOMEM; + } + return 0; +} + +static void ohci_mem_cleanup (struct ohci_hcd *ohci) +{ + if (ohci->td_cache) { + pci_pool_destroy (ohci->td_cache); + ohci->td_cache = 0; + } + if (ohci->ed_cache) { + pci_pool_destroy (ohci->ed_cache); + ohci->ed_cache = 0; + } +} + +/*-------------------------------------------------------------------------*/ + +/* ohci "done list" processing needs this mapping */ +static inline struct td * +dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) +{ + struct td *td; + + td_dma &= TD_MASK; + td = hc->td_hash [TD_HASH_FUNC(td_dma)]; + while (td && td->td_dma != td_dma) + td = td->td_hash; + return td; +} + +/* TDs ... */ +static struct td * +td_alloc (struct ohci_hcd *hc, int mem_flags) +{ + dma_addr_t dma; + struct td *td; + + td = pci_pool_alloc (hc->td_cache, mem_flags, &dma); + if (td) { + /* in case hc fetches it, make it look dead */ + memset (td, 0, sizeof *td); + td->hwNextTD = cpu_to_le32 (dma); + td->td_dma = dma; + /* hashed in td_fill */ + } + return td; +} + +static void +td_free (struct ohci_hcd *hc, struct td *td) +{ + struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)]; + + while (*prev && *prev != td) + prev = &(*prev)->td_hash; + if (*prev) + *prev = td->td_hash; + else if ((td->hwINFO & TD_DONE) != 0) + ohci_dbg (hc, "no hash for td %p\n", td); + pci_pool_free (hc->td_cache, td, td->td_dma); +} + +/*-------------------------------------------------------------------------*/ + +/* EDs ... */ +static struct ed * +ed_alloc (struct ohci_hcd *hc, int mem_flags) +{ + dma_addr_t dma; + struct ed *ed; + + ed = pci_pool_alloc (hc->ed_cache, mem_flags, &dma); + if (ed) { + memset (ed, 0, sizeof (*ed)); + INIT_LIST_HEAD (&ed->td_list); + ed->dma = dma; + } + return ed; +} + +static void +ed_free (struct ohci_hcd *hc, struct ed *ed) +{ + pci_pool_free (hc->ed_cache, ed, ed->dma); +} + diff --git a/reactos/drivers/usb/cromwell/host/ohci-pci.c b/reactos/drivers/usb/cromwell/host/ohci-pci.c index 0ce7123c541..a7c3980f177 100644 --- a/reactos/drivers/usb/cromwell/host/ohci-pci.c +++ b/reactos/drivers/usb/cromwell/host/ohci-pci.c @@ -1,412 +1,412 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * - * [ Initialisation is based on Linus' ] - * [ uhci code and gregs ohci fragments ] - * [ (C) Copyright 1999 Linus Torvalds ] - * [ (C) Copyright 1999 Gregory P. Smith] - * - * PCI Bus Glue - * - * This file is licenced under the GPL. - */ - -#ifdef CONFIG_PMAC_PBOOK -#include -#include -#include -#include -#ifndef CONFIG_PM -# define CONFIG_PM -#endif -#endif - -#ifndef CONFIG_PCI -#error "This file is PCI bus glue. CONFIG_PCI must be defined." -#endif - -#include "../linux/pci_ids.h" - -/*-------------------------------------------------------------------------*/ - -static int __devinit -ohci_pci_start (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - - DPRINT("ohci_pci_start()\n"); - - if (hcd->pdev) { - ohci->hcca = pci_alloc_consistent (hcd->pdev, - sizeof *ohci->hcca, &ohci->hcca_dma); - if (!ohci->hcca) - return -ENOMEM; - - /* AMD 756, for most chips (early revs), corrupts register - * values on read ... so enable the vendor workaround. - */ - if (hcd->pdev->vendor == PCI_VENDOR_ID_AMD - && hcd->pdev->device == 0x740c) { - ohci->flags = OHCI_QUIRK_AMD756; - ohci_info (ohci, "AMD756 erratum 4 workaround\n"); - } - - /* FIXME for some of the early AMD 760 southbridges, OHCI - * won't work at all. blacklist them. - */ - - /* Apple's OHCI driver has a lot of bizarre workarounds - * for this chip. Evidently control and bulk lists - * can get confused. (B&W G3 models, and ...) - */ - else if (hcd->pdev->vendor == PCI_VENDOR_ID_OPTI - && hcd->pdev->device == 0xc861) { - ohci_info (ohci, - "WARNING: OPTi workarounds unavailable\n"); - } - - /* Check for NSC87560. We have to look at the bridge (fn1) to - * identify the USB (fn2). This quirk might apply to more or - * even all NSC stuff. - */ - else if (hcd->pdev->vendor == PCI_VENDOR_ID_NS) { - struct pci_dev *b, *hc; - - hc = hcd->pdev; - b = pci_find_slot (hc->bus->number, - PCI_DEVFN (PCI_SLOT (hc->devfn), 1)); - if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO - && b->vendor == PCI_VENDOR_ID_NS) { - ohci->flags |= OHCI_QUIRK_SUPERIO; - ohci_info (ohci, "Using NSC SuperIO setup\n"); - } - } - - } - - memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); - if ((ret = ohci_mem_init (ohci)) < 0) { - ohci_stop (hcd); - return ret; - } - ohci->regs = hcd->regs; - - DPRINT("Controller memory init done\n"); - - if (hc_reset (ohci) < 0) { - ohci_stop (hcd); - return -ENODEV; - } - DPRINT("Controller reset done\n"); - - if (hc_start (ohci) < 0) { - ohci_err (ohci, "can't start\n"); - ohci_stop (hcd); - return -EBUSY; - } - DPRINT("Controller start done\n"); - -#ifdef DEBUG - ohci_dump (ohci, 1); -#endif - return 0; -} - -#ifdef CONFIG_PM - -static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - unsigned long flags; - u16 cmd; - - if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) { - ohci_dbg (ohci, "can't suspend (state is %s)\n", - hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS)); - return -EIO; - } - - /* act as if usb suspend can always be used */ - ohci_dbg (ohci, "suspend to %d\n", state); - ohci->sleeping = 1; - - /* First stop processing */ - spin_lock_irqsave (&ohci->lock, flags); - ohci->hc_control &= - ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE); - writel (ohci->hc_control, &ohci->regs->control); - writel (OHCI_INTR_SF, &ohci->regs->intrstatus); - (void) readl (&ohci->regs->intrstatus); - spin_unlock_irqrestore (&ohci->lock, flags); - - /* Wait a frame or two */ - mdelay (1); - if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF) - mdelay (1); - -#ifdef CONFIG_PMAC_PBOOK - if (_machine == _MACH_Pmac) - disable_irq (hcd->pdev->irq); - /* else, 2.4 assumes shared irqs -- don't disable */ -#endif - - /* Enable remote wakeup */ - writel (readl (&ohci->regs->intrenable) | OHCI_INTR_RD, - &ohci->regs->intrenable); - - /* Suspend chip and let things settle down a bit */ - ohci->hc_control = OHCI_USB_SUSPEND; - writel (ohci->hc_control, &ohci->regs->control); - (void) readl (&ohci->regs->control); - mdelay (500); /* No schedule here ! */ - - switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) { - case OHCI_USB_RESET: - ohci_dbg (ohci, "suspend->reset ?\n"); - break; - case OHCI_USB_RESUME: - ohci_dbg (ohci, "suspend->resume ?\n"); - break; - case OHCI_USB_OPER: - ohci_dbg (ohci, "suspend->operational ?\n"); - break; - case OHCI_USB_SUSPEND: - ohci_dbg (ohci, "suspended\n"); - break; - } - - /* In some rare situations, Apple's OHCI have happily trashed - * memory during sleep. We disable its bus master bit during - * suspend - */ - pci_read_config_word (hcd->pdev, PCI_COMMAND, &cmd); - cmd &= ~PCI_COMMAND_MASTER; - pci_write_config_word (hcd->pdev, PCI_COMMAND, cmd); -#ifdef CONFIG_PMAC_PBOOK - { - struct device_node *of_node; - - /* Disable USB PAD & cell clock */ - of_node = pci_device_to_OF_node (hcd->pdev); - if (of_node) - pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); - } -#endif - return 0; -} - - -static int ohci_pci_resume (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int temp; - int retval = 0; - unsigned long flags; - -#ifdef CONFIG_PMAC_PBOOK - { - struct device_node *of_node; - - /* Re-enable USB PAD & cell clock */ - of_node = pci_device_to_OF_node (hcd->pdev); - if (of_node) - pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1); - } -#endif - /* did we suspend, or were we powered off? */ - ohci->hc_control = readl (&ohci->regs->control); - temp = ohci->hc_control & OHCI_CTRL_HCFS; - -#ifdef DEBUG - /* the registers may look crazy here */ - ohci_dump_status (ohci, 0, 0); -#endif - - /* Re-enable bus mastering */ - pci_set_master (ohci->hcd.pdev); - - switch (temp) { - - case OHCI_USB_RESET: // lost power - ohci_info (ohci, "USB restart\n"); - retval = hc_restart (ohci); - break; - - case OHCI_USB_SUSPEND: // host wakeup - case OHCI_USB_RESUME: // remote wakeup - ohci_info (ohci, "USB continue from %s wakeup\n", - (temp == OHCI_USB_SUSPEND) - ? "host" : "remote"); - ohci->hc_control = OHCI_USB_RESUME; - writel (ohci->hc_control, &ohci->regs->control); - (void) readl (&ohci->regs->control); - mdelay (20); /* no schedule here ! */ - /* Some controllers (lucent) need a longer delay here */ - mdelay (15); - - temp = readl (&ohci->regs->control); - temp = ohci->hc_control & OHCI_CTRL_HCFS; - if (temp != OHCI_USB_RESUME) { - ohci_err (ohci, "controller won't resume\n"); - ohci->disabled = 1; - retval = -EIO; - break; - } - - /* Some chips likes being resumed first */ - writel (OHCI_USB_OPER, &ohci->regs->control); - (void) readl (&ohci->regs->control); - mdelay (3); - - /* Then re-enable operations */ - spin_lock_irqsave (&ohci->lock, flags); - ohci->disabled = 0; - ohci->sleeping = 0; - ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; - if (!ohci->ed_rm_list) { - if (ohci->ed_controltail) - ohci->hc_control |= OHCI_CTRL_CLE; - if (ohci->ed_bulktail) - ohci->hc_control |= OHCI_CTRL_BLE; - } - hcd->state = USB_STATE_READY; - writel (ohci->hc_control, &ohci->regs->control); - - /* trigger a start-frame interrupt (why?) */ - writel (OHCI_INTR_SF, &ohci->regs->intrstatus); - writel (OHCI_INTR_SF, &ohci->regs->intrenable); - - /* Check for a pending done list */ - writel (OHCI_INTR_WDH, &ohci->regs->intrdisable); - (void) readl (&ohci->regs->intrdisable); - spin_unlock_irqrestore (&ohci->lock, flags); - -#ifdef CONFIG_PMAC_PBOOK - if (_machine == _MACH_Pmac) - enable_irq (hcd->pdev->irq); -#endif - if (ohci->hcca->done_head) - dl_done_list (ohci, dl_reverse_done_list (ohci), NULL); - writel (OHCI_INTR_WDH, &ohci->regs->intrenable); - - /* assume there are TDs on the bulk and control lists */ - writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus); - -// ohci_dump_status (ohci); -ohci_dbg (ohci, "sleeping = %d, disabled = %d\n", - ohci->sleeping, ohci->disabled); - break; - - default: - ohci_warn (ohci, "odd PCI resume\n"); - } - return retval; -} - -#endif /* CONFIG_PM */ - - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_pci_hc_driver = { - .description = hcd_name, - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_MEMORY | HCD_USB11, - - /* - * basic lifecycle operations - */ - .start = ohci_pci_start, -#ifdef CONFIG_PM - .suspend = ohci_pci_suspend, - .resume = ohci_pci_resume, -#endif - .stop = ohci_stop, - - /* - * memory lifecycle (except per-request) - */ - .hcd_alloc = ohci_hcd_alloc, - .hcd_free = ohci_hcd_free, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -}; - -/*-------------------------------------------------------------------------*/ - -const struct pci_device_id __devinitdata pci_ids [] = { { - - /* handle any USB OHCI controller */ - .class = (PCI_CLASS_SERIAL_USB << 8) | 0x10, - .class_mask = ~0, - .driver_data = (unsigned long) &ohci_pci_hc_driver, - - /* no matter who makes it */ - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - - }, { /* end: all zeroes */ } -}; -MODULE_DEVICE_TABLE (pci, pci_ids); - -/* pci driver glue; this is a "new style" PCI driver module */ -struct pci_driver ohci_pci_driver = { - .name = (char *) hcd_name, - .id_table = pci_ids, - - .probe = usb_hcd_pci_probe, - .remove = usb_hcd_pci_remove, - -#ifdef CONFIG_PM - .suspend = usb_hcd_pci_suspend, - .resume = usb_hcd_pci_resume, -#endif -}; - - -int ohci_hcd_pci_init (void) -{ - printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name); - if (usb_disabled()) - return -ENODEV; - - // causes page fault in reactos - //printk (KERN_DEBUG "%s: block sizes: ed %Zd td %Zd\n", hcd_name, - // sizeof (struct ed), sizeof (struct td)); - return pci_module_init (&ohci_pci_driver); -} -/*module_init (ohci_hcd_pci_init);*/ - -/*-------------------------------------------------------------------------*/ - -void ohci_hcd_pci_cleanup (void) -{ - pci_unregister_driver (&ohci_pci_driver); -} -/*module_exit (ohci_hcd_pci_cleanup);*/ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * + * [ Initialisation is based on Linus' ] + * [ uhci code and gregs ohci fragments ] + * [ (C) Copyright 1999 Linus Torvalds ] + * [ (C) Copyright 1999 Gregory P. Smith] + * + * PCI Bus Glue + * + * This file is licenced under the GPL. + */ + +#ifdef CONFIG_PMAC_PBOOK +#include +#include +#include +#include +#ifndef CONFIG_PM +# define CONFIG_PM +#endif +#endif + +#ifndef CONFIG_PCI +#error "This file is PCI bus glue. CONFIG_PCI must be defined." +#endif + +#include "../linux/pci_ids.h" + +/*-------------------------------------------------------------------------*/ + +static int __devinit +ohci_pci_start (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; + + DPRINT("ohci_pci_start()\n"); + + if (hcd->pdev) { + ohci->hcca = pci_alloc_consistent (hcd->pdev, + sizeof *ohci->hcca, &ohci->hcca_dma); + if (!ohci->hcca) + return -ENOMEM; + + /* AMD 756, for most chips (early revs), corrupts register + * values on read ... so enable the vendor workaround. + */ + if (hcd->pdev->vendor == PCI_VENDOR_ID_AMD + && hcd->pdev->device == 0x740c) { + ohci->flags = OHCI_QUIRK_AMD756; + ohci_info (ohci, "AMD756 erratum 4 workaround\n"); + } + + /* FIXME for some of the early AMD 760 southbridges, OHCI + * won't work at all. blacklist them. + */ + + /* Apple's OHCI driver has a lot of bizarre workarounds + * for this chip. Evidently control and bulk lists + * can get confused. (B&W G3 models, and ...) + */ + else if (hcd->pdev->vendor == PCI_VENDOR_ID_OPTI + && hcd->pdev->device == 0xc861) { + ohci_info (ohci, + "WARNING: OPTi workarounds unavailable\n"); + } + + /* Check for NSC87560. We have to look at the bridge (fn1) to + * identify the USB (fn2). This quirk might apply to more or + * even all NSC stuff. + */ + else if (hcd->pdev->vendor == PCI_VENDOR_ID_NS) { + struct pci_dev *b, *hc; + + hc = hcd->pdev; + b = pci_find_slot (hc->bus->number, + PCI_DEVFN (PCI_SLOT (hc->devfn), 1)); + if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO + && b->vendor == PCI_VENDOR_ID_NS) { + ohci->flags |= OHCI_QUIRK_SUPERIO; + ohci_info (ohci, "Using NSC SuperIO setup\n"); + } + } + + } + + memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); + if ((ret = ohci_mem_init (ohci)) < 0) { + ohci_stop (hcd); + return ret; + } + ohci->regs = hcd->regs; + + DPRINT("Controller memory init done\n"); + + if (hc_reset (ohci) < 0) { + ohci_stop (hcd); + return -ENODEV; + } + DPRINT("Controller reset done\n"); + + if (hc_start (ohci) < 0) { + ohci_err (ohci, "can't start\n"); + ohci_stop (hcd); + return -EBUSY; + } + DPRINT("Controller start done\n"); + +#ifdef DEBUG + ohci_dump (ohci, 1); +#endif + return 0; +} + +#ifdef CONFIG_PM + +static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + unsigned long flags; + u16 cmd; + + if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) { + ohci_dbg (ohci, "can't suspend (state is %s)\n", + hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS)); + return -EIO; + } + + /* act as if usb suspend can always be used */ + ohci_dbg (ohci, "suspend to %d\n", state); + ohci->sleeping = 1; + + /* First stop processing */ + spin_lock_irqsave (&ohci->lock, flags); + ohci->hc_control &= + ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE); + writel (ohci->hc_control, &ohci->regs->control); + writel (OHCI_INTR_SF, &ohci->regs->intrstatus); + (void) readl (&ohci->regs->intrstatus); + spin_unlock_irqrestore (&ohci->lock, flags); + + /* Wait a frame or two */ + mdelay (1); + if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF) + mdelay (1); + +#ifdef CONFIG_PMAC_PBOOK + if (_machine == _MACH_Pmac) + disable_irq (hcd->pdev->irq); + /* else, 2.4 assumes shared irqs -- don't disable */ +#endif + + /* Enable remote wakeup */ + writel (readl (&ohci->regs->intrenable) | OHCI_INTR_RD, + &ohci->regs->intrenable); + + /* Suspend chip and let things settle down a bit */ + ohci->hc_control = OHCI_USB_SUSPEND; + writel (ohci->hc_control, &ohci->regs->control); + (void) readl (&ohci->regs->control); + mdelay (500); /* No schedule here ! */ + + switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) { + case OHCI_USB_RESET: + ohci_dbg (ohci, "suspend->reset ?\n"); + break; + case OHCI_USB_RESUME: + ohci_dbg (ohci, "suspend->resume ?\n"); + break; + case OHCI_USB_OPER: + ohci_dbg (ohci, "suspend->operational ?\n"); + break; + case OHCI_USB_SUSPEND: + ohci_dbg (ohci, "suspended\n"); + break; + } + + /* In some rare situations, Apple's OHCI have happily trashed + * memory during sleep. We disable its bus master bit during + * suspend + */ + pci_read_config_word (hcd->pdev, PCI_COMMAND, &cmd); + cmd &= ~PCI_COMMAND_MASTER; + pci_write_config_word (hcd->pdev, PCI_COMMAND, cmd); +#ifdef CONFIG_PMAC_PBOOK + { + struct device_node *of_node; + + /* Disable USB PAD & cell clock */ + of_node = pci_device_to_OF_node (hcd->pdev); + if (of_node) + pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); + } +#endif + return 0; +} + + +static int ohci_pci_resume (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int temp; + int retval = 0; + unsigned long flags; + +#ifdef CONFIG_PMAC_PBOOK + { + struct device_node *of_node; + + /* Re-enable USB PAD & cell clock */ + of_node = pci_device_to_OF_node (hcd->pdev); + if (of_node) + pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1); + } +#endif + /* did we suspend, or were we powered off? */ + ohci->hc_control = readl (&ohci->regs->control); + temp = ohci->hc_control & OHCI_CTRL_HCFS; + +#ifdef DEBUG + /* the registers may look crazy here */ + ohci_dump_status (ohci, 0, 0); +#endif + + /* Re-enable bus mastering */ + pci_set_master (ohci->hcd.pdev); + + switch (temp) { + + case OHCI_USB_RESET: // lost power + ohci_info (ohci, "USB restart\n"); + retval = hc_restart (ohci); + break; + + case OHCI_USB_SUSPEND: // host wakeup + case OHCI_USB_RESUME: // remote wakeup + ohci_info (ohci, "USB continue from %s wakeup\n", + (temp == OHCI_USB_SUSPEND) + ? "host" : "remote"); + ohci->hc_control = OHCI_USB_RESUME; + writel (ohci->hc_control, &ohci->regs->control); + (void) readl (&ohci->regs->control); + mdelay (20); /* no schedule here ! */ + /* Some controllers (lucent) need a longer delay here */ + mdelay (15); + + temp = readl (&ohci->regs->control); + temp = ohci->hc_control & OHCI_CTRL_HCFS; + if (temp != OHCI_USB_RESUME) { + ohci_err (ohci, "controller won't resume\n"); + ohci->disabled = 1; + retval = -EIO; + break; + } + + /* Some chips likes being resumed first */ + writel (OHCI_USB_OPER, &ohci->regs->control); + (void) readl (&ohci->regs->control); + mdelay (3); + + /* Then re-enable operations */ + spin_lock_irqsave (&ohci->lock, flags); + ohci->disabled = 0; + ohci->sleeping = 0; + ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; + if (!ohci->ed_rm_list) { + if (ohci->ed_controltail) + ohci->hc_control |= OHCI_CTRL_CLE; + if (ohci->ed_bulktail) + ohci->hc_control |= OHCI_CTRL_BLE; + } + hcd->state = USB_STATE_READY; + writel (ohci->hc_control, &ohci->regs->control); + + /* trigger a start-frame interrupt (why?) */ + writel (OHCI_INTR_SF, &ohci->regs->intrstatus); + writel (OHCI_INTR_SF, &ohci->regs->intrenable); + + /* Check for a pending done list */ + writel (OHCI_INTR_WDH, &ohci->regs->intrdisable); + (void) readl (&ohci->regs->intrdisable); + spin_unlock_irqrestore (&ohci->lock, flags); + +#ifdef CONFIG_PMAC_PBOOK + if (_machine == _MACH_Pmac) + enable_irq (hcd->pdev->irq); +#endif + if (ohci->hcca->done_head) + dl_done_list (ohci, dl_reverse_done_list (ohci), NULL); + writel (OHCI_INTR_WDH, &ohci->regs->intrenable); + + /* assume there are TDs on the bulk and control lists */ + writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus); + +// ohci_dump_status (ohci); +ohci_dbg (ohci, "sleeping = %d, disabled = %d\n", + ohci->sleeping, ohci->disabled); + break; + + default: + ohci_warn (ohci, "odd PCI resume\n"); + } + return retval; +} + +#endif /* CONFIG_PM */ + + +/*-------------------------------------------------------------------------*/ + +static const struct hc_driver ohci_pci_hc_driver = { + .description = hcd_name, + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_MEMORY | HCD_USB11, + + /* + * basic lifecycle operations + */ + .start = ohci_pci_start, +#ifdef CONFIG_PM + .suspend = ohci_pci_suspend, + .resume = ohci_pci_resume, +#endif + .stop = ohci_stop, + + /* + * memory lifecycle (except per-request) + */ + .hcd_alloc = ohci_hcd_alloc, + .hcd_free = ohci_hcd_free, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, +}; + +/*-------------------------------------------------------------------------*/ + +const struct pci_device_id __devinitdata pci_ids [] = { { + + /* handle any USB OHCI controller */ + .class = (PCI_CLASS_SERIAL_USB << 8) | 0x10, + .class_mask = ~0, + .driver_data = (unsigned long) &ohci_pci_hc_driver, + + /* no matter who makes it */ + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + + }, { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE (pci, pci_ids); + +/* pci driver glue; this is a "new style" PCI driver module */ +struct pci_driver ohci_pci_driver = { + .name = (char *) hcd_name, + .id_table = pci_ids, + + .probe = usb_hcd_pci_probe, + .remove = usb_hcd_pci_remove, + +#ifdef CONFIG_PM + .suspend = usb_hcd_pci_suspend, + .resume = usb_hcd_pci_resume, +#endif +}; + + +int ohci_hcd_pci_init (void) +{ + printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name); + if (usb_disabled()) + return -ENODEV; + + // causes page fault in reactos + //printk (KERN_DEBUG "%s: block sizes: ed %Zd td %Zd\n", hcd_name, + // sizeof (struct ed), sizeof (struct td)); + return pci_module_init (&ohci_pci_driver); +} +/*module_init (ohci_hcd_pci_init);*/ + +/*-------------------------------------------------------------------------*/ + +void ohci_hcd_pci_cleanup (void) +{ + pci_unregister_driver (&ohci_pci_driver); +} +/*module_exit (ohci_hcd_pci_cleanup);*/ diff --git a/reactos/drivers/usb/cromwell/host/ohci-q.c b/reactos/drivers/usb/cromwell/host/ohci-q.c index 71e6350b87b..eae584ae317 100644 --- a/reactos/drivers/usb/cromwell/host/ohci-q.c +++ b/reactos/drivers/usb/cromwell/host/ohci-q.c @@ -1,1014 +1,1014 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * - * This file is licenced under the GPL. - */ - -static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv) -{ - int last = urb_priv->length - 1; - - if (last >= 0) { - int i; - struct td *td; - - for (i = 0; i <= last; i++) { - td = urb_priv->td [i]; - if (td) - td_free (hc, td); - } - } - - kfree (urb_priv); -} - -/*-------------------------------------------------------------------------*/ - -/* - * URB goes back to driver, and isn't reissued. - * It's completely gone from HC data structures. - * PRECONDITION: no locks held, irqs blocked (Giveback can call into HCD.) - */ -static void -finish_urb (struct ohci_hcd *ohci, struct urb *urb, struct pt_regs *regs) -{ - // ASSERT (urb->hcpriv != 0); - - urb_free_priv (ohci, urb->hcpriv); - urb->hcpriv = NULL; - - spin_lock (&urb->lock); - if (likely (urb->status == -EINPROGRESS)) - urb->status = 0; - spin_unlock (&urb->lock); - - // what lock protects these? - switch (usb_pipetype (urb->pipe)) { - case PIPE_ISOCHRONOUS: - hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs--; - break; - case PIPE_INTERRUPT: - hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs--; - break; - } - -#ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "RET", usb_pipeout (urb->pipe)); -#endif - usb_hcd_giveback_urb (&ohci->hcd, urb, regs); -} - - -/*-------------------------------------------------------------------------* - * ED handling functions - *-------------------------------------------------------------------------*/ - -/* search for the right schedule branch to use for a periodic ed. - * does some load balancing; returns the branch, or negative errno. - */ -static int balance (struct ohci_hcd *ohci, int interval, int load) -{ - int i, branch = -ENOSPC; - - /* iso periods can be huge; iso tds specify frame numbers */ - if (interval > NUM_INTS) - interval = NUM_INTS; - - /* search for the least loaded schedule branch of that period - * that has enough bandwidth left unreserved. - */ - for (i = 0; i < interval ; i++) { - if (branch < 0 || ohci->load [branch] > ohci->load [i]) { -#if 1 /* CONFIG_USB_BANDWIDTH */ - int j; - - /* usb 1.1 says 90% of one frame */ - for (j = i; j < NUM_INTS; j += interval) { - if ((ohci->load [j] + load) > 900) - break; - } - if (j < NUM_INTS) - continue; -#endif - branch = i; - } - } - return branch; -} - -/*-------------------------------------------------------------------------*/ - -/* both iso and interrupt requests have periods; this routine puts them - * into the schedule tree in the apppropriate place. most iso devices use - * 1msec periods, but that's not required. - */ -static void periodic_link (struct ohci_hcd *ohci, struct ed *ed) -{ - unsigned i; - - ohci_vdbg (ohci, "link %sed %p branch %d [%dus.], interval %d\n", - (ed->hwINFO & ED_ISO) ? "iso " : "", - ed, ed->branch, ed->load, ed->interval); - - for (i = ed->branch; i < NUM_INTS; i += ed->interval) { - struct ed **prev = &ohci->periodic [i]; - u32 *prev_p = &ohci->hcca->int_table [i]; - struct ed *here = *prev; - - /* sorting each branch by period (slow before fast) - * lets us share the faster parts of the tree. - * (plus maybe: put interrupt eds before iso) - */ - while (here && ed != here) { - if (ed->interval > here->interval) - break; - prev = &here->ed_next; - prev_p = &here->hwNextED; - here = *prev; - } - if (ed != here) { - ed->ed_next = here; - if (here) - ed->hwNextED = *prev_p; - wmb (); - *prev = ed; - *prev_p = cpu_to_le32p (&ed->dma); - } - ohci->load [i] += ed->load; - } - hcd_to_bus (&ohci->hcd)->bandwidth_allocated += ed->load / ed->interval; -} - -/* link an ed into one of the HC chains */ - -static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) -{ - int branch; - - ed->state = ED_OPER; - ed->ed_prev = 0; - ed->ed_next = 0; - ed->hwNextED = 0; - wmb (); - - /* we care about rm_list when setting CLE/BLE in case the HC was at - * work on some TD when CLE/BLE was turned off, and isn't quiesced - * yet. finish_unlinks() restarts as needed, some upcoming INTR_SF. - * - * control and bulk EDs are doubly linked (ed_next, ed_prev), but - * periodic ones are singly linked (ed_next). that's because the - * periodic schedule encodes a tree like figure 3-5 in the ohci - * spec: each qh can have several "previous" nodes, and the tree - * doesn't have unused/idle descriptors. - */ - switch (ed->type) { - case PIPE_CONTROL: - if (ohci->ed_controltail == NULL) { - writel (ed->dma, &ohci->regs->ed_controlhead); - } else { - ohci->ed_controltail->ed_next = ed; - ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma); - } - ed->ed_prev = ohci->ed_controltail; - if (!ohci->ed_controltail && !ohci->ed_rm_list) { - ohci->hc_control |= OHCI_CTRL_CLE; - writel (0, &ohci->regs->ed_controlcurrent); - writel (ohci->hc_control, &ohci->regs->control); - } - ohci->ed_controltail = ed; - break; - - case PIPE_BULK: - if (ohci->ed_bulktail == NULL) { - writel (ed->dma, &ohci->regs->ed_bulkhead); - } else { - ohci->ed_bulktail->ed_next = ed; - ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma); - } - ed->ed_prev = ohci->ed_bulktail; - if (!ohci->ed_bulktail && !ohci->ed_rm_list) { - ohci->hc_control |= OHCI_CTRL_BLE; - writel (0, &ohci->regs->ed_bulkcurrent); - writel (ohci->hc_control, &ohci->regs->control); - } - ohci->ed_bulktail = ed; - break; - - // case PIPE_INTERRUPT: - // case PIPE_ISOCHRONOUS: - default: - branch = balance (ohci, ed->interval, ed->load); - if (branch < 0) { - ohci_dbg (ohci, - "ERR %d, interval %d msecs, load %d\n", - branch, ed->interval, ed->load); - // FIXME if there are TDs queued, fail them! - return branch; - } - ed->branch = branch; - periodic_link (ohci, ed); - } - - /* the HC may not see the schedule updates yet, but if it does - * then they'll be properly ordered. - */ - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* scan the periodic table to find and unlink this ED */ -static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) -{ - int i; - - for (i = ed->branch; i < NUM_INTS; i += ed->interval) { - struct ed *temp; - struct ed **prev = &ohci->periodic [i]; - u32 *prev_p = &ohci->hcca->int_table [i]; - - while (*prev && (temp = *prev) != ed) { - prev_p = &temp->hwNextED; - prev = &temp->ed_next; - } - if (*prev) { - *prev_p = ed->hwNextED; - *prev = ed->ed_next; - } - ohci->load [i] -= ed->load; - } - hcd_to_bus (&ohci->hcd)->bandwidth_allocated -= ed->load / ed->interval; - - ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n", - (ed->hwINFO & ED_ISO) ? "iso " : "", - ed, ed->branch, ed->load, ed->interval); -} - -/* unlink an ed from one of the HC chains. - * just the link to the ed is unlinked. - * the link from the ed still points to another operational ed or 0 - * so the HC can eventually finish the processing of the unlinked ed - */ -static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) -{ - ed->hwINFO |= ED_SKIP; - - switch (ed->type) { - case PIPE_CONTROL: - if (ed->ed_prev == NULL) { - if (!ed->hwNextED) { - ohci->hc_control &= ~OHCI_CTRL_CLE; - writel (ohci->hc_control, &ohci->regs->control); - writel (0, &ohci->regs->ed_controlcurrent); - // post those pci writes - (void) readl (&ohci->regs->control); - } - writel (le32_to_cpup (&ed->hwNextED), - &ohci->regs->ed_controlhead); - } else { - ed->ed_prev->ed_next = ed->ed_next; - ed->ed_prev->hwNextED = ed->hwNextED; - } - if (ohci->ed_controltail == ed) { - ohci->ed_controltail = ed->ed_prev; - if (ohci->ed_controltail) - ohci->ed_controltail->ed_next = 0; - } else if (ed->ed_next) { - ed->ed_next->ed_prev = ed->ed_prev; - } - break; - - case PIPE_BULK: - if (ed->ed_prev == NULL) { - if (!ed->hwNextED) { - ohci->hc_control &= ~OHCI_CTRL_BLE; - writel (ohci->hc_control, &ohci->regs->control); - writel (0, &ohci->regs->ed_bulkcurrent); - // post those pci writes - (void) readl (&ohci->regs->control); - } - writel (le32_to_cpup (&ed->hwNextED), - &ohci->regs->ed_bulkhead); - } else { - ed->ed_prev->ed_next = ed->ed_next; - ed->ed_prev->hwNextED = ed->hwNextED; - } - if (ohci->ed_bulktail == ed) { - ohci->ed_bulktail = ed->ed_prev; - if (ohci->ed_bulktail) - ohci->ed_bulktail->ed_next = 0; - } else if (ed->ed_next) { - ed->ed_next->ed_prev = ed->ed_prev; - } - break; - - // case PIPE_INTERRUPT: - // case PIPE_ISOCHRONOUS: - default: - periodic_unlink (ohci, ed); - break; - } - - /* NOTE: Except for a couple of exceptionally clean unlink cases - * (like unlinking the only c/b ED, with no TDs) HCs may still be - * caching this operational ED (or its address). Safe unlinking - * involves not marking it ED_IDLE till INTR_SF; we always do that - * if td_list isn't empty. Otherwise the race is small; but ... - */ - if (ed->state == ED_OPER) { - ed->state = ED_IDLE; - ed->hwINFO &= ~(ED_SKIP | ED_DEQUEUE); - ed->hwHeadP &= ~ED_H; - wmb (); - } -} - - -/*-------------------------------------------------------------------------*/ - -/* get and maybe (re)init an endpoint. init _should_ be done only as part - * of usb_set_configuration() or usb_set_interface() ... but the USB stack - * isn't very stateful, so we re-init whenever the HC isn't looking. - */ -static struct ed *ed_get ( - struct ohci_hcd *ohci, - struct usb_device *udev, - unsigned int pipe, - int interval -) { - int is_out = !usb_pipein (pipe); - int type = usb_pipetype (pipe); - struct hcd_dev *dev = (struct hcd_dev *) udev->hcpriv; - struct ed *ed; - unsigned ep; - unsigned long flags; - - ep = usb_pipeendpoint (pipe) << 1; - if (type != PIPE_CONTROL && is_out) - ep |= 1; - - spin_lock_irqsave (&ohci->lock, flags); - - if (!(ed = dev->ep [ep])) { - struct td *td; - - ed = ed_alloc (ohci, SLAB_ATOMIC); - if (!ed) { - /* out of memory */ - goto done; - } - dev->ep [ep] = ed; - - /* dummy td; end of td list for ed */ - td = td_alloc (ohci, SLAB_ATOMIC); - if (!td) { - /* out of memory */ - ed_free (ohci, ed); - ed = 0; - goto done; - } - ed->dummy = td; - ed->hwTailP = cpu_to_le32 (td->td_dma); - ed->hwHeadP = ed->hwTailP; /* ED_C, ED_H zeroed */ - ed->state = ED_IDLE; - ed->type = type; - } - - /* NOTE: only ep0 currently needs this "re"init logic, during - * enumeration (after set_address, or if ep0 maxpacket >8). - */ - if (ed->state == ED_IDLE) { - u32 info; - - info = usb_pipedevice (pipe); - info |= (ep >> 1) << 7; - info |= usb_maxpacket (udev, pipe, is_out) << 16; - info = cpu_to_le32 (info); - if (udev->speed == USB_SPEED_LOW) - info |= ED_LOWSPEED; - /* only control transfers store pids in tds */ - if (type != PIPE_CONTROL) { - info |= is_out ? ED_OUT : ED_IN; - if (type != PIPE_BULK) { - /* periodic transfers... */ - if (type == PIPE_ISOCHRONOUS) - info |= ED_ISO; - else if (interval > 32) /* iso can be bigger */ - interval = 32; - ed->interval = interval; - ed->load = usb_calc_bus_time ( - udev->speed, !is_out, - type == PIPE_ISOCHRONOUS, - usb_maxpacket (udev, pipe, is_out)) - / 1000; - } - } - ed->hwINFO = info; - } - -done: - spin_unlock_irqrestore (&ohci->lock, flags); - return ed; -} - -/*-------------------------------------------------------------------------*/ - -/* request unlinking of an endpoint from an operational HC. - * put the ep on the rm_list - * real work is done at the next start frame (SF) hardware interrupt - */ -static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed) -{ - ed->hwINFO |= ED_DEQUEUE; - ed->state = ED_UNLINK; - ed_deschedule (ohci, ed); - - /* SF interrupt might get delayed; record the frame counter value that - * indicates when the HC isn't looking at it, so concurrent unlinks - * behave. frame_no wraps every 2^16 msec, and changes right before - * SF is triggered. - */ - ed->tick = le16_to_cpu (ohci->hcca->frame_no) + 1; - - /* rm_list is just singly linked, for simplicity */ - ed->ed_next = ohci->ed_rm_list; - ed->ed_prev = 0; - ohci->ed_rm_list = ed; - - /* enable SOF interrupt */ - if (!ohci->sleeping) { - writel (OHCI_INTR_SF, &ohci->regs->intrstatus); - writel (OHCI_INTR_SF, &ohci->regs->intrenable); - // flush those pci writes - (void) readl (&ohci->regs->control); - } -} - -/*-------------------------------------------------------------------------* - * TD handling functions - *-------------------------------------------------------------------------*/ - -/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */ - -static void -td_fill (struct ohci_hcd *ohci, u32 info, - dma_addr_t data, int len, - struct urb *urb, int index) -{ - struct td *td, *td_pt; - struct urb_priv *urb_priv = urb->hcpriv; - int is_iso = info & TD_ISO; - int hash; - - // ASSERT (index < urb_priv->length); - - /* aim for only one interrupt per urb. mostly applies to control - * and iso; other urbs rarely need more than one TD per urb. - * this way, only final tds (or ones with an error) cause IRQs. - * at least immediately; use DI=6 in case any control request is - * tempted to die part way through. - * - * NOTE: could delay interrupts even for the last TD, and get fewer - * interrupts ... increasing per-urb latency by sharing interrupts. - * Drivers that queue bulk urbs may request that behavior. - */ - if (index != (urb_priv->length - 1) - || (urb->transfer_flags & URB_NO_INTERRUPT)) - info |= TD_DI_SET (6); - - /* use this td as the next dummy */ - td_pt = urb_priv->td [index]; - - /* fill the old dummy TD */ - td = urb_priv->td [index] = urb_priv->ed->dummy; - urb_priv->ed->dummy = td_pt; - - td->ed = urb_priv->ed; - td->next_dl_td = NULL; - td->index = index; - td->urb = urb; - td->data_dma = data; - if (!len) - data = 0; - - td->hwINFO = cpu_to_le32 (info); - if (is_iso) { - td->hwCBP = cpu_to_le32 (data & 0xFFFFF000); - td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000); - td->ed->last_iso = info & 0xffff; - } else { - td->hwCBP = cpu_to_le32 (data); - } - if (data) - td->hwBE = cpu_to_le32 (data + len - 1); - else - td->hwBE = 0; - td->hwNextTD = cpu_to_le32 (td_pt->td_dma); - - /* append to queue */ - list_add_tail (&td->td_list, &td->ed->td_list); - - /* hash it for later reverse mapping */ - hash = TD_HASH_FUNC (td->td_dma); - td->td_hash = ohci->td_hash [hash]; - ohci->td_hash [hash] = td; - - /* HC might read the TD (or cachelines) right away ... */ - wmb (); - td->ed->hwTailP = td->hwNextTD; -} - -/*-------------------------------------------------------------------------*/ - -/* Prepare all TDs of a transfer, and queue them onto the ED. - * Caller guarantees HC is active. - * Usually the ED is already on the schedule, so TDs might be - * processed as soon as they're queued. - */ -static void td_submit_urb ( - struct ohci_hcd *ohci, - struct urb *urb -) { - struct urb_priv *urb_priv = urb->hcpriv; - dma_addr_t data; - int data_len = urb->transfer_buffer_length; - int cnt = 0; - u32 info = 0; - int is_out = usb_pipeout (urb->pipe); - - /* OHCI handles the bulk/interrupt data toggles itself. We just - * use the device toggle bits for resetting, and rely on the fact - * that resetting toggle is meaningless if the endpoint is active. - */ - if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) { - usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), - is_out, 1); - urb_priv->ed->hwHeadP &= ~ED_C; - } - - urb_priv->td_cnt = 0; - - if (data_len) - data = urb->transfer_dma; - else - data = 0; - - /* NOTE: TD_CC is set so we can tell which TDs the HC processed by - * using TD_CC_GET, as well as by seeing them on the done list. - * (CC = NotAccessed ... 0x0F, or 0x0E in PSWs for ISO.) - */ - switch (urb_priv->ed->type) { - - /* Bulk and interrupt are identical except for where in the schedule - * their EDs live. - */ - case PIPE_INTERRUPT: - /* ... and periodic urbs have extra accounting */ - hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs++; - /* FALLTHROUGH */ - case PIPE_BULK: - info = is_out - ? TD_T_TOGGLE | TD_CC | TD_DP_OUT - : TD_T_TOGGLE | TD_CC | TD_DP_IN; - /* TDs _could_ transfer up to 8K each */ - while (data_len > 4096) { - td_fill (ohci, info, data, 4096, urb, cnt); - data += 4096; - data_len -= 4096; - cnt++; - } - /* maybe avoid ED halt on final TD short read */ - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) - info |= TD_R; - td_fill (ohci, info, data, data_len, urb, cnt); - cnt++; - if ((urb->transfer_flags & URB_ZERO_PACKET) - && cnt < urb_priv->length) { - td_fill (ohci, info, 0, 0, urb, cnt); - cnt++; - } - /* maybe kickstart bulk list */ - if (urb_priv->ed->type == PIPE_BULK) { - wmb (); - writel (OHCI_BLF, &ohci->regs->cmdstatus); - } - break; - - /* control manages DATA0/DATA1 toggle per-request; SETUP resets it, - * any DATA phase works normally, and the STATUS ack is special. - */ - case PIPE_CONTROL: - info = TD_CC | TD_DP_SETUP | TD_T_DATA0; - td_fill (ohci, info, urb->setup_dma, 8, urb, cnt++); - if (data_len > 0) { - info = TD_CC | TD_R | TD_T_DATA1; - info |= is_out ? TD_DP_OUT : TD_DP_IN; - /* NOTE: mishandles transfers >8K, some >4K */ - td_fill (ohci, info, data, data_len, urb, cnt++); - } - info = is_out - ? TD_CC | TD_DP_IN | TD_T_DATA1 - : TD_CC | TD_DP_OUT | TD_T_DATA1; - td_fill (ohci, info, data, 0, urb, cnt++); - /* maybe kickstart control list */ - wmb (); - writel (OHCI_CLF, &ohci->regs->cmdstatus); - break; - - /* ISO has no retransmit, so no toggle; and it uses special TDs. - * Each TD could handle multiple consecutive frames (interval 1); - * we could often reduce the number of TDs here. - */ - case PIPE_ISOCHRONOUS: - for (cnt = 0; cnt < urb->number_of_packets; cnt++) { - int frame = urb->start_frame; - - // FIXME scheduling should handle frame counter - // roll-around ... exotic case (and OHCI has - // a 2^16 iso range, vs other HCs max of 2^10) - frame += cnt * urb->interval; - frame &= 0xffff; - td_fill (ohci, TD_CC | TD_ISO | frame, - data + urb->iso_frame_desc [cnt].offset, - urb->iso_frame_desc [cnt].length, urb, cnt); - } - hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs++; - break; - } - // ASSERT (urb_priv->length == cnt); -} - -/*-------------------------------------------------------------------------* - * Done List handling functions - *-------------------------------------------------------------------------*/ - -/* calculate transfer length/status and update the urb - * PRECONDITION: irqsafe (only for urb->status locking) - */ -static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) -{ - u32 tdINFO = le32_to_cpup (&td->hwINFO); - int cc = 0; - - list_del (&td->td_list); - - /* ISO ... drivers see per-TD length/status */ - if (tdINFO & TD_ISO) { - u16 tdPSW = le16_to_cpu (td->hwPSW [0]); - int dlen = 0; - - /* NOTE: assumes FC in tdINFO == 0 (and MAXPSW == 1) */ - - cc = (tdPSW >> 12) & 0xF; - if (tdINFO & TD_CC) /* hc didn't touch? */ - return; - - if (usb_pipeout (urb->pipe)) - dlen = urb->iso_frame_desc [td->index].length; - else { - /* short reads are always OK for ISO */ - if (cc == TD_DATAUNDERRUN) - cc = TD_CC_NOERROR; - dlen = tdPSW & 0x3ff; - } - urb->actual_length += dlen; - urb->iso_frame_desc [td->index].actual_length = dlen; - urb->iso_frame_desc [td->index].status = cc_to_error [cc]; - - if (cc != TD_CC_NOERROR) - ohci_vdbg (ohci, - "urb %p iso td %p (%d) len %d cc %d\n", - urb, td, 1 + td->index, dlen, cc); - - /* BULK, INT, CONTROL ... drivers see aggregate length/status, - * except that "setup" bytes aren't counted and "short" transfers - * might not be reported as errors. - */ - } else { - int type = usb_pipetype (urb->pipe); - u32 tdBE = le32_to_cpup (&td->hwBE); - - cc = TD_CC_GET (tdINFO); - - /* control endpoints only have soft stalls */ - if (type != PIPE_CONTROL && cc == TD_CC_STALL) - usb_endpoint_halt (urb->dev, - usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe)); - - /* update packet status if needed (short is normally ok) */ - if (cc == TD_DATAUNDERRUN - && !(urb->transfer_flags & URB_SHORT_NOT_OK)) - cc = TD_CC_NOERROR; - if (cc != TD_CC_NOERROR && cc < 0x0E) { - spin_lock (&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = cc_to_error [cc]; - spin_unlock (&urb->lock); - } - - /* count all non-empty packets except control SETUP packet */ - if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) { - if (td->hwCBP == 0) - urb->actual_length += tdBE - td->data_dma + 1; - else - urb->actual_length += - le32_to_cpup (&td->hwCBP) - - td->data_dma; - } - - if (cc != TD_CC_NOERROR && cc < 0x0E) - ohci_vdbg (ohci, - "urb %p td %p (%d) cc %d, len=%d/%d\n", - urb, td, 1 + td->index, cc, - urb->actual_length, - urb->transfer_buffer_length); - } -} - -/*-------------------------------------------------------------------------*/ - -static inline struct td * -ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) -{ - struct urb *urb = td->urb; - struct ed *ed = td->ed; - struct list_head *tmp = td->td_list.next; - u32 toggle = ed->hwHeadP & ED_C; - - /* clear ed halt; this is the td that caused it, but keep it inactive - * until its urb->complete() has a chance to clean up. - */ - ed->hwINFO |= ED_SKIP; - wmb (); - ed->hwHeadP &= ~ED_H; - - /* put any later tds from this urb onto the donelist, after 'td', - * order won't matter here: no errors, and nothing was transferred. - * also patch the ed so it looks as if those tds completed normally. - */ - while (tmp != &ed->td_list) { - struct td *next; - u32 info; - - next = list_entry (tmp, struct td, td_list); - tmp = next->td_list.next; - - if (next->urb != urb) - break; - - /* NOTE: if multi-td control DATA segments get supported, - * this urb had one of them, this td wasn't the last td - * in that segment (TD_R clear), this ed halted because - * of a short read, _and_ URB_SHORT_NOT_OK is clear ... - * then we need to leave the control STATUS packet queued - * and clear ED_SKIP. - */ - info = next->hwINFO; - info |= cpu_to_le32 (TD_DONE); - info &= ~cpu_to_le32 (TD_CC); - next->hwINFO = info; - - next->next_dl_td = rev; - rev = next; - - if (ed->hwTailP == cpu_to_le32 (next->td_dma)) - ed->hwTailP = next->hwNextTD; - ed->hwHeadP = next->hwNextTD | toggle; - } - - /* help for troubleshooting: report anything that - * looks odd ... that doesn't include protocol stalls - * (or maybe some other things) - */ - if (cc != TD_CC_STALL || !usb_pipecontrol (urb->pipe)) - ohci_dbg (ohci, - "urb %p path %s ep%d%s %08x cc %d --> status %d\n", - urb, urb->dev->devpath, - usb_pipeendpoint (urb->pipe), - usb_pipein (urb->pipe) ? "in" : "out", - le32_to_cpu (td->hwINFO), - cc, cc_to_error [cc]); - - return rev; -} - -/* replies to the request have to be on a FIFO basis so - * we unreverse the hc-reversed done-list - */ -static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) -{ - u32 td_dma; - struct td *td_rev = NULL; - struct td *td = NULL; - unsigned long flags; - - spin_lock_irqsave (&ohci->lock, flags); - td_dma = le32_to_cpup (&ohci->hcca->done_head); - ohci->hcca->done_head = 0; - - /* get TD from hc's singly linked list, and - * prepend to ours. ed->td_list changes later. - */ - while (td_dma) { - int cc; - - td = dma_to_td (ohci, td_dma); - if (!td) { - ohci_err (ohci, "bad entry %8x\n", td_dma); - break; - } - - td->hwINFO |= cpu_to_le32 (TD_DONE); - cc = TD_CC_GET (le32_to_cpup (&td->hwINFO)); - - /* Non-iso endpoints can halt on error; un-halt, - * and dequeue any other TDs from this urb. - * No other TD could have caused the halt. - */ - if (cc != TD_CC_NOERROR && (td->ed->hwHeadP & ED_H)) - td_rev = ed_halted (ohci, td, cc, td_rev); - - td->next_dl_td = td_rev; - td_rev = td; - td_dma = le32_to_cpup (&td->hwNextTD); - } - spin_unlock_irqrestore (&ohci->lock, flags); - return td_rev; -} - -/*-------------------------------------------------------------------------*/ - -/* wrap-aware logic stolen from */ -#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0) - -/* there are some urbs/eds to unlink; called in_irq(), with HCD locked */ -static void -finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs) -{ - struct ed *ed, **last; - -rescan_all: - for (last = &ohci->ed_rm_list, ed = *last; ed != NULL; ed = *last) { - struct list_head *entry, *tmp; - int completed, modified; - u32 *prev; - - /* only take off EDs that the HC isn't using, accounting for - * frame counter wraps. - */ - if (tick_before (tick, ed->tick) && !ohci->disabled) { - last = &ed->ed_next; - continue; - } - - /* reentrancy: if we drop the schedule lock, someone might - * have modified this list. normally it's just prepending - * entries (which we'd ignore), but paranoia won't hurt. - */ - *last = ed->ed_next; - ed->ed_next = 0; - modified = 0; - - /* unlink urbs as requested, but rescan the list after - * we call a completion since it might have unlinked - * another (earlier) urb - */ -rescan_this: - completed = 0; - prev = &ed->hwHeadP; - list_for_each_safe (entry, tmp, &ed->td_list) { - struct td *td; - struct urb *urb; - urb_priv_t *urb_priv; - u32 savebits; - - td = list_entry (entry, struct td, td_list); - urb = td->urb; - urb_priv = td->urb->hcpriv; - - if (urb_priv->state != URB_DEL) { - prev = &td->hwNextTD; - continue; - } - - /* patch pointers hc uses ... tail, if we're removing - * an otherwise active td, and whatever td pointer - * points to this td - */ - if (ed->hwTailP == cpu_to_le32 (td->td_dma)) - ed->hwTailP = td->hwNextTD; - savebits = *prev & ~cpu_to_le32 (TD_MASK); - *prev = td->hwNextTD | savebits; - - /* HC may have partly processed this TD */ - td_done (ohci, urb, td); - urb_priv->td_cnt++; - - /* if URB is done, clean up */ - if (urb_priv->td_cnt == urb_priv->length) { - modified = completed = 1; - spin_unlock (&ohci->lock); - finish_urb (ohci, urb, regs); - spin_lock (&ohci->lock); - } - } - if (completed && !list_empty (&ed->td_list)) - goto rescan_this; - - /* ED's now officially unlinked, hc doesn't see */ - ed->state = ED_IDLE; - ed->hwINFO &= ~(ED_SKIP | ED_DEQUEUE); - ed->hwHeadP &= ~ED_H; - ed->hwNextED = 0; - - /* but if there's work queued, reschedule */ - if (!list_empty (&ed->td_list)) { - if (!ohci->disabled && !ohci->sleeping) - ed_schedule (ohci, ed); - } - - if (modified) - goto rescan_all; - } - - /* maybe reenable control and bulk lists */ - if (!ohci->disabled && !ohci->ed_rm_list) { - u32 command = 0, control = 0; - - if (ohci->ed_controltail) { - command |= OHCI_CLF; - if (!(ohci->hc_control & OHCI_CTRL_CLE)) { - control |= OHCI_CTRL_CLE; - writel (0, &ohci->regs->ed_controlcurrent); - } - } - if (ohci->ed_bulktail) { - command |= OHCI_BLF; - if (!(ohci->hc_control & OHCI_CTRL_BLE)) { - control |= OHCI_CTRL_BLE; - writel (0, &ohci->regs->ed_bulkcurrent); - } - } - - /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */ - if (control) { - ohci->hc_control |= control; - writel (ohci->hc_control, &ohci->regs->control); - } - if (command) - writel (command, &ohci->regs->cmdstatus); - } -} - - - -/*-------------------------------------------------------------------------*/ - -/* - * Process normal completions (error or success) and clean the schedules. - * - * This is the main path for handing urbs back to drivers. The only other - * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of - * scanning the (re-reversed) donelist as this does. - */ -static void -dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs *regs) -{ - unsigned long flags; - - spin_lock_irqsave (&ohci->lock, flags); - while (td) { - struct td *td_next = td->next_dl_td; - struct urb *urb = td->urb; - urb_priv_t *urb_priv = urb->hcpriv; - struct ed *ed = td->ed; - - /* update URB's length and status from TD */ - td_done (ohci, urb, td); - urb_priv->td_cnt++; - - /* If all this urb's TDs are done, call complete() */ - if (urb_priv->td_cnt == urb_priv->length) { - spin_unlock (&ohci->lock); - finish_urb (ohci, urb, regs); - spin_lock (&ohci->lock); - } - - /* clean schedule: unlink EDs that are no longer busy */ - if (list_empty (&ed->td_list)) - ed_deschedule (ohci, ed); - /* ... reenabling halted EDs only after fault cleanup */ - else if (!(ed->hwINFO & ED_DEQUEUE)) { - td = list_entry (ed->td_list.next, struct td, td_list); - if (!(td->hwINFO & TD_DONE)) - ed->hwINFO &= ~ED_SKIP; - } - - td = td_next; - } - spin_unlock_irqrestore (&ohci->lock, flags); -} +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * + * This file is licenced under the GPL. + */ + +static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv) +{ + int last = urb_priv->length - 1; + + if (last >= 0) { + int i; + struct td *td; + + for (i = 0; i <= last; i++) { + td = urb_priv->td [i]; + if (td) + td_free (hc, td); + } + } + + kfree (urb_priv); +} + +/*-------------------------------------------------------------------------*/ + +/* + * URB goes back to driver, and isn't reissued. + * It's completely gone from HC data structures. + * PRECONDITION: no locks held, irqs blocked (Giveback can call into HCD.) + */ +static void +finish_urb (struct ohci_hcd *ohci, struct urb *urb, struct pt_regs *regs) +{ + // ASSERT (urb->hcpriv != 0); + + urb_free_priv (ohci, urb->hcpriv); + urb->hcpriv = NULL; + + spin_lock (&urb->lock); + if (likely (urb->status == -EINPROGRESS)) + urb->status = 0; + spin_unlock (&urb->lock); + + // what lock protects these? + switch (usb_pipetype (urb->pipe)) { + case PIPE_ISOCHRONOUS: + hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs--; + break; + case PIPE_INTERRUPT: + hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs--; + break; + } + +#ifdef OHCI_VERBOSE_DEBUG + urb_print (urb, "RET", usb_pipeout (urb->pipe)); +#endif + usb_hcd_giveback_urb (&ohci->hcd, urb, regs); +} + + +/*-------------------------------------------------------------------------* + * ED handling functions + *-------------------------------------------------------------------------*/ + +/* search for the right schedule branch to use for a periodic ed. + * does some load balancing; returns the branch, or negative errno. + */ +static int balance (struct ohci_hcd *ohci, int interval, int load) +{ + int i, branch = -ENOSPC; + + /* iso periods can be huge; iso tds specify frame numbers */ + if (interval > NUM_INTS) + interval = NUM_INTS; + + /* search for the least loaded schedule branch of that period + * that has enough bandwidth left unreserved. + */ + for (i = 0; i < interval ; i++) { + if (branch < 0 || ohci->load [branch] > ohci->load [i]) { +#if 1 /* CONFIG_USB_BANDWIDTH */ + int j; + + /* usb 1.1 says 90% of one frame */ + for (j = i; j < NUM_INTS; j += interval) { + if ((ohci->load [j] + load) > 900) + break; + } + if (j < NUM_INTS) + continue; +#endif + branch = i; + } + } + return branch; +} + +/*-------------------------------------------------------------------------*/ + +/* both iso and interrupt requests have periods; this routine puts them + * into the schedule tree in the apppropriate place. most iso devices use + * 1msec periods, but that's not required. + */ +static void periodic_link (struct ohci_hcd *ohci, struct ed *ed) +{ + unsigned i; + + ohci_vdbg (ohci, "link %sed %p branch %d [%dus.], interval %d\n", + (ed->hwINFO & ED_ISO) ? "iso " : "", + ed, ed->branch, ed->load, ed->interval); + + for (i = ed->branch; i < NUM_INTS; i += ed->interval) { + struct ed **prev = &ohci->periodic [i]; + u32 *prev_p = &ohci->hcca->int_table [i]; + struct ed *here = *prev; + + /* sorting each branch by period (slow before fast) + * lets us share the faster parts of the tree. + * (plus maybe: put interrupt eds before iso) + */ + while (here && ed != here) { + if (ed->interval > here->interval) + break; + prev = &here->ed_next; + prev_p = &here->hwNextED; + here = *prev; + } + if (ed != here) { + ed->ed_next = here; + if (here) + ed->hwNextED = *prev_p; + wmb (); + *prev = ed; + *prev_p = cpu_to_le32p (&ed->dma); + } + ohci->load [i] += ed->load; + } + hcd_to_bus (&ohci->hcd)->bandwidth_allocated += ed->load / ed->interval; +} + +/* link an ed into one of the HC chains */ + +static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) +{ + int branch; + + ed->state = ED_OPER; + ed->ed_prev = 0; + ed->ed_next = 0; + ed->hwNextED = 0; + wmb (); + + /* we care about rm_list when setting CLE/BLE in case the HC was at + * work on some TD when CLE/BLE was turned off, and isn't quiesced + * yet. finish_unlinks() restarts as needed, some upcoming INTR_SF. + * + * control and bulk EDs are doubly linked (ed_next, ed_prev), but + * periodic ones are singly linked (ed_next). that's because the + * periodic schedule encodes a tree like figure 3-5 in the ohci + * spec: each qh can have several "previous" nodes, and the tree + * doesn't have unused/idle descriptors. + */ + switch (ed->type) { + case PIPE_CONTROL: + if (ohci->ed_controltail == NULL) { + writel (ed->dma, &ohci->regs->ed_controlhead); + } else { + ohci->ed_controltail->ed_next = ed; + ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma); + } + ed->ed_prev = ohci->ed_controltail; + if (!ohci->ed_controltail && !ohci->ed_rm_list) { + ohci->hc_control |= OHCI_CTRL_CLE; + writel (0, &ohci->regs->ed_controlcurrent); + writel (ohci->hc_control, &ohci->regs->control); + } + ohci->ed_controltail = ed; + break; + + case PIPE_BULK: + if (ohci->ed_bulktail == NULL) { + writel (ed->dma, &ohci->regs->ed_bulkhead); + } else { + ohci->ed_bulktail->ed_next = ed; + ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma); + } + ed->ed_prev = ohci->ed_bulktail; + if (!ohci->ed_bulktail && !ohci->ed_rm_list) { + ohci->hc_control |= OHCI_CTRL_BLE; + writel (0, &ohci->regs->ed_bulkcurrent); + writel (ohci->hc_control, &ohci->regs->control); + } + ohci->ed_bulktail = ed; + break; + + // case PIPE_INTERRUPT: + // case PIPE_ISOCHRONOUS: + default: + branch = balance (ohci, ed->interval, ed->load); + if (branch < 0) { + ohci_dbg (ohci, + "ERR %d, interval %d msecs, load %d\n", + branch, ed->interval, ed->load); + // FIXME if there are TDs queued, fail them! + return branch; + } + ed->branch = branch; + periodic_link (ohci, ed); + } + + /* the HC may not see the schedule updates yet, but if it does + * then they'll be properly ordered. + */ + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* scan the periodic table to find and unlink this ED */ +static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) +{ + int i; + + for (i = ed->branch; i < NUM_INTS; i += ed->interval) { + struct ed *temp; + struct ed **prev = &ohci->periodic [i]; + u32 *prev_p = &ohci->hcca->int_table [i]; + + while (*prev && (temp = *prev) != ed) { + prev_p = &temp->hwNextED; + prev = &temp->ed_next; + } + if (*prev) { + *prev_p = ed->hwNextED; + *prev = ed->ed_next; + } + ohci->load [i] -= ed->load; + } + hcd_to_bus (&ohci->hcd)->bandwidth_allocated -= ed->load / ed->interval; + + ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n", + (ed->hwINFO & ED_ISO) ? "iso " : "", + ed, ed->branch, ed->load, ed->interval); +} + +/* unlink an ed from one of the HC chains. + * just the link to the ed is unlinked. + * the link from the ed still points to another operational ed or 0 + * so the HC can eventually finish the processing of the unlinked ed + */ +static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) +{ + ed->hwINFO |= ED_SKIP; + + switch (ed->type) { + case PIPE_CONTROL: + if (ed->ed_prev == NULL) { + if (!ed->hwNextED) { + ohci->hc_control &= ~OHCI_CTRL_CLE; + writel (ohci->hc_control, &ohci->regs->control); + writel (0, &ohci->regs->ed_controlcurrent); + // post those pci writes + (void) readl (&ohci->regs->control); + } + writel (le32_to_cpup (&ed->hwNextED), + &ohci->regs->ed_controlhead); + } else { + ed->ed_prev->ed_next = ed->ed_next; + ed->ed_prev->hwNextED = ed->hwNextED; + } + if (ohci->ed_controltail == ed) { + ohci->ed_controltail = ed->ed_prev; + if (ohci->ed_controltail) + ohci->ed_controltail->ed_next = 0; + } else if (ed->ed_next) { + ed->ed_next->ed_prev = ed->ed_prev; + } + break; + + case PIPE_BULK: + if (ed->ed_prev == NULL) { + if (!ed->hwNextED) { + ohci->hc_control &= ~OHCI_CTRL_BLE; + writel (ohci->hc_control, &ohci->regs->control); + writel (0, &ohci->regs->ed_bulkcurrent); + // post those pci writes + (void) readl (&ohci->regs->control); + } + writel (le32_to_cpup (&ed->hwNextED), + &ohci->regs->ed_bulkhead); + } else { + ed->ed_prev->ed_next = ed->ed_next; + ed->ed_prev->hwNextED = ed->hwNextED; + } + if (ohci->ed_bulktail == ed) { + ohci->ed_bulktail = ed->ed_prev; + if (ohci->ed_bulktail) + ohci->ed_bulktail->ed_next = 0; + } else if (ed->ed_next) { + ed->ed_next->ed_prev = ed->ed_prev; + } + break; + + // case PIPE_INTERRUPT: + // case PIPE_ISOCHRONOUS: + default: + periodic_unlink (ohci, ed); + break; + } + + /* NOTE: Except for a couple of exceptionally clean unlink cases + * (like unlinking the only c/b ED, with no TDs) HCs may still be + * caching this operational ED (or its address). Safe unlinking + * involves not marking it ED_IDLE till INTR_SF; we always do that + * if td_list isn't empty. Otherwise the race is small; but ... + */ + if (ed->state == ED_OPER) { + ed->state = ED_IDLE; + ed->hwINFO &= ~(ED_SKIP | ED_DEQUEUE); + ed->hwHeadP &= ~ED_H; + wmb (); + } +} + + +/*-------------------------------------------------------------------------*/ + +/* get and maybe (re)init an endpoint. init _should_ be done only as part + * of usb_set_configuration() or usb_set_interface() ... but the USB stack + * isn't very stateful, so we re-init whenever the HC isn't looking. + */ +static struct ed *ed_get ( + struct ohci_hcd *ohci, + struct usb_device *udev, + unsigned int pipe, + int interval +) { + int is_out = !usb_pipein (pipe); + int type = usb_pipetype (pipe); + struct hcd_dev *dev = (struct hcd_dev *) udev->hcpriv; + struct ed *ed; + unsigned ep; + unsigned long flags; + + ep = usb_pipeendpoint (pipe) << 1; + if (type != PIPE_CONTROL && is_out) + ep |= 1; + + spin_lock_irqsave (&ohci->lock, flags); + + if (!(ed = dev->ep [ep])) { + struct td *td; + + ed = ed_alloc (ohci, SLAB_ATOMIC); + if (!ed) { + /* out of memory */ + goto done; + } + dev->ep [ep] = ed; + + /* dummy td; end of td list for ed */ + td = td_alloc (ohci, SLAB_ATOMIC); + if (!td) { + /* out of memory */ + ed_free (ohci, ed); + ed = 0; + goto done; + } + ed->dummy = td; + ed->hwTailP = cpu_to_le32 (td->td_dma); + ed->hwHeadP = ed->hwTailP; /* ED_C, ED_H zeroed */ + ed->state = ED_IDLE; + ed->type = type; + } + + /* NOTE: only ep0 currently needs this "re"init logic, during + * enumeration (after set_address, or if ep0 maxpacket >8). + */ + if (ed->state == ED_IDLE) { + u32 info; + + info = usb_pipedevice (pipe); + info |= (ep >> 1) << 7; + info |= usb_maxpacket (udev, pipe, is_out) << 16; + info = cpu_to_le32 (info); + if (udev->speed == USB_SPEED_LOW) + info |= ED_LOWSPEED; + /* only control transfers store pids in tds */ + if (type != PIPE_CONTROL) { + info |= is_out ? ED_OUT : ED_IN; + if (type != PIPE_BULK) { + /* periodic transfers... */ + if (type == PIPE_ISOCHRONOUS) + info |= ED_ISO; + else if (interval > 32) /* iso can be bigger */ + interval = 32; + ed->interval = interval; + ed->load = usb_calc_bus_time ( + udev->speed, !is_out, + type == PIPE_ISOCHRONOUS, + usb_maxpacket (udev, pipe, is_out)) + / 1000; + } + } + ed->hwINFO = info; + } + +done: + spin_unlock_irqrestore (&ohci->lock, flags); + return ed; +} + +/*-------------------------------------------------------------------------*/ + +/* request unlinking of an endpoint from an operational HC. + * put the ep on the rm_list + * real work is done at the next start frame (SF) hardware interrupt + */ +static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed) +{ + ed->hwINFO |= ED_DEQUEUE; + ed->state = ED_UNLINK; + ed_deschedule (ohci, ed); + + /* SF interrupt might get delayed; record the frame counter value that + * indicates when the HC isn't looking at it, so concurrent unlinks + * behave. frame_no wraps every 2^16 msec, and changes right before + * SF is triggered. + */ + ed->tick = le16_to_cpu (ohci->hcca->frame_no) + 1; + + /* rm_list is just singly linked, for simplicity */ + ed->ed_next = ohci->ed_rm_list; + ed->ed_prev = 0; + ohci->ed_rm_list = ed; + + /* enable SOF interrupt */ + if (!ohci->sleeping) { + writel (OHCI_INTR_SF, &ohci->regs->intrstatus); + writel (OHCI_INTR_SF, &ohci->regs->intrenable); + // flush those pci writes + (void) readl (&ohci->regs->control); + } +} + +/*-------------------------------------------------------------------------* + * TD handling functions + *-------------------------------------------------------------------------*/ + +/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */ + +static void +td_fill (struct ohci_hcd *ohci, u32 info, + dma_addr_t data, int len, + struct urb *urb, int index) +{ + struct td *td, *td_pt; + struct urb_priv *urb_priv = urb->hcpriv; + int is_iso = info & TD_ISO; + int hash; + + // ASSERT (index < urb_priv->length); + + /* aim for only one interrupt per urb. mostly applies to control + * and iso; other urbs rarely need more than one TD per urb. + * this way, only final tds (or ones with an error) cause IRQs. + * at least immediately; use DI=6 in case any control request is + * tempted to die part way through. + * + * NOTE: could delay interrupts even for the last TD, and get fewer + * interrupts ... increasing per-urb latency by sharing interrupts. + * Drivers that queue bulk urbs may request that behavior. + */ + if (index != (urb_priv->length - 1) + || (urb->transfer_flags & URB_NO_INTERRUPT)) + info |= TD_DI_SET (6); + + /* use this td as the next dummy */ + td_pt = urb_priv->td [index]; + + /* fill the old dummy TD */ + td = urb_priv->td [index] = urb_priv->ed->dummy; + urb_priv->ed->dummy = td_pt; + + td->ed = urb_priv->ed; + td->next_dl_td = NULL; + td->index = index; + td->urb = urb; + td->data_dma = data; + if (!len) + data = 0; + + td->hwINFO = cpu_to_le32 (info); + if (is_iso) { + td->hwCBP = cpu_to_le32 (data & 0xFFFFF000); + td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000); + td->ed->last_iso = info & 0xffff; + } else { + td->hwCBP = cpu_to_le32 (data); + } + if (data) + td->hwBE = cpu_to_le32 (data + len - 1); + else + td->hwBE = 0; + td->hwNextTD = cpu_to_le32 (td_pt->td_dma); + + /* append to queue */ + list_add_tail (&td->td_list, &td->ed->td_list); + + /* hash it for later reverse mapping */ + hash = TD_HASH_FUNC (td->td_dma); + td->td_hash = ohci->td_hash [hash]; + ohci->td_hash [hash] = td; + + /* HC might read the TD (or cachelines) right away ... */ + wmb (); + td->ed->hwTailP = td->hwNextTD; +} + +/*-------------------------------------------------------------------------*/ + +/* Prepare all TDs of a transfer, and queue them onto the ED. + * Caller guarantees HC is active. + * Usually the ED is already on the schedule, so TDs might be + * processed as soon as they're queued. + */ +static void td_submit_urb ( + struct ohci_hcd *ohci, + struct urb *urb +) { + struct urb_priv *urb_priv = urb->hcpriv; + dma_addr_t data; + int data_len = urb->transfer_buffer_length; + int cnt = 0; + u32 info = 0; + int is_out = usb_pipeout (urb->pipe); + + /* OHCI handles the bulk/interrupt data toggles itself. We just + * use the device toggle bits for resetting, and rely on the fact + * that resetting toggle is meaningless if the endpoint is active. + */ + if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) { + usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), + is_out, 1); + urb_priv->ed->hwHeadP &= ~ED_C; + } + + urb_priv->td_cnt = 0; + + if (data_len) + data = urb->transfer_dma; + else + data = 0; + + /* NOTE: TD_CC is set so we can tell which TDs the HC processed by + * using TD_CC_GET, as well as by seeing them on the done list. + * (CC = NotAccessed ... 0x0F, or 0x0E in PSWs for ISO.) + */ + switch (urb_priv->ed->type) { + + /* Bulk and interrupt are identical except for where in the schedule + * their EDs live. + */ + case PIPE_INTERRUPT: + /* ... and periodic urbs have extra accounting */ + hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs++; + /* FALLTHROUGH */ + case PIPE_BULK: + info = is_out + ? TD_T_TOGGLE | TD_CC | TD_DP_OUT + : TD_T_TOGGLE | TD_CC | TD_DP_IN; + /* TDs _could_ transfer up to 8K each */ + while (data_len > 4096) { + td_fill (ohci, info, data, 4096, urb, cnt); + data += 4096; + data_len -= 4096; + cnt++; + } + /* maybe avoid ED halt on final TD short read */ + if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) + info |= TD_R; + td_fill (ohci, info, data, data_len, urb, cnt); + cnt++; + if ((urb->transfer_flags & URB_ZERO_PACKET) + && cnt < urb_priv->length) { + td_fill (ohci, info, 0, 0, urb, cnt); + cnt++; + } + /* maybe kickstart bulk list */ + if (urb_priv->ed->type == PIPE_BULK) { + wmb (); + writel (OHCI_BLF, &ohci->regs->cmdstatus); + } + break; + + /* control manages DATA0/DATA1 toggle per-request; SETUP resets it, + * any DATA phase works normally, and the STATUS ack is special. + */ + case PIPE_CONTROL: + info = TD_CC | TD_DP_SETUP | TD_T_DATA0; + td_fill (ohci, info, urb->setup_dma, 8, urb, cnt++); + if (data_len > 0) { + info = TD_CC | TD_R | TD_T_DATA1; + info |= is_out ? TD_DP_OUT : TD_DP_IN; + /* NOTE: mishandles transfers >8K, some >4K */ + td_fill (ohci, info, data, data_len, urb, cnt++); + } + info = is_out + ? TD_CC | TD_DP_IN | TD_T_DATA1 + : TD_CC | TD_DP_OUT | TD_T_DATA1; + td_fill (ohci, info, data, 0, urb, cnt++); + /* maybe kickstart control list */ + wmb (); + writel (OHCI_CLF, &ohci->regs->cmdstatus); + break; + + /* ISO has no retransmit, so no toggle; and it uses special TDs. + * Each TD could handle multiple consecutive frames (interval 1); + * we could often reduce the number of TDs here. + */ + case PIPE_ISOCHRONOUS: + for (cnt = 0; cnt < urb->number_of_packets; cnt++) { + int frame = urb->start_frame; + + // FIXME scheduling should handle frame counter + // roll-around ... exotic case (and OHCI has + // a 2^16 iso range, vs other HCs max of 2^10) + frame += cnt * urb->interval; + frame &= 0xffff; + td_fill (ohci, TD_CC | TD_ISO | frame, + data + urb->iso_frame_desc [cnt].offset, + urb->iso_frame_desc [cnt].length, urb, cnt); + } + hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs++; + break; + } + // ASSERT (urb_priv->length == cnt); +} + +/*-------------------------------------------------------------------------* + * Done List handling functions + *-------------------------------------------------------------------------*/ + +/* calculate transfer length/status and update the urb + * PRECONDITION: irqsafe (only for urb->status locking) + */ +static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) +{ + u32 tdINFO = le32_to_cpup (&td->hwINFO); + int cc = 0; + + list_del (&td->td_list); + + /* ISO ... drivers see per-TD length/status */ + if (tdINFO & TD_ISO) { + u16 tdPSW = le16_to_cpu (td->hwPSW [0]); + int dlen = 0; + + /* NOTE: assumes FC in tdINFO == 0 (and MAXPSW == 1) */ + + cc = (tdPSW >> 12) & 0xF; + if (tdINFO & TD_CC) /* hc didn't touch? */ + return; + + if (usb_pipeout (urb->pipe)) + dlen = urb->iso_frame_desc [td->index].length; + else { + /* short reads are always OK for ISO */ + if (cc == TD_DATAUNDERRUN) + cc = TD_CC_NOERROR; + dlen = tdPSW & 0x3ff; + } + urb->actual_length += dlen; + urb->iso_frame_desc [td->index].actual_length = dlen; + urb->iso_frame_desc [td->index].status = cc_to_error [cc]; + + if (cc != TD_CC_NOERROR) + ohci_vdbg (ohci, + "urb %p iso td %p (%d) len %d cc %d\n", + urb, td, 1 + td->index, dlen, cc); + + /* BULK, INT, CONTROL ... drivers see aggregate length/status, + * except that "setup" bytes aren't counted and "short" transfers + * might not be reported as errors. + */ + } else { + int type = usb_pipetype (urb->pipe); + u32 tdBE = le32_to_cpup (&td->hwBE); + + cc = TD_CC_GET (tdINFO); + + /* control endpoints only have soft stalls */ + if (type != PIPE_CONTROL && cc == TD_CC_STALL) + usb_endpoint_halt (urb->dev, + usb_pipeendpoint (urb->pipe), + usb_pipeout (urb->pipe)); + + /* update packet status if needed (short is normally ok) */ + if (cc == TD_DATAUNDERRUN + && !(urb->transfer_flags & URB_SHORT_NOT_OK)) + cc = TD_CC_NOERROR; + if (cc != TD_CC_NOERROR && cc < 0x0E) { + spin_lock (&urb->lock); + if (urb->status == -EINPROGRESS) + urb->status = cc_to_error [cc]; + spin_unlock (&urb->lock); + } + + /* count all non-empty packets except control SETUP packet */ + if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) { + if (td->hwCBP == 0) + urb->actual_length += tdBE - td->data_dma + 1; + else + urb->actual_length += + le32_to_cpup (&td->hwCBP) + - td->data_dma; + } + + if (cc != TD_CC_NOERROR && cc < 0x0E) + ohci_vdbg (ohci, + "urb %p td %p (%d) cc %d, len=%d/%d\n", + urb, td, 1 + td->index, cc, + urb->actual_length, + urb->transfer_buffer_length); + } +} + +/*-------------------------------------------------------------------------*/ + +static inline struct td * +ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) +{ + struct urb *urb = td->urb; + struct ed *ed = td->ed; + struct list_head *tmp = td->td_list.next; + u32 toggle = ed->hwHeadP & ED_C; + + /* clear ed halt; this is the td that caused it, but keep it inactive + * until its urb->complete() has a chance to clean up. + */ + ed->hwINFO |= ED_SKIP; + wmb (); + ed->hwHeadP &= ~ED_H; + + /* put any later tds from this urb onto the donelist, after 'td', + * order won't matter here: no errors, and nothing was transferred. + * also patch the ed so it looks as if those tds completed normally. + */ + while (tmp != &ed->td_list) { + struct td *next; + u32 info; + + next = list_entry (tmp, struct td, td_list); + tmp = next->td_list.next; + + if (next->urb != urb) + break; + + /* NOTE: if multi-td control DATA segments get supported, + * this urb had one of them, this td wasn't the last td + * in that segment (TD_R clear), this ed halted because + * of a short read, _and_ URB_SHORT_NOT_OK is clear ... + * then we need to leave the control STATUS packet queued + * and clear ED_SKIP. + */ + info = next->hwINFO; + info |= cpu_to_le32 (TD_DONE); + info &= ~cpu_to_le32 (TD_CC); + next->hwINFO = info; + + next->next_dl_td = rev; + rev = next; + + if (ed->hwTailP == cpu_to_le32 (next->td_dma)) + ed->hwTailP = next->hwNextTD; + ed->hwHeadP = next->hwNextTD | toggle; + } + + /* help for troubleshooting: report anything that + * looks odd ... that doesn't include protocol stalls + * (or maybe some other things) + */ + if (cc != TD_CC_STALL || !usb_pipecontrol (urb->pipe)) + ohci_dbg (ohci, + "urb %p path %s ep%d%s %08x cc %d --> status %d\n", + urb, urb->dev->devpath, + usb_pipeendpoint (urb->pipe), + usb_pipein (urb->pipe) ? "in" : "out", + le32_to_cpu (td->hwINFO), + cc, cc_to_error [cc]); + + return rev; +} + +/* replies to the request have to be on a FIFO basis so + * we unreverse the hc-reversed done-list + */ +static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) +{ + u32 td_dma; + struct td *td_rev = NULL; + struct td *td = NULL; + unsigned long flags; + + spin_lock_irqsave (&ohci->lock, flags); + td_dma = le32_to_cpup (&ohci->hcca->done_head); + ohci->hcca->done_head = 0; + + /* get TD from hc's singly linked list, and + * prepend to ours. ed->td_list changes later. + */ + while (td_dma) { + int cc; + + td = dma_to_td (ohci, td_dma); + if (!td) { + ohci_err (ohci, "bad entry %8x\n", td_dma); + break; + } + + td->hwINFO |= cpu_to_le32 (TD_DONE); + cc = TD_CC_GET (le32_to_cpup (&td->hwINFO)); + + /* Non-iso endpoints can halt on error; un-halt, + * and dequeue any other TDs from this urb. + * No other TD could have caused the halt. + */ + if (cc != TD_CC_NOERROR && (td->ed->hwHeadP & ED_H)) + td_rev = ed_halted (ohci, td, cc, td_rev); + + td->next_dl_td = td_rev; + td_rev = td; + td_dma = le32_to_cpup (&td->hwNextTD); + } + spin_unlock_irqrestore (&ohci->lock, flags); + return td_rev; +} + +/*-------------------------------------------------------------------------*/ + +/* wrap-aware logic stolen from */ +#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0) + +/* there are some urbs/eds to unlink; called in_irq(), with HCD locked */ +static void +finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs) +{ + struct ed *ed, **last; + +rescan_all: + for (last = &ohci->ed_rm_list, ed = *last; ed != NULL; ed = *last) { + struct list_head *entry, *tmp; + int completed, modified; + u32 *prev; + + /* only take off EDs that the HC isn't using, accounting for + * frame counter wraps. + */ + if (tick_before (tick, ed->tick) && !ohci->disabled) { + last = &ed->ed_next; + continue; + } + + /* reentrancy: if we drop the schedule lock, someone might + * have modified this list. normally it's just prepending + * entries (which we'd ignore), but paranoia won't hurt. + */ + *last = ed->ed_next; + ed->ed_next = 0; + modified = 0; + + /* unlink urbs as requested, but rescan the list after + * we call a completion since it might have unlinked + * another (earlier) urb + */ +rescan_this: + completed = 0; + prev = &ed->hwHeadP; + list_for_each_safe (entry, tmp, &ed->td_list) { + struct td *td; + struct urb *urb; + urb_priv_t *urb_priv; + u32 savebits; + + td = list_entry (entry, struct td, td_list); + urb = td->urb; + urb_priv = td->urb->hcpriv; + + if (urb_priv->state != URB_DEL) { + prev = &td->hwNextTD; + continue; + } + + /* patch pointers hc uses ... tail, if we're removing + * an otherwise active td, and whatever td pointer + * points to this td + */ + if (ed->hwTailP == cpu_to_le32 (td->td_dma)) + ed->hwTailP = td->hwNextTD; + savebits = *prev & ~cpu_to_le32 (TD_MASK); + *prev = td->hwNextTD | savebits; + + /* HC may have partly processed this TD */ + td_done (ohci, urb, td); + urb_priv->td_cnt++; + + /* if URB is done, clean up */ + if (urb_priv->td_cnt == urb_priv->length) { + modified = completed = 1; + spin_unlock (&ohci->lock); + finish_urb (ohci, urb, regs); + spin_lock (&ohci->lock); + } + } + if (completed && !list_empty (&ed->td_list)) + goto rescan_this; + + /* ED's now officially unlinked, hc doesn't see */ + ed->state = ED_IDLE; + ed->hwINFO &= ~(ED_SKIP | ED_DEQUEUE); + ed->hwHeadP &= ~ED_H; + ed->hwNextED = 0; + + /* but if there's work queued, reschedule */ + if (!list_empty (&ed->td_list)) { + if (!ohci->disabled && !ohci->sleeping) + ed_schedule (ohci, ed); + } + + if (modified) + goto rescan_all; + } + + /* maybe reenable control and bulk lists */ + if (!ohci->disabled && !ohci->ed_rm_list) { + u32 command = 0, control = 0; + + if (ohci->ed_controltail) { + command |= OHCI_CLF; + if (!(ohci->hc_control & OHCI_CTRL_CLE)) { + control |= OHCI_CTRL_CLE; + writel (0, &ohci->regs->ed_controlcurrent); + } + } + if (ohci->ed_bulktail) { + command |= OHCI_BLF; + if (!(ohci->hc_control & OHCI_CTRL_BLE)) { + control |= OHCI_CTRL_BLE; + writel (0, &ohci->regs->ed_bulkcurrent); + } + } + + /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */ + if (control) { + ohci->hc_control |= control; + writel (ohci->hc_control, &ohci->regs->control); + } + if (command) + writel (command, &ohci->regs->cmdstatus); + } +} + + + +/*-------------------------------------------------------------------------*/ + +/* + * Process normal completions (error or success) and clean the schedules. + * + * This is the main path for handing urbs back to drivers. The only other + * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of + * scanning the (re-reversed) donelist as this does. + */ +static void +dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs *regs) +{ + unsigned long flags; + + spin_lock_irqsave (&ohci->lock, flags); + while (td) { + struct td *td_next = td->next_dl_td; + struct urb *urb = td->urb; + urb_priv_t *urb_priv = urb->hcpriv; + struct ed *ed = td->ed; + + /* update URB's length and status from TD */ + td_done (ohci, urb, td); + urb_priv->td_cnt++; + + /* If all this urb's TDs are done, call complete() */ + if (urb_priv->td_cnt == urb_priv->length) { + spin_unlock (&ohci->lock); + finish_urb (ohci, urb, regs); + spin_lock (&ohci->lock); + } + + /* clean schedule: unlink EDs that are no longer busy */ + if (list_empty (&ed->td_list)) + ed_deschedule (ohci, ed); + /* ... reenabling halted EDs only after fault cleanup */ + else if (!(ed->hwINFO & ED_DEQUEUE)) { + td = list_entry (ed->td_list.next, struct td, td_list); + if (!(td->hwINFO & TD_DONE)) + ed->hwINFO &= ~ED_SKIP; + } + + td = td_next; + } + spin_unlock_irqrestore (&ohci->lock, flags); +} diff --git a/reactos/drivers/usb/cromwell/host/ohci.def b/reactos/drivers/usb/cromwell/host/ohci.def index 9bc5544dd2f..26010d9aa68 100644 --- a/reactos/drivers/usb/cromwell/host/ohci.def +++ b/reactos/drivers/usb/cromwell/host/ohci.def @@ -1,2 +1,2 @@ -LIBRARY ohci.sys -EXPORTS +LIBRARY ohci.sys +EXPORTS diff --git a/reactos/drivers/usb/cromwell/host/ohci.h b/reactos/drivers/usb/cromwell/host/ohci.h index 632382e88ba..8af7d8803ec 100644 --- a/reactos/drivers/usb/cromwell/host/ohci.h +++ b/reactos/drivers/usb/cromwell/host/ohci.h @@ -1,418 +1,418 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * - * This file is licenced under the GPL. - */ - -/* - * OHCI Endpoint Descriptor (ED) ... holds TD queue - * See OHCI spec, section 4.2 - * - * This is a "Queue Head" for those transfers, which is why - * both EHCI and UHCI call similar structures a "QH". - */ -struct ed { - /* first fields are hardware-specified, le32 */ - __u32 hwINFO; /* endpoint config bitmap */ - /* info bits defined by hcd */ -#define ED_DEQUEUE __constant_cpu_to_le32(1 << 27) - /* info bits defined by the hardware */ -#define ED_ISO __constant_cpu_to_le32(1 << 15) -#define ED_SKIP __constant_cpu_to_le32(1 << 14) -#define ED_LOWSPEED __constant_cpu_to_le32(1 << 13) -#define ED_OUT __constant_cpu_to_le32(0x01 << 11) -#define ED_IN __constant_cpu_to_le32(0x02 << 11) - __u32 hwTailP; /* tail of TD list */ - __u32 hwHeadP; /* head of TD list (hc r/w) */ -#define ED_C __constant_cpu_to_le32(0x02) /* toggle carry */ -#define ED_H __constant_cpu_to_le32(0x01) /* halted */ - __u32 hwNextED; /* next ED in list */ - - /* rest are purely for the driver's use */ - dma_addr_t dma; /* addr of ED */ - struct td *dummy; /* next TD to activate */ - - /* host's view of schedule */ - struct ed *ed_next; /* on schedule or rm_list */ - struct ed *ed_prev; /* for non-interrupt EDs */ - struct list_head td_list; /* "shadow list" of our TDs */ - - /* create --> IDLE --> OPER --> ... --> IDLE --> destroy - * usually: OPER --> UNLINK --> (IDLE | OPER) --> ... - * some special cases : OPER --> IDLE ... - */ - u8 state; /* ED_{IDLE,UNLINK,OPER} */ -#define ED_IDLE 0x00 /* NOT linked to HC */ -#define ED_UNLINK 0x01 /* being unlinked from hc */ -#define ED_OPER 0x02 /* IS linked to hc */ - - u8 type; /* PIPE_{BULK,...} */ - - /* periodic scheduling params (for intr and iso) */ - u8 branch; - u16 interval; - u16 load; - u16 last_iso; /* iso only */ - - /* HC may see EDs on rm_list until next frame (frame_no == tick) */ - u16 tick; -} __attribute__ ((aligned(16))); - -#define ED_MASK ((u32)~0x0f) /* strip hw status in low addr bits */ - - -/* - * OHCI Transfer Descriptor (TD) ... one per transfer segment - * See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt) - * and 4.3.2 (iso) - */ -struct td { - /* first fields are hardware-specified, le32 */ - __u32 hwINFO; /* transfer info bitmask */ - - /* hwINFO bits for both general and iso tds: */ -#define TD_CC 0xf0000000 /* condition code */ -#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f) -//#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28) -#define TD_DI 0x00E00000 /* frames before interrupt */ -#define TD_DI_SET(X) (((X) & 0x07)<< 21) - /* these two bits are available for definition/use by HCDs in both - * general and iso tds ... others are available for only one type - */ -#define TD_DONE 0x00020000 /* retired to donelist */ -#define TD_ISO 0x00010000 /* copy of ED_ISO */ - - /* hwINFO bits for general tds: */ -#define TD_EC 0x0C000000 /* error count */ -#define TD_T 0x03000000 /* data toggle state */ -#define TD_T_DATA0 0x02000000 /* DATA0 */ -#define TD_T_DATA1 0x03000000 /* DATA1 */ -#define TD_T_TOGGLE 0x00000000 /* uses ED_C */ -#define TD_DP 0x00180000 /* direction/pid */ -#define TD_DP_SETUP 0x00000000 /* SETUP pid */ -#define TD_DP_IN 0x00100000 /* IN pid */ -#define TD_DP_OUT 0x00080000 /* OUT pid */ - /* 0x00180000 rsvd */ -#define TD_R 0x00040000 /* round: short packets OK? */ - - /* (no hwINFO #defines yet for iso tds) */ - - __u32 hwCBP; /* Current Buffer Pointer (or 0) */ - __u32 hwNextTD; /* Next TD Pointer */ - __u32 hwBE; /* Memory Buffer End Pointer */ - - /* PSW is only for ISO */ -#define MAXPSW 1 /* hardware allows 8 */ - __u16 hwPSW [MAXPSW]; - - /* rest are purely for the driver's use */ - __u8 index; - struct ed *ed; - struct td *td_hash; /* dma-->td hashtable */ - struct td *next_dl_td; - struct urb *urb; - - dma_addr_t td_dma; /* addr of this TD */ - dma_addr_t data_dma; /* addr of data it points to */ - - struct list_head td_list; /* "shadow list", TDs on same ED */ -} __attribute__ ((aligned(32))); /* c/b/i need 16; only iso needs 32 */ - -#define TD_MASK ((u32)~0x1f) /* strip hw status in low addr bits */ - -/* - * Hardware transfer status codes -- CC from td->hwINFO or td->hwPSW - */ -#define TD_CC_NOERROR 0x00 -#define TD_CC_CRC 0x01 -#define TD_CC_BITSTUFFING 0x02 -#define TD_CC_DATATOGGLEM 0x03 -#define TD_CC_STALL 0x04 -#define TD_DEVNOTRESP 0x05 -#define TD_PIDCHECKFAIL 0x06 -#define TD_UNEXPECTEDPID 0x07 -#define TD_DATAOVERRUN 0x08 -#define TD_DATAUNDERRUN 0x09 - /* 0x0A, 0x0B reserved for hardware */ -#define TD_BUFFEROVERRUN 0x0C -#define TD_BUFFERUNDERRUN 0x0D - /* 0x0E, 0x0F reserved for HCD */ -#define TD_NOTACCESSED 0x0F - - -/* map OHCI TD status codes (CC) to errno values */ -static const int cc_to_error [16] = { - /* No Error */ 0, - /* CRC Error */ -EILSEQ, - /* Bit Stuff */ -EPROTO, - /* Data Togg */ -EILSEQ, - /* Stall */ -EPIPE, - /* DevNotResp */ -ETIMEDOUT, - /* PIDCheck */ -EPROTO, - /* UnExpPID */ -EPROTO, - /* DataOver */ -EOVERFLOW, - /* DataUnder */ -EREMOTEIO, - /* (for hw) */ -EIO, - /* (for hw) */ -EIO, - /* BufferOver */ -ECOMM, - /* BuffUnder */ -ENOSR, - /* (for HCD) */ -EALREADY, - /* (for HCD) */ -EALREADY -}; - - -/* - * The HCCA (Host Controller Communications Area) is a 256 byte - * structure defined section 4.4.1 of the OHCI spec. The HC is - * told the base address of it. It must be 256-byte aligned. - */ -struct ohci_hcca { -#define NUM_INTS 32 - __u32 int_table [NUM_INTS]; /* periodic schedule */ - __u16 frame_no; /* current frame number */ - __u16 pad1; /* set to 0 on each frame_no change */ - __u32 done_head; /* info returned for an interrupt */ - u8 reserved_for_hc [116]; - u8 what [4]; /* spec only identifies 252 bytes :) */ -} __attribute__ ((aligned(256))); - - -/* - * This is the structure of the OHCI controller's memory mapped I/O region. - * You must use readl() and writel() (in ) to access these fields!! - * Layout is in section 7 (and appendix B) of the spec. - */ -struct ohci_regs { - /* control and status registers (section 7.1) */ - __u32 revision; - __u32 control; - __u32 cmdstatus; - __u32 intrstatus; - __u32 intrenable; - __u32 intrdisable; - - /* memory pointers (section 7.2) */ - __u32 hcca; - __u32 ed_periodcurrent; - __u32 ed_controlhead; - __u32 ed_controlcurrent; - __u32 ed_bulkhead; - __u32 ed_bulkcurrent; - __u32 donehead; - - /* frame counters (section 7.3) */ - __u32 fminterval; - __u32 fmremaining; - __u32 fmnumber; - __u32 periodicstart; - __u32 lsthresh; - - /* Root hub ports (section 7.4) */ - struct ohci_roothub_regs { - __u32 a; - __u32 b; - __u32 status; -#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports (RH_A_NDP) */ - __u32 portstatus [MAX_ROOT_PORTS]; - } roothub; - - /* and optional "legacy support" registers (appendix B) at 0x0100 */ - -} __attribute__ ((aligned(32))); - - -/* OHCI CONTROL AND STATUS REGISTER MASKS */ - -/* - * HcControl (control) register masks - */ -#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */ -#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */ -#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */ -#define OHCI_CTRL_CLE (1 << 4) /* control list enable */ -#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */ -#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */ -#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ -#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ -#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */ - -/* pre-shifted values for HCFS */ -#define OHCI_USB_RESET (0 << 6) -#define OHCI_USB_RESUME (1 << 6) -#define OHCI_USB_OPER (2 << 6) -#define OHCI_USB_SUSPEND (3 << 6) - -// HCFS itself -static char *hcfs2string (int state) -{ - switch (state) { - case OHCI_USB_RESET: return "reset"; - case OHCI_USB_RESUME: return "resume"; - case OHCI_USB_OPER: return "operational"; - case OHCI_USB_SUSPEND: return "suspend"; - } - return "?"; -} - -/* - * HcCommandStatus (cmdstatus) register masks - */ -#define OHCI_HCR (1 << 0) /* host controller reset */ -#define OHCI_CLF (1 << 1) /* control list filled */ -#define OHCI_BLF (1 << 2) /* bulk list filled */ -#define OHCI_OCR (1 << 3) /* ownership change request */ -#define OHCI_SOC (3 << 16) /* scheduling overrun count */ - -/* - * masks used with interrupt registers: - * HcInterruptStatus (intrstatus) - * HcInterruptEnable (intrenable) - * HcInterruptDisable (intrdisable) - */ -#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */ -#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */ -#define OHCI_INTR_SF (1 << 2) /* start frame */ -#define OHCI_INTR_RD (1 << 3) /* resume detect */ -#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */ -#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */ -#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */ -#define OHCI_INTR_OC (1 << 30) /* ownership change */ -#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */ - - -/* OHCI ROOT HUB REGISTER MASKS */ - -/* roothub.portstatus [i] bits */ -#define RH_PS_CCS 0x00000001 /* current connect status */ -#define RH_PS_PES 0x00000002 /* port enable status*/ -#define RH_PS_PSS 0x00000004 /* port suspend status */ -#define RH_PS_POCI 0x00000008 /* port over current indicator */ -#define RH_PS_PRS 0x00000010 /* port reset status */ -#define RH_PS_PPS 0x00000100 /* port power status */ -#define RH_PS_LSDA 0x00000200 /* low speed device attached */ -#define RH_PS_CSC 0x00010000 /* connect status change */ -#define RH_PS_PESC 0x00020000 /* port enable status change */ -#define RH_PS_PSSC 0x00040000 /* port suspend status change */ -#define RH_PS_OCIC 0x00080000 /* over current indicator change */ -#define RH_PS_PRSC 0x00100000 /* port reset status change */ - -/* roothub.status bits */ -#define RH_HS_LPS 0x00000001 /* local power status */ -#define RH_HS_OCI 0x00000002 /* over current indicator */ -#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */ -#define RH_HS_LPSC 0x00010000 /* local power status change */ -#define RH_HS_OCIC 0x00020000 /* over current indicator change */ -#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */ - -/* roothub.b masks */ -#define RH_B_DR 0x0000ffff /* device removable flags */ -#define RH_B_PPCM 0xffff0000 /* port power control mask */ - -/* roothub.a masks */ -#define RH_A_NDP (0xff << 0) /* number of downstream ports */ -#define RH_A_PSM (1 << 8) /* power switching mode */ -#define RH_A_NPS (1 << 9) /* no power switching */ -#define RH_A_DT (1 << 10) /* device type (mbz) */ -#define RH_A_OCPM (1 << 11) /* over current protection mode */ -#define RH_A_NOCP (1 << 12) /* no over current protection */ -#define RH_A_POTPGT (0xff << 24) /* power on to power good time */ - - -/* hcd-private per-urb state */ -typedef struct urb_priv { - struct ed *ed; - __u16 length; // # tds in this request - __u16 td_cnt; // tds already serviced - int state; - struct td *td [0]; // all TDs in this request - -} urb_priv_t; - -#define URB_DEL 1 - -#define TD_HASH_SIZE 64 /* power'o'two */ -// sizeof (struct td) ~= 64 == 2^6 ... -#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE) - - -/* - * This is the full ohci controller description - * - * Note how the "proper" USB information is just - * a subset of what the full implementation needs. (Linus) - */ - -struct ohci_hcd { - spinlock_t lock; - - /* - * I/O memory used to communicate with the HC (dma-consistent) - */ - struct ohci_regs *regs; - - /* - * main memory used to communicate with the HC (dma-consistent). - * hcd adds to schedule for a live hc any time, but removals finish - * only at the start of the next frame. - */ - struct ohci_hcca *hcca; - dma_addr_t hcca_dma; - - struct ed *ed_rm_list; /* to be removed */ - - struct ed *ed_bulktail; /* last in bulk list */ - struct ed *ed_controltail; /* last in ctrl list */ - struct ed *periodic [NUM_INTS]; /* shadow int_table */ - - /* - * memory management for queue data structures - */ - struct pci_pool *td_cache; - struct pci_pool *ed_cache; - struct td *td_hash [TD_HASH_SIZE]; - - /* - * driver state - */ - int disabled; /* e.g. got a UE, we're hung */ - int sleeping; - int load [NUM_INTS]; - u32 hc_control; /* copy of hc control reg */ - - unsigned long flags; /* for HC bugs */ -#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ -#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */ - // there are also chip quirks/bugs in init logic - - /* - * framework state - */ - struct usb_hcd hcd; -}; - -#define hcd_to_ohci(hcd_ptr) container_of(hcd_ptr, struct ohci_hcd, hcd) - -/*-------------------------------------------------------------------------*/ - -#ifndef DEBUG -#define STUB_DEBUG_FILES -#endif /* DEBUG */ - -#define ohci_dbg(ohci, fmt, args...) \ - dev_dbg ((ohci)->hcd.controller , fmt , ## args ) -#define ohci_err(ohci, fmt, args...) \ - dev_err ((ohci)->hcd.controller , fmt , ## args ) -#define ohci_info(ohci, fmt, args...) \ - dev_info ((ohci)->hcd.controller , fmt , ## args ) -#define ohci_warn(ohci, fmt, args...) \ - dev_warn ((ohci)->hcd.controller , fmt , ## args ) - -#ifdef OHCI_VERBOSE_DEBUG -# define ohci_vdbg ohci_dbg -#else -# define ohci_vdbg(ohci, fmt, args...) do { } while (0) -#endif - +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * + * This file is licenced under the GPL. + */ + +/* + * OHCI Endpoint Descriptor (ED) ... holds TD queue + * See OHCI spec, section 4.2 + * + * This is a "Queue Head" for those transfers, which is why + * both EHCI and UHCI call similar structures a "QH". + */ +struct ed { + /* first fields are hardware-specified, le32 */ + __u32 hwINFO; /* endpoint config bitmap */ + /* info bits defined by hcd */ +#define ED_DEQUEUE __constant_cpu_to_le32(1 << 27) + /* info bits defined by the hardware */ +#define ED_ISO __constant_cpu_to_le32(1 << 15) +#define ED_SKIP __constant_cpu_to_le32(1 << 14) +#define ED_LOWSPEED __constant_cpu_to_le32(1 << 13) +#define ED_OUT __constant_cpu_to_le32(0x01 << 11) +#define ED_IN __constant_cpu_to_le32(0x02 << 11) + __u32 hwTailP; /* tail of TD list */ + __u32 hwHeadP; /* head of TD list (hc r/w) */ +#define ED_C __constant_cpu_to_le32(0x02) /* toggle carry */ +#define ED_H __constant_cpu_to_le32(0x01) /* halted */ + __u32 hwNextED; /* next ED in list */ + + /* rest are purely for the driver's use */ + dma_addr_t dma; /* addr of ED */ + struct td *dummy; /* next TD to activate */ + + /* host's view of schedule */ + struct ed *ed_next; /* on schedule or rm_list */ + struct ed *ed_prev; /* for non-interrupt EDs */ + struct list_head td_list; /* "shadow list" of our TDs */ + + /* create --> IDLE --> OPER --> ... --> IDLE --> destroy + * usually: OPER --> UNLINK --> (IDLE | OPER) --> ... + * some special cases : OPER --> IDLE ... + */ + u8 state; /* ED_{IDLE,UNLINK,OPER} */ +#define ED_IDLE 0x00 /* NOT linked to HC */ +#define ED_UNLINK 0x01 /* being unlinked from hc */ +#define ED_OPER 0x02 /* IS linked to hc */ + + u8 type; /* PIPE_{BULK,...} */ + + /* periodic scheduling params (for intr and iso) */ + u8 branch; + u16 interval; + u16 load; + u16 last_iso; /* iso only */ + + /* HC may see EDs on rm_list until next frame (frame_no == tick) */ + u16 tick; +} __attribute__ ((aligned(16))); + +#define ED_MASK ((u32)~0x0f) /* strip hw status in low addr bits */ + + +/* + * OHCI Transfer Descriptor (TD) ... one per transfer segment + * See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt) + * and 4.3.2 (iso) + */ +struct td { + /* first fields are hardware-specified, le32 */ + __u32 hwINFO; /* transfer info bitmask */ + + /* hwINFO bits for both general and iso tds: */ +#define TD_CC 0xf0000000 /* condition code */ +#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f) +//#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28) +#define TD_DI 0x00E00000 /* frames before interrupt */ +#define TD_DI_SET(X) (((X) & 0x07)<< 21) + /* these two bits are available for definition/use by HCDs in both + * general and iso tds ... others are available for only one type + */ +#define TD_DONE 0x00020000 /* retired to donelist */ +#define TD_ISO 0x00010000 /* copy of ED_ISO */ + + /* hwINFO bits for general tds: */ +#define TD_EC 0x0C000000 /* error count */ +#define TD_T 0x03000000 /* data toggle state */ +#define TD_T_DATA0 0x02000000 /* DATA0 */ +#define TD_T_DATA1 0x03000000 /* DATA1 */ +#define TD_T_TOGGLE 0x00000000 /* uses ED_C */ +#define TD_DP 0x00180000 /* direction/pid */ +#define TD_DP_SETUP 0x00000000 /* SETUP pid */ +#define TD_DP_IN 0x00100000 /* IN pid */ +#define TD_DP_OUT 0x00080000 /* OUT pid */ + /* 0x00180000 rsvd */ +#define TD_R 0x00040000 /* round: short packets OK? */ + + /* (no hwINFO #defines yet for iso tds) */ + + __u32 hwCBP; /* Current Buffer Pointer (or 0) */ + __u32 hwNextTD; /* Next TD Pointer */ + __u32 hwBE; /* Memory Buffer End Pointer */ + + /* PSW is only for ISO */ +#define MAXPSW 1 /* hardware allows 8 */ + __u16 hwPSW [MAXPSW]; + + /* rest are purely for the driver's use */ + __u8 index; + struct ed *ed; + struct td *td_hash; /* dma-->td hashtable */ + struct td *next_dl_td; + struct urb *urb; + + dma_addr_t td_dma; /* addr of this TD */ + dma_addr_t data_dma; /* addr of data it points to */ + + struct list_head td_list; /* "shadow list", TDs on same ED */ +} __attribute__ ((aligned(32))); /* c/b/i need 16; only iso needs 32 */ + +#define TD_MASK ((u32)~0x1f) /* strip hw status in low addr bits */ + +/* + * Hardware transfer status codes -- CC from td->hwINFO or td->hwPSW + */ +#define TD_CC_NOERROR 0x00 +#define TD_CC_CRC 0x01 +#define TD_CC_BITSTUFFING 0x02 +#define TD_CC_DATATOGGLEM 0x03 +#define TD_CC_STALL 0x04 +#define TD_DEVNOTRESP 0x05 +#define TD_PIDCHECKFAIL 0x06 +#define TD_UNEXPECTEDPID 0x07 +#define TD_DATAOVERRUN 0x08 +#define TD_DATAUNDERRUN 0x09 + /* 0x0A, 0x0B reserved for hardware */ +#define TD_BUFFEROVERRUN 0x0C +#define TD_BUFFERUNDERRUN 0x0D + /* 0x0E, 0x0F reserved for HCD */ +#define TD_NOTACCESSED 0x0F + + +/* map OHCI TD status codes (CC) to errno values */ +static const int cc_to_error [16] = { + /* No Error */ 0, + /* CRC Error */ -EILSEQ, + /* Bit Stuff */ -EPROTO, + /* Data Togg */ -EILSEQ, + /* Stall */ -EPIPE, + /* DevNotResp */ -ETIMEDOUT, + /* PIDCheck */ -EPROTO, + /* UnExpPID */ -EPROTO, + /* DataOver */ -EOVERFLOW, + /* DataUnder */ -EREMOTEIO, + /* (for hw) */ -EIO, + /* (for hw) */ -EIO, + /* BufferOver */ -ECOMM, + /* BuffUnder */ -ENOSR, + /* (for HCD) */ -EALREADY, + /* (for HCD) */ -EALREADY +}; + + +/* + * The HCCA (Host Controller Communications Area) is a 256 byte + * structure defined section 4.4.1 of the OHCI spec. The HC is + * told the base address of it. It must be 256-byte aligned. + */ +struct ohci_hcca { +#define NUM_INTS 32 + __u32 int_table [NUM_INTS]; /* periodic schedule */ + __u16 frame_no; /* current frame number */ + __u16 pad1; /* set to 0 on each frame_no change */ + __u32 done_head; /* info returned for an interrupt */ + u8 reserved_for_hc [116]; + u8 what [4]; /* spec only identifies 252 bytes :) */ +} __attribute__ ((aligned(256))); + + +/* + * This is the structure of the OHCI controller's memory mapped I/O region. + * You must use readl() and writel() (in ) to access these fields!! + * Layout is in section 7 (and appendix B) of the spec. + */ +struct ohci_regs { + /* control and status registers (section 7.1) */ + __u32 revision; + __u32 control; + __u32 cmdstatus; + __u32 intrstatus; + __u32 intrenable; + __u32 intrdisable; + + /* memory pointers (section 7.2) */ + __u32 hcca; + __u32 ed_periodcurrent; + __u32 ed_controlhead; + __u32 ed_controlcurrent; + __u32 ed_bulkhead; + __u32 ed_bulkcurrent; + __u32 donehead; + + /* frame counters (section 7.3) */ + __u32 fminterval; + __u32 fmremaining; + __u32 fmnumber; + __u32 periodicstart; + __u32 lsthresh; + + /* Root hub ports (section 7.4) */ + struct ohci_roothub_regs { + __u32 a; + __u32 b; + __u32 status; +#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports (RH_A_NDP) */ + __u32 portstatus [MAX_ROOT_PORTS]; + } roothub; + + /* and optional "legacy support" registers (appendix B) at 0x0100 */ + +} __attribute__ ((aligned(32))); + + +/* OHCI CONTROL AND STATUS REGISTER MASKS */ + +/* + * HcControl (control) register masks + */ +#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */ +#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */ +#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */ +#define OHCI_CTRL_CLE (1 << 4) /* control list enable */ +#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */ +#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */ +#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ +#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ +#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */ + +/* pre-shifted values for HCFS */ +#define OHCI_USB_RESET (0 << 6) +#define OHCI_USB_RESUME (1 << 6) +#define OHCI_USB_OPER (2 << 6) +#define OHCI_USB_SUSPEND (3 << 6) + +// HCFS itself +static char *hcfs2string (int state) +{ + switch (state) { + case OHCI_USB_RESET: return "reset"; + case OHCI_USB_RESUME: return "resume"; + case OHCI_USB_OPER: return "operational"; + case OHCI_USB_SUSPEND: return "suspend"; + } + return "?"; +} + +/* + * HcCommandStatus (cmdstatus) register masks + */ +#define OHCI_HCR (1 << 0) /* host controller reset */ +#define OHCI_CLF (1 << 1) /* control list filled */ +#define OHCI_BLF (1 << 2) /* bulk list filled */ +#define OHCI_OCR (1 << 3) /* ownership change request */ +#define OHCI_SOC (3 << 16) /* scheduling overrun count */ + +/* + * masks used with interrupt registers: + * HcInterruptStatus (intrstatus) + * HcInterruptEnable (intrenable) + * HcInterruptDisable (intrdisable) + */ +#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */ +#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */ +#define OHCI_INTR_SF (1 << 2) /* start frame */ +#define OHCI_INTR_RD (1 << 3) /* resume detect */ +#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */ +#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */ +#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */ +#define OHCI_INTR_OC (1 << 30) /* ownership change */ +#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */ + + +/* OHCI ROOT HUB REGISTER MASKS */ + +/* roothub.portstatus [i] bits */ +#define RH_PS_CCS 0x00000001 /* current connect status */ +#define RH_PS_PES 0x00000002 /* port enable status*/ +#define RH_PS_PSS 0x00000004 /* port suspend status */ +#define RH_PS_POCI 0x00000008 /* port over current indicator */ +#define RH_PS_PRS 0x00000010 /* port reset status */ +#define RH_PS_PPS 0x00000100 /* port power status */ +#define RH_PS_LSDA 0x00000200 /* low speed device attached */ +#define RH_PS_CSC 0x00010000 /* connect status change */ +#define RH_PS_PESC 0x00020000 /* port enable status change */ +#define RH_PS_PSSC 0x00040000 /* port suspend status change */ +#define RH_PS_OCIC 0x00080000 /* over current indicator change */ +#define RH_PS_PRSC 0x00100000 /* port reset status change */ + +/* roothub.status bits */ +#define RH_HS_LPS 0x00000001 /* local power status */ +#define RH_HS_OCI 0x00000002 /* over current indicator */ +#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */ +#define RH_HS_LPSC 0x00010000 /* local power status change */ +#define RH_HS_OCIC 0x00020000 /* over current indicator change */ +#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */ + +/* roothub.b masks */ +#define RH_B_DR 0x0000ffff /* device removable flags */ +#define RH_B_PPCM 0xffff0000 /* port power control mask */ + +/* roothub.a masks */ +#define RH_A_NDP (0xff << 0) /* number of downstream ports */ +#define RH_A_PSM (1 << 8) /* power switching mode */ +#define RH_A_NPS (1 << 9) /* no power switching */ +#define RH_A_DT (1 << 10) /* device type (mbz) */ +#define RH_A_OCPM (1 << 11) /* over current protection mode */ +#define RH_A_NOCP (1 << 12) /* no over current protection */ +#define RH_A_POTPGT (0xff << 24) /* power on to power good time */ + + +/* hcd-private per-urb state */ +typedef struct urb_priv { + struct ed *ed; + __u16 length; // # tds in this request + __u16 td_cnt; // tds already serviced + int state; + struct td *td [0]; // all TDs in this request + +} urb_priv_t; + +#define URB_DEL 1 + +#define TD_HASH_SIZE 64 /* power'o'two */ +// sizeof (struct td) ~= 64 == 2^6 ... +#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE) + + +/* + * This is the full ohci controller description + * + * Note how the "proper" USB information is just + * a subset of what the full implementation needs. (Linus) + */ + +struct ohci_hcd { + spinlock_t lock; + + /* + * I/O memory used to communicate with the HC (dma-consistent) + */ + struct ohci_regs *regs; + + /* + * main memory used to communicate with the HC (dma-consistent). + * hcd adds to schedule for a live hc any time, but removals finish + * only at the start of the next frame. + */ + struct ohci_hcca *hcca; + dma_addr_t hcca_dma; + + struct ed *ed_rm_list; /* to be removed */ + + struct ed *ed_bulktail; /* last in bulk list */ + struct ed *ed_controltail; /* last in ctrl list */ + struct ed *periodic [NUM_INTS]; /* shadow int_table */ + + /* + * memory management for queue data structures + */ + struct pci_pool *td_cache; + struct pci_pool *ed_cache; + struct td *td_hash [TD_HASH_SIZE]; + + /* + * driver state + */ + int disabled; /* e.g. got a UE, we're hung */ + int sleeping; + int load [NUM_INTS]; + u32 hc_control; /* copy of hc control reg */ + + unsigned long flags; /* for HC bugs */ +#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ +#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */ + // there are also chip quirks/bugs in init logic + + /* + * framework state + */ + struct usb_hcd hcd; +}; + +#define hcd_to_ohci(hcd_ptr) container_of(hcd_ptr, struct ohci_hcd, hcd) + +/*-------------------------------------------------------------------------*/ + +#ifndef DEBUG +#define STUB_DEBUG_FILES +#endif /* DEBUG */ + +#define ohci_dbg(ohci, fmt, args...) \ + dev_dbg ((ohci)->hcd.controller , fmt , ## args ) +#define ohci_err(ohci, fmt, args...) \ + dev_err ((ohci)->hcd.controller , fmt , ## args ) +#define ohci_info(ohci, fmt, args...) \ + dev_info ((ohci)->hcd.controller , fmt , ## args ) +#define ohci_warn(ohci, fmt, args...) \ + dev_warn ((ohci)->hcd.controller , fmt , ## args ) + +#ifdef OHCI_VERBOSE_DEBUG +# define ohci_vdbg ohci_dbg +#else +# define ohci_vdbg(ohci, fmt, args...) do { } while (0) +#endif + diff --git a/reactos/drivers/usb/cromwell/host/ohci.rc b/reactos/drivers/usb/cromwell/host/ohci.rc index fa183242a97..a31d60c3796 100644 --- a/reactos/drivers/usb/cromwell/host/ohci.rc +++ b/reactos/drivers/usb/cromwell/host/ohci.rc @@ -1,5 +1,5 @@ -#define REACTOS_VERSION_DLL -#define REACTOS_STR_FILE_DESCRIPTION "USB OHCI Device Driver\0" -#define REACTOS_STR_INTERNAL_NAME "ohci\0" -#define REACTOS_STR_ORIGINAL_FILENAME "ohci.sys\0" -#include +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "USB OHCI Device Driver\0" +#define REACTOS_STR_INTERNAL_NAME "ohci\0" +#define REACTOS_STR_ORIGINAL_FILENAME "ohci.sys\0" +#include diff --git a/reactos/drivers/usb/cromwell/host/ohci_config.h b/reactos/drivers/usb/cromwell/host/ohci_config.h index ec73b9099f3..01fd7cdcb08 100644 --- a/reactos/drivers/usb/cromwell/host/ohci_config.h +++ b/reactos/drivers/usb/cromwell/host/ohci_config.h @@ -1,5 +1,5 @@ -/* - * Configs for OHCI - */ - -#define CONFIG_PCI +/* + * Configs for OHCI + */ + +#define CONFIG_PCI diff --git a/reactos/drivers/usb/cromwell/host/ohci_main.c b/reactos/drivers/usb/cromwell/host/ohci_main.c index aba234a8082..57c61828e48 100644 --- a/reactos/drivers/usb/cromwell/host/ohci_main.c +++ b/reactos/drivers/usb/cromwell/host/ohci_main.c @@ -1,309 +1,309 @@ -/* - ReactOS specific functions for OHCI module - by Aleksey Bragin (aleksey@reactos.com) - Some parts of code are inspired (or even just copied) from ReactOS Videoport driver -*/ - -#include -#include -#include "../linux/linux_wrapper.h" -#include "ohci_main.h" - -// declare basic init funcs -void init_wrapper(struct pci_dev *probe_dev); -int ohci_hcd_pci_init (void); -void ohci_hcd_pci_cleanup (void); -int STDCALL usb_init(void); -void STDCALL usb_exit(void); -extern struct pci_driver ohci_pci_driver; -extern const struct pci_device_id pci_ids[]; - - - -// This should be removed, but for testing purposes it's here -struct pci_dev *dev; -//struct pci_device_id *dev_id; - - -#define USB_OHCI_TAG TAG('u','s','b','o') - -NTSTATUS STDCALL AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo) -{ - PDEVICE_OBJECT fdo; - NTSTATUS Status; - WCHAR DeviceBuffer[20]; - UNICODE_STRING DeviceName; - POHCI_DRIVER_EXTENSION DriverExtension; - POHCI_DEVICE_EXTENSION DeviceExtension; - ULONG Size, DeviceNumber; - - DPRINT1("ohci: AddDevice called\n"); - - // Allocate driver extension now - DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); - if (DriverExtension == NULL) - { - Status = IoAllocateDriverObjectExtension( - DriverObject, - DriverObject, - sizeof(OHCI_DRIVER_EXTENSION), - (PVOID *)&DriverExtension); - - if (!NT_SUCCESS(Status)) - { - DPRINT1("Allocating DriverObjectExtension failed.\n"); - return Status; - } - } - - // Create a unicode device name - DeviceNumber = 0; //TODO: Allocate new device number every time - swprintf(DeviceBuffer, L"\\Device\\USBFDO-%lu", DeviceNumber); - RtlInitUnicodeString(&DeviceName, DeviceBuffer); - - Status = IoCreateDevice(DriverObject, - sizeof(OHCI_DEVICE_EXTENSION)/* + DriverExtension->InitializationData.HwDeviceExtensionSize*/, - &DeviceName, - FILE_DEVICE_CONTROLLER, - 0, - FALSE, - &fdo); - - if (!NT_SUCCESS(Status)) - { - DPRINT("IoCreateDevice call failed with status 0x%08x\n", Status); - return Status; - } - - // zerofill device extension - DeviceExtension = (POHCI_DEVICE_EXTENSION)pdo->DeviceExtension; - RtlZeroMemory(DeviceExtension, sizeof(OHCI_DEVICE_EXTENSION)); - DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo); - - fdo->Flags &= ~DO_DEVICE_INITIALIZING; - - // Initialize device extension - DeviceExtension->DeviceNumber = DeviceNumber; - DeviceExtension->PhysicalDeviceObject = pdo; - DeviceExtension->FunctionalDeviceObject = fdo; - DeviceExtension->DriverExtension = DriverExtension; - - /* Get bus number from the upper level bus driver. */ - Size = sizeof(ULONG); - Status = IoGetDeviceProperty( - pdo, - DevicePropertyBusNumber, - Size, - &DeviceExtension->SystemIoBusNumber, - &Size); - - if (!NT_SUCCESS(Status)) - { - DPRINT("Couldn't get an information from bus driver. Panic!!!\n"); - return Status; - } - - DPRINT("Done AddDevice\n"); - return STATUS_SUCCESS; -} - -VOID STDCALL DriverUnload(PDRIVER_OBJECT DriverObject) -{ - DPRINT1("DriverUnload()\n"); - - // Exit usb device - usb_exit(); - - // Remove device (ohci_pci_driver.remove) - ohci_pci_driver.remove(dev); - - ExFreePool(dev->slot_name); - ExFreePool(dev); - - // Perform some cleanup - ohci_hcd_pci_cleanup(); -} - -NTSTATUS InitLinuxWrapper(PDEVICE_OBJECT DeviceObject) -{ - NTSTATUS Status; - POHCI_DEVICE_EXTENSION DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension; - - // Fill generic linux structs - dev = ExAllocatePoolWithTag(PagedPool, sizeof(struct pci_dev), USB_OHCI_TAG); - - init_wrapper(dev); - dev->irq = DeviceExtension->InterruptLevel; - dev->dev_ext = (PVOID)DeviceExtension; - dev->slot_name = ExAllocatePoolWithTag(NonPagedPool, 128, USB_OHCI_TAG); // 128 max len for slot name - - strcpy(dev->dev.name, "OpenHCI PCI-USB Controller"); - strcpy(dev->slot_name, "OHCD PCI Slot"); - - // Init the OHCI HCD. Probe will be called automatically, but will fail because id=NULL - Status = ohci_hcd_pci_init(); - //FIXME: Check status returned value - - // Init core usb - usb_init(); - - // Probe device with real id now - ohci_pci_driver.probe(dev, pci_ids); - - DPRINT("InitLinuxWrapper() done\n"); - - return STATUS_SUCCESS; -} - -NTSTATUS STDCALL -OHCD_PnPStartDevice(IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp) -{ - PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); - PDRIVER_OBJECT DriverObject; - POHCI_DRIVER_EXTENSION DriverExtension; - POHCI_DEVICE_EXTENSION DeviceExtension; - PCM_RESOURCE_LIST AllocatedResources; - - /* - * Get the initialization data we saved in VideoPortInitialize. - */ - DriverObject = DeviceObject->DriverObject; - DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); - DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension; - - /* - * Store some resources in the DeviceExtension. - */ - AllocatedResources = Stack->Parameters.StartDevice.AllocatedResources; - if (AllocatedResources != NULL) - { - CM_FULL_RESOURCE_DESCRIPTOR *FullList; - CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor; - ULONG ResourceCount; - ULONG ResourceListSize; - - /* Save the resource list */ - ResourceCount = AllocatedResources->List[0].PartialResourceList.Count; - ResourceListSize = - FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList. - PartialDescriptors[ResourceCount]); - DeviceExtension->AllocatedResources = ExAllocatePool(PagedPool, ResourceListSize); - if (DeviceExtension->AllocatedResources == NULL) - { - return STATUS_INSUFFICIENT_RESOURCES; - } - - RtlCopyMemory(DeviceExtension->AllocatedResources, - AllocatedResources, - ResourceListSize); - - /* Get the interrupt level/vector - needed by HwFindAdapter sometimes */ - for (FullList = AllocatedResources->List; - FullList < AllocatedResources->List + AllocatedResources->Count; - FullList++) - { - /* FIXME: Is this ASSERT ok for resources from the PNP manager? */ - /*ASSERT(FullList->InterfaceType == PCIBus && - FullList->BusNumber == DeviceExtension->SystemIoBusNumber && - 1 == FullList->PartialResourceList.Version && - 1 == FullList->PartialResourceList.Revision);*/ - for (Descriptor = FullList->PartialResourceList.PartialDescriptors; - Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count; - Descriptor++) - { - if (Descriptor->Type == CmResourceTypeInterrupt) - { - DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level; - DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector; - } - else if (Descriptor->Type == CmResourceTypeMemory) - { - DeviceExtension->BaseAddress = Descriptor->u.Memory.Start; - DeviceExtension->BaseAddrLength = Descriptor->u.Memory.Length; - } - } - } - } - DPRINT1("Interrupt level: 0x%x Interrupt Vector: 0x%x\n", - DeviceExtension->InterruptLevel, - DeviceExtension->InterruptVector); - - /* - * Init wrapper with this object - */ - return InitLinuxWrapper(DeviceObject); -} - -// Dispatch PNP -NTSTATUS STDCALL DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - PIO_STACK_LOCATION IrpSp; - NTSTATUS Status; - - IrpSp = IoGetCurrentIrpStackLocation(Irp); - - switch (IrpSp->MinorFunction) - { - case IRP_MN_START_DEVICE: - //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp); - //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status)) - - Status = OHCD_PnPStartDevice(DeviceObject, Irp); - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - break; - - - case IRP_MN_REMOVE_DEVICE: - case IRP_MN_QUERY_REMOVE_DEVICE: - case IRP_MN_CANCEL_REMOVE_DEVICE: - case IRP_MN_SURPRISE_REMOVAL: - - case IRP_MN_STOP_DEVICE: - //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp); - //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status)) - Status = STATUS_SUCCESS; - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - - IoDeleteDevice(DeviceObject); // just delete device for now - break; - - case IRP_MN_QUERY_STOP_DEVICE: - case IRP_MN_CANCEL_STOP_DEVICE: - Status = STATUS_SUCCESS; - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - break; - - default: - return STATUS_NOT_IMPLEMENTED; - break; - } - - return Status; -} - -NTSTATUS STDCALL DispatchPower(PDEVICE_OBJECT fido, PIRP Irp) -{ - DbgPrint("IRP_MJ_POWER dispatch\n"); - return STATUS_SUCCESS; -} - -/* - * Standard DriverEntry method. - */ -NTSTATUS STDCALL -DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegPath) -{ - DriverObject->DriverUnload = DriverUnload; - DriverObject->DriverExtension->AddDevice = AddDevice; - DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp; - DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower; - - return STATUS_SUCCESS; -} +/* + ReactOS specific functions for OHCI module + by Aleksey Bragin (aleksey@reactos.com) + Some parts of code are inspired (or even just copied) from ReactOS Videoport driver +*/ + +#include +#include +#include "../linux/linux_wrapper.h" +#include "ohci_main.h" + +// declare basic init funcs +void init_wrapper(struct pci_dev *probe_dev); +int ohci_hcd_pci_init (void); +void ohci_hcd_pci_cleanup (void); +int STDCALL usb_init(void); +void STDCALL usb_exit(void); +extern struct pci_driver ohci_pci_driver; +extern const struct pci_device_id pci_ids[]; + + + +// This should be removed, but for testing purposes it's here +struct pci_dev *dev; +//struct pci_device_id *dev_id; + + +#define USB_OHCI_TAG TAG('u','s','b','o') + +NTSTATUS STDCALL AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo) +{ + PDEVICE_OBJECT fdo; + NTSTATUS Status; + WCHAR DeviceBuffer[20]; + UNICODE_STRING DeviceName; + POHCI_DRIVER_EXTENSION DriverExtension; + POHCI_DEVICE_EXTENSION DeviceExtension; + ULONG Size, DeviceNumber; + + DPRINT1("ohci: AddDevice called\n"); + + // Allocate driver extension now + DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); + if (DriverExtension == NULL) + { + Status = IoAllocateDriverObjectExtension( + DriverObject, + DriverObject, + sizeof(OHCI_DRIVER_EXTENSION), + (PVOID *)&DriverExtension); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("Allocating DriverObjectExtension failed.\n"); + return Status; + } + } + + // Create a unicode device name + DeviceNumber = 0; //TODO: Allocate new device number every time + swprintf(DeviceBuffer, L"\\Device\\USBFDO-%lu", DeviceNumber); + RtlInitUnicodeString(&DeviceName, DeviceBuffer); + + Status = IoCreateDevice(DriverObject, + sizeof(OHCI_DEVICE_EXTENSION)/* + DriverExtension->InitializationData.HwDeviceExtensionSize*/, + &DeviceName, + FILE_DEVICE_CONTROLLER, + 0, + FALSE, + &fdo); + + if (!NT_SUCCESS(Status)) + { + DPRINT("IoCreateDevice call failed with status 0x%08x\n", Status); + return Status; + } + + // zerofill device extension + DeviceExtension = (POHCI_DEVICE_EXTENSION)pdo->DeviceExtension; + RtlZeroMemory(DeviceExtension, sizeof(OHCI_DEVICE_EXTENSION)); + DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo); + + fdo->Flags &= ~DO_DEVICE_INITIALIZING; + + // Initialize device extension + DeviceExtension->DeviceNumber = DeviceNumber; + DeviceExtension->PhysicalDeviceObject = pdo; + DeviceExtension->FunctionalDeviceObject = fdo; + DeviceExtension->DriverExtension = DriverExtension; + + /* Get bus number from the upper level bus driver. */ + Size = sizeof(ULONG); + Status = IoGetDeviceProperty( + pdo, + DevicePropertyBusNumber, + Size, + &DeviceExtension->SystemIoBusNumber, + &Size); + + if (!NT_SUCCESS(Status)) + { + DPRINT("Couldn't get an information from bus driver. Panic!!!\n"); + return Status; + } + + DPRINT("Done AddDevice\n"); + return STATUS_SUCCESS; +} + +VOID STDCALL DriverUnload(PDRIVER_OBJECT DriverObject) +{ + DPRINT1("DriverUnload()\n"); + + // Exit usb device + usb_exit(); + + // Remove device (ohci_pci_driver.remove) + ohci_pci_driver.remove(dev); + + ExFreePool(dev->slot_name); + ExFreePool(dev); + + // Perform some cleanup + ohci_hcd_pci_cleanup(); +} + +NTSTATUS InitLinuxWrapper(PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS Status; + POHCI_DEVICE_EXTENSION DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // Fill generic linux structs + dev = ExAllocatePoolWithTag(PagedPool, sizeof(struct pci_dev), USB_OHCI_TAG); + + init_wrapper(dev); + dev->irq = DeviceExtension->InterruptLevel; + dev->dev_ext = (PVOID)DeviceExtension; + dev->slot_name = ExAllocatePoolWithTag(NonPagedPool, 128, USB_OHCI_TAG); // 128 max len for slot name + + strcpy(dev->dev.name, "OpenHCI PCI-USB Controller"); + strcpy(dev->slot_name, "OHCD PCI Slot"); + + // Init the OHCI HCD. Probe will be called automatically, but will fail because id=NULL + Status = ohci_hcd_pci_init(); + //FIXME: Check status returned value + + // Init core usb + usb_init(); + + // Probe device with real id now + ohci_pci_driver.probe(dev, pci_ids); + + DPRINT("InitLinuxWrapper() done\n"); + + return STATUS_SUCCESS; +} + +NTSTATUS STDCALL +OHCD_PnPStartDevice(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); + PDRIVER_OBJECT DriverObject; + POHCI_DRIVER_EXTENSION DriverExtension; + POHCI_DEVICE_EXTENSION DeviceExtension; + PCM_RESOURCE_LIST AllocatedResources; + + /* + * Get the initialization data we saved in VideoPortInitialize. + */ + DriverObject = DeviceObject->DriverObject; + DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); + DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* + * Store some resources in the DeviceExtension. + */ + AllocatedResources = Stack->Parameters.StartDevice.AllocatedResources; + if (AllocatedResources != NULL) + { + CM_FULL_RESOURCE_DESCRIPTOR *FullList; + CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor; + ULONG ResourceCount; + ULONG ResourceListSize; + + /* Save the resource list */ + ResourceCount = AllocatedResources->List[0].PartialResourceList.Count; + ResourceListSize = + FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList. + PartialDescriptors[ResourceCount]); + DeviceExtension->AllocatedResources = ExAllocatePool(PagedPool, ResourceListSize); + if (DeviceExtension->AllocatedResources == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory(DeviceExtension->AllocatedResources, + AllocatedResources, + ResourceListSize); + + /* Get the interrupt level/vector - needed by HwFindAdapter sometimes */ + for (FullList = AllocatedResources->List; + FullList < AllocatedResources->List + AllocatedResources->Count; + FullList++) + { + /* FIXME: Is this ASSERT ok for resources from the PNP manager? */ + /*ASSERT(FullList->InterfaceType == PCIBus && + FullList->BusNumber == DeviceExtension->SystemIoBusNumber && + 1 == FullList->PartialResourceList.Version && + 1 == FullList->PartialResourceList.Revision);*/ + for (Descriptor = FullList->PartialResourceList.PartialDescriptors; + Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count; + Descriptor++) + { + if (Descriptor->Type == CmResourceTypeInterrupt) + { + DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level; + DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector; + } + else if (Descriptor->Type == CmResourceTypeMemory) + { + DeviceExtension->BaseAddress = Descriptor->u.Memory.Start; + DeviceExtension->BaseAddrLength = Descriptor->u.Memory.Length; + } + } + } + } + DPRINT1("Interrupt level: 0x%x Interrupt Vector: 0x%x\n", + DeviceExtension->InterruptLevel, + DeviceExtension->InterruptVector); + + /* + * Init wrapper with this object + */ + return InitLinuxWrapper(DeviceObject); +} + +// Dispatch PNP +NTSTATUS STDCALL DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + PIO_STACK_LOCATION IrpSp; + NTSTATUS Status; + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + switch (IrpSp->MinorFunction) + { + case IRP_MN_START_DEVICE: + //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp); + //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status)) + + Status = OHCD_PnPStartDevice(DeviceObject, Irp); + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + break; + + + case IRP_MN_REMOVE_DEVICE: + case IRP_MN_QUERY_REMOVE_DEVICE: + case IRP_MN_CANCEL_REMOVE_DEVICE: + case IRP_MN_SURPRISE_REMOVAL: + + case IRP_MN_STOP_DEVICE: + //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp); + //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status)) + Status = STATUS_SUCCESS; + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + IoDeleteDevice(DeviceObject); // just delete device for now + break; + + case IRP_MN_QUERY_STOP_DEVICE: + case IRP_MN_CANCEL_STOP_DEVICE: + Status = STATUS_SUCCESS; + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + break; + + default: + return STATUS_NOT_IMPLEMENTED; + break; + } + + return Status; +} + +NTSTATUS STDCALL DispatchPower(PDEVICE_OBJECT fido, PIRP Irp) +{ + DbgPrint("IRP_MJ_POWER dispatch\n"); + return STATUS_SUCCESS; +} + +/* + * Standard DriverEntry method. + */ +NTSTATUS STDCALL +DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegPath) +{ + DriverObject->DriverUnload = DriverUnload; + DriverObject->DriverExtension->AddDevice = AddDevice; + DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp; + DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower; + + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/usb/cromwell/host/ohci_main.h b/reactos/drivers/usb/cromwell/host/ohci_main.h index 1324d1ba165..06e3b4ea875 100644 --- a/reactos/drivers/usb/cromwell/host/ohci_main.h +++ b/reactos/drivers/usb/cromwell/host/ohci_main.h @@ -1,46 +1,47 @@ -/* - * OHCI WDM/PNP driver - * - * Copyright (C) 2005 ReactOS Team - * - * Author: Aleksey Bragin (aleksey@reactos.com) - * - */ - -#ifndef OHCI_MAIN_H -#define OHCI_MAIN_H - -typedef struct _OHCI_DRIVER_EXTENSION -{ - //OHCI_HW_INITIALIZATION_DATA InitializationData; - PVOID HwContext; - //UNICODE_STRING RegistryPath; -} OHCI_DRIVER_EXTENSION, *POHCI_DRIVER_EXTENSION; - -typedef struct _OHCI_DEVICE_EXTENSTION -{ - ULONG DeviceNumber; - PDEVICE_OBJECT PhysicalDeviceObject; - PDEVICE_OBJECT FunctionalDeviceObject; - PDEVICE_OBJECT NextDeviceObject; - //UNICODE_STRING RegistryPath; - PKINTERRUPT InterruptObject; - KSPIN_LOCK InterruptSpinLock; - PCM_RESOURCE_LIST AllocatedResources; - ULONG InterruptVector; - ULONG InterruptLevel; - PHYSICAL_ADDRESS BaseAddress; - ULONG BaseAddrLength; - ULONG AdapterInterfaceType; - ULONG SystemIoBusNumber; - ULONG SystemIoSlotNumber; - LIST_ENTRY AddressMappingListHead; - //KDPC DpcObject; - OHCI_DRIVER_EXTENSION *DriverExtension; - ULONG DeviceOpened; - //KMUTEX DeviceLock; - //CHAR MiniPortDeviceExtension[1]; -} OHCI_DEVICE_EXTENSION, *POHCI_DEVICE_EXTENSION; - - -#endif +/* + * OHCI WDM/PNP driver + * + * Copyright (C) 2005 ReactOS Team + * + * Author: Aleksey Bragin (aleksey@reactos.com) + * + */ + +#ifndef OHCI_MAIN_H +#define OHCI_MAIN_H + +typedef struct _OHCI_DRIVER_EXTENSION +{ + //OHCI_HW_INITIALIZATION_DATA InitializationData; + PVOID HwContext; + //UNICODE_STRING RegistryPath; +} OHCI_DRIVER_EXTENSION, *POHCI_DRIVER_EXTENSION; + +typedef struct _OHCI_DEVICE_EXTENSTION +{ + ULONG DeviceNumber; + PDEVICE_OBJECT PhysicalDeviceObject; + PDEVICE_OBJECT FunctionalDeviceObject; + PDEVICE_OBJECT NextDeviceObject; + //UNICODE_STRING RegistryPath; + PKINTERRUPT InterruptObject; + KSPIN_LOCK InterruptSpinLock; + PCM_RESOURCE_LIST AllocatedResources; + ULONG InterruptVector; + ULONG InterruptLevel; + PHYSICAL_ADDRESS BaseAddress; + ULONG BaseAddrLength; + ULONG Flags; + ULONG AdapterInterfaceType; + ULONG SystemIoBusNumber; + ULONG SystemIoSlotNumber; + LIST_ENTRY AddressMappingListHead; + //KDPC DpcObject; + OHCI_DRIVER_EXTENSION *DriverExtension; + ULONG DeviceOpened; + //KMUTEX DeviceLock; + //CHAR MiniPortDeviceExtension[1]; +} OHCI_DEVICE_EXTENSION, *POHCI_DEVICE_EXTENSION; + + +#endif diff --git a/reactos/drivers/usb/cromwell/linux/asm/bitops.h b/reactos/drivers/usb/cromwell/linux/asm/bitops.h index f16396ad4ac..bb194fa25f2 100644 --- a/reactos/drivers/usb/cromwell/linux/asm/bitops.h +++ b/reactos/drivers/usb/cromwell/linux/asm/bitops.h @@ -1,384 +1,384 @@ -#ifndef _I386_BITOPS_H -#define _I386_BITOPS_H - -/* - * Copyright 1992, Linus Torvalds. - */ - -//#include - -/* - * These have to be done with inline assembly: that way the bit-setting - * is guaranteed to be atomic. All bit operations return 0 if the bit - * was cleared before the operation and != 0 if it was not. - * - * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). - */ - -#ifdef CONFIG_SMP -#define LOCK_PREFIX "lock ; " -#else -#define LOCK_PREFIX "" -#endif - -#define ADDR (*(volatile long *) addr) - -/** - * set_bit - Atomically set a bit in memory - * @nr: the bit to set - * @addr: the address to start counting from - * - * This function is atomic and may not be reordered. See __set_bit() - * if you do not require the atomic guarantees. - * Note that @nr may be almost arbitrarily large; this function is not - * restricted to acting on a single-word quantity. - */ -static __inline__ void set_bit(int nr, volatile void * addr) -{ - __asm__ __volatile__( LOCK_PREFIX - "btsl %1,%0" - :"=m" (ADDR) - :"Ir" (nr)); -} - -/** - * __set_bit - Set a bit in memory - * @nr: the bit to set - * @addr: the address to start counting from - * - * Unlike set_bit(), this function is non-atomic and may be reordered. - * If it's called on the same region of memory simultaneously, the effect - * may be that only one operation succeeds. - */ -static __inline__ void __set_bit(int nr, volatile void * addr) -{ - __asm__( - "btsl %1,%0" - :"=m" (ADDR) - :"Ir" (nr)); -} - -/** - * clear_bit - Clears a bit in memory - * @nr: Bit to clear - * @addr: Address to start counting from - * - * clear_bit() is atomic and may not be reordered. However, it does - * not contain a memory barrier, so if it is used for locking purposes, - * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() - * in order to ensure changes are visible on other processors. - */ -static __inline__ void clear_bit(int nr, volatile void * addr) -{ - __asm__ __volatile__( LOCK_PREFIX - "btrl %1,%0" - :"=m" (ADDR) - :"Ir" (nr)); -} -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() - -/** - * __change_bit - Toggle a bit in memory - * @nr: the bit to set - * @addr: the address to start counting from - * - * Unlike change_bit(), this function is non-atomic and may be reordered. - * If it's called on the same region of memory simultaneously, the effect - * may be that only one operation succeeds. - */ -static __inline__ void __change_bit(int nr, volatile void * addr) -{ - __asm__ __volatile__( - "btcl %1,%0" - :"=m" (ADDR) - :"Ir" (nr)); -} - -/** - * change_bit - Toggle a bit in memory - * @nr: Bit to clear - * @addr: Address to start counting from - * - * change_bit() is atomic and may not be reordered. - * Note that @nr may be almost arbitrarily large; this function is not - * restricted to acting on a single-word quantity. - */ -static __inline__ void change_bit(int nr, volatile void * addr) -{ - __asm__ __volatile__( LOCK_PREFIX - "btcl %1,%0" - :"=m" (ADDR) - :"Ir" (nr)); -} - -/** - * test_and_set_bit - Set a bit and return its old value - * @nr: Bit to set - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It also implies a memory barrier. - */ -static __inline__ int test_and_set_bit(int nr, volatile void * addr) -{ - int oldbit; - - __asm__ __volatile__( LOCK_PREFIX - "btsl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit),"=m" (ADDR) - :"Ir" (nr) : "memory"); - return oldbit; -} - -/** - * __test_and_set_bit - Set a bit and return its old value - * @nr: Bit to set - * @addr: Address to count from - * - * This operation is non-atomic and can be reordered. - * If two examples of this operation race, one can appear to succeed - * but actually fail. You must protect multiple accesses with a lock. - */ -static __inline__ int __test_and_set_bit(int nr, volatile void * addr) -{ - int oldbit; - - __asm__( - "btsl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit),"=m" (ADDR) - :"Ir" (nr)); - return oldbit; -} - -/** - * test_and_clear_bit - Clear a bit and return its old value - * @nr: Bit to set - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It also implies a memory barrier. - */ -static __inline__ int test_and_clear_bit(int nr, volatile void * addr) -{ - int oldbit; - - __asm__ __volatile__( LOCK_PREFIX - "btrl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit),"=m" (ADDR) - :"Ir" (nr) : "memory"); - return oldbit; -} - -/** - * __test_and_clear_bit - Clear a bit and return its old value - * @nr: Bit to set - * @addr: Address to count from - * - * This operation is non-atomic and can be reordered. - * If two examples of this operation race, one can appear to succeed - * but actually fail. You must protect multiple accesses with a lock. - */ -static __inline__ int __test_and_clear_bit(int nr, volatile void * addr) -{ - int oldbit; - - __asm__( - "btrl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit),"=m" (ADDR) - :"Ir" (nr)); - return oldbit; -} - -/* WARNING: non atomic and it can be reordered! */ -static __inline__ int __test_and_change_bit(int nr, volatile void * addr) -{ - int oldbit; - - __asm__ __volatile__( - "btcl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit),"=m" (ADDR) - :"Ir" (nr) : "memory"); - return oldbit; -} - -/** - * test_and_change_bit - Change a bit and return its new value - * @nr: Bit to set - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It also implies a memory barrier. - */ -static __inline__ int test_and_change_bit(int nr, volatile void * addr) -{ - int oldbit; - - __asm__ __volatile__( LOCK_PREFIX - "btcl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit),"=m" (ADDR) - :"Ir" (nr) : "memory"); - return oldbit; -} - -#if 0 /* Fool kernel-doc since it doesn't do macros yet */ -/** - * test_bit - Determine whether a bit is set - * @nr: bit number to test - * @addr: Address to start counting from - */ -static int test_bit(int nr, const volatile void * addr); -#endif - -static __inline__ int constant_test_bit(int nr, const volatile void * addr) -{ - return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0; -} - -static __inline__ int variable_test_bit(int nr, volatile void * addr) -{ - int oldbit; - - __asm__ __volatile__( - "btl %2,%1\n\tsbbl %0,%0" - :"=r" (oldbit) - :"m" (ADDR),"Ir" (nr)); - return oldbit; -} - -#define test_bit(nr,addr) \ -(__builtin_constant_p(nr) ? \ - constant_test_bit((nr),(addr)) : \ - variable_test_bit((nr),(addr))) - -/** - * find_first_zero_bit - find the first zero bit in a memory region - * @addr: The address to start the search at - * @size: The maximum size to search - * - * Returns the bit-number of the first zero bit, not the number of the byte - * containing a bit. - */ -static __inline__ int find_first_zero_bit(void * addr, unsigned size) -{ - int d0, d1, d2; - int res; - - if (!size) - return 0; - /* This looks at memory. Mark it volatile to tell gcc not to move it around */ - __asm__ __volatile__( - "movl $-1,%%eax\n\t" - "xorl %%edx,%%edx\n\t" - "repe; scasl\n\t" - "je 1f\n\t" - "xorl -4(%%edi),%%eax\n\t" - "subl $4,%%edi\n\t" - "bsfl %%eax,%%edx\n" - "1:\tsubl %%ebx,%%edi\n\t" - "shll $3,%%edi\n\t" - "addl %%edi,%%edx" - :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2) - :"1" ((size + 31) >> 5), "2" (addr), "b" (addr)); - return res; -} - -/** - * find_next_zero_bit - find the first zero bit in a memory region - * @addr: The address to base the search on - * @offset: The bitnumber to start searching at - * @size: The maximum size to search - */ -static __inline__ int find_next_zero_bit (void * addr, int size, int offset) -{ - unsigned long * p = ((unsigned long *) addr) + (offset >> 5); - int set = 0, bit = offset & 31, res; - - if (bit) { - /* - * Look for zero in first byte - */ - __asm__("bsfl %1,%0\n\t" - "jne 1f\n\t" - "movl $32, %0\n" - "1:" - : "=r" (set) - : "r" (~(*p >> bit))); - if (set < (32 - bit)) - return set + offset; - set = 32 - bit; - p++; - } - /* - * No zero yet, search remaining full bytes for a zero - */ - res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr)); - return (offset + set + res); -} - -/** - * ffz - find first zero in word. - * @word: The word to search - * - * Undefined if no zero exists, so code should check against ~0UL first. - */ -static __inline__ unsigned long ffz(unsigned long word) -{ - __asm__("bsfl %1,%0" - :"=r" (word) - :"r" (~word)); - return word; -} - -#ifdef __KERNEL__ - -/** - * ffs - find first bit set - * @x: the word to search - * - * This is defined the same way as - * the libc and compiler builtin ffs routines, therefore - * differs in spirit from the above ffz (man ffs). - */ -static __inline__ int ffs(int x) -{ - int r; - - __asm__("bsfl %1,%0\n\t" - "jnz 1f\n\t" - "movl $-1,%0\n" - "1:" : "=r" (r) : "rm" (x)); - return r+1; -} - -/** - * hweightN - returns the hamming weight of a N-bit word - * @x: the word to weigh - * - * The Hamming Weight of a number is the total number of bits set in it. - */ - -#define hweight32(x) generic_hweight32(x) -#define hweight16(x) generic_hweight16(x) -#define hweight8(x) generic_hweight8(x) - -#endif /* __KERNEL__ */ - -#ifdef __KERNEL__ - -#define ext2_set_bit __test_and_set_bit -#define ext2_clear_bit __test_and_clear_bit -#define ext2_test_bit test_bit -#define ext2_find_first_zero_bit find_first_zero_bit -#define ext2_find_next_zero_bit find_next_zero_bit - -/* Bitmap functions for the minix filesystem. */ -#define minix_test_and_set_bit(nr,addr) __test_and_set_bit(nr,addr) -#define minix_set_bit(nr,addr) __set_bit(nr,addr) -#define minix_test_and_clear_bit(nr,addr) __test_and_clear_bit(nr,addr) -#define minix_test_bit(nr,addr) test_bit(nr,addr) -#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) - -#endif /* __KERNEL__ */ - -#endif /* _I386_BITOPS_H */ +#ifndef _I386_BITOPS_H +#define _I386_BITOPS_H + +/* + * Copyright 1992, Linus Torvalds. + */ + +//#include + +/* + * These have to be done with inline assembly: that way the bit-setting + * is guaranteed to be atomic. All bit operations return 0 if the bit + * was cleared before the operation and != 0 if it was not. + * + * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). + */ + +#ifdef CONFIG_SMP +#define LOCK_PREFIX "lock ; " +#else +#define LOCK_PREFIX "" +#endif + +#define ADDR (*(volatile long *) addr) + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. See __set_bit() + * if you do not require the atomic guarantees. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ +static __inline__ void set_bit(int nr, volatile void * addr) +{ + __asm__ __volatile__( LOCK_PREFIX + "btsl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} + +/** + * __set_bit - Set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Unlike set_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ +static __inline__ void __set_bit(int nr, volatile void * addr) +{ + __asm__( + "btsl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. However, it does + * not contain a memory barrier, so if it is used for locking purposes, + * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * in order to ensure changes are visible on other processors. + */ +static __inline__ void clear_bit(int nr, volatile void * addr) +{ + __asm__ __volatile__( LOCK_PREFIX + "btrl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() + +/** + * __change_bit - Toggle a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Unlike change_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ +static __inline__ void __change_bit(int nr, volatile void * addr) +{ + __asm__ __volatile__( + "btcl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} + +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ +static __inline__ void change_bit(int nr, volatile void * addr) +{ + __asm__ __volatile__( LOCK_PREFIX + "btcl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static __inline__ int test_and_set_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__ __volatile__( LOCK_PREFIX + "btsl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr) : "memory"); + return oldbit; +} + +/** + * __test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +static __inline__ int __test_and_set_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__( + "btsl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr)); + return oldbit; +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static __inline__ int test_and_clear_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__ __volatile__( LOCK_PREFIX + "btrl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr) : "memory"); + return oldbit; +} + +/** + * __test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +static __inline__ int __test_and_clear_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__( + "btrl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr)); + return oldbit; +} + +/* WARNING: non atomic and it can be reordered! */ +static __inline__ int __test_and_change_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__ __volatile__( + "btcl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr) : "memory"); + return oldbit; +} + +/** + * test_and_change_bit - Change a bit and return its new value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static __inline__ int test_and_change_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__ __volatile__( LOCK_PREFIX + "btcl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr) : "memory"); + return oldbit; +} + +#if 0 /* Fool kernel-doc since it doesn't do macros yet */ +/** + * test_bit - Determine whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static int test_bit(int nr, const volatile void * addr); +#endif + +static __inline__ int constant_test_bit(int nr, const volatile void * addr) +{ + return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0; +} + +static __inline__ int variable_test_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__ __volatile__( + "btl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit) + :"m" (ADDR),"Ir" (nr)); + return oldbit; +} + +#define test_bit(nr,addr) \ +(__builtin_constant_p(nr) ? \ + constant_test_bit((nr),(addr)) : \ + variable_test_bit((nr),(addr))) + +/** + * find_first_zero_bit - find the first zero bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first zero bit, not the number of the byte + * containing a bit. + */ +static __inline__ int find_first_zero_bit(void * addr, unsigned size) +{ + int d0, d1, d2; + int res; + + if (!size) + return 0; + /* This looks at memory. Mark it volatile to tell gcc not to move it around */ + __asm__ __volatile__( + "movl $-1,%%eax\n\t" + "xorl %%edx,%%edx\n\t" + "repe; scasl\n\t" + "je 1f\n\t" + "xorl -4(%%edi),%%eax\n\t" + "subl $4,%%edi\n\t" + "bsfl %%eax,%%edx\n" + "1:\tsubl %%ebx,%%edi\n\t" + "shll $3,%%edi\n\t" + "addl %%edi,%%edx" + :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2) + :"1" ((size + 31) >> 5), "2" (addr), "b" (addr)); + return res; +} + +/** + * find_next_zero_bit - find the first zero bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +static __inline__ int find_next_zero_bit (void * addr, int size, int offset) +{ + unsigned long * p = ((unsigned long *) addr) + (offset >> 5); + int set = 0, bit = offset & 31, res; + + if (bit) { + /* + * Look for zero in first byte + */ + __asm__("bsfl %1,%0\n\t" + "jne 1f\n\t" + "movl $32, %0\n" + "1:" + : "=r" (set) + : "r" (~(*p >> bit))); + if (set < (32 - bit)) + return set + offset; + set = 32 - bit; + p++; + } + /* + * No zero yet, search remaining full bytes for a zero + */ + res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr)); + return (offset + set + res); +} + +/** + * ffz - find first zero in word. + * @word: The word to search + * + * Undefined if no zero exists, so code should check against ~0UL first. + */ +static __inline__ unsigned long ffz(unsigned long word) +{ + __asm__("bsfl %1,%0" + :"=r" (word) + :"r" (~word)); + return word; +} + +#ifdef __KERNEL__ + +/** + * ffs - find first bit set + * @x: the word to search + * + * This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ +static __inline__ int ffs(int x) +{ + int r; + + __asm__("bsfl %1,%0\n\t" + "jnz 1f\n\t" + "movl $-1,%0\n" + "1:" : "=r" (r) : "rm" (x)); + return r+1; +} + +/** + * hweightN - returns the hamming weight of a N-bit word + * @x: the word to weigh + * + * The Hamming Weight of a number is the total number of bits set in it. + */ + +#define hweight32(x) generic_hweight32(x) +#define hweight16(x) generic_hweight16(x) +#define hweight8(x) generic_hweight8(x) + +#endif /* __KERNEL__ */ + +#ifdef __KERNEL__ + +#define ext2_set_bit __test_and_set_bit +#define ext2_clear_bit __test_and_clear_bit +#define ext2_test_bit test_bit +#define ext2_find_first_zero_bit find_first_zero_bit +#define ext2_find_next_zero_bit find_next_zero_bit + +/* Bitmap functions for the minix filesystem. */ +#define minix_test_and_set_bit(nr,addr) __test_and_set_bit(nr,addr) +#define minix_set_bit(nr,addr) __set_bit(nr,addr) +#define minix_test_and_clear_bit(nr,addr) __test_and_clear_bit(nr,addr) +#define minix_test_bit(nr,addr) test_bit(nr,addr) +#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) + +#endif /* __KERNEL__ */ + +#endif /* _I386_BITOPS_H */ diff --git a/reactos/drivers/usb/cromwell/linux/bitops.h b/reactos/drivers/usb/cromwell/linux/bitops.h index 6509d07ba90..ac05ed65c53 100644 --- a/reactos/drivers/usb/cromwell/linux/bitops.h +++ b/reactos/drivers/usb/cromwell/linux/bitops.h @@ -1,72 +1,72 @@ -#ifndef _LINUX_BITOPS_H -#define _LINUX_BITOPS_H - - -/* - * ffs: find first bit set. This is defined the same way as - * the libc and compiler builtin ffs routines, therefore - * differs in spirit from the above ffz (man ffs). - */ - -static inline int generic_ffs(int x) -{ - int r = 1; - - if (!x) - return 0; - if (!(x & 0xffff)) { - x >>= 16; - r += 16; - } - if (!(x & 0xff)) { - x >>= 8; - r += 8; - } - if (!(x & 0xf)) { - x >>= 4; - r += 4; - } - if (!(x & 3)) { - x >>= 2; - r += 2; - } - if (!(x & 1)) { - x >>= 1; - r += 1; - } - return r; -} - -/* - * hweightN: returns the hamming weight (i.e. the number - * of bits set) of a N-bit word - */ - -static inline unsigned int generic_hweight32(unsigned int w) -{ - unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); - res = (res & 0x33333333) + ((res >> 2) & 0x33333333); - res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); - res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); - return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); -} - -static inline unsigned int generic_hweight16(unsigned int w) -{ - unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555); - res = (res & 0x3333) + ((res >> 2) & 0x3333); - res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F); - return (res & 0x00FF) + ((res >> 8) & 0x00FF); -} - -static inline unsigned int generic_hweight8(unsigned int w) -{ - unsigned int res = (w & 0x55) + ((w >> 1) & 0x55); - res = (res & 0x33) + ((res >> 2) & 0x33); - return (res & 0x0F) + ((res >> 4) & 0x0F); -} - -#include "asm/bitops.h" - - -#endif +#ifndef _LINUX_BITOPS_H +#define _LINUX_BITOPS_H + + +/* + * ffs: find first bit set. This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ + +static inline int generic_ffs(int x) +{ + int r = 1; + + if (!x) + return 0; + if (!(x & 0xffff)) { + x >>= 16; + r += 16; + } + if (!(x & 0xff)) { + x >>= 8; + r += 8; + } + if (!(x & 0xf)) { + x >>= 4; + r += 4; + } + if (!(x & 3)) { + x >>= 2; + r += 2; + } + if (!(x & 1)) { + x >>= 1; + r += 1; + } + return r; +} + +/* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word + */ + +static inline unsigned int generic_hweight32(unsigned int w) +{ + unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); + res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); + return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); +} + +static inline unsigned int generic_hweight16(unsigned int w) +{ + unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555); + res = (res & 0x3333) + ((res >> 2) & 0x3333); + res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F); + return (res & 0x00FF) + ((res >> 8) & 0x00FF); +} + +static inline unsigned int generic_hweight8(unsigned int w) +{ + unsigned int res = (w & 0x55) + ((w >> 1) & 0x55); + res = (res & 0x33) + ((res >> 2) & 0x33); + return (res & 0x0F) + ((res >> 4) & 0x0F); +} + +#include "asm/bitops.h" + + +#endif diff --git a/reactos/drivers/usb/cromwell/linux/boot.h b/reactos/drivers/usb/cromwell/linux/boot.h index d99b7f22427..db64976aa76 100644 --- a/reactos/drivers/usb/cromwell/linux/boot.h +++ b/reactos/drivers/usb/cromwell/linux/boot.h @@ -1,337 +1,337 @@ -#ifndef _Boot_H_ -#define _Boot_H_ - -#include "config.h" - -/*************************************************************************** - Includes used by XBox boot code - ***************************************************************************/ -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -///////////////////////////////// -// configuration - -#include "consts.h" -#include "stdint.h" -#include "cromwell_types.h" - - -unsigned int cromwell_config; -unsigned int cromwell_retryload; -unsigned int cromwell_loadbank; -unsigned int cromwell_Biostype; - -unsigned int xbox_ram; - -#define XROMWELL 0 -#define CROMWELL 1 - -#define ICON_WIDTH 64 -#define ICON_HEIGHT 64 -/* -static double min (double a, double b) -{ - if (a < b) return a; else return b; -} - -static inline double max (double a, double b) -{ - if (a > b) return a; else return b; -} -*/ -//#include "iso_fs.h" -//#include "BootVideo.h" - -//#define ASSERT(exp) { if(!(exp)) { bprintf("Assert failed file " __FILE__ " line %d\n", __LINE__); } } - -#if 0 -extern volatile CURRENT_VIDEO_MODE_DETAILS vmode; -unsigned int video_encoder; - -volatile u32 VIDEO_CURSOR_POSX; -volatile u32 VIDEO_CURSOR_POSY; -volatile u32 VIDEO_ATTR; -volatile u32 VIDEO_LUMASCALING; -volatile u32 VIDEO_RSCALING; -volatile u32 VIDEO_BSCALING; -volatile u32 BIOS_TICK_COUNT; -volatile u32 VIDEO_VSYNC_POSITION; -volatile u32 VIDEO_VSYNC_DIR; -volatile u32 DVD_TRAY_STATE; - -u8 VIDEO_AV_MODE ; - -#define DVD_CLOSED 0 -#define DVD_CLOSING 1 -#define DVD_OPEN 2 -#define DVD_OPENING 3 - -///////////////////////////////// -// Superfunky i386 internal structures - -typedef struct gdt_t { - unsigned short m_wSize __attribute__ ((packed)); - unsigned long m_dwBase32 __attribute__ ((packed)); - unsigned short m_wDummy __attribute__ ((packed)); -} ts_descriptor_pointer; - -typedef struct { // inside an 8-byte protected mode interrupt vector - u16 m_wHandlerHighAddressLow16; - u16 m_wSelector; - u16 m_wType; - u16 m_wHandlerLinearAddressHigh16; -} ts_pm_interrupt; - -typedef enum { - EDT_UNKNOWN= 0, - EDT_XBOXFS -} enumDriveType; - -typedef struct tsHarddiskInfo { // this is the retained knowledge about an IDE device after init - unsigned short m_fwPortBase; - unsigned short m_wCountHeads; - unsigned short m_wCountCylinders; - unsigned short m_wCountSectorsPerTrack; - unsigned long m_dwCountSectorsTotal; /* total */ - unsigned char m_bLbaMode; /* am i lba (0x40) or chs (0x00) */ - unsigned char m_szIdentityModelNumber[40]; - unsigned char term_space_1[2]; - unsigned char m_szSerial[20]; - unsigned char term_space_2[2]; - char m_szFirmware[8]; - unsigned char term_space_3[2]; - unsigned char m_fDriveExists; - unsigned char m_fAtapi; // true if a CDROM, etc - enumDriveType m_enumDriveType; - unsigned char m_bCableConductors; // valid for device 0 if present - unsigned short m_wAtaRevisionSupported; - unsigned char s_length; - unsigned char m_length; - unsigned char m_fHasMbr; - unsigned short m_securitySettings; //This contains the contents of the ATA security regs -} tsHarddiskInfo; - -///////////////////////////////// -// LED-flashing codes -// or these together as argument to I2cSetFrontpanelLed - -enum { - I2C_LED_RED0 = 0x80, - I2C_LED_RED1 = 0x40, - I2C_LED_RED2 = 0x20, - I2C_LED_RED3 = 0x10, - I2C_LED_GREEN0 = 0x08, - I2C_LED_GREEN1 = 0x04, - I2C_LED_GREEN2 = 0x02, - I2C_LED_GREEN3 = 0x01 -}; - -/////////////////////////////// -/* BIOS-wide error codes all have b31 set */ - -enum { - ERR_SUCCESS = 0, // completed without error - - ERR_I2C_ERROR_TIMEOUT = 0x80000001, // I2C action failed because it did not complete in a reasonable time - ERR_I2C_ERROR_BUS = 0x80000002, // I2C action failed due to non retryable bus error - - ERR_BOOT_PIC_ALG_BROKEN = 0x80000101 // PIC algorithm did not pass its self-test -}; - -///////////////////////////////// -// some Boot API prototypes - -//////// BootPerformPicChallengeResponseAction.c - -/* ---------------------------- IO primitives ----------------------------------------------------------- -*/ - -static __inline void IoOutputByte(u16 wAds, u8 bValue) { -// __asm__ (" out %%al,%%dx" : : "edx" (dwAds), "al" (bValue) ); - __asm__ __volatile__ ("outb %b0,%w1": :"a" (bValue), "Nd" (wAds)); -} - -static __inline void IoOutputWord(u16 wAds, u16 wValue) { -// __asm__ (" out %%ax,%%dx " : : "edx" (dwAds), "ax" (wValue) ); - __asm__ __volatile__ ("outw %0,%w1": :"a" (wValue), "Nd" (wAds)); - } - -static __inline void IoOutputDword(u16 wAds, u32 dwValue) { -// __asm__ (" out %%eax,%%dx " : : "edx" (dwAds), "ax" (wValue) ); - __asm__ __volatile__ ("outl %0,%w1": :"a" (dwValue), "Nd" (wAds)); -} - - -static __inline u8 IoInputByte(u16 wAds) { - unsigned char _v; - - __asm__ __volatile__ ("inb %w1,%0":"=a" (_v):"Nd" (wAds)); - return _v; -} - -static __inline u16 IoInputWord(u16 wAds) { - u16 _v; - - __asm__ __volatile__ ("inw %w1,%0":"=a" (_v):"Nd" (wAds)); - return _v; -} - -static __inline u32 IoInputDword(u16 wAds) { - u32 _v; - - __asm__ __volatile__ ("inl %w1,%0":"=a" (_v):"Nd" (wAds)); - return _v; -} - -#define rdmsr(msr,val1,val2) \ - __asm__ __volatile__("rdmsr" \ - : "=a" (val1), "=d" (val2) \ - : "c" (msr)) - -#define wrmsr(msr,val1,val2) \ - __asm__ __volatile__("wrmsr" \ - : /* no outputs */ \ - : "c" (msr), "a" (val1), "d" (val2)) - - -void BootPciInterruptEnable(void); - - // boot process -int BootPerformPicChallengeResponseAction(void); - // LED control (see associated enum above) -int I2cSetFrontpanelLed(u8 b); - -#define bprintf(...) - -#if PRINT_TRACE -#define TRACE bprintf(__FILE__ " :%d\n\r",__LINE__); -#else -#define TRACE -#endif - -typedef struct _LIST_ENTRY { - struct _LIST_ENTRY *m_plistentryNext; - struct _LIST_ENTRY *m_plistentryPrevious; -} LIST_ENTRY; - -void ListEntryInsertAfterCurrent(LIST_ENTRY *plistentryCurrent, LIST_ENTRY *plistentryNew); -void ListEntryRemove(LIST_ENTRY *plistentryCurrent); - -////////// BootPerformXCodeActions.c - -int BootPerformXCodeActions(void); - -#include "BootEEPROM.h" -#include "BootParser.h" - -////////// BootStartBios.c - -void StartBios(CONFIGENTRY *config,int nActivePartition, int nFATXPresent,int bootfrom); -int BootMenu(CONFIGENTRY *config,int nDrive,int nActivePartition, int nFATXPresent); - -////////// BootResetActions.c -void ClearIDT (void); -void BootResetAction(void); -void BootCpuCache(bool fEnable) ; -int printk(const char *szFormat, ...); -void BiosCmosWrite(u8 bAds, u8 bData); -u8 BiosCmosRead(u8 bAds); - - -///////// BootPciPeripheralInitialization.c -void BootPciPeripheralInitialization(void); -void BootAGPBUSInitialization(void); -void BootDetectMemorySize(void); -extern void ReadPCIByte(unsigned int bus, unsigned int dev, unsigned intfunc, unsigned int reg_off, unsigned char *pbyteval); -extern void WritePCIByte(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off, unsigned char byteval); -extern void ReadPCIDword(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off, unsigned int *pdwordval); -extern void WritePCIDword(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off, unsigned int dwordval); -extern void ReadPCIBlock(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off, unsigned char *buf, unsigned int nbytes); -extern void WritePCIBlock(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off, unsigned char *buf, unsigned int nbytes); - -void PciWriteByte (unsigned int bus, unsigned int dev, unsigned int func, - unsigned int reg_off, unsigned char byteval); -u8 PciReadByte(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off); -u32 PciWriteDword(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off, u32 dw); -u32 PciReadDword(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off); - -///////// BootPerformPicChallengeResponseAction.c - -int I2CTransmitWord(u8 bPicAddressI2cFormat, u16 wDataToWrite); -int I2CTransmitByteGetReturn(u8 bPicAddressI2cFormat, u8 bDataToWrite); -bool I2CGetTemperature(int *, int *); -void I2CModifyBits(u8 bAds, u8 bReg, u8 bData, u8 bMask); - -///////// BootIde.c - -extern tsHarddiskInfo tsaHarddiskInfo[]; // static struct stores data about attached drives -int BootIdeInit(void); -int BootIdeReadSector(int nDriveIndex, void * pbBuffer, unsigned int block, int byte_offset, int n_bytes); -int BootIdeBootSectorHddOrElTorito(int nDriveIndex, u8 * pbaResult); -int BootIdeAtapiAdditionalSenseCode(int nDrive, u8 * pba, int nLengthMaxReturn); -int BootIdeSetTransferMode(int nIndexDrive, int nMode); -int BootIdeWaitNotBusy(unsigned uIoBase); -bool BootIdeAtapiReportFriendlyError(int nDriveIndex, char * szErrorReturn, int nMaxLengthError); -void BootIdeAtapiPrintkFriendlyError(int nDriveIndex); - -///////// BootUSB.c - -void BootStopUSB(void); -void BootStartUSB(void); -void USBGetEvents(void); - -#include "xpad.h" - -extern struct xpad_data XPAD_current[4]; -extern struct xpad_data XPAD_last[4]; - -extern void wait_ms(u32 ticks); -extern void wait_us(u32 ticks); -extern void wait_smalldelay(void); - - -void * memcpy(void *dest, const void *src, size_t size); -void * memset(void *dest, int data, size_t size); -int memcmp(const void *buffer1, const void *buffer2, size_t num); -int _strncmp(const char *sz1, const char *sz2, int nMax); -char * strcpy(char *sz, const char *szc); -char * _strncpy (char * dest, const char * src, size_t n); -void chrreplace(char *string, char search, char ch); - -#define printf printk -#define sleep wait_ms -int tolower(int ch); -int isspace (int c); - -void MemoryManagementInitialization(void * pvStartAddress, u32 dwTotalMemoryAllocLength); -void * malloc(size_t size); -void free(void *); - -extern volatile int nCountI2cinterrupts, nCountUnusedInterrupts, nCountUnusedInterruptsPic2, nCountInterruptsSmc, nCountInterruptsIde; -extern volatile bool fSeenPowerdown; -typedef enum { - ETS_OPEN_OR_OPENING=0, - ETS_CLOSING, - ETS_CLOSED -} TRAY_STATE; -extern volatile TRAY_STATE traystate; - - -extern void BootInterruptsWriteIdt(void); -#endif -int copy_swap_trim(unsigned char *dst, unsigned char *src, int len); -void HMAC_SHA1( unsigned char *result, - unsigned char *key, int key_length, - unsigned char *text1, int text1_length, - unsigned char *text2, int text2_length ); - -char *strrchr0(char *string, char ch); - -#endif // _Boot_H_ +#ifndef _Boot_H_ +#define _Boot_H_ + +#include "config.h" + +/*************************************************************************** + Includes used by XBox boot code + ***************************************************************************/ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +///////////////////////////////// +// configuration + +#include "consts.h" +#include "stdint.h" +#include "cromwell_types.h" + + +unsigned int cromwell_config; +unsigned int cromwell_retryload; +unsigned int cromwell_loadbank; +unsigned int cromwell_Biostype; + +unsigned int xbox_ram; + +#define XROMWELL 0 +#define CROMWELL 1 + +#define ICON_WIDTH 64 +#define ICON_HEIGHT 64 +/* +static double min (double a, double b) +{ + if (a < b) return a; else return b; +} + +static inline double max (double a, double b) +{ + if (a > b) return a; else return b; +} +*/ +//#include "iso_fs.h" +//#include "BootVideo.h" + +//#define ASSERT(exp) { if(!(exp)) { bprintf("Assert failed file " __FILE__ " line %d\n", __LINE__); } } + +#if 0 +extern volatile CURRENT_VIDEO_MODE_DETAILS vmode; +unsigned int video_encoder; + +volatile u32 VIDEO_CURSOR_POSX; +volatile u32 VIDEO_CURSOR_POSY; +volatile u32 VIDEO_ATTR; +volatile u32 VIDEO_LUMASCALING; +volatile u32 VIDEO_RSCALING; +volatile u32 VIDEO_BSCALING; +volatile u32 BIOS_TICK_COUNT; +volatile u32 VIDEO_VSYNC_POSITION; +volatile u32 VIDEO_VSYNC_DIR; +volatile u32 DVD_TRAY_STATE; + +u8 VIDEO_AV_MODE ; + +#define DVD_CLOSED 0 +#define DVD_CLOSING 1 +#define DVD_OPEN 2 +#define DVD_OPENING 3 + +///////////////////////////////// +// Superfunky i386 internal structures + +typedef struct gdt_t { + unsigned short m_wSize __attribute__ ((packed)); + unsigned long m_dwBase32 __attribute__ ((packed)); + unsigned short m_wDummy __attribute__ ((packed)); +} ts_descriptor_pointer; + +typedef struct { // inside an 8-byte protected mode interrupt vector + u16 m_wHandlerHighAddressLow16; + u16 m_wSelector; + u16 m_wType; + u16 m_wHandlerLinearAddressHigh16; +} ts_pm_interrupt; + +typedef enum { + EDT_UNKNOWN= 0, + EDT_XBOXFS +} enumDriveType; + +typedef struct tsHarddiskInfo { // this is the retained knowledge about an IDE device after init + unsigned short m_fwPortBase; + unsigned short m_wCountHeads; + unsigned short m_wCountCylinders; + unsigned short m_wCountSectorsPerTrack; + unsigned long m_dwCountSectorsTotal; /* total */ + unsigned char m_bLbaMode; /* am i lba (0x40) or chs (0x00) */ + unsigned char m_szIdentityModelNumber[40]; + unsigned char term_space_1[2]; + unsigned char m_szSerial[20]; + unsigned char term_space_2[2]; + char m_szFirmware[8]; + unsigned char term_space_3[2]; + unsigned char m_fDriveExists; + unsigned char m_fAtapi; // true if a CDROM, etc + enumDriveType m_enumDriveType; + unsigned char m_bCableConductors; // valid for device 0 if present + unsigned short m_wAtaRevisionSupported; + unsigned char s_length; + unsigned char m_length; + unsigned char m_fHasMbr; + unsigned short m_securitySettings; //This contains the contents of the ATA security regs +} tsHarddiskInfo; + +///////////////////////////////// +// LED-flashing codes +// or these together as argument to I2cSetFrontpanelLed + +enum { + I2C_LED_RED0 = 0x80, + I2C_LED_RED1 = 0x40, + I2C_LED_RED2 = 0x20, + I2C_LED_RED3 = 0x10, + I2C_LED_GREEN0 = 0x08, + I2C_LED_GREEN1 = 0x04, + I2C_LED_GREEN2 = 0x02, + I2C_LED_GREEN3 = 0x01 +}; + +/////////////////////////////// +/* BIOS-wide error codes all have b31 set */ + +enum { + ERR_SUCCESS = 0, // completed without error + + ERR_I2C_ERROR_TIMEOUT = 0x80000001, // I2C action failed because it did not complete in a reasonable time + ERR_I2C_ERROR_BUS = 0x80000002, // I2C action failed due to non retryable bus error + + ERR_BOOT_PIC_ALG_BROKEN = 0x80000101 // PIC algorithm did not pass its self-test +}; + +///////////////////////////////// +// some Boot API prototypes + +//////// BootPerformPicChallengeResponseAction.c + +/* ---------------------------- IO primitives ----------------------------------------------------------- +*/ + +static __inline void IoOutputByte(u16 wAds, u8 bValue) { +// __asm__ (" out %%al,%%dx" : : "edx" (dwAds), "al" (bValue) ); + __asm__ __volatile__ ("outb %b0,%w1": :"a" (bValue), "Nd" (wAds)); +} + +static __inline void IoOutputWord(u16 wAds, u16 wValue) { +// __asm__ (" out %%ax,%%dx " : : "edx" (dwAds), "ax" (wValue) ); + __asm__ __volatile__ ("outw %0,%w1": :"a" (wValue), "Nd" (wAds)); + } + +static __inline void IoOutputDword(u16 wAds, u32 dwValue) { +// __asm__ (" out %%eax,%%dx " : : "edx" (dwAds), "ax" (wValue) ); + __asm__ __volatile__ ("outl %0,%w1": :"a" (dwValue), "Nd" (wAds)); +} + + +static __inline u8 IoInputByte(u16 wAds) { + unsigned char _v; + + __asm__ __volatile__ ("inb %w1,%0":"=a" (_v):"Nd" (wAds)); + return _v; +} + +static __inline u16 IoInputWord(u16 wAds) { + u16 _v; + + __asm__ __volatile__ ("inw %w1,%0":"=a" (_v):"Nd" (wAds)); + return _v; +} + +static __inline u32 IoInputDword(u16 wAds) { + u32 _v; + + __asm__ __volatile__ ("inl %w1,%0":"=a" (_v):"Nd" (wAds)); + return _v; +} + +#define rdmsr(msr,val1,val2) \ + __asm__ __volatile__("rdmsr" \ + : "=a" (val1), "=d" (val2) \ + : "c" (msr)) + +#define wrmsr(msr,val1,val2) \ + __asm__ __volatile__("wrmsr" \ + : /* no outputs */ \ + : "c" (msr), "a" (val1), "d" (val2)) + + +void BootPciInterruptEnable(void); + + // boot process +int BootPerformPicChallengeResponseAction(void); + // LED control (see associated enum above) +int I2cSetFrontpanelLed(u8 b); + +#define bprintf(...) + +#if PRINT_TRACE +#define TRACE bprintf(__FILE__ " :%d\n\r",__LINE__); +#else +#define TRACE +#endif + +typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *m_plistentryNext; + struct _LIST_ENTRY *m_plistentryPrevious; +} LIST_ENTRY; + +void ListEntryInsertAfterCurrent(LIST_ENTRY *plistentryCurrent, LIST_ENTRY *plistentryNew); +void ListEntryRemove(LIST_ENTRY *plistentryCurrent); + +////////// BootPerformXCodeActions.c + +int BootPerformXCodeActions(void); + +#include "BootEEPROM.h" +#include "BootParser.h" + +////////// BootStartBios.c + +void StartBios(CONFIGENTRY *config,int nActivePartition, int nFATXPresent,int bootfrom); +int BootMenu(CONFIGENTRY *config,int nDrive,int nActivePartition, int nFATXPresent); + +////////// BootResetActions.c +void ClearIDT (void); +void BootResetAction(void); +void BootCpuCache(bool fEnable) ; +int printk(const char *szFormat, ...); +void BiosCmosWrite(u8 bAds, u8 bData); +u8 BiosCmosRead(u8 bAds); + + +///////// BootPciPeripheralInitialization.c +void BootPciPeripheralInitialization(void); +void BootAGPBUSInitialization(void); +void BootDetectMemorySize(void); +extern void ReadPCIByte(unsigned int bus, unsigned int dev, unsigned intfunc, unsigned int reg_off, unsigned char *pbyteval); +extern void WritePCIByte(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off, unsigned char byteval); +extern void ReadPCIDword(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off, unsigned int *pdwordval); +extern void WritePCIDword(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off, unsigned int dwordval); +extern void ReadPCIBlock(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off, unsigned char *buf, unsigned int nbytes); +extern void WritePCIBlock(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off, unsigned char *buf, unsigned int nbytes); + +void PciWriteByte (unsigned int bus, unsigned int dev, unsigned int func, + unsigned int reg_off, unsigned char byteval); +u8 PciReadByte(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off); +u32 PciWriteDword(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off, u32 dw); +u32 PciReadDword(unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg_off); + +///////// BootPerformPicChallengeResponseAction.c + +int I2CTransmitWord(u8 bPicAddressI2cFormat, u16 wDataToWrite); +int I2CTransmitByteGetReturn(u8 bPicAddressI2cFormat, u8 bDataToWrite); +bool I2CGetTemperature(int *, int *); +void I2CModifyBits(u8 bAds, u8 bReg, u8 bData, u8 bMask); + +///////// BootIde.c + +extern tsHarddiskInfo tsaHarddiskInfo[]; // static struct stores data about attached drives +int BootIdeInit(void); +int BootIdeReadSector(int nDriveIndex, void * pbBuffer, unsigned int block, int byte_offset, int n_bytes); +int BootIdeBootSectorHddOrElTorito(int nDriveIndex, u8 * pbaResult); +int BootIdeAtapiAdditionalSenseCode(int nDrive, u8 * pba, int nLengthMaxReturn); +int BootIdeSetTransferMode(int nIndexDrive, int nMode); +int BootIdeWaitNotBusy(unsigned uIoBase); +bool BootIdeAtapiReportFriendlyError(int nDriveIndex, char * szErrorReturn, int nMaxLengthError); +void BootIdeAtapiPrintkFriendlyError(int nDriveIndex); + +///////// BootUSB.c + +void BootStopUSB(void); +void BootStartUSB(void); +void USBGetEvents(void); + +#include "xpad.h" + +extern struct xpad_data XPAD_current[4]; +extern struct xpad_data XPAD_last[4]; + +extern void wait_ms(u32 ticks); +extern void wait_us(u32 ticks); +extern void wait_smalldelay(void); + + +void * memcpy(void *dest, const void *src, size_t size); +void * memset(void *dest, int data, size_t size); +int memcmp(const void *buffer1, const void *buffer2, size_t num); +int _strncmp(const char *sz1, const char *sz2, int nMax); +char * strcpy(char *sz, const char *szc); +char * _strncpy (char * dest, const char * src, size_t n); +void chrreplace(char *string, char search, char ch); + +#define printf printk +#define sleep wait_ms +int tolower(int ch); +int isspace (int c); + +void MemoryManagementInitialization(void * pvStartAddress, u32 dwTotalMemoryAllocLength); +void * malloc(size_t size); +void free(void *); + +extern volatile int nCountI2cinterrupts, nCountUnusedInterrupts, nCountUnusedInterruptsPic2, nCountInterruptsSmc, nCountInterruptsIde; +extern volatile bool fSeenPowerdown; +typedef enum { + ETS_OPEN_OR_OPENING=0, + ETS_CLOSING, + ETS_CLOSED +} TRAY_STATE; +extern volatile TRAY_STATE traystate; + + +extern void BootInterruptsWriteIdt(void); +#endif +int copy_swap_trim(unsigned char *dst, unsigned char *src, int len); +void HMAC_SHA1( unsigned char *result, + unsigned char *key, int key_length, + unsigned char *text1, int text1_length, + unsigned char *text2, int text2_length ); + +char *strrchr0(char *string, char ch); + +#endif // _Boot_H_ diff --git a/reactos/drivers/usb/cromwell/linux/consts.h b/reactos/drivers/usb/cromwell/linux/consts.h index 755bf6a5128..d3fb6cebae0 100644 --- a/reactos/drivers/usb/cromwell/linux/consts.h +++ b/reactos/drivers/usb/cromwell/linux/consts.h @@ -1,70 +1,70 @@ -#ifndef _Consts_H_ -#define _Consts_H_ - -/* - * - * includes for startup code in a form usable by the .S files - * - */ - - /*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#define PCI_CFG_ADDR 0x0CF8 -#define PCI_CFG_DATA 0x0CFC - - -#define I2C_IO_BASE 0xc000 - -#define BUS_0 0 -#define BUS_1 1 - -#define DEV_0 0 -#define DEV_1 1 -#define DEV_2 2 -#define DEV_3 3 -#define DEV_4 4 -#define DEV_5 5 -#define DEV_6 6 -#define DEV_7 7 -#define DEV_8 8 -#define DEV_9 9 -#define DEV_a 0xa -#define DEV_b 0xb -#define DEV_c 0xc -#define DEV_d 0xd -#define DEV_e 0xe -#define DEV_f 0xf -#define DEV_10 0x10 -#define DEV_11 0x11 -#define DEV_12 0x12 -#define DEV_13 0x13 -#define DEV_14 0x14 -#define DEV_15 0x15 -#define DEV_16 0x16 -#define DEV_17 0x17 -#define DEV_18 0x18 -#define DEV_19 0x19 -#define DEV_1a 0x1a -#define DEV_1b 0x1b -#define DEV_1c 0x1c -#define DEV_1d 0x1d -#define DEV_1e 0x1e -#define DEV_1f 0x1f - -#define FUNC_0 0 -/* -#define boot_post_macro(value) \ - movb $(value), %al ;\ - outb %al, $0x80 -*/ - -#endif // _Consts_H_ - - +#ifndef _Consts_H_ +#define _Consts_H_ + +/* + * + * includes for startup code in a form usable by the .S files + * + */ + + /*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#define PCI_CFG_ADDR 0x0CF8 +#define PCI_CFG_DATA 0x0CFC + + +#define I2C_IO_BASE 0xc000 + +#define BUS_0 0 +#define BUS_1 1 + +#define DEV_0 0 +#define DEV_1 1 +#define DEV_2 2 +#define DEV_3 3 +#define DEV_4 4 +#define DEV_5 5 +#define DEV_6 6 +#define DEV_7 7 +#define DEV_8 8 +#define DEV_9 9 +#define DEV_a 0xa +#define DEV_b 0xb +#define DEV_c 0xc +#define DEV_d 0xd +#define DEV_e 0xe +#define DEV_f 0xf +#define DEV_10 0x10 +#define DEV_11 0x11 +#define DEV_12 0x12 +#define DEV_13 0x13 +#define DEV_14 0x14 +#define DEV_15 0x15 +#define DEV_16 0x16 +#define DEV_17 0x17 +#define DEV_18 0x18 +#define DEV_19 0x19 +#define DEV_1a 0x1a +#define DEV_1b 0x1b +#define DEV_1c 0x1c +#define DEV_1d 0x1d +#define DEV_1e 0x1e +#define DEV_1f 0x1f + +#define FUNC_0 0 +/* +#define boot_post_macro(value) \ + movb $(value), %al ;\ + outb %al, $0x80 +*/ + +#endif // _Consts_H_ + + diff --git a/reactos/drivers/usb/cromwell/linux/cromwell_types.h b/reactos/drivers/usb/cromwell/linux/cromwell_types.h index d03e9158393..cccc05c681b 100644 --- a/reactos/drivers/usb/cromwell/linux/cromwell_types.h +++ b/reactos/drivers/usb/cromwell/linux/cromwell_types.h @@ -1,27 +1,27 @@ -#ifndef cromwell_types_h -#define cromwell_types_h - -///////////////////////////////// -// some typedefs to make for easy sizing - -//typedef unsigned long ULONG; -typedef unsigned int u32; -typedef unsigned short u16; -typedef unsigned char u8; -#ifndef bool_already_defined_ - typedef int bool; -#endif -typedef unsigned long RGBA; // LSB=R -> MSB = A -//typedef long long __int64; - -#define guint int -#define guint8 unsigned char - -#define true 1 -#define false 0 - -#ifndef NULL -#define NULL ((void *)0) -#endif - -#endif /* #ifndef cromwell_types_h */ +#ifndef cromwell_types_h +#define cromwell_types_h + +///////////////////////////////// +// some typedefs to make for easy sizing + +//typedef unsigned long ULONG; +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; +#ifndef bool_already_defined_ + typedef int bool; +#endif +typedef unsigned long RGBA; // LSB=R -> MSB = A +//typedef long long __int64; + +#define guint int +#define guint8 unsigned char + +#define true 1 +#define false 0 + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#endif /* #ifndef cromwell_types_h */ diff --git a/reactos/drivers/usb/cromwell/linux/errno.h b/reactos/drivers/usb/cromwell/linux/errno.h index dcd2ede98d7..1b667890877 100644 --- a/reactos/drivers/usb/cromwell/linux/errno.h +++ b/reactos/drivers/usb/cromwell/linux/errno.h @@ -1,132 +1,132 @@ -#ifndef _I386_ERRNO_H -#define _I386_ERRNO_H - -#define EPERM 1 /* Operation not permitted */ -#define ENOENT 2 /* No such file or directory */ -#define ESRCH 3 /* No such process */ -#define EINTR 4 /* Interrupted system call */ -#define EIO 5 /* I/O error */ -#define ENXIO 6 /* No such device or address */ -#define E2BIG 7 /* Argument list too long */ -#define ENOEXEC 8 /* Exec format error */ -#define EBADF 9 /* Bad file number */ -#define ECHILD 10 /* No child processes */ -#define EAGAIN 11 /* Try again */ -#define ENOMEM 12 /* Out of memory */ -#define EACCES 13 /* Permission denied */ -#define EFAULT 14 /* Bad address */ -#define ENOTBLK 15 /* Block device required */ -#define EBUSY 16 /* Device or resource busy */ -#define EEXIST 17 /* File exists */ -#define EXDEV 18 /* Cross-device link */ -#define ENODEV 19 /* No such device */ -#define ENOTDIR 20 /* Not a directory */ -#define EISDIR 21 /* Is a directory */ -#define EINVAL 22 /* Invalid argument */ -#define ENFILE 23 /* File table overflow */ -#define EMFILE 24 /* Too many open files */ -#define ENOTTY 25 /* Not a typewriter */ -#define ETXTBSY 26 /* Text file busy */ -#define EFBIG 27 /* File too large */ -#define ENOSPC 28 /* No space left on device */ -#define ESPIPE 29 /* Illegal seek */ -#define EROFS 30 /* Read-only file system */ -#define EMLINK 31 /* Too many links */ -#define EPIPE 32 /* Broken pipe */ -#define EDOM 33 /* Math argument out of domain of func */ -#define ERANGE 34 /* Math result not representable */ -#define EDEADLK 35 /* Resource deadlock would occur */ -#define ENAMETOOLONG 36 /* File name too long */ -#define ENOLCK 37 /* No record locks available */ -#define ENOSYS 38 /* Function not implemented */ -#define ENOTEMPTY 39 /* Directory not empty */ -#define ELOOP 40 /* Too many symbolic links encountered */ -#define EWOULDBLOCK EAGAIN /* Operation would block */ -#define ENOMSG 42 /* No message of desired type */ -#define EIDRM 43 /* Identifier removed */ -#define ECHRNG 44 /* Channel number out of range */ -#define EL2NSYNC 45 /* Level 2 not synchronized */ -#define EL3HLT 46 /* Level 3 halted */ -#define EL3RST 47 /* Level 3 reset */ -#define ELNRNG 48 /* Link number out of range */ -#define EUNATCH 49 /* Protocol driver not attached */ -#define ENOCSI 50 /* No CSI structure available */ -#define EL2HLT 51 /* Level 2 halted */ -#define EBADE 52 /* Invalid exchange */ -#define EBADR 53 /* Invalid request descriptor */ -#define EXFULL 54 /* Exchange full */ -#define ENOANO 55 /* No anode */ -#define EBADRQC 56 /* Invalid request code */ -#define EBADSLT 57 /* Invalid slot */ - -#define EDEADLOCK EDEADLK - -#define EBFONT 59 /* Bad font file format */ -#define ENOSTR 60 /* Device not a stream */ -#define ENODATA 61 /* No data available */ -#define ETIME 62 /* Timer expired */ -#define ENOSR 63 /* Out of streams resources */ -#define ENONET 64 /* Machine is not on the network */ -#define ENOPKG 65 /* Package not installed */ -#define EREMOTE 66 /* Object is remote */ -#define ENOLINK 67 /* Link has been severed */ -#define EADV 68 /* Advertise error */ -#define ESRMNT 69 /* Srmount error */ -#define ECOMM 70 /* Communication error on send */ -#define EPROTO 71 /* Protocol error */ -#define EMULTIHOP 72 /* Multihop attempted */ -#define EDOTDOT 73 /* RFS specific error */ -#define EBADMSG 74 /* Not a data message */ -#define EOVERFLOW 75 /* Value too large for defined data type */ -#define ENOTUNIQ 76 /* Name not unique on network */ -#define EBADFD 77 /* File descriptor in bad state */ -#define EREMCHG 78 /* Remote address changed */ -#define ELIBACC 79 /* Can not access a needed shared library */ -#define ELIBBAD 80 /* Accessing a corrupted shared library */ -#define ELIBSCN 81 /* .lib section in a.out corrupted */ -#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ -#define ELIBEXEC 83 /* Cannot exec a shared library directly */ -#define EILSEQ 84 /* Illegal byte sequence */ -#define ERESTART 85 /* Interrupted system call should be restarted */ -#define ESTRPIPE 86 /* Streams pipe error */ -#define EUSERS 87 /* Too many users */ -#define ENOTSOCK 88 /* Socket operation on non-socket */ -#define EDESTADDRREQ 89 /* Destination address required */ -#define EMSGSIZE 90 /* Message too long */ -#define EPROTOTYPE 91 /* Protocol wrong type for socket */ -#define ENOPROTOOPT 92 /* Protocol not available */ -#define EPROTONOSUPPORT 93 /* Protocol not supported */ -#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ -#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ -#define EPFNOSUPPORT 96 /* Protocol family not supported */ -#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ -#define EADDRINUSE 98 /* Address already in use */ -#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ -#define ENETDOWN 100 /* Network is down */ -#define ENETUNREACH 101 /* Network is unreachable */ -#define ENETRESET 102 /* Network dropped connection because of reset */ -#define ECONNABORTED 103 /* Software caused connection abort */ -#define ECONNRESET 104 /* Connection reset by peer */ -#define ENOBUFS 105 /* No buffer space available */ -#define EISCONN 106 /* Transport endpoint is already connected */ -#define ENOTCONN 107 /* Transport endpoint is not connected */ -#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ -#define ETOOMANYREFS 109 /* Too many references: cannot splice */ -#define ETIMEDOUT 110 /* Connection timed out */ -#define ECONNREFUSED 111 /* Connection refused */ -#define EHOSTDOWN 112 /* Host is down */ -#define EHOSTUNREACH 113 /* No route to host */ -#define EALREADY 114 /* Operation already in progress */ -#define EINPROGRESS 115 /* Operation now in progress */ -#define ESTALE 116 /* Stale NFS file handle */ -#define EUCLEAN 117 /* Structure needs cleaning */ -#define ENOTNAM 118 /* Not a XENIX named type file */ -#define ENAVAIL 119 /* No XENIX semaphores available */ -#define EISNAM 120 /* Is a named type file */ -#define EREMOTEIO 121 /* Remote I/O error */ -#define EDQUOT 122 /* Quota exceeded */ - -#define ENOMEDIUM 123 /* No medium found */ -#define EMEDIUMTYPE 124 /* Wrong medium type */ - -#endif +#ifndef _I386_ERRNO_H +#define _I386_ERRNO_H + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ + +#endif diff --git a/reactos/drivers/usb/cromwell/linux/linux_wrapper.h b/reactos/drivers/usb/cromwell/linux/linux_wrapper.h index 382f186d60f..acd892e8e7a 100644 --- a/reactos/drivers/usb/cromwell/linux/linux_wrapper.h +++ b/reactos/drivers/usb/cromwell/linux/linux_wrapper.h @@ -1,802 +1,803 @@ -/* - * linux-wrapper.h - * - * Hard coded Linux kernel replacements for x86 - * - * (c) 2003 Georg Acher (georg@acher.org) - * - * Emulation of: - * typedefs - * structs - * macros - * - * All structs and prototypes are based on kernel source 2.5.72 - * - * Modified by Aleksey Bragin (aleksey@reactos.com) for ReactOS needs - * - * - * #include - */ - -/*------------------------------------------------------------------------*/ -/* Typedefs */ -/*------------------------------------------------------------------------*/ -#include "cromwell_types.h" - -typedef unsigned int __u32; -//typedef __u32 u32; -typedef unsigned short __u16; -//typedef __u16 u16; -typedef unsigned char __u8; -//typedef __u8 u8; - -typedef short s16; - -typedef u32 dma_addr_t; - -typedef int spinlock_t; -typedef int atomic_t; -#ifndef STANDALONE -typedef int mode_t; -typedef int pid_t; -typedef int ssize_t; - -#endif -typedef int irqreturn_t; -typedef unsigned long kernel_ulong_t; - -typedef int wait_queue_head_t; -/*------------------------------------------------------------------------*/ -/* Stuff from xbox/linux environment */ -/*------------------------------------------------------------------------*/ - -#include "list.h" - -#ifndef STANDALONE -#ifdef MODULE -typedef int size_t; -#define NULL ((void*)0) -extern void * memset(void *,int,unsigned int); -extern void * memcpy(void *,const void *,unsigned int); -#if 0 -extern char * strcpy(char *,const char *); -#else -static inline char * strcpy(char * dest,const char *src) -{ -int d0, d1, d2; -__asm__ __volatile__( - "1:\tlodsb\n\t" - "stosb\n\t" - "testb %%al,%%al\n\t" - "jne 1b" - : "=&S" (d0), "=&D" (d1), "=&a" (d2) - :"0" (src),"1" (dest) : "memory"); -return dest; -} -#endif -extern size_t strlen(const char *); - -extern int memcmp(const void *,const void *,unsigned int); - -#else -#include "boot.h" -#include "config.h" -#endif -#else -#include -#include -#include -#include "consts.h" -#include -#endif - -/*------------------------------------------------------------------------*/ -/* General structs */ -/*------------------------------------------------------------------------*/ - -struct timer_list { - void (*function)(unsigned long); - unsigned long data; - int expires; - struct list_head timer_list; -}; - -struct work_struct { - void (*func)(void *); -}; -struct device { - char name[128]; - struct bus_type *bus; - int dma_mask; - char bus_id[16]; - struct device_driver* driver; - void *driver_data; - struct device *parent; - struct list_head driver_list; - void (*release)(struct device * dev); -}; -struct class_device{int a;}; -struct semaphore{int a;}; - -struct device_driver{ - char *name; - struct bus_type *bus; - int (*probe) (struct device * dev); - int (*remove) (struct device * dev); - struct list_head devices; -}; - -struct bus_type { - char * name; - int (*match)(struct device * dev, struct device_driver * drv); - struct device * (*add) (struct device * parent, char * bus_id); - int (*hotplug) (struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); -}; - -struct dummy_process -{ - int flags; -}; - -struct pt_regs -{ - int a; -}; -struct completion { - unsigned int done; - wait_queue_head_t wait; -}; - -// windows lookaside list head -typedef void* kmem_cache_t; - -struct dma_pool -{ - int dummy; -}; - -/* from mod_devicetable.h */ - -struct usb_device_id { - /* which fields to match against? */ - __u16 match_flags; - - /* Used for product specific matches; range is inclusive */ - __u16 idVendor; - __u16 idProduct; - __u16 bcdDevice_lo; - __u16 bcdDevice_hi; - - /* Used for device class matches */ - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - - /* Used for interface class matches */ - __u8 bInterfaceClass; - __u8 bInterfaceSubClass; - __u8 bInterfaceProtocol; - - /* not matched against */ - kernel_ulong_t driver_info; -}; - -/* Some useful macros to use to create struct usb_device_id */ -#define USB_DEVICE_ID_MATCH_VENDOR 0x0001 -#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002 -#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004 -#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008 -#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010 -#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020 -#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040 -#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080 -#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100 -#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 - -/*------------------------------------------------------------------------*/ -/* imported functions from top-level */ -/*------------------------------------------------------------------------*/ - -//void zxprintf(char* fmt, ...); -//void zxsprintf(char *buffer, char* fmt, ...); -//int zxsnprintf(char *buffer, size_t s, char* fmt, ...); - -/*------------------------------------------------------------------------*/ -/* PCI structs (taken from linux/pci.h et al., but slightly modified) */ -/*------------------------------------------------------------------------*/ - -struct pci_dev { - int vendor; - int device; - struct pci_bus *bus; - int irq; - char *slot_name; - struct device dev; - int base[4]; - int flags[4]; - void * data; - void * dev_ext; // link to Windows DeviceExtension -}; - -struct pci_bus { - unsigned char number; -}; - -struct pci_device_id { - __u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/ - __u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ - __u32 class, class_mask; /* (class,subclass,prog-if) triplet */ - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - -struct pci_driver { - struct list_head node; - char *name; - const struct pci_device_id *id_table; /* must be non-NULL for probe to be called */ - int (*probe) (struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */ - void (*remove) (struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */ - int (*save_state) (struct pci_dev *dev, u32 state); /* Save Device Context */ - int (*suspend) (struct pci_dev *dev, u32 state); /* Device suspended */ - int (*resume) (struct pci_dev *dev); /* Device woken up */ - int (*enable_wake) (struct pci_dev *dev, u32 state, int enable); /* Enable wake event */ -}; - -struct scatterlist -{ - int page; - int offset; - int length; -}; - -struct usbdevfs_hub_portinfo -{ - int nports; - int port[8]; -}; - -/*------------------------------------------------------------------------*/ -/* constant defines */ -/*------------------------------------------------------------------------*/ - -#define TASK_UNINTERRUPTIBLE 0 -#define HZ 100 /* Don't rely on that... */ -#define KERN_DEBUG "DBG: " -#define KERN_ERR "ERR: " -#define KERN_WARNING "WRN: " -#define KERN_INFO "INF: " -#define GFP_KERNEL 0 -#define GFP_ATOMIC 0 -#define GFP_NOIO 0 -#define SLAB_ATOMIC 0 -#define PCI_ANY_ID (~0) -#define SIGKILL 9 -#define THIS_MODULE 0 -//#define PAGE_SIZE 4096 - - -#define CLONE_FS 0 -#define CLONE_FILES 0 -#define CLONE_SIGHAND 0 -#define PF_FREEZE 0 -#define PF_IOTHREAD 0 - - -#define USBDEVFS_HUB_PORTINFO 1234 -#define SA_SHIRQ 0 - -#undef PCI_COMMAND -#define PCI_COMMAND 0 -#undef PCI_COMMAND_MASTER -#define PCI_COMMAND_MASTER 0 -/*------------------------------------------------------------------------*/ -/* Module/export macros */ -/*------------------------------------------------------------------------*/ - -#define MODULE_AUTHOR(a) -#define MODULE_DESCRIPTION(a) -#define MODULE_LICENSE(a) -#define MODULE_DEVICE_TABLE(type,name) void* module_table_##name=&name -#define MODULE_PARM(a,b) -#define MODULE_PARM_DESC(a,b) - -#define __devinit -#define __exit -#define __init -#define __devinitdata -#define module_init(x) static void module_init_##x(void){ x();} -#define module_exit(x) void module_exit_##x(void){ x();} -#define EXPORT_SYMBOL_GPL(x) -#define EXPORT_SYMBOL(x) - -#define __setup(x,y) int setup_##y=(int)y -#define subsys_initcall(x) void subsys_##x(void){x();} - -/*------------------------------------------------------------------------*/ -/* Access macros */ -/*------------------------------------------------------------------------*/ - -#define dev_get_drvdata(a) (a)->driver_data -#define dev_set_drvdata(a,b) (a)->driver_data=(b) - -#define __io_virt(x) ((void *)(x)) -#define readl(addr) (*(volatile unsigned int *) __io_virt(addr)) -#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b)) -#define likely(x) (x) -#define unlikely(x) (x) -#define prefetch(x) 1 - -#define inw(x) READ_PORT_USHORT((PUSHORT)(x)) -#define outw(x,p) WRITE_PORT_USHORT((PUSHORT)(p),(x)) -#define outl(x,p) WRITE_PORT_ULONG((PUSHORT)(p),(x)) - -/* The kernel macro for list_for_each_entry makes nonsense (have no clue - * why, this is just the same definition...) */ - -#undef list_for_each_entry -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - prefetch(pos->member.next); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member), \ - prefetch(pos->member.next)) - -/*------------------------------------------------------------------------*/ -/* function wrapper macros */ -/*------------------------------------------------------------------------*/ -#define kmalloc(x,y) ExAllocatePool(PagedPool,x) -#define kfree(x) ExFreePool(x) - -//#define sprintf(a,b,format, arg...) zxsprintf((a),(b),format, ## arg) -//#define snprintf(a,b,format, arg...) zxsnprintf((a),(b),format, ##arg) -//#define printk(format, arg...) zxprintf(format, ## arg) -#define snprintf(a,b,format, arg...) _snprintf((a),(b),format, ##arg) -#define printk(format, arg...) DPRINT1(format, ## arg) -#define BUG(...) do {} while(0) - -/* Locks & friends */ - -#define DECLARE_MUTEX(x) struct semaphore x -#define init_MUTEX(x) - -#define SPIN_LOCK_UNLOCKED 0 -#define spin_lock_init(a) do {} while(0) -#define spin_lock(a) *(int*)a=1 -#define spin_unlock(a) do {} while(0) - -#define spin_lock_irqsave(a,b) b=0 -#define spin_unlock_irqrestore(a,b) - -#if 0 -#define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") -#define local_irq_restore(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc") -#else -#define local_irq_save(x) do {} while(0) -#define local_irq_restore(x) do {} while(0) -#endif - -#define atomic_inc(x) *(x)+=1 -#define atomic_dec(x) *(x)-=1 -#define atomic_dec_and_test(x) (*(x)-=1,(*(x))==0) -#define atomic_set(x,a) *(x)=a -#define atomic_read(x) *(x) -#define ATOMIC_INIT(x) (x) - -#define down(x) do {} while(0) -#define up(x) do {} while(0) -#define down_trylock(a) 0 - -#define down_read(a) do {} while(0) -#define up_read(a) do {} while(0) - -#define DECLARE_WAIT_QUEUE_HEAD(x) KEVENT x - -#define DECLARE_COMPLETION(x) struct completion x - -/* driver */ - -#define driver_unregister(a) do {} while(0) -#define put_device(a) do {} while(0) - - -/* PCI */ -#define to_pci_dev(n) container_of(n, struct pci_dev, dev) - -#define pci_pool_create(a,b,c,d,e) (void*)1 - -#define pci_pool_alloc(a,b,c) my_pci_pool_alloc(a,b,c) - -static void __inline__ *my_pci_pool_alloc(void* pool, size_t size, - dma_addr_t *dma_handle) -{ - void* a; - a=kmalloc(size,0); //FIXME -#ifdef MODULE - *dma_handle=((u32)a)&0xfffffff; -#else - *dma_handle=(u32)a; -#endif - return a; -} - - -#define pci_pool_free(a,b,c) kfree(b) -#define pci_alloc_consistent(a,b,c) my_pci_alloc_consistent(a,b,c) - -static void __inline__ *my_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) -{ - void* a; - - a=kmalloc(size+256,0); //FIXME - a=(void*)(((int)a+255)&~255); // 256 alignment - *dma_handle=((u32)a)&0xfffffff; - - return a; -} - -#define pci_free_consistent(a,b,c,d) kfree(c) -#define pci_pool_destroy(a) do {} while(0) - -#define pci_module_init(x) my_pci_module_init(x) -int my_pci_module_init(struct pci_driver *x); - -#define pci_unregister_driver(a) do {} while(0) - -#define pci_write_config_word(a,b,c) my_pci_write_config_word(a,b,c) - -#define bus_register(a) do {} while(0) -#define bus_unregister(a) do {} while(0) - -/* DMA */ -//#define dma_pool_alloc(a,b,c) my_dma_pool_alloc((a),(b),(c)) -#define dma_pool_alloc(a,b,c) pci_pool_alloc(a,b,c) -#define dma_pool_create(a,b,c,d,e) pci_pool_create(a,b,c,d,e) -#define dma_pool_free(a,b,c) pci_pool_free(a,b,c) -#define dma_pool_destroy(a) pci_pool_destroy(a) - -#define dma_alloc_coherent(a,b,c,d) NULL -#define dma_free_coherent(a,b,c,d) do {} while(0) - -#define dma_map_single(a,b,c,d) ((u32)(b)&0xfffffff) -#define dma_unmap_single(a,b,c,d) do {} while(0) -#define pci_unmap_single(a,b,c,d) do {} while(0) -#define dma_sync_single(a,b,c,d) do {} while(0) -#define dma_sync_sg(a,b,c,d) do {} while(0) -#define dma_map_sg(a,b,c,d) 0 -#define dma_unmap_sg(a,b,c,d) do {} while(0) - -#define usb_create_driverfs_dev_files(a) do {} while(0) -#define usb_create_driverfs_intf_files(a) do {} while(0) -#define sg_dma_address(x) ((u32)((x)->page*4096 + (x)->offset)) -#define sg_dma_len(x) ((x)->length) - -#define page_address(x) ((void*)(x/4096)) - -#define DMA_TO_DEVICE 0 -#define DMA_FROM_DEVICE 0 -#define PCI_DMA_TODEVICE -#define PCI_DMA_FROMDEVICE -#define PCI_DMA_TODEVICE - -#define PCI_ROM_RESOURCE 0 -#define IORESOURCE_IO 1 - -#define DECLARE_WAITQUEUE(a,b) KEVENT a=0 -#define init_waitqueue_head(a) my_init_waitqueue_head(a) -#define add_wait_queue(a,b) do {} while(0) -#define remove_wait_queue(a,b) do {} while(0) -void my_init_waitqueue_head(PKEVENT a); - -VOID KeMemoryBarrier(VOID); - -#define mb() KeMemoryBarrier() -#define wmb() __asm__ __volatile__ ("": : :"memory") -#define rmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") - -#define in_interrupt() 0 - -#define init_completion(x) (x)->done=0 -#define wait_for_completion(x) my_wait_for_completion(x) -void my_wait_for_completion(struct completion*); - -#define IRQ_NONE 0 -#define IRQ_HANDLED 1 - -#define INIT_WORK(a,b,c) (a)->func=b - -#define set_current_state(a) do {} while(0) - -#define might_sleep() do {} while(0) -#define daemonize(a) do {} while(0) -#define allow_signal(a) do {} while(0) -#define wait_event_interruptible(x,y) do {} while(0) - -#define interruptible_sleep_on(a) my_interruptible_sleep_on(a) -void my_interruptible_sleep_on(PKEVENT evnt); - -#define flush_scheduled_work() do {} while(0) -#define refrigerator(x) do {} while(0) -#define signal_pending(x) 1 // fall through threads -#define complete_and_exit(a,b) return 0 - -//#define kill_proc(a,b,c) 0 -#define kill_proc(a,b,c) my_kill_proc(a, b, c); -int my_kill_proc(int pid, int signal, int unk); - -#define yield() do {} while(0) -#define cpu_relax() do {} while(0) - -#define WARN_ON(a) do {} while(0) - -/*------------------------------------------------------------------------*/ -/* Lookaside lists funcs */ -/*------------------------------------------------------------------------*/ -#define kmem_cache_create(a,b,c,d,e,f) my_kmem_cache_create((a),(b),(c),(d),(e),(f)) -#define kmem_cache_destroy(a) my_kmem_cache_destroy((a)) -#define kmem_cache_alloc(co, flags) my_kmem_cache_alloc((co), (flags)) -#define kmem_cache_free(co, ptr) my_kmem_cache_free((co), (ptr)) - -kmem_cache_t *my_kmem_cache_create(const char *tag, size_t alloc_size, - size_t offset, unsigned long flags, - void *ctor, - void *dtor); - -BOOLEAN my_kmem_cache_destroy(kmem_cache_t *co); -void *my_kmem_cache_alloc(kmem_cache_t *co, int flags); -void my_kmem_cache_free(kmem_cache_t *co, void *ptr); - -/*------------------------------------------------------------------------*/ -/* Kernel macros */ -/*------------------------------------------------------------------------*/ - -#define LINUX_VERSION_CODE 0x020572 -#define UTS_SYSNAME "XBOX" -#define UTS_RELEASE "----" - -/* from linux/kernel.h */ -#define max_t(type,x,y) \ - ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) - -#define min_t(type,x,y) \ - ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) - -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -/* from linux/stddef.h */ - -#undef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - -/*------------------------------------------------------------------------*/ -/* Conversion macros */ -/*------------------------------------------------------------------------*/ - -#define __constant_cpu_to_le32(x) (x) -#define cpu_to_le16(x) (x) -#define le16_to_cpu(x) (x) -#define cpu_to_le32(x) (x) -#define cpu_to_le32p(x) (*(__u32*)(x)) -#define le32_to_cpup(x) (*(__u32*)(x)) -#define le32_to_cpu(x) ((u32)x) -#define le16_to_cpus(x) do {} while (0) -#define le16_to_cpup(x) (*(__u16*)(x)) -#define cpu_to_le16p(x) (*(__u16*)(x)) - -/*------------------------------------------------------------------------*/ -/* Debug output */ -/*------------------------------------------------------------------------*/ -#ifdef DEBUG_MODE -#define dev_printk(lvl,x,f,arg...) printk(f, ## arg) -#define dev_dbg(x,f,arg...) printk(f, ## arg) -#define dev_info(x,f,arg...) printk(f,## arg) -#define dev_warn(x,f,arg...) printk(f,## arg) -#define dev_err(x,f,arg...) printk(f,## arg) -#define pr_debug(x,f,arg...) printk(f,## arg) -#define usbprintk printk -#endif - -#ifndef DEBUG_MODE -#define dev_printk(lvl,x,f,arg...) do {} while (0) -#define dev_dbg(x,f,arg...) do {} while (0) //printk(f, ## arg) -#define dev_info(x,f,arg...) do {} while (0) -#define dev_warn(x,f,arg...) do {} while (0) -#define dev_err(x,f,arg...) do {} while (0) -#define pr_debug(x,f,arg...) do {} while (0) -#define usbprintk -#endif - - - -#define PCI_DEVFN(a,b) 0 -#define PCI_SLOT(a) 0 - -/** - * PCI_DEVICE_CLASS - macro used to describe a specific pci device class - * @dev_class: the class, subclass, prog-if triple for this device - * @dev_class_mask: the class mask for this device - * - * This macro is used to create a struct pci_device_id that matches a - * specific PCI class. The vendor, device, subvendor, and subdevice - * fields will be set to PCI_ANY_ID. - */ -#define PCI_DEVICE_CLASS(dev_class,dev_class_mask) \ - .class = (dev_class), .class_mask = (dev_class_mask), \ - .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \ - .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID - - -/*------------------------------------------------------------------------*/ -/* Stuff from kernel */ -/*------------------------------------------------------------------------*/ - -#include "errno.h" -#include "bitops.h" -//#include "linux/pci_ids.h" - -/*------------------------------------------------------------------------*/ -/* global variables */ -/*------------------------------------------------------------------------*/ - -#define jiffies my_jiffies -extern int my_jiffies; -#define current my_current -extern struct dummy_process *my_current; - -extern struct list_head interrupt_list; - -/*------------------------------------------------------------------------*/ -/* Function prototypes */ -/*------------------------------------------------------------------------*/ -void STDCALL usb_hcd_pci_remove (struct pci_dev *dev); - -#define my_wait_ms(x) wait_ms(x) - -#define my_udelay(x) wait_ms(x) -#define udelay(x) my_udelay(x) - -#define my_mdelay(x) wait_ms(1+x/1000); -#define mdelay(x) my_mdelay(x); - -#define pci_find_slot(a,b) my_pci_find_slot(a,b) -struct pci_dev *my_pci_find_slot(int a,int b); - -/*------------------------------------------------------------------------*/ -/* Timer management */ -/*------------------------------------------------------------------------*/ - -#define MAX_TIMERS 20 -extern struct timer_list *main_timer_list[MAX_TIMERS]; - -static void __inline__ init_timer(struct timer_list* t) -{ - INIT_LIST_HEAD(&t->timer_list); - t->function=NULL; - t->expires=0; -} - -static void __inline__ add_timer(struct timer_list* t) -{ - int n; - for(n=0;nexpires=ex; - add_timer(t); -} - -#define time_after_eq(a,b) \ - (((long)(a) - (long)(b) >= 0)) - -/*------------------------------------------------------------------------*/ -/* Device driver and process related stuff */ -/*------------------------------------------------------------------------*/ - -static int __inline__ usb_major_init(void){return 0;} -static void __inline__ usb_major_cleanup(void){} -static void __inline__ schedule_work(void* p){} - -#define device_initialize(x) my_device_initialize(x) -void my_device_initialize(struct device *dev); - -#define get_device(x) my_get_device(x) -struct device *my_get_device(struct device *dev); - -#define device_add(x) my_device_add(x) -int my_device_add(struct device *dev); - -#define driver_register(x) my_driver_register(x) -int my_driver_register(struct device_driver *driver); - -#define device_unregister(a) my_device_unregister(a) -int my_device_unregister(struct device *dev); - -#define DEVICE_ATTR(a,b,c,d) int xxx_##a -#define device_create_file(a,b) do {} while(0) -#define device_remove_file(a,b) do {} while(0) - -#define schedule_timeout(x) my_schedule_timeout(x) -int my_schedule_timeout(int x); - -#define wake_up(x) my_wake_up(x) -void my_wake_up(PKEVENT); - -// cannot be mapped via macro due to collision with urb->complete -static void __inline__ complete(struct completion *p) -{ - /* Wake up x->wait */ - p->done++; - wake_up(&p->wait); -} - -#define kernel_thread(a,b,c) my_kernel_thread(a,b,c) -int my_kernel_thread(int STDCALL (*handler)(void*), void* parm, int flags); - -/*------------------------------------------------------------------------*/ -/* PCI, simple and inlined... */ -/*------------------------------------------------------------------------*/ -#include "pci_hal.c" - -/*------------------------------------------------------------------------*/ -/* IRQ handling */ -/*------------------------------------------------------------------------*/ - -#define request_irq(a,b,c,d,e) my_request_irq(a,b,c,d,e) -int my_request_irq(unsigned int irq, - int (*handler)(int, void *, struct pt_regs *), - unsigned long mode, const char *desc, void *data); - -#define free_irq(a,b) my_free_irq(a,b) -int free_irq(int irq, void* p); - - - -struct my_irqs { - int (*handler)(int, void *, struct pt_regs *); - int irq; - void* data; -}; - -#define MAX_IRQS 8 - -// Exported to top level - -void handle_irqs(int irq); -void inc_jiffies(int); -void init_wrapper(struct pci_dev *pci_dev); -void do_all_timers(void); - -#define __KERNEL_DS 0x18 - - +/* + * linux-wrapper.h + * + * Hard coded Linux kernel replacements for x86 + * + * (c) 2003 Georg Acher (georg@acher.org) + * + * Emulation of: + * typedefs + * structs + * macros + * + * All structs and prototypes are based on kernel source 2.5.72 + * + * Modified by Aleksey Bragin (aleksey@reactos.com) for ReactOS needs + * + * + * #include + */ + +/*------------------------------------------------------------------------*/ +/* Typedefs */ +/*------------------------------------------------------------------------*/ +#include "cromwell_types.h" + +typedef unsigned int __u32; +//typedef __u32 u32; +typedef unsigned short __u16; +//typedef __u16 u16; +typedef unsigned char __u8; +//typedef __u8 u8; + +typedef short s16; + +typedef u32 dma_addr_t; + +typedef int spinlock_t; +typedef int atomic_t; +#ifndef STANDALONE +typedef int mode_t; +typedef int pid_t; +typedef int ssize_t; + +#endif +typedef int irqreturn_t; +typedef unsigned long kernel_ulong_t; + +typedef int wait_queue_head_t; +/*------------------------------------------------------------------------*/ +/* Stuff from xbox/linux environment */ +/*------------------------------------------------------------------------*/ + +#include "list.h" + +#ifndef STANDALONE +#ifdef MODULE +typedef int size_t; +#define NULL ((void*)0) +extern void * memset(void *,int,unsigned int); +extern void * memcpy(void *,const void *,unsigned int); +#if 0 +extern char * strcpy(char *,const char *); +#else +static inline char * strcpy(char * dest,const char *src) +{ +int d0, d1, d2; +__asm__ __volatile__( + "1:\tlodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b" + : "=&S" (d0), "=&D" (d1), "=&a" (d2) + :"0" (src),"1" (dest) : "memory"); +return dest; +} +#endif +extern size_t strlen(const char *); + +extern int memcmp(const void *,const void *,unsigned int); + +#else +#include "boot.h" +#include "config.h" +#endif +#else +#include +#include +#include +#include "consts.h" +#include +#endif + +/*------------------------------------------------------------------------*/ +/* General structs */ +/*------------------------------------------------------------------------*/ + +struct timer_list { + void (*function)(unsigned long); + unsigned long data; + int expires; + struct list_head timer_list; +}; + +struct work_struct { + void (*func)(void *); +}; +struct device { + char name[128]; + struct bus_type *bus; + int dma_mask; + char bus_id[16]; + struct device_driver* driver; + void *driver_data; + struct device *parent; + struct list_head driver_list; + void (*release)(struct device * dev); +}; +struct class_device{int a;}; +struct semaphore{int a;}; + +struct device_driver{ + char *name; + struct bus_type *bus; + int (*probe) (struct device * dev); + int (*remove) (struct device * dev); + struct list_head devices; +}; + +struct bus_type { + char * name; + int (*match)(struct device * dev, struct device_driver * drv); + struct device * (*add) (struct device * parent, char * bus_id); + int (*hotplug) (struct device *dev, char **envp, + int num_envp, char *buffer, int buffer_size); +}; + +struct dummy_process +{ + int flags; +}; + +struct pt_regs +{ + int a; +}; +struct completion { + unsigned int done; + wait_queue_head_t wait; +}; + +// windows lookaside list head +typedef void* kmem_cache_t; + +struct dma_pool +{ + int dummy; +}; + +/* from mod_devicetable.h */ + +struct usb_device_id { + /* which fields to match against? */ + __u16 match_flags; + + /* Used for product specific matches; range is inclusive */ + __u16 idVendor; + __u16 idProduct; + __u16 bcdDevice_lo; + __u16 bcdDevice_hi; + + /* Used for device class matches */ + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + + /* Used for interface class matches */ + __u8 bInterfaceClass; + __u8 bInterfaceSubClass; + __u8 bInterfaceProtocol; + + /* not matched against */ + kernel_ulong_t driver_info; +}; + +/* Some useful macros to use to create struct usb_device_id */ +#define USB_DEVICE_ID_MATCH_VENDOR 0x0001 +#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002 +#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004 +#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008 +#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010 +#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020 +#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040 +#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080 +#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100 +#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 + +/*------------------------------------------------------------------------*/ +/* imported functions from top-level */ +/*------------------------------------------------------------------------*/ + +//void zxprintf(char* fmt, ...); +//void zxsprintf(char *buffer, char* fmt, ...); +//int zxsnprintf(char *buffer, size_t s, char* fmt, ...); + +/*------------------------------------------------------------------------*/ +/* PCI structs (taken from linux/pci.h et al., but slightly modified) */ +/*------------------------------------------------------------------------*/ + +struct pci_dev { + int vendor; + int device; + struct pci_bus *bus; + int irq; + char *slot_name; + struct device dev; + int base[4]; + int flags[4]; + void * data; + void * dev_ext; // link to Windows DeviceExtension +}; + +struct pci_bus { + unsigned char number; +}; + +struct pci_device_id { + __u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/ + __u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ + __u32 class, class_mask; /* (class,subclass,prog-if) triplet */ + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + +struct pci_driver { + struct list_head node; + char *name; + const struct pci_device_id *id_table; /* must be non-NULL for probe to be called */ + int STDCALL (*probe) (struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */ + void STDCALL (*remove) (struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */ + int (*save_state) (struct pci_dev *dev, u32 state); /* Save Device Context */ + int (*suspend) (struct pci_dev *dev, u32 state); /* Device suspended */ + int (*resume) (struct pci_dev *dev); /* Device woken up */ + int (*enable_wake) (struct pci_dev *dev, u32 state, int enable); /* Enable wake event */ +}; + +struct scatterlist +{ + int page; + int offset; + int length; +}; + +struct usbdevfs_hub_portinfo +{ + int nports; + int port[8]; +}; + +/*------------------------------------------------------------------------*/ +/* constant defines */ +/*------------------------------------------------------------------------*/ + +#define TASK_UNINTERRUPTIBLE 0 +#define HZ 100 /* Don't rely on that... */ +#define KERN_DEBUG "DBG: " +#define KERN_ERR "ERR: " +#define KERN_WARNING "WRN: " +#define KERN_INFO "INF: " +#define GFP_KERNEL 0 +#define GFP_ATOMIC 0x20 +#define GFP_NOIO 0 +#define SLAB_ATOMIC 0 +#define PCI_ANY_ID (~0) +#define SIGKILL 9 +#define THIS_MODULE 0 +//#define PAGE_SIZE 4096 + + +#define CLONE_FS 0 +#define CLONE_FILES 0 +#define CLONE_SIGHAND 0 +#define PF_FREEZE 0 +#define PF_IOTHREAD 0 + + +#define USBDEVFS_HUB_PORTINFO 1234 +#define SA_SHIRQ 0 + +#undef PCI_COMMAND +#define PCI_COMMAND 0 +#undef PCI_COMMAND_MASTER +#define PCI_COMMAND_MASTER 0 +/*------------------------------------------------------------------------*/ +/* Module/export macros */ +/*------------------------------------------------------------------------*/ + +#define MODULE_AUTHOR(a) +#define MODULE_DESCRIPTION(a) +#define MODULE_LICENSE(a) +#define MODULE_DEVICE_TABLE(type,name) void* module_table_##name=&name +#define MODULE_PARM(a,b) +#define MODULE_PARM_DESC(a,b) + +#define __devinit +#define __exit +#define __init +#define __devinitdata +#define module_init(x) static void module_init_##x(void){ x();} +#define module_exit(x) void module_exit_##x(void){ x();} +#define EXPORT_SYMBOL_GPL(x) +#define EXPORT_SYMBOL(x) + +#define __setup(x,y) int setup_##y=(int)y +#define subsys_initcall(x) void subsys_##x(void){x();} + +/*------------------------------------------------------------------------*/ +/* Access macros */ +/*------------------------------------------------------------------------*/ + +#define dev_get_drvdata(a) (a)->driver_data +#define dev_set_drvdata(a,b) (a)->driver_data=(b) + +#define __io_virt(x) ((void *)(x)) +#define readl(addr) (*(volatile unsigned int *) __io_virt(addr)) +#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b)) +#define likely(x) (x) +#define unlikely(x) (x) +#define prefetch(x) 1 + +#define inw(x) READ_PORT_USHORT((PUSHORT)(x)) +#define outw(x,p) WRITE_PORT_USHORT((PUSHORT)(p),(x)) +#define outl(x,p) WRITE_PORT_ULONG((PULONG)(p),(x)) + +/* The kernel macro for list_for_each_entry makes nonsense (have no clue + * why, this is just the same definition...) */ + +#undef list_for_each_entry +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/*------------------------------------------------------------------------*/ +/* function wrapper macros */ +/*------------------------------------------------------------------------*/ +#define kmalloc(x,y) ExAllocatePool(PagedPool,x) +#define kfree(x) ExFreePool(x) + +//#define sprintf(a,b,format, arg...) zxsprintf((a),(b),format, ## arg) +//#define snprintf(a,b,format, arg...) zxsnprintf((a),(b),format, ##arg) +//#define printk(format, arg...) zxprintf(format, ## arg) +#define snprintf(a,b,format, arg...) _snprintf((a),(b),format, ##arg) +#define printk(format, arg...) DPRINT1(format, ## arg) +#define BUG(...) do {} while(0) + +/* Locks & friends */ + +#define DECLARE_MUTEX(x) struct semaphore x +#define init_MUTEX(x) + +#define SPIN_LOCK_UNLOCKED 0 +#define spin_lock_init(a) do {} while(0) +#define spin_lock(a) *(int*)a=1 +#define spin_unlock(a) do {} while(0) + +#define spin_lock_irqsave(a,b) b=0 +#define spin_unlock_irqrestore(a,b) + +#if 0 +#define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") +#define local_irq_restore(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc") +#else +#define local_irq_save(x) do {} while(0) +#define local_irq_restore(x) do {} while(0) +#endif + +#define atomic_inc(x) *(x)+=1 +#define atomic_dec(x) *(x)-=1 +#define atomic_dec_and_test(x) (*(x)-=1,(*(x))==0) +#define atomic_set(x,a) *(x)=a +#define atomic_read(x) *(x) +#define ATOMIC_INIT(x) (x) + +#define down(x) do {} while(0) +#define up(x) do {} while(0) +#define down_trylock(a) 0 + +#define down_read(a) do {} while(0) +#define up_read(a) do {} while(0) + +#define DECLARE_WAIT_QUEUE_HEAD(x) KEVENT x + +#define DECLARE_COMPLETION(x) struct completion x + +/* driver */ + +#define driver_unregister(a) do {} while(0) +#define put_device(a) do {} while(0) + + +/* PCI */ +#define to_pci_dev(n) container_of(n, struct pci_dev, dev) + +#define pci_pool_create(a,b,c,d,e) (void*)1 + +#define pci_pool_alloc(a,b,c) my_pci_pool_alloc(a,b,c) + +static void __inline__ *my_pci_pool_alloc(void* pool, size_t size, + dma_addr_t *dma_handle) +{ + void* a; + a=kmalloc(size,0); //FIXME +#ifdef MODULE + *dma_handle=((u32)a)&0xfffffff; +#else + *dma_handle=(u32)a; +#endif + return a; +} + + +#define pci_pool_free(a,b,c) kfree(b) +#define pci_alloc_consistent(a,b,c) my_pci_alloc_consistent(a,b,c) + +static void __inline__ *my_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void* a; + + a=kmalloc(size+256,0); //FIXME + a=(void*)(((int)a+255)&~255); // 256 alignment + *dma_handle=((u32)a)&0xfffffff; + + return a; +} + +#define pci_free_consistent(a,b,c,d) kfree(c) +#define pci_pool_destroy(a) do {} while(0) + +#define pci_module_init(x) my_pci_module_init(x) +int my_pci_module_init(struct pci_driver *x); + +#define pci_unregister_driver(a) do {} while(0) + +#define pci_write_config_word(a,b,c) my_pci_write_config_word(a,b,c) + +#define bus_register(a) do {} while(0) +#define bus_unregister(a) do {} while(0) + +/* DMA */ +//#define dma_pool_alloc(a,b,c) my_dma_pool_alloc((a),(b),(c)) +#define dma_pool_alloc(a,b,c) pci_pool_alloc(a,b,c) +#define dma_pool_create(a,b,c,d,e) pci_pool_create(a,b,c,d,e) +#define dma_pool_free(a,b,c) pci_pool_free(a,b,c) +#define dma_pool_destroy(a) pci_pool_destroy(a) + +#define dma_alloc_coherent(a,b,c,d) NULL +#define dma_free_coherent(a,b,c,d) do {} while(0) + +#define dma_map_single(a,b,c,d) ((u32)(b)&0xfffffff) +#define dma_unmap_single(a,b,c,d) do {} while(0) +#define pci_unmap_single(a,b,c,d) do {} while(0) +#define dma_sync_single(a,b,c,d) do {} while(0) +#define dma_sync_sg(a,b,c,d) do {} while(0) +#define dma_map_sg(a,b,c,d) 0 +#define dma_unmap_sg(a,b,c,d) do {} while(0) + +#define usb_create_driverfs_dev_files(a) do {} while(0) +#define usb_create_driverfs_intf_files(a) do {} while(0) +#define sg_dma_address(x) ((u32)((x)->page*4096 + (x)->offset)) +#define sg_dma_len(x) ((x)->length) + +#define page_address(x) ((void*)(x/4096)) + +#define DMA_TO_DEVICE 0 +#define DMA_FROM_DEVICE 0 +#define PCI_DMA_TODEVICE +#define PCI_DMA_FROMDEVICE +#define PCI_DMA_TODEVICE + +#define PCI_ROM_RESOURCE 1 +#define IORESOURCE_IO CM_RESOURCE_PORT_IO + +#define DECLARE_WAITQUEUE(a,b) KEVENT a=0 +#define init_waitqueue_head(a) my_init_waitqueue_head(a) +#define add_wait_queue(a,b) do {} while(0) +#define remove_wait_queue(a,b) do {} while(0) +void my_init_waitqueue_head(PKEVENT a); + +VOID KeMemoryBarrier(VOID); + +#define mb() KeMemoryBarrier() +#define wmb() __asm__ __volatile__ ("": : :"memory") +#define rmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") + +#define in_interrupt() 0 + +#define init_completion(x) (x)->done=0 +#define wait_for_completion(x) my_wait_for_completion(x) +void my_wait_for_completion(struct completion*); + +#define IRQ_NONE 0 +#define IRQ_HANDLED 1 + +#define INIT_WORK(a,b,c) (a)->func=b + +#define set_current_state(a) do {} while(0) + +#define might_sleep() do {} while(0) +#define daemonize(a) do {} while(0) +#define allow_signal(a) do {} while(0) +#define wait_event_interruptible(x,y) do {} while(0) + +#define interruptible_sleep_on(a) my_interruptible_sleep_on(a) +void my_interruptible_sleep_on(PKEVENT evnt); + +#define flush_scheduled_work() do {} while(0) +#define refrigerator(x) do {} while(0) +#define signal_pending(x) 1 // fall through threads +#define complete_and_exit(a,b) return 0 + +//#define kill_proc(a,b,c) 0 +#define kill_proc(a,b,c) my_kill_proc(a, b, c); +int my_kill_proc(int pid, int signal, int unk); + +#define yield() do {} while(0) +#define cpu_relax() do {} while(0) + +#define WARN_ON(a) do {} while(0) + +/*------------------------------------------------------------------------*/ +/* Lookaside lists funcs */ +/*------------------------------------------------------------------------*/ +#define kmem_cache_create(a,b,c,d,e,f) my_kmem_cache_create((a),(b),(c),(d),(e),(f)) +#define kmem_cache_destroy(a) my_kmem_cache_destroy((a)) +#define kmem_cache_alloc(co, flags) my_kmem_cache_alloc((co), (flags)) +#define kmem_cache_free(co, ptr) my_kmem_cache_free((co), (ptr)) + +kmem_cache_t *my_kmem_cache_create(const char *tag, size_t alloc_size, + size_t offset, unsigned long flags, + void *ctor, + void *dtor); + +BOOLEAN my_kmem_cache_destroy(kmem_cache_t *co); +void *my_kmem_cache_alloc(kmem_cache_t *co, int flags); +void my_kmem_cache_free(kmem_cache_t *co, void *ptr); + +/*------------------------------------------------------------------------*/ +/* Kernel macros */ +/*------------------------------------------------------------------------*/ + +#define LINUX_VERSION_CODE 0x020572 +#define UTS_SYSNAME "XBOX" +#define UTS_RELEASE "----" + +/* from linux/kernel.h */ +#define max_t(type,x,y) \ + ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) + +#define min_t(type,x,y) \ + ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/* from linux/stddef.h */ + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +/*------------------------------------------------------------------------*/ +/* Conversion macros */ +/*------------------------------------------------------------------------*/ + +#define __constant_cpu_to_le32(x) (x) +#define cpu_to_le16(x) (x) +#define le16_to_cpu(x) (x) +#define cpu_to_le32(x) (x) +#define cpu_to_le32p(x) (*(__u32*)(x)) +#define le32_to_cpup(x) (*(__u32*)(x)) +#define le32_to_cpu(x) ((u32)x) +#define le16_to_cpus(x) do {} while (0) +#define le16_to_cpup(x) (*(__u16*)(x)) +#define cpu_to_le16p(x) (*(__u16*)(x)) + +/*------------------------------------------------------------------------*/ +/* Debug output */ +/*------------------------------------------------------------------------*/ +#ifdef DEBUG_MODE +#define dev_printk(lvl,x,f,arg...) printk(f, ## arg) +#define dev_dbg(x,f,arg...) printk(f, ## arg) +#define dev_info(x,f,arg...) printk(f,## arg) +#define dev_warn(x,f,arg...) printk(f,## arg) +#define dev_err(x,f,arg...) printk(f,## arg) +#define pr_debug(x,f,arg...) printk(f,## arg) +#define usbprintk printk +#endif + +#ifndef DEBUG_MODE +#define dev_printk(lvl,x,f,arg...) do {} while (0) +#define dev_dbg(x,f,arg...) do {} while (0) //printk(f, ## arg) +#define dev_info(x,f,arg...) do {} while (0) +#define dev_warn(x,f,arg...) do {} while (0) +#define dev_err(x,f,arg...) do {} while (0) +#define pr_debug(x,f,arg...) do {} while (0) +#define usbprintk +#endif + + + +#define PCI_DEVFN(a,b) 0 +#define PCI_SLOT(a) 0 + +/** + * PCI_DEVICE_CLASS - macro used to describe a specific pci device class + * @dev_class: the class, subclass, prog-if triple for this device + * @dev_class_mask: the class mask for this device + * + * This macro is used to create a struct pci_device_id that matches a + * specific PCI class. The vendor, device, subvendor, and subdevice + * fields will be set to PCI_ANY_ID. + */ +#define PCI_DEVICE_CLASS(dev_class,dev_class_mask) \ + .class = (dev_class), .class_mask = (dev_class_mask), \ + .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \ + .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID + + +/*------------------------------------------------------------------------*/ +/* Stuff from kernel */ +/*------------------------------------------------------------------------*/ + +#include "errno.h" +#include "bitops.h" +//#include "linux/pci_ids.h" + +/*------------------------------------------------------------------------*/ +/* global variables */ +/*------------------------------------------------------------------------*/ + +#define jiffies my_jiffies +extern int my_jiffies; +#define current my_current +extern struct dummy_process *my_current; + +extern struct list_head interrupt_list; + +/*------------------------------------------------------------------------*/ +/* Function prototypes */ +/*------------------------------------------------------------------------*/ +void STDCALL usb_hcd_pci_remove (struct pci_dev *dev); + +#define my_wait_ms(x) wait_ms(x) + +#define my_udelay(x) wait_ms(x) +#define udelay(x) my_udelay(x) + +#define my_mdelay(x) wait_ms(1+x/1000); +#define mdelay(x) my_mdelay(x); + +#define pci_find_slot(a,b) my_pci_find_slot(a,b) +struct pci_dev *my_pci_find_slot(int a,int b); + +/*------------------------------------------------------------------------*/ +/* Timer management */ +/*------------------------------------------------------------------------*/ + +#define MAX_TIMERS 20 +extern struct timer_list *main_timer_list[MAX_TIMERS]; + +static void __inline__ init_timer(struct timer_list* t) +{ + INIT_LIST_HEAD(&t->timer_list); + t->function=NULL; + t->expires=0; +} + +static void __inline__ add_timer(struct timer_list* t) +{ + int n; + for(n=0;nexpires=ex; + add_timer(t); +} + +#define time_after_eq(a,b) \ + (((long)(a) - (long)(b) >= 0)) + +/*------------------------------------------------------------------------*/ +/* Device driver and process related stuff */ +/*------------------------------------------------------------------------*/ + +static int __inline__ usb_major_init(void){return 0;} +static void __inline__ usb_major_cleanup(void){} +static void __inline__ schedule_work(void* p){} + +#define device_initialize(x) my_device_initialize(x) +void my_device_initialize(struct device *dev); + +#define get_device(x) my_get_device(x) +struct device *my_get_device(struct device *dev); + +#define device_add(x) my_device_add(x) +int my_device_add(struct device *dev); + +#define driver_register(x) my_driver_register(x) +int my_driver_register(struct device_driver *driver); + +#define device_unregister(a) my_device_unregister(a) +int my_device_unregister(struct device *dev); + +#define DEVICE_ATTR(a,b,c,d) int xxx_##a +#define device_create_file(a,b) do {} while(0) +#define device_remove_file(a,b) do {} while(0) + +#define schedule_timeout(x) my_schedule_timeout(x) +int my_schedule_timeout(int x); + +#define wake_up(x) my_wake_up(x) +void my_wake_up(PKEVENT); + +// cannot be mapped via macro due to collision with urb->complete +static void __inline__ complete(struct completion *p) +{ + /* Wake up x->wait */ + p->done++; + wake_up((PKEVENT)&p->wait); +} + +#define kernel_thread(a,b,c) my_kernel_thread(a,b,c) +int my_kernel_thread(int STDCALL (*handler)(void*), void* parm, int flags); + +/*------------------------------------------------------------------------*/ +/* PCI, simple and inlined... */ +/*------------------------------------------------------------------------*/ +#include "pci_hal.c" + +/*------------------------------------------------------------------------*/ +/* IRQ handling */ +/*------------------------------------------------------------------------*/ + +#define request_irq(a,b,c,d,e) my_request_irq(a,b,c,d,e) +int my_request_irq(unsigned int irq, + int (*handler)(int, void *, struct pt_regs *), + unsigned long mode, const char *desc, void *data); + +#define free_irq(a,b) my_free_irq(a,b) +int free_irq(int irq, void* p); + + + +struct my_irqs { + int (*handler)(int, void *, struct pt_regs *); + int irq; + void* data; +}; + +#define MAX_IRQS 8 + +// Exported to top level + +void handle_irqs(int irq); +void inc_jiffies(int); +void init_wrapper(struct pci_dev *pci_dev); +void do_all_timers(void); + +#define __KERNEL_DS 0x18 + +int my_pci_write_config_word(struct pci_dev *, int, u16); + diff --git a/reactos/drivers/usb/cromwell/linux/list.h b/reactos/drivers/usb/cromwell/linux/list.h index fbbfabed39a..ef8fdd29f55 100644 --- a/reactos/drivers/usb/cromwell/linux/list.h +++ b/reactos/drivers/usb/cromwell/linux/list.h @@ -1,224 +1,224 @@ -#ifndef _BOOT_LIST_H -#define _BOOT_LIST_H - -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -#define INIT_LIST_HEAD(ptr) do { \ - (ptr)->next = (ptr); (ptr)->prev = (ptr); \ -} while (0) - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head *prev, struct list_head *next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty on entry does not return true after this, the entry is in an undefined state. - */ -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = (void *) 0; - entry->prev = (void *) 0; -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(struct list_head *head) -{ - return head->next == head; -} - -static inline void __list_splice(struct list_head *list, - struct list_head *head) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - - last->next = at; - at->prev = last; -} - -/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(struct list_head *list, struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); \ - pos = pos->next) -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; pos != (head); \ - pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop counter. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member) \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -#endif +#ifndef _BOOT_LIST_H +#define _BOOT_LIST_H + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = (void *) 0; + entry->prev = (void *) 0; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(struct list_head *head) +{ + return head->next == head; +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next) +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member) \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +#endif diff --git a/reactos/drivers/usb/cromwell/linux/pci_hal.c b/reactos/drivers/usb/cromwell/linux/pci_hal.c index 1fed7ddb4f4..10338eaff60 100644 --- a/reactos/drivers/usb/cromwell/linux/pci_hal.c +++ b/reactos/drivers/usb/cromwell/linux/pci_hal.c @@ -1,158 +1,162 @@ -// PCI -> HAL interface -// this file is part of linux_wrapper.h - -//FIXME: Move this file, make its definitions more general -#include "../host/ohci_main.h" - -/* - Initialize device before it's used by a driver. Ask low-level code to enable I/O and memory. - Wake up the device if it was suspended. Beware, this function can fail. - */ -static int __inline__ pci_enable_device(struct pci_dev *dev) -{ - DPRINT1("pci_enable_device() called...\n"); - return 0; -} - -// Get physical address where resource x resides -static PHYSICAL_ADDRESS __inline__ pci_resource_start (struct pci_dev *dev, int x) -{ - POHCI_DEVICE_EXTENSION dev_ext = (POHCI_DEVICE_EXTENSION)dev->dev_ext; - DPRINT1("pci_resource_start() called, x=0x%x\n", x); - - //FIXME: Take x into account - return dev_ext->BaseAddress; - //return dev->base[x]; -} - -// ??? -static unsigned long __inline__ pci_resource_len (struct pci_dev *dev, int x) -{ - POHCI_DEVICE_EXTENSION ext = (POHCI_DEVICE_EXTENSION)dev->dev_ext; - - DPRINT1("pci_resource_len() called, x=0x%x\n", x); - - //FIXME: Take x into account - return ext->BaseAddrLength; -} - -// ??? -static int __inline__ pci_resource_flags(struct pci_dev *dev, int x) -{ - DPRINT1("pci_resource_flags() called, x=0x%x\n"); - return dev->flags[x]; -} - -/* - Enables bus-mastering for device dev -*/ -static int __inline__ pci_set_master(struct pci_dev *dev) {return 0;} - -// Store pointer to data for this device -static int __inline__ pci_set_drvdata(struct pci_dev *dev, void* d) -{ - DPRINT1("pci_set_drvdata() called...\n"); - dev->data=(void*)d; - return 0; -} - -// Get pointer to previously saved data -static void __inline__ *pci_get_drvdata(struct pci_dev *dev) -{ - DPRINT1("pci_get_drvdata() called...\n"); - return dev->data; -} - - -/* - =========================================================================== - I/O mem related stuff below -*/ - -/* -Allocate I/O memory region. - -Parameters: -start begin of region -n length of region -name name of requester -*/ -static int __inline__ request_region(PHYSICAL_ADDRESS addr, unsigned long len, const char * d) -{ - DPRINT1("request_region(): addr=0x%x, len=0x%x\n", addr, len); - return 0; -} - -/* -Unmap I/O memory from kernel address space. - -Parameters: -addr virtual start address - -*/ -static int __inline__ iounmap(void* p) -{ - DPRINT1("iounmap(): p=0x%x. FIXME - how to obtain len of mapped region?\n", p); - - //MmUnnapIoSpace(p); - - return 0; -} - -/* -Release I/O port region. - -Parameters: -start begin of region -n length of region -*/ -static int __inline__ release_region(PHYSICAL_ADDRESS addr, unsigned long len) -{ - DPRINT1("release_region(): addr=0x%x, len=0x%x\n", addr, len); - return 0; -} - -/* -Allocate I/O memory region. - -Parameters: -start begin of region -n length of region -name name of requester -*/ -static int __inline__ request_mem_region(PHYSICAL_ADDRESS addr, unsigned long len, const char * d) -{ - DPRINT1("request_mem_region(): addr=0x%x, len=0x%x\n", addr, len); - return 1; -} - -/* -Remap I/O memory into kernel address space (no cache). - -Parameters: -phys_addr begin of physical address range -size size of physical address range - -Returns: -virtual start address of mapped range -*/ -static void __inline__ *ioremap_nocache(PHYSICAL_ADDRESS addr, unsigned long len) -{ - // MmMapIoSpace with NoCache param - DPRINT1("ioremap_nocache(): addr=0x%x, len=0x%x\n", addr, len); - - return MmMapIoSpace(addr, len, MmNonCached); -} - -/* -Release I/O memory region. - -Parameters: -start begin of region -n length of region -*/ -static int __inline__ release_mem_region(PHYSICAL_ADDRESS addr, unsigned long len) -{ - DPRINT1("release_mem_region(): addr=0x%x, len=0x%x\n", addr, len); - return 0; -} +// PCI -> HAL interface +// this file is part of linux_wrapper.h + +//FIXME: Move this file, make its definitions more general +#include "../host/ohci_main.h" + +/* + Initialize device before it's used by a driver. Ask low-level code to enable I/O and memory. + Wake up the device if it was suspended. Beware, this function can fail. + */ +static int __inline__ pci_enable_device(struct pci_dev *dev) +{ + DPRINT1("pci_enable_device() called...\n"); + return 0; +} + +// Get physical address where resource x resides +static PHYSICAL_ADDRESS __inline__ pci_resource_start (struct pci_dev *dev, int x) +{ + POHCI_DEVICE_EXTENSION dev_ext = (POHCI_DEVICE_EXTENSION)dev->dev_ext; + DPRINT1("pci_resource_start() called, x=0x%x\n", x); + + //FIXME: Take x into account + return dev_ext->BaseAddress; + //return dev->base[x]; +} + +// ??? +static unsigned long __inline__ pci_resource_len (struct pci_dev *dev, int x) +{ + POHCI_DEVICE_EXTENSION ext = (POHCI_DEVICE_EXTENSION)dev->dev_ext; + + DPRINT1("pci_resource_len() called, x=0x%x\n", x); + + //FIXME: Take x into account + return ext->BaseAddrLength; +} + +// ??? +static int __inline__ pci_resource_flags(struct pci_dev *dev, int x) +{ + POHCI_DEVICE_EXTENSION ext = (POHCI_DEVICE_EXTENSION)dev->dev_ext; + + DPRINT1("pci_resource_flags() called, x=0x%x\n", x); + + //FIXME: Take x into account + return ext->Flags; +} + +/* + Enables bus-mastering for device dev +*/ +static int __inline__ pci_set_master(struct pci_dev *dev) {return 0;} + +// Store pointer to data for this device +static int __inline__ pci_set_drvdata(struct pci_dev *dev, void* d) +{ + DPRINT1("pci_set_drvdata() called...\n"); + dev->data=(void*)d; + return 0; +} + +// Get pointer to previously saved data +static void __inline__ *pci_get_drvdata(struct pci_dev *dev) +{ + DPRINT1("pci_get_drvdata() called...\n"); + return dev->data; +} + + +/* + =========================================================================== + I/O mem related stuff below +*/ + +/* +Allocate I/O memory region. + +Parameters: +start begin of region +n length of region +name name of requester +*/ +static int __inline__ request_region(PHYSICAL_ADDRESS addr, unsigned long len, const char * d) +{ + DPRINT1("request_region(): addr=0x%lx, len=0x%lx\n", addr.u.LowPart, len); + return ~0; +} + +/* +Unmap I/O memory from kernel address space. + +Parameters: +addr virtual start address + +*/ +static int __inline__ iounmap(void* p) +{ + DPRINT1("iounmap(): p=0x%x. FIXME - how to obtain len of mapped region?\n", p); + + //MmUnnapIoSpace(p); + + return 0; +} + +/* +Release I/O port region. + +Parameters: +start begin of region +n length of region +*/ +static int __inline__ release_region(PHYSICAL_ADDRESS addr, unsigned long len) +{ + DPRINT1("release_region(): addr=0x%lx, len=0x%lx\n", addr.u.LowPart, len); + return 0; +} + +/* +Allocate I/O memory region. + +Parameters: +start begin of region +n length of region +name name of requester +*/ +static int __inline__ request_mem_region(PHYSICAL_ADDRESS addr, unsigned long len, const char * d) +{ + DPRINT1("request_mem_region(): addr=0x%lx, len=0x%lx\n", addr.u.LowPart, len); + return 1; +} + +/* +Remap I/O memory into kernel address space (no cache). + +Parameters: +phys_addr begin of physical address range +size size of physical address range + +Returns: +virtual start address of mapped range +*/ +static void __inline__ *ioremap_nocache(PHYSICAL_ADDRESS addr, unsigned long len) +{ + // MmMapIoSpace with NoCache param + DPRINT1("ioremap_nocache(): addr=0x%lx, len=0x%lx\n", addr.u.LowPart, len); + + return MmMapIoSpace(addr, len, MmNonCached); +} + +/* +Release I/O memory region. + +Parameters: +start begin of region +n length of region +*/ +static int __inline__ release_mem_region(PHYSICAL_ADDRESS addr, unsigned long len) +{ + DPRINT1("release_mem_region(): addr=0x%lx, len=0x%lx\n", addr.u.LowPart, len); + return 0; +} diff --git a/reactos/drivers/usb/cromwell/linux/pci_ids.h b/reactos/drivers/usb/cromwell/linux/pci_ids.h index 5d0f0185c54..64b293d8ebf 100644 --- a/reactos/drivers/usb/cromwell/linux/pci_ids.h +++ b/reactos/drivers/usb/cromwell/linux/pci_ids.h @@ -1,16 +1,16 @@ -#ifndef PCI_IDS__H -#define PCI_IDS__H - -#define PCI_VENDOR_ID_NS 0x100b -#define PCI_VENDOR_ID_AMD 0x1022 -#define PCI_VENDOR_ID_OPTI 0x1045 -#define PCI_VENDOR_ID_VIA 0x1106 -#define PCI_VENDOR_ID_INTEL 0x8086 - -#define PCI_DEVICE_ID_NS_87560_LIO 0x000e -#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 - -#define PCI_CLASS_SERIAL_USB (PCI_CLASS_SERIAL_BUS_CTLR << 8 + PCI_SUBCLASS_SB_USB) - -#endif - +#ifndef PCI_IDS__H +#define PCI_IDS__H + +#define PCI_VENDOR_ID_NS 0x100b +#define PCI_VENDOR_ID_AMD 0x1022 +#define PCI_VENDOR_ID_OPTI 0x1045 +#define PCI_VENDOR_ID_VIA 0x1106 +#define PCI_VENDOR_ID_INTEL 0x8086 + +#define PCI_DEVICE_ID_NS_87560_LIO 0x000e +#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 + +#define PCI_CLASS_SERIAL_USB ((PCI_CLASS_SERIAL_BUS_CTLR << 8) + PCI_SUBCLASS_SB_USB) + +#endif + diff --git a/reactos/drivers/usb/cromwell/linux/usb.h b/reactos/drivers/usb/cromwell/linux/usb.h index 0e3d67ff5a3..ef1c1f7785e 100644 --- a/reactos/drivers/usb/cromwell/linux/usb.h +++ b/reactos/drivers/usb/cromwell/linux/usb.h @@ -1,1032 +1,1032 @@ -#ifndef __LINUX_USB_H -#define __LINUX_USB_H - - -#include "usb_ch9.h" - -#define USB_MAJOR 180 - - -#ifdef __KERNEL__ -#if 0 -#include -#include /* for -ENODEV */ -#include /* for mdelay() */ -#include /* for in_interrupt() */ -#include /* for struct list_head */ -#include /* for struct device */ -#include /* for struct file_operations */ -#include /* for struct completion */ -#include /* for current && schedule_timeout */ - - -static __inline__ void wait_ms(unsigned int ms) -{ - if(!in_interrupt()) { - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(1 + ms * HZ / 1000); - } - else - mdelay(ms); -} -#endif -struct usb_device; - -/*-------------------------------------------------------------------------*/ - -/* - * Host-side wrappers for standard USB descriptors ... these are parsed - * from the data provided by devices. Parsing turns them from a flat - * sequence of descriptors into a hierarchy: - * - * - devices have one (usually) or more configs; - * - configs have one (often) or more interfaces; - * - interfaces have one (usually) or more settings; - * - each interface setting has zero or (usually) more endpoints. - * - * And there might be other descriptors mixed in with those. - * - * Devices may also have class-specific or vendor-specific descriptors. - */ - -/* host-side wrapper for parsed endpoint descriptors */ -struct usb_host_endpoint { - struct usb_endpoint_descriptor desc; - - unsigned char *extra; /* Extra descriptors */ - int extralen; -}; - -/* host-side wrapper for one interface setting's parsed descriptors */ -struct usb_host_interface { - struct usb_interface_descriptor desc; - - /* array of desc.bNumEndpoint endpoints associated with this - * interface setting. these will be in no particular order. - */ - struct usb_host_endpoint *endpoint; - - unsigned char *extra; /* Extra descriptors */ - int extralen; -}; - -/** - * struct usb_interface - what usb device drivers talk to - * @altsetting: array of interface descriptors, one for each alternate - * setting that may be selected. Each one includes a set of - * endpoint configurations and will be in numberic order, - * 0..num_altsetting. - * @num_altsetting: number of altsettings defined. - * @act_altsetting: index of current altsetting. this number is always - * less than num_altsetting. after the device is configured, each - * interface uses its default setting of zero. - * @max_altsetting: - * @minor: the minor number assigned to this interface, if this - * interface is bound to a driver that uses the USB major number. - * If this interface does not use the USB major, this field should - * be unused. The driver should set this value in the probe() - * function of the driver, after it has been assigned a minor - * number from the USB core by calling usb_register_dev(). - * @dev: driver model's view of this device - * @class_dev: driver model's class view of this device. - * - * USB device drivers attach to interfaces on a physical device. Each - * interface encapsulates a single high level function, such as feeding - * an audio stream to a speaker or reporting a change in a volume control. - * Many USB devices only have one interface. The protocol used to talk to - * an interface's endpoints can be defined in a usb "class" specification, - * or by a product's vendor. The (default) control endpoint is part of - * every interface, but is never listed among the interface's descriptors. - * - * The driver that is bound to the interface can use standard driver model - * calls such as dev_get_drvdata() on the dev member of this structure. - * - * Each interface may have alternate settings. The initial configuration - * of a device sets the first of these, but the device driver can change - * that setting using usb_set_interface(). Alternate settings are often - * used to control the the use of periodic endpoints, such as by having - * different endpoints use different amounts of reserved USB bandwidth. - * All standards-conformant USB devices that use isochronous endpoints - * will use them in non-default settings. - */ -struct usb_interface { - /* array of alternate settings for this interface. - * these will be in numeric order, 0..num_altsettting - */ - struct usb_host_interface *altsetting; - - unsigned act_altsetting; /* active alternate setting */ - unsigned num_altsetting; /* number of alternate settings */ - unsigned max_altsetting; /* total memory allocated */ - - struct usb_driver *driver; /* driver */ - int minor; /* minor number this interface is bound to */ - struct device dev; /* interface specific device info */ - struct class_device class_dev; -}; -#define to_usb_interface(d) container_of(d, struct usb_interface, dev) -#define class_dev_to_usb_interface(d) container_of(d, struct usb_interface, class_dev) -#define interface_to_usbdev(intf) \ - container_of(intf->dev.parent, struct usb_device, dev) - -static inline void *usb_get_intfdata (struct usb_interface *intf) -{ - return dev_get_drvdata (&intf->dev); -} - -static inline void usb_set_intfdata (struct usb_interface *intf, void *data) -{ - dev_set_drvdata(&intf->dev, data); -} - -/* USB_DT_CONFIG: Configuration descriptor information. - * - * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the - * descriptor type is different. Highspeed-capable devices can look - * different depending on what speed they're currently running. Only - * devices with a USB_DT_DEVICE_QUALIFIER have an OTHER_SPEED_CONFIG. - */ -struct usb_host_config { - struct usb_config_descriptor desc; - - /* the interfaces associated with this configuration - * these will be in numeric order, 0..desc.bNumInterfaces - */ - struct usb_interface *interface; - - unsigned char *extra; /* Extra descriptors */ - int extralen; -}; - -// FIXME remove; exported only for drivers/usb/misc/auserwald.c -// prefer usb_device->epnum[0..31] -extern struct usb_endpoint_descriptor * - usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum); - -int __usb_get_extra_descriptor(char *buffer, unsigned size, - unsigned char type, void **ptr); -#define usb_get_extra_descriptor(ifpoint,type,ptr)\ - __usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,\ - type,(void**)ptr) - -/* -------------------------------------------------------------------------- */ - -struct usb_operations; - -/* USB device number allocation bitmap */ -struct usb_devmap { - unsigned long devicemap[128 / (8*sizeof(unsigned long))]; -}; - -/* - * Allocated per bus (tree of devices) we have: - */ -struct usb_bus { - struct device *controller; /* host/master side hardware */ - int busnum; /* Bus number (in order of reg) */ - char *bus_name; /* stable id (PCI slot_name etc) */ - - int devnum_next; /* Next open device number in round-robin allocation */ - - struct usb_devmap devmap; /* device address allocation map */ - struct usb_operations *op; /* Operations (specific to the HC) */ - struct usb_device *root_hub; /* Root hub */ - struct list_head bus_list; /* list of busses */ - void *hcpriv; /* Host Controller private data */ - - int bandwidth_allocated; /* on this bus: how much of the time - * reserved for periodic (intr/iso) - * requests is used, on average? - * Units: microseconds/frame. - * Limits: Full/low speed reserve 90%, - * while high speed reserves 80%. - */ - int bandwidth_int_reqs; /* number of Interrupt requests */ - int bandwidth_isoc_reqs; /* number of Isoc. requests */ - - struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */ - struct dentry *usbdevfs_dentry; /* usbdevfs dentry entry for the bus */ - - atomic_t refcnt; -}; - - -/* -------------------------------------------------------------------------- */ - -/* This is arbitrary. - * From USB 2.0 spec Table 11-13, offset 7, a hub can - * have up to 255 ports. The most yet reported is 10. - */ -#define USB_MAXCHILDREN (16) - -struct usb_tt; - -struct usb_device { - int devnum; /* Address on USB bus */ - char devpath [16]; /* Use in messages: /port/port/... */ - enum usb_device_state state; /* configured, not attached, etc */ - enum usb_device_speed speed; /* high/full/low (or error) */ - - struct usb_tt *tt; /* low/full speed dev, highspeed hub */ - int ttport; /* device port on that tt hub */ - - struct semaphore serialize; - - unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */ - unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */ - /* [0] = IN, [1] = OUT */ - int epmaxpacketin[16]; /* INput endpoint specific maximums */ - int epmaxpacketout[16]; /* OUTput endpoint specific maximums */ - - struct usb_device *parent; /* our hub, unless we're the root */ - struct usb_bus *bus; /* Bus we're part of */ - - struct device dev; /* Generic device interface */ - - struct usb_device_descriptor descriptor;/* Descriptor */ - struct usb_host_config *config; /* All of the configs */ - struct usb_host_config *actconfig;/* the active configuration */ - - char **rawdescriptors; /* Raw descriptors for each config */ - - int have_langid; /* whether string_langid is valid yet */ - int string_langid; /* language ID for strings */ - - void *hcpriv; /* Host Controller private data */ - - struct list_head filelist; - struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */ - struct dentry *usbdevfs_dentry; /* usbdevfs dentry entry for the device */ - - /* - * Child devices - these can be either new devices - * (if this is a hub device), or different instances - * of this same device. - * - * Each instance needs its own set of data structures. - */ - - int maxchild; /* Number of ports if hub */ - struct usb_device *children[USB_MAXCHILDREN]; -}; -#define to_usb_device(d) container_of(d, struct usb_device, dev) - -extern struct usb_device STDCALL *usb_alloc_dev(struct usb_device *parent, struct usb_bus *); -extern struct usb_device STDCALL *usb_get_dev(struct usb_device *dev); -extern void STDCALL usb_put_dev(struct usb_device *dev); - -/* mostly for devices emulating SCSI over USB */ -extern int usb_reset_device(struct usb_device *dev); - -extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); - -/* for drivers using iso endpoints */ -extern int usb_get_current_frame_number (struct usb_device *usb_dev); - -/* used these for multi-interface device registration */ -extern void usb_driver_claim_interface(struct usb_driver *driver, - struct usb_interface *iface, void* priv); -extern int usb_interface_claimed(struct usb_interface *iface); -extern void usb_driver_release_interface(struct usb_driver *driver, - struct usb_interface *iface); -const struct usb_device_id *usb_match_id(struct usb_interface *interface, - const struct usb_device_id *id); - -extern struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor); -extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum); - - -/** - * usb_make_path - returns stable device path in the usb tree - * @dev: the device whose path is being constructed - * @buf: where to put the string - * @size: how big is "buf"? - * - * Returns length of the string (> 0) or negative if size was too small. - * - * This identifier is intended to be "stable", reflecting physical paths in - * hardware such as physical bus addresses for host controllers or ports on - * USB hubs. That makes it stay the same until systems are physically - * reconfigured, by re-cabling a tree of USB devices or by moving USB host - * controllers. Adding and removing devices, including virtual root hubs - * in host controller driver modules, does not change these path identifers; - * neither does rebooting or re-enumerating. These are more useful identifiers - * than changeable ("unstable") ones like bus numbers or device addresses. - * - * With a partial exception for devices connected to USB 2.0 root hubs, these - * identifiers are also predictable. So long as the device tree isn't changed, - * plugging any USB device into a given hub port always gives it the same path. - * Because of the use of "companion" controllers, devices connected to ports on - * USB 2.0 root hubs (EHCI host controllers) will get one path ID if they are - * high speed, and a different one if they are full or low speed. - */ -static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size) -{ - int actual; - actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name, dev->devpath); - return (actual >= size) ? -1 : actual; -} - -/*-------------------------------------------------------------------------*/ - -#define USB_DEVICE_ID_MATCH_DEVICE (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT) -#define USB_DEVICE_ID_MATCH_DEV_RANGE (USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI) -#define USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE) -#define USB_DEVICE_ID_MATCH_DEV_INFO \ - (USB_DEVICE_ID_MATCH_DEV_CLASS | USB_DEVICE_ID_MATCH_DEV_SUBCLASS | USB_DEVICE_ID_MATCH_DEV_PROTOCOL) -#define USB_DEVICE_ID_MATCH_INT_INFO \ - (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_INT_PROTOCOL) - -/** - * USB_DEVICE - macro used to describe a specific usb device - * @vend: the 16 bit USB Vendor ID - * @prod: the 16 bit USB Product ID - * - * This macro is used to create a struct usb_device_id that matches a - * specific device. - */ -#define USB_DEVICE(vend,prod) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), .idProduct = (prod) -/** - * USB_DEVICE_VER - macro used to describe a specific usb device with a version range - * @vend: the 16 bit USB Vendor ID - * @prod: the 16 bit USB Product ID - * @lo: the bcdDevice_lo value - * @hi: the bcdDevice_hi value - * - * This macro is used to create a struct usb_device_id that matches a - * specific device, with a version range. - */ -#define USB_DEVICE_VER(vend,prod,lo,hi) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, .idVendor = (vend), .idProduct = (prod), .bcdDevice_lo = (lo), .bcdDevice_hi = (hi) - -/** - * USB_DEVICE_INFO - macro used to describe a class of usb devices - * @cl: bDeviceClass value - * @sc: bDeviceSubClass value - * @pr: bDeviceProtocol value - * - * This macro is used to create a struct usb_device_id that matches a - * specific class of devices. - */ -#define USB_DEVICE_INFO(cl,sc,pr) \ - .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, .bDeviceClass = (cl), .bDeviceSubClass = (sc), .bDeviceProtocol = (pr) - -/** - * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces - * @cl: bInterfaceClass value - * @sc: bInterfaceSubClass value - * @pr: bInterfaceProtocol value - * - * This macro is used to create a struct usb_device_id that matches a - * specific class of interfaces. - */ -#define USB_INTERFACE_INFO(cl,sc,pr) \ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr) - -/* -------------------------------------------------------------------------- */ - -/** - * struct usb_driver - identifies USB driver to usbcore - * @owner: Pointer to the module owner of this driver; initialize - * it using THIS_MODULE. - * @name: The driver name should be unique among USB drivers, - * and should normally be the same as the module name. - * @probe: Called to see if the driver is willing to manage a particular - * interface on a device. If it is, probe returns zero and uses - * dev_set_drvdata() to associate driver-specific data with the - * interface. It may also use usb_set_interface() to specify the - * appropriate altsetting. If unwilling to manage the interface, - * return a negative errno value. - * @disconnect: Called when the interface is no longer accessible, usually - * because its device has been (or is being) disconnected or the - * driver module is being unloaded. - * @ioctl: Used for drivers that want to talk to userspace through - * the "usbfs" filesystem. This lets devices provide ways to - * expose information to user space regardless of where they - * do (or don't) show up otherwise in the filesystem. - * @id_table: USB drivers use ID table to support hotplugging. - * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set - * or your driver's probe function will never get called. - * - * USB drivers must provide a name, probe() and disconnect() methods, - * and an id_table. Other driver fields are optional. - * - * The id_table is used in hotplugging. It holds a set of descriptors, - * and specialized data may be associated with each entry. That table - * is used by both user and kernel mode hotplugging support. - * - * The probe() and disconnect() methods are called in a context where - * they can sleep, but they should avoid abusing the privilege. Most - * work to connect to a device should be done when the device is opened, - * and undone at the last close. The disconnect code needs to address - * concurrency issues with respect to open() and close() methods, as - * well as forcing all pending I/O requests to complete (by unlinking - * them as necessary, and blocking until the unlinks complete). - */ -struct usb_driver { - struct module *owner; - - const char *name; - - int (*probe) (struct usb_interface *intf, - const struct usb_device_id *id); - - void (*disconnect) (struct usb_interface *intf); - - int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf); - - const struct usb_device_id *id_table; - - struct device_driver driver; - - struct semaphore serialize; -}; -#define to_usb_driver(d) container_of(d, struct usb_driver, driver) - -extern struct bus_type usb_bus_type; - -/** - * struct usb_class_driver - identifies a USB driver that wants to use the USB major number - * @name: devfs name for this driver. Will also be used by the driver - * class code to create a usb class device. - * @fops: pointer to the struct file_operations of this driver. - * @mode: the mode for the devfs file to be created for this driver. - * @minor_base: the start of the minor range for this driver. - * - * This structure is used for the usb_register_dev() and - * usb_unregister_dev() functions, to consolodate a number of the - * paramaters used for them. - */ -struct usb_class_driver { - char *name; - struct file_operations *fops; - mode_t mode; - int minor_base; -}; - -/* - * use these in module_init()/module_exit() - * and don't forget MODULE_DEVICE_TABLE(usb, ...) - */ -extern int usb_register(struct usb_driver *); -extern void usb_deregister(struct usb_driver *); - -extern int usb_register_dev(struct usb_interface *intf, - struct usb_class_driver *class_driver); -extern void usb_deregister_dev(struct usb_interface *intf, - struct usb_class_driver *class_driver); - -extern int usb_device_probe(struct device *dev); -extern int usb_device_remove(struct device *dev); -extern int STDCALL usb_disabled(void); - -/* -------------------------------------------------------------------------- */ - -/* - * URB support, for asynchronous request completions - */ - -/* - * urb->transfer_flags: - */ -#define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */ -#define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame ignored */ -#define URB_NO_DMA_MAP 0x0004 /* urb->*_dma are valid on submit */ -#define URB_ASYNC_UNLINK 0x0008 /* usb_unlink_urb() returns asap */ -#define URB_NO_FSBR 0x0020 /* UHCI-specific */ -#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUTs with short packet */ -#define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */ - -struct usb_iso_packet_descriptor { - unsigned int offset; - unsigned int length; /* expected length */ - unsigned int actual_length; - unsigned int status; -}; - -struct urb; -struct pt_regs; - -typedef void (*usb_complete_t)(struct urb *, struct pt_regs *); - -/** - * struct urb - USB Request Block - * @urb_list: For use by current owner of the URB. - * @pipe: Holds endpoint number, direction, type, and more. - * Create these values with the eight macros available; - * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the type is "ctrl" - * (control), "bulk", "int" (interrupt), or "iso" (isochronous). - * For example usb_sndbulkpipe() or usb_rcvintpipe(). Endpoint - * numbers range from zero to fifteen. Note that "in" endpoint two - * is a different endpoint (and pipe) from "out" endpoint two. - * The current configuration controls the existence, type, and - * maximum packet size of any given endpoint. - * @dev: Identifies the USB device to perform the request. - * @status: This is read in non-iso completion functions to get the - * status of the particular request. ISO requests only use it - * to tell whether the URB was unlinked; detailed status for - * each frame is in the fields of the iso_frame-desc. - * @transfer_flags: A variety of flags may be used to affect how URB - * submission, unlinking, or operation are handled. Different - * kinds of URB can use different flags. - * @transfer_buffer: This identifies the buffer to (or from) which - * the I/O request will be performed (unless URB_NO_DMA_MAP is set). - * This buffer must be suitable for DMA; allocate it with kmalloc() - * or equivalent. For transfers to "in" endpoints, contents of - * this buffer will be modified. This buffer is used for data - * phases of control transfers. - * @transfer_dma: When transfer_flags includes URB_NO_DMA_MAP, the device - * driver is saying that it provided this DMA address, which the host - * controller driver should use instead of the transfer_buffer. - * @transfer_buffer_length: How big is transfer_buffer. The transfer may - * be broken up into chunks according to the current maximum packet - * size for the endpoint, which is a function of the configuration - * and is encoded in the pipe. When the length is zero, neither - * transfer_buffer nor transfer_dma is used. - * @actual_length: This is read in non-iso completion functions, and - * it tells how many bytes (out of transfer_buffer_length) were - * transferred. It will normally be the same as requested, unless - * either an error was reported or a short read was performed. - * The URB_SHORT_NOT_OK transfer flag may be used to make such - * short reads be reported as errors. - * @setup_packet: Only used for control transfers, this points to eight bytes - * of setup data. Control transfers always start by sending this data - * to the device. Then transfer_buffer is read or written, if needed. - * (Not used when URB_NO_DMA_MAP is set.) - * @setup_dma: For control transfers with URB_NO_DMA_MAP set, the device - * driver has provided this DMA address for the setup packet. The - * host controller driver should use this instead of setup_buffer. - * If there is a data phase, its buffer is identified by transfer_dma. - * @start_frame: Returns the initial frame for interrupt or isochronous - * transfers. - * @number_of_packets: Lists the number of ISO transfer buffers. - * @interval: Specifies the polling interval for interrupt or isochronous - * transfers. The units are frames (milliseconds) for for full and low - * speed devices, and microframes (1/8 millisecond) for highspeed ones. - * @error_count: Returns the number of ISO transfers that reported errors. - * @context: For use in completion functions. This normally points to - * request-specific driver context. - * @complete: Completion handler. This URB is passed as the parameter to the - * completion function. The completion function may then do what - * it likes with the URB, including resubmitting or freeing it. - * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to - * collect the transfer status for each buffer. - * - * This structure identifies USB transfer requests. URBs must be allocated by - * calling usb_alloc_urb() and freed with a call to usb_free_urb(). - * Initialization may be done using various usb_fill_*_urb() functions. URBs - * are submitted using usb_submit_urb(), and pending requests may be canceled - * using usb_unlink_urb(). - * - * Data Transfer Buffers: - * - * Normally drivers provide I/O buffers allocated with kmalloc() or otherwise - * taken from the general page pool. That is provided by transfer_buffer - * (control requests also use setup_packet), and host controller drivers - * perform a dma mapping (and unmapping) for each buffer transferred. Those - * mapping operations can be expensive on some platforms (perhaps using a dma - * bounce buffer or talking to an IOMMU), - * although they're cheap on commodity x86 and ppc hardware. - * - * Alternatively, drivers may pass the URB_NO_DMA_MAP transfer flag, which - * tells the host controller driver that no such mapping is needed since - * the device driver is DMA-aware. For example, they might allocate a DMA - * buffer with usb_buffer_alloc(), or call usb_buffer_map(). - * When this transfer flag is provided, host controller drivers will use the - * dma addresses found in the transfer_dma and/or setup_dma fields rather than - * determing a dma address themselves. - * - * Initialization: - * - * All URBs submitted must initialize dev, pipe, - * transfer_flags (may be zero), complete, timeout (may be zero). - * The URB_ASYNC_UNLINK transfer flag affects later invocations of - * the usb_unlink_urb() routine. - * - * All URBs must also initialize - * transfer_buffer and transfer_buffer_length. They may provide the - * URB_SHORT_NOT_OK transfer flag, indicating that short reads are - * to be treated as errors; that flag is invalid for write requests. - * - * Bulk URBs may - * use the URB_ZERO_PACKET transfer flag, indicating that bulk OUT transfers - * should always terminate with a short packet, even if it means adding an - * extra zero length packet. - * - * Control URBs must provide a setup_packet. - * - * Interrupt UBS must provide an interval, saying how often (in milliseconds - * or, for highspeed devices, 125 microsecond units) - * to poll for transfers. After the URB has been submitted, the interval - * and start_frame fields reflect how the transfer was actually scheduled. - * The polling interval may be more frequent than requested. - * For example, some controllers have a maximum interval of 32 microseconds, - * while others support intervals of up to 1024 microseconds. - * Isochronous URBs also have transfer intervals. (Note that for isochronous - * endpoints, as well as high speed interrupt endpoints, the encoding of - * the transfer interval in the endpoint descriptor is logarithmic.) - * - * Isochronous URBs normally use the URB_ISO_ASAP transfer flag, telling - * the host controller to schedule the transfer as soon as bandwidth - * utilization allows, and then set start_frame to reflect the actual frame - * selected during submission. Otherwise drivers must specify the start_frame - * and handle the case where the transfer can't begin then. However, drivers - * won't know how bandwidth is currently allocated, and while they can - * find the current frame using usb_get_current_frame_number () they can't - * know the range for that frame number. (Ranges for frame counter values - * are HC-specific, and can go from 256 to 65536 frames from "now".) - * - * Isochronous URBs have a different data transfer model, in part because - * the quality of service is only "best effort". Callers provide specially - * allocated URBs, with number_of_packets worth of iso_frame_desc structures - * at the end. Each such packet is an individual ISO transfer. Isochronous - * URBs are normally queued, submitted by drivers to arrange that - * transfers are at least double buffered, and then explicitly resubmitted - * in completion handlers, so - * that data (such as audio or video) streams at as constant a rate as the - * host controller scheduler can support. - * - * Completion Callbacks: - * - * The completion callback is made in_interrupt(), and one of the first - * things that a completion handler should do is check the status field. - * The status field is provided for all URBs. It is used to report - * unlinked URBs, and status for all non-ISO transfers. It should not - * be examined before the URB is returned to the completion handler. - * - * The context field is normally used to link URBs back to the relevant - * driver or request state. - * - * When completion callback is invoked for non-isochronous URBs, the - * actual_length field tells how many bytes were transferred. - * - * ISO transfer status is reported in the status and actual_length fields - * of the iso_frame_desc array, and the number of errors is reported in - * error_count. Completion callbacks for ISO transfers will normally - * (re)submit URBs to ensure a constant transfer rate. - */ -struct urb -{ - spinlock_t lock; /* lock for the URB */ - atomic_t count; /* reference count of the URB */ - void *hcpriv; /* private data for host controller */ - struct list_head urb_list; /* list pointer to all active urbs */ - struct usb_device *dev; /* (in) pointer to associated device */ - unsigned int pipe; /* (in) pipe information */ - int status; /* (return) non-ISO status */ - unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/ - void *transfer_buffer; /* (in) associated data buffer */ - dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */ - int transfer_buffer_length; /* (in) data buffer length */ - int actual_length; /* (return) actual transfer length */ - int bandwidth; /* bandwidth for INT/ISO request */ - unsigned char *setup_packet; /* (in) setup packet (control only) */ - dma_addr_t setup_dma; /* (in) dma addr for setup_packet */ - int start_frame; /* (modify) start frame (INT/ISO) */ - int number_of_packets; /* (in) number of ISO packets */ - int interval; /* (in) transfer interval (INT/ISO) */ - int error_count; /* (return) number of ISO errors */ - int timeout; /* (in) timeout, in jiffies */ - void *context; /* (in) context for completion */ - usb_complete_t complete; /* (in) completion routine */ - struct usb_iso_packet_descriptor iso_frame_desc[0]; /* (in) ISO ONLY */ -}; - -/* -------------------------------------------------------------------------- */ - -/** - * usb_fill_control_urb - initializes a control urb - * @urb: pointer to the urb to initialize. - * @dev: pointer to the struct usb_device for this urb. - * @pipe: the endpoint pipe - * @setup_packet: pointer to the setup_packet buffer - * @transfer_buffer: pointer to the transfer buffer - * @buffer_length: length of the transfer buffer - * @complete: pointer to the usb_complete_t function - * @context: what to set the urb context to. - * - * Initializes a control urb with the proper information needed to submit - * it to a device. - */ -static inline void usb_fill_control_urb (struct urb *urb, - struct usb_device *dev, - unsigned int pipe, - unsigned char *setup_packet, - void *transfer_buffer, - int buffer_length, - usb_complete_t complete, - void *context) -{ - spin_lock_init(&urb->lock); - urb->dev = dev; - urb->pipe = pipe; - urb->setup_packet = setup_packet; - urb->transfer_buffer = transfer_buffer; - urb->transfer_buffer_length = buffer_length; - urb->complete = complete; - urb->context = context; -} - -/** - * usb_fill_bulk_urb - macro to help initialize a bulk urb - * @urb: pointer to the urb to initialize. - * @dev: pointer to the struct usb_device for this urb. - * @pipe: the endpoint pipe - * @transfer_buffer: pointer to the transfer buffer - * @buffer_length: length of the transfer buffer - * @complete: pointer to the usb_complete_t function - * @context: what to set the urb context to. - * - * Initializes a bulk urb with the proper information needed to submit it - * to a device. - */ -static inline void usb_fill_bulk_urb (struct urb *urb, - struct usb_device *dev, - unsigned int pipe, - void *transfer_buffer, - int buffer_length, - usb_complete_t complete, - void *context) -{ - spin_lock_init(&urb->lock); - urb->dev = dev; - urb->pipe = pipe; - urb->transfer_buffer = transfer_buffer; - urb->transfer_buffer_length = buffer_length; - urb->complete = complete; - urb->context = context; -} - -/** - * usb_fill_int_urb - macro to help initialize a interrupt urb - * @urb: pointer to the urb to initialize. - * @dev: pointer to the struct usb_device for this urb. - * @pipe: the endpoint pipe - * @transfer_buffer: pointer to the transfer buffer - * @buffer_length: length of the transfer buffer - * @complete: pointer to the usb_complete_t function - * @context: what to set the urb context to. - * @interval: what to set the urb interval to, encoded like - * the endpoint descriptor's bInterval value. - * - * Initializes a interrupt urb with the proper information needed to submit - * it to a device. - * Note that high speed interrupt endpoints use a logarithmic encoding of - * the endpoint interval, and express polling intervals in microframes - * (eight per millisecond) rather than in frames (one per millisecond). - */ -static inline void usb_fill_int_urb (struct urb *urb, - struct usb_device *dev, - unsigned int pipe, - void *transfer_buffer, - int buffer_length, - usb_complete_t complete, - void *context, - int interval) -{ - spin_lock_init(&urb->lock); - urb->dev = dev; - urb->pipe = pipe; - urb->transfer_buffer = transfer_buffer; - urb->transfer_buffer_length = buffer_length; - urb->complete = complete; - urb->context = context; - if (dev->speed == USB_SPEED_HIGH) - urb->interval = 1 << (interval - 1); - else - urb->interval = interval; - urb->start_frame = -1; -} - -extern void STDCALL usb_init_urb(struct urb *urb); -extern struct urb STDCALL *usb_alloc_urb(int iso_packets, int mem_flags); -extern void STDCALL usb_free_urb(struct urb *urb); -#define usb_put_urb usb_free_urb -extern struct urb STDCALL *usb_get_urb(struct urb *urb); -extern int STDCALL usb_submit_urb(struct urb *urb, int mem_flags); -extern int STDCALL usb_unlink_urb(struct urb *urb); - -#define HAVE_USB_BUFFERS -void *usb_buffer_alloc (struct usb_device *dev, size_t size, - int mem_flags, dma_addr_t *dma); -void usb_buffer_free (struct usb_device *dev, size_t size, - void *addr, dma_addr_t dma); - -struct urb *usb_buffer_map (struct urb *urb); -void usb_buffer_dmasync (struct urb *urb); -void usb_buffer_unmap (struct urb *urb); - -struct scatterlist; -int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int nents); -void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int n_hw_ents); -void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, - struct scatterlist *sg, int n_hw_ents); - -/*-------------------------------------------------------------------* - * SYNCHRONOUS CALL SUPPORT * - *-------------------------------------------------------------------*/ - -extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, - __u8 request, __u8 requesttype, __u16 value, __u16 index, - void *data, __u16 size, int timeout); -extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, - void *data, int len, int *actual_length, - int timeout); - -/* wrappers around usb_control_msg() for the most common standard requests */ -extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, - unsigned char descindex, void *buf, int size); -extern int usb_get_device_descriptor(struct usb_device *dev); -extern int usb_get_status(struct usb_device *dev, - int type, int target, void *data); -extern int usb_get_string(struct usb_device *dev, - unsigned short langid, unsigned char index, void *buf, int size); -extern int usb_string(struct usb_device *dev, int index, - char *buf, size_t size); - -/* wrappers that also update important state inside usbcore */ -extern int usb_clear_halt(struct usb_device *dev, int pipe); -extern int usb_set_configuration(struct usb_device *dev, int configuration); -extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate); - -/* - * timeouts, in seconds, used for sending/receiving control messages - * they typically complete within a few frames (msec) after they're issued - * USB identifies 5 second timeouts, maybe more in a few cases, and a few - * slow devices (like some MGE Ellipse UPSes) actually push that limit. - */ -#define USB_CTRL_GET_TIMEOUT 5 -#define USB_CTRL_SET_TIMEOUT 5 - - -/** - * struct usb_sg_request - support for scatter/gather I/O - * @status: zero indicates success, else negative errno - * @bytes: counts bytes transferred. - * - * These requests are initialized using usb_sg_init(), and then are used - * as request handles passed to usb_sg_wait() or usb_sg_cancel(). Most - * members of the request object aren't for driver access. - * - * The status and bytecount values are valid only after usb_sg_wait() - * returns. If the status is zero, then the bytecount matches the total - * from the request. - * - * After an error completion, drivers may need to clear a halt condition - * on the endpoint. - */ -struct usb_sg_request { - int status; - size_t bytes; - - // members not documented above are private to usbcore, - // and are not provided for driver access! - spinlock_t lock; - - struct usb_device *dev; - int pipe; - struct scatterlist *sg; - int nents; - - int entries; - struct urb **urbs; - - int count; - struct completion complete; -}; - -int usb_sg_init ( - struct usb_sg_request *io, - struct usb_device *dev, - unsigned pipe, - unsigned period, - struct scatterlist *sg, - int nents, - size_t length, - int mem_flags -); -void usb_sg_cancel (struct usb_sg_request *io); -void usb_sg_wait (struct usb_sg_request *io); - - -/* -------------------------------------------------------------------------- */ - -/* - * Calling this entity a "pipe" is glorifying it. A USB pipe - * is something embarrassingly simple: it basically consists - * of the following information: - * - device number (7 bits) - * - endpoint number (4 bits) - * - current Data0/1 state (1 bit) [Historical; now gone] - * - direction (1 bit) - * - speed (1 bit) [Historical and specific to USB 1.1; now gone.] - * - max packet size (2 bits: 8, 16, 32 or 64) [Historical; now gone.] - * - pipe type (2 bits: control, interrupt, bulk, isochronous) - * - * That's 18 bits. Really. Nothing more. And the USB people have - * documented these eighteen bits as some kind of glorious - * virtual data structure. - * - * Let's not fall in that trap. We'll just encode it as a simple - * unsigned int. The encoding is: - * - * - max size: bits 0-1 [Historical; now gone.] - * - direction: bit 7 (0 = Host-to-Device [Out], - * 1 = Device-to-Host [In] ... - * like endpoint bEndpointAddress) - * - device: bits 8-14 ... bit positions known to uhci-hcd - * - endpoint: bits 15-18 ... bit positions known to uhci-hcd - * - Data0/1: bit 19 [Historical; now gone. ] - * - lowspeed: bit 26 [Historical; now gone. ] - * - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt, - * 10 = control, 11 = bulk) - * - * Why? Because it's arbitrary, and whatever encoding we select is really - * up to us. This one happens to share a lot of bit positions with the UHCI - * specification, so that much of the uhci driver can just mask the bits - * appropriately. - */ - -/* NOTE: these are not the standard USB_ENDPOINT_XFER_* values!! */ -#define PIPE_ISOCHRONOUS 0 -#define PIPE_INTERRUPT 1 -#define PIPE_CONTROL 2 -#define PIPE_BULK 3 - -#define usb_maxpacket(dev, pipe, out) (out \ - ? (dev)->epmaxpacketout[usb_pipeendpoint(pipe)] \ - : (dev)->epmaxpacketin [usb_pipeendpoint(pipe)] ) - -#define usb_pipein(pipe) ((pipe) & USB_DIR_IN) -#define usb_pipeout(pipe) (!usb_pipein(pipe)) -#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f) -#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf) -#define usb_pipetype(pipe) (((pipe) >> 30) & 3) -#define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS) -#define usb_pipeint(pipe) (usb_pipetype((pipe)) == PIPE_INTERRUPT) -#define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == PIPE_CONTROL) -#define usb_pipebulk(pipe) (usb_pipetype((pipe)) == PIPE_BULK) - -/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */ -#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1) -#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep))) -#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | ((bit) << (ep))) - -/* Endpoint halt control/status ... likewise USE WITH CAUTION */ -#define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep))) -#define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep))) - - -static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint) -{ - return (dev->devnum << 8) | (endpoint << 15); -} - -/* Create various pipes... */ -#define usb_sndctrlpipe(dev,endpoint) ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint)) -#define usb_rcvctrlpipe(dev,endpoint) ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) -#define usb_sndisocpipe(dev,endpoint) ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint)) -#define usb_rcvisocpipe(dev,endpoint) ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) -#define usb_sndbulkpipe(dev,endpoint) ((PIPE_BULK << 30) | __create_pipe(dev,endpoint)) -#define usb_rcvbulkpipe(dev,endpoint) ((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) -#define usb_sndintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint)) -#define usb_rcvintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) - -/* -------------------------------------------------------------------------- */ - -/* - * Debugging and troubleshooting/diagnostic helpers. - */ -void usb_show_device_descriptor(struct usb_device_descriptor *); -void usb_show_config_descriptor(struct usb_config_descriptor *); -void usb_show_interface_descriptor(struct usb_interface_descriptor *); -void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *); -void usb_show_device(struct usb_device *); -void usb_show_string(struct usb_device *dev, char *id, int index); - -#ifdef DEBUG -#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg) -#else -#define dbg(format, arg...) do {} while (0) -#endif - - - -#ifdef DEBUG_MODE -#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ## arg) -#define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg) -#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg) -#endif - -#ifndef DEBUG_MODE -#define info(format, arg...) do {} while (0) -#define err(format, arg...) do {} while (0) -#define warn(format, arg...) do {} while (0) -#endif - -#endif /* __KERNEL__ */ - -#endif +#ifndef __LINUX_USB_H +#define __LINUX_USB_H + + +#include "usb_ch9.h" + +#define USB_MAJOR 180 + + +#ifdef __KERNEL__ +#if 0 +#include +#include /* for -ENODEV */ +#include /* for mdelay() */ +#include /* for in_interrupt() */ +#include /* for struct list_head */ +#include /* for struct device */ +#include /* for struct file_operations */ +#include /* for struct completion */ +#include /* for current && schedule_timeout */ + + +static __inline__ void wait_ms(unsigned int ms) +{ + if(!in_interrupt()) { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1 + ms * HZ / 1000); + } + else + mdelay(ms); +} +#endif +struct usb_device; + +/*-------------------------------------------------------------------------*/ + +/* + * Host-side wrappers for standard USB descriptors ... these are parsed + * from the data provided by devices. Parsing turns them from a flat + * sequence of descriptors into a hierarchy: + * + * - devices have one (usually) or more configs; + * - configs have one (often) or more interfaces; + * - interfaces have one (usually) or more settings; + * - each interface setting has zero or (usually) more endpoints. + * + * And there might be other descriptors mixed in with those. + * + * Devices may also have class-specific or vendor-specific descriptors. + */ + +/* host-side wrapper for parsed endpoint descriptors */ +struct usb_host_endpoint { + struct usb_endpoint_descriptor desc; + + unsigned char *extra; /* Extra descriptors */ + int extralen; +}; + +/* host-side wrapper for one interface setting's parsed descriptors */ +struct usb_host_interface { + struct usb_interface_descriptor desc; + + /* array of desc.bNumEndpoint endpoints associated with this + * interface setting. these will be in no particular order. + */ + struct usb_host_endpoint *endpoint; + + unsigned char *extra; /* Extra descriptors */ + int extralen; +}; + +/** + * struct usb_interface - what usb device drivers talk to + * @altsetting: array of interface descriptors, one for each alternate + * setting that may be selected. Each one includes a set of + * endpoint configurations and will be in numberic order, + * 0..num_altsetting. + * @num_altsetting: number of altsettings defined. + * @act_altsetting: index of current altsetting. this number is always + * less than num_altsetting. after the device is configured, each + * interface uses its default setting of zero. + * @max_altsetting: + * @minor: the minor number assigned to this interface, if this + * interface is bound to a driver that uses the USB major number. + * If this interface does not use the USB major, this field should + * be unused. The driver should set this value in the probe() + * function of the driver, after it has been assigned a minor + * number from the USB core by calling usb_register_dev(). + * @dev: driver model's view of this device + * @class_dev: driver model's class view of this device. + * + * USB device drivers attach to interfaces on a physical device. Each + * interface encapsulates a single high level function, such as feeding + * an audio stream to a speaker or reporting a change in a volume control. + * Many USB devices only have one interface. The protocol used to talk to + * an interface's endpoints can be defined in a usb "class" specification, + * or by a product's vendor. The (default) control endpoint is part of + * every interface, but is never listed among the interface's descriptors. + * + * The driver that is bound to the interface can use standard driver model + * calls such as dev_get_drvdata() on the dev member of this structure. + * + * Each interface may have alternate settings. The initial configuration + * of a device sets the first of these, but the device driver can change + * that setting using usb_set_interface(). Alternate settings are often + * used to control the the use of periodic endpoints, such as by having + * different endpoints use different amounts of reserved USB bandwidth. + * All standards-conformant USB devices that use isochronous endpoints + * will use them in non-default settings. + */ +struct usb_interface { + /* array of alternate settings for this interface. + * these will be in numeric order, 0..num_altsettting + */ + struct usb_host_interface *altsetting; + + unsigned act_altsetting; /* active alternate setting */ + unsigned num_altsetting; /* number of alternate settings */ + unsigned max_altsetting; /* total memory allocated */ + + struct usb_driver *driver; /* driver */ + int minor; /* minor number this interface is bound to */ + struct device dev; /* interface specific device info */ + struct class_device class_dev; +}; +#define to_usb_interface(d) container_of(d, struct usb_interface, dev) +#define class_dev_to_usb_interface(d) container_of(d, struct usb_interface, class_dev) +#define interface_to_usbdev(intf) \ + container_of(intf->dev.parent, struct usb_device, dev) + +static inline void *usb_get_intfdata (struct usb_interface *intf) +{ + return dev_get_drvdata (&intf->dev); +} + +static inline void usb_set_intfdata (struct usb_interface *intf, void *data) +{ + dev_set_drvdata(&intf->dev, data); +} + +/* USB_DT_CONFIG: Configuration descriptor information. + * + * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the + * descriptor type is different. Highspeed-capable devices can look + * different depending on what speed they're currently running. Only + * devices with a USB_DT_DEVICE_QUALIFIER have an OTHER_SPEED_CONFIG. + */ +struct usb_host_config { + struct usb_config_descriptor desc; + + /* the interfaces associated with this configuration + * these will be in numeric order, 0..desc.bNumInterfaces + */ + struct usb_interface *interface; + + unsigned char *extra; /* Extra descriptors */ + int extralen; +}; + +// FIXME remove; exported only for drivers/usb/misc/auserwald.c +// prefer usb_device->epnum[0..31] +extern struct usb_endpoint_descriptor * + usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum); + +int __usb_get_extra_descriptor(char *buffer, unsigned size, + unsigned char type, void **ptr); +#define usb_get_extra_descriptor(ifpoint,type,ptr)\ + __usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,\ + type,(void**)ptr) + +/* -------------------------------------------------------------------------- */ + +struct usb_operations; + +/* USB device number allocation bitmap */ +struct usb_devmap { + unsigned long devicemap[128 / (8*sizeof(unsigned long))]; +}; + +/* + * Allocated per bus (tree of devices) we have: + */ +struct usb_bus { + struct device *controller; /* host/master side hardware */ + int busnum; /* Bus number (in order of reg) */ + char *bus_name; /* stable id (PCI slot_name etc) */ + + int devnum_next; /* Next open device number in round-robin allocation */ + + struct usb_devmap devmap; /* device address allocation map */ + struct usb_operations *op; /* Operations (specific to the HC) */ + struct usb_device *root_hub; /* Root hub */ + struct list_head bus_list; /* list of busses */ + void *hcpriv; /* Host Controller private data */ + + int bandwidth_allocated; /* on this bus: how much of the time + * reserved for periodic (intr/iso) + * requests is used, on average? + * Units: microseconds/frame. + * Limits: Full/low speed reserve 90%, + * while high speed reserves 80%. + */ + int bandwidth_int_reqs; /* number of Interrupt requests */ + int bandwidth_isoc_reqs; /* number of Isoc. requests */ + + struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */ + struct dentry *usbdevfs_dentry; /* usbdevfs dentry entry for the bus */ + + atomic_t refcnt; +}; + + +/* -------------------------------------------------------------------------- */ + +/* This is arbitrary. + * From USB 2.0 spec Table 11-13, offset 7, a hub can + * have up to 255 ports. The most yet reported is 10. + */ +#define USB_MAXCHILDREN (16) + +struct usb_tt; + +struct usb_device { + int devnum; /* Address on USB bus */ + char devpath [16]; /* Use in messages: /port/port/... */ + enum usb_device_state state; /* configured, not attached, etc */ + enum usb_device_speed speed; /* high/full/low (or error) */ + + struct usb_tt *tt; /* low/full speed dev, highspeed hub */ + int ttport; /* device port on that tt hub */ + + struct semaphore serialize; + + unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */ + unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */ + /* [0] = IN, [1] = OUT */ + int epmaxpacketin[16]; /* INput endpoint specific maximums */ + int epmaxpacketout[16]; /* OUTput endpoint specific maximums */ + + struct usb_device *parent; /* our hub, unless we're the root */ + struct usb_bus *bus; /* Bus we're part of */ + + struct device dev; /* Generic device interface */ + + struct usb_device_descriptor descriptor;/* Descriptor */ + struct usb_host_config *config; /* All of the configs */ + struct usb_host_config *actconfig;/* the active configuration */ + + char **rawdescriptors; /* Raw descriptors for each config */ + + int have_langid; /* whether string_langid is valid yet */ + int string_langid; /* language ID for strings */ + + void *hcpriv; /* Host Controller private data */ + + struct list_head filelist; + struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */ + struct dentry *usbdevfs_dentry; /* usbdevfs dentry entry for the device */ + + /* + * Child devices - these can be either new devices + * (if this is a hub device), or different instances + * of this same device. + * + * Each instance needs its own set of data structures. + */ + + int maxchild; /* Number of ports if hub */ + struct usb_device *children[USB_MAXCHILDREN]; +}; +#define to_usb_device(d) container_of(d, struct usb_device, dev) + +extern struct usb_device STDCALL *usb_alloc_dev(struct usb_device *parent, struct usb_bus *); +extern struct usb_device STDCALL *usb_get_dev(struct usb_device *dev); +extern void STDCALL usb_put_dev(struct usb_device *dev); + +/* mostly for devices emulating SCSI over USB */ +extern int usb_reset_device(struct usb_device *dev); + +extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); + +/* for drivers using iso endpoints */ +extern int usb_get_current_frame_number (struct usb_device *usb_dev); + +/* used these for multi-interface device registration */ +extern void usb_driver_claim_interface(struct usb_driver *driver, + struct usb_interface *iface, void* priv); +extern int usb_interface_claimed(struct usb_interface *iface); +extern void usb_driver_release_interface(struct usb_driver *driver, + struct usb_interface *iface); +const struct usb_device_id *usb_match_id(struct usb_interface *interface, + const struct usb_device_id *id); + +extern struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor); +extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum); + + +/** + * usb_make_path - returns stable device path in the usb tree + * @dev: the device whose path is being constructed + * @buf: where to put the string + * @size: how big is "buf"? + * + * Returns length of the string (> 0) or negative if size was too small. + * + * This identifier is intended to be "stable", reflecting physical paths in + * hardware such as physical bus addresses for host controllers or ports on + * USB hubs. That makes it stay the same until systems are physically + * reconfigured, by re-cabling a tree of USB devices or by moving USB host + * controllers. Adding and removing devices, including virtual root hubs + * in host controller driver modules, does not change these path identifers; + * neither does rebooting or re-enumerating. These are more useful identifiers + * than changeable ("unstable") ones like bus numbers or device addresses. + * + * With a partial exception for devices connected to USB 2.0 root hubs, these + * identifiers are also predictable. So long as the device tree isn't changed, + * plugging any USB device into a given hub port always gives it the same path. + * Because of the use of "companion" controllers, devices connected to ports on + * USB 2.0 root hubs (EHCI host controllers) will get one path ID if they are + * high speed, and a different one if they are full or low speed. + */ +static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size) +{ + int actual; + actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name, dev->devpath); + return (actual >= size) ? -1 : actual; +} + +/*-------------------------------------------------------------------------*/ + +#define USB_DEVICE_ID_MATCH_DEVICE (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT) +#define USB_DEVICE_ID_MATCH_DEV_RANGE (USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI) +#define USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE) +#define USB_DEVICE_ID_MATCH_DEV_INFO \ + (USB_DEVICE_ID_MATCH_DEV_CLASS | USB_DEVICE_ID_MATCH_DEV_SUBCLASS | USB_DEVICE_ID_MATCH_DEV_PROTOCOL) +#define USB_DEVICE_ID_MATCH_INT_INFO \ + (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_INT_PROTOCOL) + +/** + * USB_DEVICE - macro used to describe a specific usb device + * @vend: the 16 bit USB Vendor ID + * @prod: the 16 bit USB Product ID + * + * This macro is used to create a struct usb_device_id that matches a + * specific device. + */ +#define USB_DEVICE(vend,prod) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), .idProduct = (prod) +/** + * USB_DEVICE_VER - macro used to describe a specific usb device with a version range + * @vend: the 16 bit USB Vendor ID + * @prod: the 16 bit USB Product ID + * @lo: the bcdDevice_lo value + * @hi: the bcdDevice_hi value + * + * This macro is used to create a struct usb_device_id that matches a + * specific device, with a version range. + */ +#define USB_DEVICE_VER(vend,prod,lo,hi) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, .idVendor = (vend), .idProduct = (prod), .bcdDevice_lo = (lo), .bcdDevice_hi = (hi) + +/** + * USB_DEVICE_INFO - macro used to describe a class of usb devices + * @cl: bDeviceClass value + * @sc: bDeviceSubClass value + * @pr: bDeviceProtocol value + * + * This macro is used to create a struct usb_device_id that matches a + * specific class of devices. + */ +#define USB_DEVICE_INFO(cl,sc,pr) \ + .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, .bDeviceClass = (cl), .bDeviceSubClass = (sc), .bDeviceProtocol = (pr) + +/** + * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces + * @cl: bInterfaceClass value + * @sc: bInterfaceSubClass value + * @pr: bInterfaceProtocol value + * + * This macro is used to create a struct usb_device_id that matches a + * specific class of interfaces. + */ +#define USB_INTERFACE_INFO(cl,sc,pr) \ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr) + +/* -------------------------------------------------------------------------- */ + +/** + * struct usb_driver - identifies USB driver to usbcore + * @owner: Pointer to the module owner of this driver; initialize + * it using THIS_MODULE. + * @name: The driver name should be unique among USB drivers, + * and should normally be the same as the module name. + * @probe: Called to see if the driver is willing to manage a particular + * interface on a device. If it is, probe returns zero and uses + * dev_set_drvdata() to associate driver-specific data with the + * interface. It may also use usb_set_interface() to specify the + * appropriate altsetting. If unwilling to manage the interface, + * return a negative errno value. + * @disconnect: Called when the interface is no longer accessible, usually + * because its device has been (or is being) disconnected or the + * driver module is being unloaded. + * @ioctl: Used for drivers that want to talk to userspace through + * the "usbfs" filesystem. This lets devices provide ways to + * expose information to user space regardless of where they + * do (or don't) show up otherwise in the filesystem. + * @id_table: USB drivers use ID table to support hotplugging. + * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set + * or your driver's probe function will never get called. + * + * USB drivers must provide a name, probe() and disconnect() methods, + * and an id_table. Other driver fields are optional. + * + * The id_table is used in hotplugging. It holds a set of descriptors, + * and specialized data may be associated with each entry. That table + * is used by both user and kernel mode hotplugging support. + * + * The probe() and disconnect() methods are called in a context where + * they can sleep, but they should avoid abusing the privilege. Most + * work to connect to a device should be done when the device is opened, + * and undone at the last close. The disconnect code needs to address + * concurrency issues with respect to open() and close() methods, as + * well as forcing all pending I/O requests to complete (by unlinking + * them as necessary, and blocking until the unlinks complete). + */ +struct usb_driver { + struct module *owner; + + const char *name; + + int (*probe) (struct usb_interface *intf, + const struct usb_device_id *id); + + void (*disconnect) (struct usb_interface *intf); + + int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf); + + const struct usb_device_id *id_table; + + struct device_driver driver; + + struct semaphore serialize; +}; +#define to_usb_driver(d) container_of(d, struct usb_driver, driver) + +extern struct bus_type usb_bus_type; + +/** + * struct usb_class_driver - identifies a USB driver that wants to use the USB major number + * @name: devfs name for this driver. Will also be used by the driver + * class code to create a usb class device. + * @fops: pointer to the struct file_operations of this driver. + * @mode: the mode for the devfs file to be created for this driver. + * @minor_base: the start of the minor range for this driver. + * + * This structure is used for the usb_register_dev() and + * usb_unregister_dev() functions, to consolodate a number of the + * paramaters used for them. + */ +struct usb_class_driver { + char *name; + struct file_operations *fops; + mode_t mode; + int minor_base; +}; + +/* + * use these in module_init()/module_exit() + * and don't forget MODULE_DEVICE_TABLE(usb, ...) + */ +extern int usb_register(struct usb_driver *); +extern void usb_deregister(struct usb_driver *); + +extern int usb_register_dev(struct usb_interface *intf, + struct usb_class_driver *class_driver); +extern void usb_deregister_dev(struct usb_interface *intf, + struct usb_class_driver *class_driver); + +extern int usb_device_probe(struct device *dev); +extern int usb_device_remove(struct device *dev); +extern int STDCALL usb_disabled(void); + +/* -------------------------------------------------------------------------- */ + +/* + * URB support, for asynchronous request completions + */ + +/* + * urb->transfer_flags: + */ +#define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */ +#define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame ignored */ +#define URB_NO_DMA_MAP 0x0004 /* urb->*_dma are valid on submit */ +#define URB_ASYNC_UNLINK 0x0008 /* usb_unlink_urb() returns asap */ +#define URB_NO_FSBR 0x0020 /* UHCI-specific */ +#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUTs with short packet */ +#define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */ + +struct usb_iso_packet_descriptor { + unsigned int offset; + unsigned int length; /* expected length */ + unsigned int actual_length; + unsigned int status; +}; + +struct urb; +struct pt_regs; + +typedef void (*usb_complete_t)(struct urb *, struct pt_regs *); + +/** + * struct urb - USB Request Block + * @urb_list: For use by current owner of the URB. + * @pipe: Holds endpoint number, direction, type, and more. + * Create these values with the eight macros available; + * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the type is "ctrl" + * (control), "bulk", "int" (interrupt), or "iso" (isochronous). + * For example usb_sndbulkpipe() or usb_rcvintpipe(). Endpoint + * numbers range from zero to fifteen. Note that "in" endpoint two + * is a different endpoint (and pipe) from "out" endpoint two. + * The current configuration controls the existence, type, and + * maximum packet size of any given endpoint. + * @dev: Identifies the USB device to perform the request. + * @status: This is read in non-iso completion functions to get the + * status of the particular request. ISO requests only use it + * to tell whether the URB was unlinked; detailed status for + * each frame is in the fields of the iso_frame-desc. + * @transfer_flags: A variety of flags may be used to affect how URB + * submission, unlinking, or operation are handled. Different + * kinds of URB can use different flags. + * @transfer_buffer: This identifies the buffer to (or from) which + * the I/O request will be performed (unless URB_NO_DMA_MAP is set). + * This buffer must be suitable for DMA; allocate it with kmalloc() + * or equivalent. For transfers to "in" endpoints, contents of + * this buffer will be modified. This buffer is used for data + * phases of control transfers. + * @transfer_dma: When transfer_flags includes URB_NO_DMA_MAP, the device + * driver is saying that it provided this DMA address, which the host + * controller driver should use instead of the transfer_buffer. + * @transfer_buffer_length: How big is transfer_buffer. The transfer may + * be broken up into chunks according to the current maximum packet + * size for the endpoint, which is a function of the configuration + * and is encoded in the pipe. When the length is zero, neither + * transfer_buffer nor transfer_dma is used. + * @actual_length: This is read in non-iso completion functions, and + * it tells how many bytes (out of transfer_buffer_length) were + * transferred. It will normally be the same as requested, unless + * either an error was reported or a short read was performed. + * The URB_SHORT_NOT_OK transfer flag may be used to make such + * short reads be reported as errors. + * @setup_packet: Only used for control transfers, this points to eight bytes + * of setup data. Control transfers always start by sending this data + * to the device. Then transfer_buffer is read or written, if needed. + * (Not used when URB_NO_DMA_MAP is set.) + * @setup_dma: For control transfers with URB_NO_DMA_MAP set, the device + * driver has provided this DMA address for the setup packet. The + * host controller driver should use this instead of setup_buffer. + * If there is a data phase, its buffer is identified by transfer_dma. + * @start_frame: Returns the initial frame for interrupt or isochronous + * transfers. + * @number_of_packets: Lists the number of ISO transfer buffers. + * @interval: Specifies the polling interval for interrupt or isochronous + * transfers. The units are frames (milliseconds) for for full and low + * speed devices, and microframes (1/8 millisecond) for highspeed ones. + * @error_count: Returns the number of ISO transfers that reported errors. + * @context: For use in completion functions. This normally points to + * request-specific driver context. + * @complete: Completion handler. This URB is passed as the parameter to the + * completion function. The completion function may then do what + * it likes with the URB, including resubmitting or freeing it. + * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to + * collect the transfer status for each buffer. + * + * This structure identifies USB transfer requests. URBs must be allocated by + * calling usb_alloc_urb() and freed with a call to usb_free_urb(). + * Initialization may be done using various usb_fill_*_urb() functions. URBs + * are submitted using usb_submit_urb(), and pending requests may be canceled + * using usb_unlink_urb(). + * + * Data Transfer Buffers: + * + * Normally drivers provide I/O buffers allocated with kmalloc() or otherwise + * taken from the general page pool. That is provided by transfer_buffer + * (control requests also use setup_packet), and host controller drivers + * perform a dma mapping (and unmapping) for each buffer transferred. Those + * mapping operations can be expensive on some platforms (perhaps using a dma + * bounce buffer or talking to an IOMMU), + * although they're cheap on commodity x86 and ppc hardware. + * + * Alternatively, drivers may pass the URB_NO_DMA_MAP transfer flag, which + * tells the host controller driver that no such mapping is needed since + * the device driver is DMA-aware. For example, they might allocate a DMA + * buffer with usb_buffer_alloc(), or call usb_buffer_map(). + * When this transfer flag is provided, host controller drivers will use the + * dma addresses found in the transfer_dma and/or setup_dma fields rather than + * determing a dma address themselves. + * + * Initialization: + * + * All URBs submitted must initialize dev, pipe, + * transfer_flags (may be zero), complete, timeout (may be zero). + * The URB_ASYNC_UNLINK transfer flag affects later invocations of + * the usb_unlink_urb() routine. + * + * All URBs must also initialize + * transfer_buffer and transfer_buffer_length. They may provide the + * URB_SHORT_NOT_OK transfer flag, indicating that short reads are + * to be treated as errors; that flag is invalid for write requests. + * + * Bulk URBs may + * use the URB_ZERO_PACKET transfer flag, indicating that bulk OUT transfers + * should always terminate with a short packet, even if it means adding an + * extra zero length packet. + * + * Control URBs must provide a setup_packet. + * + * Interrupt UBS must provide an interval, saying how often (in milliseconds + * or, for highspeed devices, 125 microsecond units) + * to poll for transfers. After the URB has been submitted, the interval + * and start_frame fields reflect how the transfer was actually scheduled. + * The polling interval may be more frequent than requested. + * For example, some controllers have a maximum interval of 32 microseconds, + * while others support intervals of up to 1024 microseconds. + * Isochronous URBs also have transfer intervals. (Note that for isochronous + * endpoints, as well as high speed interrupt endpoints, the encoding of + * the transfer interval in the endpoint descriptor is logarithmic.) + * + * Isochronous URBs normally use the URB_ISO_ASAP transfer flag, telling + * the host controller to schedule the transfer as soon as bandwidth + * utilization allows, and then set start_frame to reflect the actual frame + * selected during submission. Otherwise drivers must specify the start_frame + * and handle the case where the transfer can't begin then. However, drivers + * won't know how bandwidth is currently allocated, and while they can + * find the current frame using usb_get_current_frame_number () they can't + * know the range for that frame number. (Ranges for frame counter values + * are HC-specific, and can go from 256 to 65536 frames from "now".) + * + * Isochronous URBs have a different data transfer model, in part because + * the quality of service is only "best effort". Callers provide specially + * allocated URBs, with number_of_packets worth of iso_frame_desc structures + * at the end. Each such packet is an individual ISO transfer. Isochronous + * URBs are normally queued, submitted by drivers to arrange that + * transfers are at least double buffered, and then explicitly resubmitted + * in completion handlers, so + * that data (such as audio or video) streams at as constant a rate as the + * host controller scheduler can support. + * + * Completion Callbacks: + * + * The completion callback is made in_interrupt(), and one of the first + * things that a completion handler should do is check the status field. + * The status field is provided for all URBs. It is used to report + * unlinked URBs, and status for all non-ISO transfers. It should not + * be examined before the URB is returned to the completion handler. + * + * The context field is normally used to link URBs back to the relevant + * driver or request state. + * + * When completion callback is invoked for non-isochronous URBs, the + * actual_length field tells how many bytes were transferred. + * + * ISO transfer status is reported in the status and actual_length fields + * of the iso_frame_desc array, and the number of errors is reported in + * error_count. Completion callbacks for ISO transfers will normally + * (re)submit URBs to ensure a constant transfer rate. + */ +struct urb +{ + spinlock_t lock; /* lock for the URB */ + atomic_t count; /* reference count of the URB */ + void *hcpriv; /* private data for host controller */ + struct list_head urb_list; /* list pointer to all active urbs */ + struct usb_device *dev; /* (in) pointer to associated device */ + unsigned int pipe; /* (in) pipe information */ + int status; /* (return) non-ISO status */ + unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/ + void *transfer_buffer; /* (in) associated data buffer */ + dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */ + int transfer_buffer_length; /* (in) data buffer length */ + int actual_length; /* (return) actual transfer length */ + int bandwidth; /* bandwidth for INT/ISO request */ + unsigned char *setup_packet; /* (in) setup packet (control only) */ + dma_addr_t setup_dma; /* (in) dma addr for setup_packet */ + int start_frame; /* (modify) start frame (INT/ISO) */ + int number_of_packets; /* (in) number of ISO packets */ + int interval; /* (in) transfer interval (INT/ISO) */ + int error_count; /* (return) number of ISO errors */ + int timeout; /* (in) timeout, in jiffies */ + void *context; /* (in) context for completion */ + usb_complete_t complete; /* (in) completion routine */ + struct usb_iso_packet_descriptor iso_frame_desc[0]; /* (in) ISO ONLY */ +}; + +/* -------------------------------------------------------------------------- */ + +/** + * usb_fill_control_urb - initializes a control urb + * @urb: pointer to the urb to initialize. + * @dev: pointer to the struct usb_device for this urb. + * @pipe: the endpoint pipe + * @setup_packet: pointer to the setup_packet buffer + * @transfer_buffer: pointer to the transfer buffer + * @buffer_length: length of the transfer buffer + * @complete: pointer to the usb_complete_t function + * @context: what to set the urb context to. + * + * Initializes a control urb with the proper information needed to submit + * it to a device. + */ +static inline void usb_fill_control_urb (struct urb *urb, + struct usb_device *dev, + unsigned int pipe, + unsigned char *setup_packet, + void *transfer_buffer, + int buffer_length, + usb_complete_t complete, + void *context) +{ + spin_lock_init(&urb->lock); + urb->dev = dev; + urb->pipe = pipe; + urb->setup_packet = setup_packet; + urb->transfer_buffer = transfer_buffer; + urb->transfer_buffer_length = buffer_length; + urb->complete = complete; + urb->context = context; +} + +/** + * usb_fill_bulk_urb - macro to help initialize a bulk urb + * @urb: pointer to the urb to initialize. + * @dev: pointer to the struct usb_device for this urb. + * @pipe: the endpoint pipe + * @transfer_buffer: pointer to the transfer buffer + * @buffer_length: length of the transfer buffer + * @complete: pointer to the usb_complete_t function + * @context: what to set the urb context to. + * + * Initializes a bulk urb with the proper information needed to submit it + * to a device. + */ +static inline void usb_fill_bulk_urb (struct urb *urb, + struct usb_device *dev, + unsigned int pipe, + void *transfer_buffer, + int buffer_length, + usb_complete_t complete, + void *context) +{ + spin_lock_init(&urb->lock); + urb->dev = dev; + urb->pipe = pipe; + urb->transfer_buffer = transfer_buffer; + urb->transfer_buffer_length = buffer_length; + urb->complete = complete; + urb->context = context; +} + +/** + * usb_fill_int_urb - macro to help initialize a interrupt urb + * @urb: pointer to the urb to initialize. + * @dev: pointer to the struct usb_device for this urb. + * @pipe: the endpoint pipe + * @transfer_buffer: pointer to the transfer buffer + * @buffer_length: length of the transfer buffer + * @complete: pointer to the usb_complete_t function + * @context: what to set the urb context to. + * @interval: what to set the urb interval to, encoded like + * the endpoint descriptor's bInterval value. + * + * Initializes a interrupt urb with the proper information needed to submit + * it to a device. + * Note that high speed interrupt endpoints use a logarithmic encoding of + * the endpoint interval, and express polling intervals in microframes + * (eight per millisecond) rather than in frames (one per millisecond). + */ +static inline void usb_fill_int_urb (struct urb *urb, + struct usb_device *dev, + unsigned int pipe, + void *transfer_buffer, + int buffer_length, + usb_complete_t complete, + void *context, + int interval) +{ + spin_lock_init(&urb->lock); + urb->dev = dev; + urb->pipe = pipe; + urb->transfer_buffer = transfer_buffer; + urb->transfer_buffer_length = buffer_length; + urb->complete = complete; + urb->context = context; + if (dev->speed == USB_SPEED_HIGH) + urb->interval = 1 << (interval - 1); + else + urb->interval = interval; + urb->start_frame = -1; +} + +extern void STDCALL usb_init_urb(struct urb *urb); +extern struct urb STDCALL *usb_alloc_urb(int iso_packets, int mem_flags); +extern void STDCALL usb_free_urb(struct urb *urb); +#define usb_put_urb usb_free_urb +extern struct urb STDCALL *usb_get_urb(struct urb *urb); +extern int STDCALL usb_submit_urb(struct urb *urb, int mem_flags); +extern int STDCALL usb_unlink_urb(struct urb *urb); + +#define HAVE_USB_BUFFERS +void *usb_buffer_alloc (struct usb_device *dev, size_t size, + int mem_flags, dma_addr_t *dma); +void usb_buffer_free (struct usb_device *dev, size_t size, + void *addr, dma_addr_t dma); + +struct urb *usb_buffer_map (struct urb *urb); +void usb_buffer_dmasync (struct urb *urb); +void usb_buffer_unmap (struct urb *urb); + +struct scatterlist; +int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int nents); +void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents); +void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents); + +/*-------------------------------------------------------------------* + * SYNCHRONOUS CALL SUPPORT * + *-------------------------------------------------------------------*/ + +extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, + __u8 request, __u8 requesttype, __u16 value, __u16 index, + void *data, __u16 size, int timeout); +extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, + void *data, int len, int *actual_length, + int timeout); + +/* wrappers around usb_control_msg() for the most common standard requests */ +extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, + unsigned char descindex, void *buf, int size); +extern int usb_get_device_descriptor(struct usb_device *dev); +extern int usb_get_status(struct usb_device *dev, + int type, int target, void *data); +extern int usb_get_string(struct usb_device *dev, + unsigned short langid, unsigned char index, void *buf, int size); +extern int usb_string(struct usb_device *dev, int index, + char *buf, size_t size); + +/* wrappers that also update important state inside usbcore */ +extern int usb_clear_halt(struct usb_device *dev, int pipe); +extern int usb_set_configuration(struct usb_device *dev, int configuration); +extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate); + +/* + * timeouts, in seconds, used for sending/receiving control messages + * they typically complete within a few frames (msec) after they're issued + * USB identifies 5 second timeouts, maybe more in a few cases, and a few + * slow devices (like some MGE Ellipse UPSes) actually push that limit. + */ +#define USB_CTRL_GET_TIMEOUT 5 +#define USB_CTRL_SET_TIMEOUT 5 + + +/** + * struct usb_sg_request - support for scatter/gather I/O + * @status: zero indicates success, else negative errno + * @bytes: counts bytes transferred. + * + * These requests are initialized using usb_sg_init(), and then are used + * as request handles passed to usb_sg_wait() or usb_sg_cancel(). Most + * members of the request object aren't for driver access. + * + * The status and bytecount values are valid only after usb_sg_wait() + * returns. If the status is zero, then the bytecount matches the total + * from the request. + * + * After an error completion, drivers may need to clear a halt condition + * on the endpoint. + */ +struct usb_sg_request { + int status; + size_t bytes; + + // members not documented above are private to usbcore, + // and are not provided for driver access! + spinlock_t lock; + + struct usb_device *dev; + int pipe; + struct scatterlist *sg; + int nents; + + int entries; + struct urb **urbs; + + int count; + struct completion complete; +}; + +int usb_sg_init ( + struct usb_sg_request *io, + struct usb_device *dev, + unsigned pipe, + unsigned period, + struct scatterlist *sg, + int nents, + size_t length, + int mem_flags +); +void usb_sg_cancel (struct usb_sg_request *io); +void usb_sg_wait (struct usb_sg_request *io); + + +/* -------------------------------------------------------------------------- */ + +/* + * Calling this entity a "pipe" is glorifying it. A USB pipe + * is something embarrassingly simple: it basically consists + * of the following information: + * - device number (7 bits) + * - endpoint number (4 bits) + * - current Data0/1 state (1 bit) [Historical; now gone] + * - direction (1 bit) + * - speed (1 bit) [Historical and specific to USB 1.1; now gone.] + * - max packet size (2 bits: 8, 16, 32 or 64) [Historical; now gone.] + * - pipe type (2 bits: control, interrupt, bulk, isochronous) + * + * That's 18 bits. Really. Nothing more. And the USB people have + * documented these eighteen bits as some kind of glorious + * virtual data structure. + * + * Let's not fall in that trap. We'll just encode it as a simple + * unsigned int. The encoding is: + * + * - max size: bits 0-1 [Historical; now gone.] + * - direction: bit 7 (0 = Host-to-Device [Out], + * 1 = Device-to-Host [In] ... + * like endpoint bEndpointAddress) + * - device: bits 8-14 ... bit positions known to uhci-hcd + * - endpoint: bits 15-18 ... bit positions known to uhci-hcd + * - Data0/1: bit 19 [Historical; now gone. ] + * - lowspeed: bit 26 [Historical; now gone. ] + * - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt, + * 10 = control, 11 = bulk) + * + * Why? Because it's arbitrary, and whatever encoding we select is really + * up to us. This one happens to share a lot of bit positions with the UHCI + * specification, so that much of the uhci driver can just mask the bits + * appropriately. + */ + +/* NOTE: these are not the standard USB_ENDPOINT_XFER_* values!! */ +#define PIPE_ISOCHRONOUS 0 +#define PIPE_INTERRUPT 1 +#define PIPE_CONTROL 2 +#define PIPE_BULK 3 + +#define usb_maxpacket(dev, pipe, out) (out \ + ? (dev)->epmaxpacketout[usb_pipeendpoint(pipe)] \ + : (dev)->epmaxpacketin [usb_pipeendpoint(pipe)] ) + +#define usb_pipein(pipe) ((pipe) & USB_DIR_IN) +#define usb_pipeout(pipe) (!usb_pipein(pipe)) +#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f) +#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf) +#define usb_pipetype(pipe) (((pipe) >> 30) & 3) +#define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS) +#define usb_pipeint(pipe) (usb_pipetype((pipe)) == PIPE_INTERRUPT) +#define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == PIPE_CONTROL) +#define usb_pipebulk(pipe) (usb_pipetype((pipe)) == PIPE_BULK) + +/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */ +#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1) +#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep))) +#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | ((bit) << (ep))) + +/* Endpoint halt control/status ... likewise USE WITH CAUTION */ +#define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep))) +#define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep))) + + +static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint) +{ + return (dev->devnum << 8) | (endpoint << 15); +} + +/* Create various pipes... */ +#define usb_sndctrlpipe(dev,endpoint) ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint)) +#define usb_rcvctrlpipe(dev,endpoint) ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) +#define usb_sndisocpipe(dev,endpoint) ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint)) +#define usb_rcvisocpipe(dev,endpoint) ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) +#define usb_sndbulkpipe(dev,endpoint) ((PIPE_BULK << 30) | __create_pipe(dev,endpoint)) +#define usb_rcvbulkpipe(dev,endpoint) ((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) +#define usb_sndintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint)) +#define usb_rcvintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) + +/* -------------------------------------------------------------------------- */ + +/* + * Debugging and troubleshooting/diagnostic helpers. + */ +void usb_show_device_descriptor(struct usb_device_descriptor *); +void usb_show_config_descriptor(struct usb_config_descriptor *); +void usb_show_interface_descriptor(struct usb_interface_descriptor *); +void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *); +void usb_show_device(struct usb_device *); +void usb_show_string(struct usb_device *dev, char *id, int index); + +#ifdef DEBUG +#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif + + + +#ifdef DEBUG_MODE +#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ## arg) +#define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg) +#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg) +#endif + +#ifndef DEBUG_MODE +#define info(format, arg...) do {} while (0) +#define err(format, arg...) do {} while (0) +#define warn(format, arg...) do {} while (0) +#endif + +#endif /* __KERNEL__ */ + +#endif diff --git a/reactos/drivers/usb/cromwell/linux/usb_ch9.h b/reactos/drivers/usb/cromwell/linux/usb_ch9.h index a679168973a..109ec384d59 100644 --- a/reactos/drivers/usb/cromwell/linux/usb_ch9.h +++ b/reactos/drivers/usb/cromwell/linux/usb_ch9.h @@ -1,315 +1,315 @@ -/* - * This file holds USB constants and structures that are needed for USB - * device APIs. These are used by the USB device model, which is defined - * in chapter 9 of the USB 2.0 specification. Linux has several APIs in C - * that need these: - * - * - the master/host side Linux-USB kernel driver API; - * - the "usbfs" user space API; and - * - (eventually) a Linux "gadget" slave/device side driver API. - * - * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems - * act either as a USB master/host or as a USB slave/device. That means - * the master and slave side APIs will benefit from working well together. - */ - -#ifndef __LINUX_USB_CH9_H -#define __LINUX_USB_CH9_H -#if 0 -#include /* __u8 etc */ -#endif -/*-------------------------------------------------------------------------*/ - -/* CONTROL REQUEST SUPPORT */ - -/* - * USB directions - * - * This bit flag is used in endpoint descriptors' bEndpointAddress field. - * It's also one of three fields in control requests bRequestType. - */ -#define USB_DIR_OUT 0 /* to device */ -#define USB_DIR_IN 0x80 /* to host */ - -/* - * USB types, the second of three bRequestType fields - */ -#define USB_TYPE_MASK (0x03 << 5) -#define USB_TYPE_STANDARD (0x00 << 5) -#define USB_TYPE_CLASS (0x01 << 5) -#define USB_TYPE_VENDOR (0x02 << 5) -#define USB_TYPE_RESERVED (0x03 << 5) - -/* - * USB recipients, the third of three bRequestType fields - */ -#define USB_RECIP_MASK 0x1f -#define USB_RECIP_DEVICE 0x00 -#define USB_RECIP_INTERFACE 0x01 -#define USB_RECIP_ENDPOINT 0x02 -#define USB_RECIP_OTHER 0x03 - -/* - * Standard requests, for the bRequest field of a SETUP packet. - * - * These are qualified by the bRequestType field, so that for example - * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved - * by a GET_STATUS request. - */ -#define USB_REQ_GET_STATUS 0x00 -#define USB_REQ_CLEAR_FEATURE 0x01 -#define USB_REQ_SET_FEATURE 0x03 -#define USB_REQ_SET_ADDRESS 0x05 -#define USB_REQ_GET_DESCRIPTOR 0x06 -#define USB_REQ_SET_DESCRIPTOR 0x07 -#define USB_REQ_GET_CONFIGURATION 0x08 -#define USB_REQ_SET_CONFIGURATION 0x09 -#define USB_REQ_GET_INTERFACE 0x0A -#define USB_REQ_SET_INTERFACE 0x0B -#define USB_REQ_SYNCH_FRAME 0x0C - - -/** - * struct usb_ctrlrequest - SETUP data for a USB device control request - * @bRequestType: matches the USB bmRequestType field - * @bRequest: matches the USB bRequest field - * @wValue: matches the USB wValue field (le16 byte order) - * @wIndex: matches the USB wIndex field (le16 byte order) - * @wLength: matches the USB wLength field (le16 byte order) - * - * This structure is used to send control requests to a USB device. It matches - * the different fields of the USB 2.0 Spec section 9.3, table 9-2. See the - * USB spec for a fuller description of the different fields, and what they are - * used for. - * - * Note that the driver for any interface can issue control requests. - * For most devices, interfaces don't coordinate with each other, so - * such requests may be made at any time. - */ -struct usb_ctrlrequest { - __u8 bRequestType; - __u8 bRequest; - __u16 wValue; - __u16 wIndex; - __u16 wLength; -} __attribute__ ((packed)); - -/*-------------------------------------------------------------------------*/ - -/* - * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or - * (rarely) accepted by SET_DESCRIPTOR. - * - * Note that all multi-byte values here are encoded in little endian - * byte order "on the wire". But when exposed through Linux-USB APIs, - * they've been converted to cpu byte order. - */ - -/* - * Descriptor types ... USB 2.0 spec table 9.5 - */ -#define USB_DT_DEVICE 0x01 -#define USB_DT_CONFIG 0x02 -#define USB_DT_STRING 0x03 -#define USB_DT_INTERFACE 0x04 -#define USB_DT_ENDPOINT 0x05 -#define USB_DT_DEVICE_QUALIFIER 0x06 -#define USB_DT_OTHER_SPEED_CONFIG 0x07 -#define USB_DT_INTERFACE_POWER 0x08 - -/* All standard descriptors have these 2 fields at the beginning */ -struct usb_descriptor_header { - __u8 bLength; - __u8 bDescriptorType; -} __attribute__ ((packed)); - - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_DEVICE: Device descriptor */ -struct usb_device_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __u16 bcdUSB; - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - __u8 bMaxPacketSize0; - __u16 idVendor; - __u16 idProduct; - __u16 bcdDevice; - __u8 iManufacturer; - __u8 iProduct; - __u8 iSerialNumber; - __u8 bNumConfigurations; -} __attribute__ ((packed)); - -#define USB_DT_DEVICE_SIZE 18 - - -/* - * Device and/or Interface Class codes - * as found in bDeviceClass or bInterfaceClass - * and defined by www.usb.org documents - */ -#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ -#define USB_CLASS_AUDIO 1 -#define USB_CLASS_COMM 2 -#define USB_CLASS_HID 3 -#define USB_CLASS_PHYSICAL 5 -#define USB_CLASS_STILL_IMAGE 6 -#define USB_CLASS_PRINTER 7 -#define USB_CLASS_MASS_STORAGE 8 -#define USB_CLASS_HUB 9 -#define USB_CLASS_CDC_DATA 0x0a -#define USB_CLASS_CSCID 0x0b /* chip+ smart card */ -#define USB_CLASS_CONTENT_SEC 0x0d /* content security */ -#define USB_CLASS_APP_SPEC 0xfe -#define USB_CLASS_VENDOR_SPEC 0xff - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_CONFIG: Configuration descriptor information. - * - * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the - * descriptor type is different. Highspeed-capable devices can look - * different depending on what speed they're currently running. Only - * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG - * descriptors. - */ -struct usb_config_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __u16 wTotalLength; - __u8 bNumInterfaces; - __u8 bConfigurationValue; - __u8 iConfiguration; - __u8 bmAttributes; - __u8 bMaxPower; -} __attribute__ ((packed)); - -#define USB_DT_CONFIG_SIZE 9 - -/* from config descriptor bmAttributes */ -#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */ -#define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */ -#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */ - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_STRING: String descriptor */ -struct usb_string_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __u16 wData[1]; /* UTF-16LE encoded */ -} __attribute__ ((packed)); - -/* note that "string" zero is special, it holds language codes that - * the device supports, not Unicode characters. - */ - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_INTERFACE: Interface descriptor */ -struct usb_interface_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __u8 bInterfaceNumber; - __u8 bAlternateSetting; - __u8 bNumEndpoints; - __u8 bInterfaceClass; - __u8 bInterfaceSubClass; - __u8 bInterfaceProtocol; - __u8 iInterface; -} __attribute__ ((packed)); - -#define USB_DT_INTERFACE_SIZE 9 - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_ENDPOINT: Endpoint descriptor */ -struct usb_endpoint_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __u8 bEndpointAddress; - __u8 bmAttributes; - __u16 wMaxPacketSize; - __u8 bInterval; - - // NOTE: these two are _only_ in audio endpoints. - // use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. - __u8 bRefresh; - __u8 bSynchAddress; -} __attribute__ ((packed)); - -#define USB_DT_ENDPOINT_SIZE 7 -#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ - - -/* - * Endpoints - */ -#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */ -#define USB_ENDPOINT_DIR_MASK 0x80 - -#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ -#define USB_ENDPOINT_XFER_CONTROL 0 -#define USB_ENDPOINT_XFER_ISOC 1 -#define USB_ENDPOINT_XFER_BULK 2 -#define USB_ENDPOINT_XFER_INT 3 - - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ -struct usb_qualifier_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __u16 bcdUSB; - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - __u8 bMaxPacketSize0; - __u8 bNumConfigurations; - __u8 bRESERVED; -} __attribute__ ((packed)); - - -/*-------------------------------------------------------------------------*/ - -/* USB 2.0 defines three speeds, here's how Linux identifies them */ - -enum usb_device_speed { - USB_SPEED_UNKNOWN = 0, /* enumerating */ - USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ - USB_SPEED_HIGH /* usb 2.0 */ -}; - -enum usb_device_state { - /* NOTATTACHED isn't in the USB spec, and this state acts - * the same as ATTACHED ... but it's clearer this way. - */ - USB_STATE_NOTATTACHED = 0, - - /* the chapter 9 device states */ - USB_STATE_ATTACHED, - USB_STATE_POWERED, - USB_STATE_DEFAULT, /* limited function */ - USB_STATE_ADDRESS, - USB_STATE_CONFIGURED, /* most functions */ - - USB_STATE_SUSPENDED - - /* NOTE: there are actually four different SUSPENDED - * states, returning to POWERED, DEFAULT, ADDRESS, or - * CONFIGURED respectively when SOF tokens flow again. - */ -}; - -#endif /* __LINUX_USB_CH9_H */ +/* + * This file holds USB constants and structures that are needed for USB + * device APIs. These are used by the USB device model, which is defined + * in chapter 9 of the USB 2.0 specification. Linux has several APIs in C + * that need these: + * + * - the master/host side Linux-USB kernel driver API; + * - the "usbfs" user space API; and + * - (eventually) a Linux "gadget" slave/device side driver API. + * + * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems + * act either as a USB master/host or as a USB slave/device. That means + * the master and slave side APIs will benefit from working well together. + */ + +#ifndef __LINUX_USB_CH9_H +#define __LINUX_USB_CH9_H +#if 0 +#include /* __u8 etc */ +#endif +/*-------------------------------------------------------------------------*/ + +/* CONTROL REQUEST SUPPORT */ + +/* + * USB directions + * + * This bit flag is used in endpoint descriptors' bEndpointAddress field. + * It's also one of three fields in control requests bRequestType. + */ +#define USB_DIR_OUT 0 /* to device */ +#define USB_DIR_IN 0x80 /* to host */ + +/* + * USB types, the second of three bRequestType fields + */ +#define USB_TYPE_MASK (0x03 << 5) +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +/* + * USB recipients, the third of three bRequestType fields + */ +#define USB_RECIP_MASK 0x1f +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 + +/* + * Standard requests, for the bRequest field of a SETUP packet. + * + * These are qualified by the bRequestType field, so that for example + * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved + * by a GET_STATUS request. + */ +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + + +/** + * struct usb_ctrlrequest - SETUP data for a USB device control request + * @bRequestType: matches the USB bmRequestType field + * @bRequest: matches the USB bRequest field + * @wValue: matches the USB wValue field (le16 byte order) + * @wIndex: matches the USB wIndex field (le16 byte order) + * @wLength: matches the USB wLength field (le16 byte order) + * + * This structure is used to send control requests to a USB device. It matches + * the different fields of the USB 2.0 Spec section 9.3, table 9-2. See the + * USB spec for a fuller description of the different fields, and what they are + * used for. + * + * Note that the driver for any interface can issue control requests. + * For most devices, interfaces don't coordinate with each other, so + * such requests may be made at any time. + */ +struct usb_ctrlrequest { + __u8 bRequestType; + __u8 bRequest; + __u16 wValue; + __u16 wIndex; + __u16 wLength; +} __attribute__ ((packed)); + +/*-------------------------------------------------------------------------*/ + +/* + * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or + * (rarely) accepted by SET_DESCRIPTOR. + * + * Note that all multi-byte values here are encoded in little endian + * byte order "on the wire". But when exposed through Linux-USB APIs, + * they've been converted to cpu byte order. + */ + +/* + * Descriptor types ... USB 2.0 spec table 9.5 + */ +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 +#define USB_DT_DEVICE_QUALIFIER 0x06 +#define USB_DT_OTHER_SPEED_CONFIG 0x07 +#define USB_DT_INTERFACE_POWER 0x08 + +/* All standard descriptors have these 2 fields at the beginning */ +struct usb_descriptor_header { + __u8 bLength; + __u8 bDescriptorType; +} __attribute__ ((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEVICE: Device descriptor */ +struct usb_device_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u16 bcdUSB; + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + __u8 bMaxPacketSize0; + __u16 idVendor; + __u16 idProduct; + __u16 bcdDevice; + __u8 iManufacturer; + __u8 iProduct; + __u8 iSerialNumber; + __u8 bNumConfigurations; +} __attribute__ ((packed)); + +#define USB_DT_DEVICE_SIZE 18 + + +/* + * Device and/or Interface Class codes + * as found in bDeviceClass or bInterfaceClass + * and defined by www.usb.org documents + */ +#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PHYSICAL 5 +#define USB_CLASS_STILL_IMAGE 6 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 +#define USB_CLASS_CDC_DATA 0x0a +#define USB_CLASS_CSCID 0x0b /* chip+ smart card */ +#define USB_CLASS_CONTENT_SEC 0x0d /* content security */ +#define USB_CLASS_APP_SPEC 0xfe +#define USB_CLASS_VENDOR_SPEC 0xff + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_CONFIG: Configuration descriptor information. + * + * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the + * descriptor type is different. Highspeed-capable devices can look + * different depending on what speed they're currently running. Only + * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG + * descriptors. + */ +struct usb_config_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u16 wTotalLength; + __u8 bNumInterfaces; + __u8 bConfigurationValue; + __u8 iConfiguration; + __u8 bmAttributes; + __u8 bMaxPower; +} __attribute__ ((packed)); + +#define USB_DT_CONFIG_SIZE 9 + +/* from config descriptor bmAttributes */ +#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */ +#define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */ +#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */ + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_STRING: String descriptor */ +struct usb_string_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u16 wData[1]; /* UTF-16LE encoded */ +} __attribute__ ((packed)); + +/* note that "string" zero is special, it holds language codes that + * the device supports, not Unicode characters. + */ + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_INTERFACE: Interface descriptor */ +struct usb_interface_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bInterfaceNumber; + __u8 bAlternateSetting; + __u8 bNumEndpoints; + __u8 bInterfaceClass; + __u8 bInterfaceSubClass; + __u8 bInterfaceProtocol; + __u8 iInterface; +} __attribute__ ((packed)); + +#define USB_DT_INTERFACE_SIZE 9 + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_ENDPOINT: Endpoint descriptor */ +struct usb_endpoint_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bEndpointAddress; + __u8 bmAttributes; + __u16 wMaxPacketSize; + __u8 bInterval; + + // NOTE: these two are _only_ in audio endpoints. + // use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. + __u8 bRefresh; + __u8 bSynchAddress; +} __attribute__ ((packed)); + +#define USB_DT_ENDPOINT_SIZE 7 +#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ + + +/* + * Endpoints + */ +#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */ +#define USB_ENDPOINT_DIR_MASK 0x80 + +#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ +#define USB_ENDPOINT_XFER_CONTROL 0 +#define USB_ENDPOINT_XFER_ISOC 1 +#define USB_ENDPOINT_XFER_BULK 2 +#define USB_ENDPOINT_XFER_INT 3 + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ +struct usb_qualifier_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u16 bcdUSB; + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + __u8 bMaxPacketSize0; + __u8 bNumConfigurations; + __u8 bRESERVED; +} __attribute__ ((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB 2.0 defines three speeds, here's how Linux identifies them */ + +enum usb_device_speed { + USB_SPEED_UNKNOWN = 0, /* enumerating */ + USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ + USB_SPEED_HIGH /* usb 2.0 */ +}; + +enum usb_device_state { + /* NOTATTACHED isn't in the USB spec, and this state acts + * the same as ATTACHED ... but it's clearer this way. + */ + USB_STATE_NOTATTACHED = 0, + + /* the chapter 9 device states */ + USB_STATE_ATTACHED, + USB_STATE_POWERED, + USB_STATE_DEFAULT, /* limited function */ + USB_STATE_ADDRESS, + USB_STATE_CONFIGURED, /* most functions */ + + USB_STATE_SUSPENDED + + /* NOTE: there are actually four different SUSPENDED + * states, returning to POWERED, DEFAULT, ADDRESS, or + * CONFIGURED respectively when SOF tokens flow again. + */ +}; + +#endif /* __LINUX_USB_CH9_H */ diff --git a/reactos/drivers/usb/cromwell/sys/BootUSB.c b/reactos/drivers/usb/cromwell/sys/BootUSB.c index 2f582c5925a..243d101f9e7 100644 --- a/reactos/drivers/usb/cromwell/sys/BootUSB.c +++ b/reactos/drivers/usb/cromwell/sys/BootUSB.c @@ -1,90 +1,90 @@ -/* - * USB support for XBOX, based on Linux kernel source - * - * 2003-06-21 Georg Acher (georg@acher.org) - * -*/ - -#include "../usb_wrapper.h" - -void subsys_usb_init(void); -void module_exit_usb_exit(void); - -extern struct pci_device_id *module_table_pci_ids; - -// straigth call... -int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id); -void usb_hcd_pci_remove (struct pci_dev *dev); - -void XPADInit(void); -void XPADRemove(void); -void XRemoteInit(void); -void XRemoteRemove(void); - -extern int (*thread_handler)(void*); -int (*hub_thread_handler)(void*); - -extern int nousb; -extern int xpad_num; - -struct pci_dev xx_ohci_dev={ - .vendor = 0, - .device = 0, - .bus = NULL, - .irq = 1, // currently not used... - .slot_name = "OHCI", - .dev = {.name = "PCI",.dma_mask=1}, - .base = {0xfed00000}, - .flags = {} -}; - -/*------------------------------------------------------------------------*/ -void BootStartUSB(void) -{ - int n; - - nousb=0; - - init_wrapper(); - subsys_usb_init(); - hub_thread_handler=thread_handler; - usb_hcd_pci_probe(&xx_ohci_dev, module_table_pci_ids); - XPADInit(); - - XRemoteInit(); - - UsbKeyBoardInit(); - - for(n=0;n<30;n++) { - USBGetEvents(); - wait_ms(1); - } -} -/*------------------------------------------------------------------------*/ -void USBGetEvents(void) -{ - inc_jiffies(1); - do_all_timers(); - hub_thread_handler(NULL); - handle_irqs(-1); -} -/*------------------------------------------------------------------------*/ -void BootStopUSB(void) -{ - int n; - - XPADRemove(); - XRemoteRemove(); - UsbKeyBoardRemove(); - - for(n=0;n<100;n++) - { - USBGetEvents(); - wait_ms(1); - } - - module_exit_usb_exit(); - usb_hcd_pci_remove(&xx_ohci_dev); - -} -/*------------------------------------------------------------------------*/ +/* + * USB support for XBOX, based on Linux kernel source + * + * 2003-06-21 Georg Acher (georg@acher.org) + * +*/ + +#include "../usb_wrapper.h" + +void subsys_usb_init(void); +void module_exit_usb_exit(void); + +extern struct pci_device_id *module_table_pci_ids; + +// straigth call... +int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id); +void usb_hcd_pci_remove (struct pci_dev *dev); + +void XPADInit(void); +void XPADRemove(void); +void XRemoteInit(void); +void XRemoteRemove(void); + +extern int (*thread_handler)(void*); +int (*hub_thread_handler)(void*); + +extern int nousb; +extern int xpad_num; + +struct pci_dev xx_ohci_dev={ + .vendor = 0, + .device = 0, + .bus = NULL, + .irq = 1, // currently not used... + .slot_name = "OHCI", + .dev = {.name = "PCI",.dma_mask=1}, + .base = {0xfed00000}, + .flags = {} +}; + +/*------------------------------------------------------------------------*/ +void BootStartUSB(void) +{ + int n; + + nousb=0; + + init_wrapper(); + subsys_usb_init(); + hub_thread_handler=thread_handler; + usb_hcd_pci_probe(&xx_ohci_dev, module_table_pci_ids); + XPADInit(); + + XRemoteInit(); + + UsbKeyBoardInit(); + + for(n=0;n<30;n++) { + USBGetEvents(); + wait_ms(1); + } +} +/*------------------------------------------------------------------------*/ +void USBGetEvents(void) +{ + inc_jiffies(1); + do_all_timers(); + hub_thread_handler(NULL); + handle_irqs(-1); +} +/*------------------------------------------------------------------------*/ +void BootStopUSB(void) +{ + int n; + + XPADRemove(); + XRemoteRemove(); + UsbKeyBoardRemove(); + + for(n=0;n<100;n++) + { + USBGetEvents(); + wait_ms(1); + } + + module_exit_usb_exit(); + usb_hcd_pci_remove(&xx_ohci_dev); + +} +/*------------------------------------------------------------------------*/ diff --git a/reactos/drivers/usb/cromwell/sys/Makefile b/reactos/drivers/usb/cromwell/sys/Makefile index a57d8cec5c6..fb93c8a4a21 100644 --- a/reactos/drivers/usb/cromwell/sys/Makefile +++ b/reactos/drivers/usb/cromwell/sys/Makefile @@ -1,4 +1,5 @@ - -O_TARGET := usbwrapper.o BootUSB.o linuxwrapper.o xpad.o xremote.o usbkey.o risefall.o - -include $(TOPDIR)/Rules.make + +O_TARGET := usbwrapper.o BootUSB.o linuxwrapper.o xpad.o xremote.o usbkey.o risefall.o + +include $(TOPDIR)/Rules.make + diff --git a/reactos/drivers/usb/cromwell/sys/linuxwrapper.c b/reactos/drivers/usb/cromwell/sys/linuxwrapper.c index 616cbd79a74..6b5af2adb3c 100644 --- a/reactos/drivers/usb/cromwell/sys/linuxwrapper.c +++ b/reactos/drivers/usb/cromwell/sys/linuxwrapper.c @@ -1,375 +1,382 @@ -/* - * USB support based on Linux kernel source - * - * 2003-06-21 Georg Acher (georg@acher.org) - * - * Concept: - * - * 1) Forget all device interrupts, scheduling, semaphores, threads etc. - * 1a) Forget all DMA and PCI helper functions - * 2) Forget usbdevfs, procfs and ioctls - * 3) Emulate OHCI interrupts and root hub timer by polling - * 4) Emulate hub kernel thread by polling - * 5) Emulate synchronous USB-messages (usb_*_msg) with busy waiting - * - * To be done: - * 6) Remove code bloat - * - */ - -#include "../usb_wrapper.h" - -/* internal state */ - -static struct pci_dev *pci_probe_dev; -extern int (*thread_handler)(void*); -extern void* thread_parm; - -struct my_irqs reg_irqs[MAX_IRQS]; -int num_irqs; -int need_wakeup; - -int my_jiffies; - -struct timer_list *main_timer_list[MAX_TIMERS]; -struct dummy_process act_cur={0}; -struct dummy_process *my_current; - -int (*thread_handler)(void*); -void* thread_parm; - -#define MAX_DRVS 8 -static struct device_driver *m_drivers[MAX_DRVS]; -static int drvs_num; - -/*------------------------------------------------------------------------*/ -/* - * Helper functions for top-level system - */ -/*------------------------------------------------------------------------*/ -void init_wrapper(struct pci_dev *probe_dev) -{ - int n; - for(n=0;nfunction && main_timer_list[n]->expires) - { - void (*function)(unsigned long)=main_timer_list[n]->function; - unsigned long data=main_timer_list[n]->data; - main_timer_list[n]->expires=0; - - main_timer_list[n]=NULL; // remove timer -// printk("do timer %i fn %p\n",n,function); - - function(data); - } - } -} -/*------------------------------------------------------------------------*/ -// Purpose: Remember thread procedure and data in global var -// ReactOS Purpose: Create real kernel thread -int my_kernel_thread(int STDCALL (*handler)(void*), void* parm, int flags) -{ - HANDLE hThread; - //thread_handler=handler; - //thread_parm=parm; - //return 42; // PID :-) - - ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); - - PsCreateSystemThread(&hThread, - THREAD_ALL_ACCESS, - NULL, - NULL, - NULL, - (PKSTART_ROUTINE)handler, - parm); - - return (int)hThread; // FIXME: Correct? -} - -// Kill the process -int my_kill_proc(int pid, int signal, int unk) -{ - HANDLE hThread; - - // TODO: Implement actual process killing - - hThread = (HANDLE)pid; - ZwClose(hThread); - - return 0; -} - -/*------------------------------------------------------------------------*/ -/* Device management - * As simple as possible, but as complete as necessary ... - */ -/*------------------------------------------------------------------------*/ - - -/* calls probe function for hotplug (which does device matching), this is the -only link between usbcore and the registered device drivers! */ -int my_device_add(struct device *dev) -{ - int n,found=0; -// printk("drv_num %i %p %p\n",drvs_num,m_drivers[0]->probe,m_drivers[1]->probe); - if (dev->driver) - { - if (dev->driver->probe) - return dev->driver->probe(dev); - } - else - { - for(n=0;nprobe) - { - dev->driver=m_drivers[n]; -// printk("probe%i %p ",n,m_drivers[n]->probe); - if (m_drivers[n]->probe(dev) == 0) - { -// return 0; - found=1; - } - } - } - if (found) return 0; - } - dev->driver=NULL; - return -ENODEV; -} -/*------------------------------------------------------------------------*/ -int my_driver_register(struct device_driver *driver) -{ - - if (drvs_numprobe); - m_drivers[drvs_num++]=driver; - return 0; - } - return -1; -} -/*------------------------------------------------------------------------*/ -int my_device_unregister(struct device *dev) -{ - if (dev->driver && dev->driver->remove) - dev->driver->remove(dev); - return 0; - -} -/*------------------------------------------------------------------------*/ -struct device *my_get_device(struct device *dev) -{ - return NULL; -} -/*------------------------------------------------------------------------*/ -void my_device_initialize(struct device *dev) -{ -} -/*------------------------------------------------------------------------*/ -void my_wake_up(PKEVENT evnt) -{ - need_wakeup=1; - - KeSetEvent(evnt, 0, FALSE); // Signal event -} -/*------------------------------------------------------------------------*/ -void my_init_waitqueue_head(PKEVENT evnt) -{ - // this is used only in core/message.c, and it isn't needed there - //KeInitializeEvent(evnt, NotificationEvent, TRUE); // signalled state -} -/*------------------------------------------------------------------------*/ -/* wait until woken up (only one wait allowed!) */ -int my_schedule_timeout(int x) -{ - int wait=1; - x+=10; // safety -// printk("schedule_timeout %i\n",x); - while(x>0) - { - do_all_timers(); -#ifndef HAVE_IRQS - handle_irqs(-1); - -#endif - if (need_wakeup) - break; - wait_ms(wait); - inc_jiffies(wait); - x-=wait; - } - need_wakeup=0; -// printk("schedule DONE!!!!!!\n"); - return x; -} -/*------------------------------------------------------------------------*/ -void my_wait_for_completion(struct completion *x) -{ - int n=100; -// printk("wait for completion\n"); - while(!x->done && (n>0)) - { - do_all_timers(); -#ifndef HAVE_IRQS - handle_irqs(-1); - -#endif - wait_ms(10); - n--; - } -// printk("wait for completion done %i\n",x->done); -} -/*------------------------------------------------------------------------*/ -void my_interruptible_sleep_on(PKEVENT evnt) -{ - KeWaitForSingleObject(evnt, Executive, KernelMode, FALSE, NULL); - KeClearEvent(evnt); // reset to not-signalled -} -/*------------------------------------------------------------------------*/ -// Helper for pci_module_init -/*------------------------------------------------------------------------*/ -int my_pci_module_init(struct pci_driver *x) -{ - struct pci_dev *dev=pci_probe_dev; - const struct pci_device_id *id=NULL; - if (!pci_probe_dev) - { - printk(KERN_ERR "PCI device not set!\n"); - return 0; - } - x->probe(dev, id); - return 0; -} -/*------------------------------------------------------------------------*/ -struct pci_dev *my_pci_find_slot(int a,int b) -{ - return NULL; -} -/*------------------------------------------------------------------------*/ -int my_pci_write_config_word(struct pci_dev *dev, int where, u16 val) -{ - //dev->bus, dev->devfn, where, val - OHCI_DEVICE_EXTENSION *dev_ext = (OHCI_DEVICE_EXTENSION *)dev->dev_ext; - - //FIXME: Is returning this value correct? - //FIXME: Mixing pci_dev and win structs isn't a good thing at all - return HalSetBusDataByOffset(PCIConfiguration, dev->bus->number, dev_ext->SystemIoSlotNumber, &val, where, sizeof(val)); -} -/*------------------------------------------------------------------------*/ -int my_request_irq(unsigned int irq, - int (*handler)(int,void *, struct pt_regs *), - unsigned long mode, const char *desc, void *data) -{ - if (num_irqsfunction && main_timer_list[n]->expires) + { + void (*function)(unsigned long)=main_timer_list[n]->function; + unsigned long data=main_timer_list[n]->data; + main_timer_list[n]->expires=0; + + main_timer_list[n]=NULL; // remove timer + printk("do timer %i fn %p\n",n,function); + + function(data); + } + } +} +/*------------------------------------------------------------------------*/ +// Purpose: Remember thread procedure and data in global var +// ReactOS Purpose: Create real kernel thread +int my_kernel_thread(int STDCALL (*handler)(void*), void* parm, int flags) +{ + HANDLE hThread; + //thread_handler=handler; + //thread_parm=parm; + //return 42; // PID :-) + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + PsCreateSystemThread(&hThread, + THREAD_ALL_ACCESS, + NULL, + NULL, + NULL, + (PKSTART_ROUTINE)handler, + parm); + + return (int)hThread; // FIXME: Correct? +} + +// Kill the process +int my_kill_proc(int pid, int signal, int unk) +{ + HANDLE hThread; + + // TODO: Implement actual process killing + + hThread = (HANDLE)pid; + ZwClose(hThread); + + return 0; +} + +/*------------------------------------------------------------------------*/ +/* Device management + * As simple as possible, but as complete as necessary ... + */ +/*------------------------------------------------------------------------*/ + + +/* calls probe function for hotplug (which does device matching), this is the +only link between usbcore and the registered device drivers! */ +int my_device_add(struct device *dev) +{ + int n,found=0; + printk("drv_num %i %p %p\n",drvs_num,m_drivers[0]->probe,m_drivers[1]->probe); + + if (dev->driver) + { + if (dev->driver->probe) + return dev->driver->probe(dev); + } + else + { + for(n=0;nprobe) + { + dev->driver=m_drivers[n]; + printk("probe%i %p ",n,m_drivers[n]->probe); + + if (m_drivers[n]->probe(dev) == 0) + { +// return 0; + found=1; + } + } + } + if (found) return 0; + } + dev->driver=NULL; + return -ENODEV; +} +/*------------------------------------------------------------------------*/ +int my_driver_register(struct device_driver *driver) +{ + + if (drvs_numprobe); + + m_drivers[drvs_num++]=driver; + return 0; + } + return -1; +} +/*------------------------------------------------------------------------*/ +int my_device_unregister(struct device *dev) +{ + if (dev->driver && dev->driver->remove) + dev->driver->remove(dev); + return 0; + +} +/*------------------------------------------------------------------------*/ +struct device *my_get_device(struct device *dev) +{ + return NULL; +} +/*------------------------------------------------------------------------*/ +void my_device_initialize(struct device *dev) +{ +} +/*------------------------------------------------------------------------*/ +void my_wake_up(PKEVENT evnt) +{ + need_wakeup=1; + + KeSetEvent(evnt, 0, FALSE); // Signal event +} +/*------------------------------------------------------------------------*/ +void my_init_waitqueue_head(PKEVENT evnt) +{ + // this is used only in core/message.c, and it isn't needed there + //KeInitializeEvent(evnt, NotificationEvent, TRUE); // signalled state +} +/*------------------------------------------------------------------------*/ +/* wait until woken up (only one wait allowed!) */ +int my_schedule_timeout(int x) +{ + int wait=1; + x+=10; // safety + printk("schedule_timeout %i\n",x); + + while(x>0) + { + do_all_timers(); +#ifndef HAVE_IRQS + handle_irqs(-1); + +#endif + if (need_wakeup) + break; + wait_ms(wait); + inc_jiffies(wait); + x-=wait; + } + need_wakeup=0; + printk("schedule DONE!!!!!!\n"); + + return x; +} +/*------------------------------------------------------------------------*/ +void my_wait_for_completion(struct completion *x) +{ + int n=100; + printk("wait for completion\n"); + + while(!x->done && (n>0)) + { + do_all_timers(); +#ifndef HAVE_IRQS + handle_irqs(-1); + +#endif + wait_ms(10); + n--; + } + printk("wait for completion done %i\n",x->done); + +} +/*------------------------------------------------------------------------*/ +void my_interruptible_sleep_on(PKEVENT evnt) +{ + KeWaitForSingleObject(evnt, Executive, KernelMode, FALSE, NULL); + KeClearEvent(evnt); // reset to not-signalled +} +/*------------------------------------------------------------------------*/ +// Helper for pci_module_init +/*------------------------------------------------------------------------*/ +int my_pci_module_init(struct pci_driver *x) +{ + struct pci_dev *dev=pci_probe_dev; + const struct pci_device_id *id=NULL; + if (!pci_probe_dev) + { + DPRINT1("PCI device not set!\n"); + return 0; + } + x->probe(dev, id); + return 0; +} +/*------------------------------------------------------------------------*/ +struct pci_dev *my_pci_find_slot(int a,int b) +{ + return NULL; +} +/*------------------------------------------------------------------------*/ +int my_pci_write_config_word(struct pci_dev *dev, int where, u16 val) +{ + //dev->bus, dev->devfn, where, val + OHCI_DEVICE_EXTENSION *dev_ext = (OHCI_DEVICE_EXTENSION *)dev->dev_ext; + + //FIXME: Is returning this value correct? + //FIXME: Mixing pci_dev and win structs isn't a good thing at all + return HalSetBusDataByOffset(PCIConfiguration, dev->bus->number, dev_ext->SystemIoSlotNumber, &val, where, sizeof(val)); +} +/*------------------------------------------------------------------------*/ +int my_request_irq(unsigned int irq, + int (*handler)(int,void *, struct pt_regs *), + unsigned long mode, const char *desc, void *data) +{ + if (num_irqs0x30)&&(xpad_button_history[selected_Button]==0)) { - // Button Rising Edge - xpad_button_history[selected_Button] = 1; - return 1; - } - - if ((Button==0x00)&&(xpad_button_history[selected_Button]==1)) { - // Button Falling Edge - xpad_button_history[selected_Button] = 0; - return -1; - } - } - - if ((selected_Button > 5) & (selected_Button < 10) ) { - - unsigned char Buttonmask; - - switch (selected_Button) { - case TRIGGER_XPAD_PAD_UP : - Buttonmask = XPAD_PAD_UP; - break; - case TRIGGER_XPAD_PAD_DOWN : - Buttonmask = XPAD_PAD_DOWN; - break; - case TRIGGER_XPAD_PAD_LEFT : - Buttonmask = XPAD_PAD_LEFT; - break; - case TRIGGER_XPAD_PAD_RIGHT : - Buttonmask = XPAD_PAD_RIGHT; - break; - } - - // Rising Edge - if (((XPAD_current[0].pad&Buttonmask) != 0) & ((xpad_button_history[6]&Buttonmask) == 0)) { - xpad_button_history[6] ^= Buttonmask; // Flip the Bit - return 1; - } - // Falling Edge - if (((XPAD_current[0].pad&Buttonmask) == 0) & ((xpad_button_history[6]&Buttonmask) != 0)) { - xpad_button_history[6] ^= Buttonmask; // Flip the Bit - return -1; - } - } - return 0; -} +#include "../usb_wrapper.h" +#include "config.h" +#include "xremote.h" + +// This is for the Xpad +extern unsigned char xpad_button_history[7]; + +// This is for the Keyboard +extern unsigned int current_keyboard_key; + +int risefall_xpad_BUTTON(unsigned char selected_Button) { + + int xpad_id; + int match; + extern int xpad_num; + + // USB keyboard section + + match=0; + if (current_keyboard_key!=0) { + switch (selected_Button) { + case TRIGGER_XPAD_KEY_A : + if (current_keyboard_key == 0x28) match=1; + break; + case TRIGGER_XPAD_KEY_B : + if (current_keyboard_key == 0x29) match=1; + break; + case TRIGGER_XPAD_PAD_UP : + if (current_keyboard_key == 0x52) match=1; + break; + case TRIGGER_XPAD_PAD_DOWN : + if (current_keyboard_key == 0x51) match=1; + break; + case TRIGGER_XPAD_PAD_LEFT : + if (current_keyboard_key == 0x50) match=1; + break; + case TRIGGER_XPAD_PAD_RIGHT : + if (current_keyboard_key == 0x4f) match=1; + break; + } + + if (match) { + //A match occurred, so the event has now been processed + //Clear it, and return success + current_keyboard_key=0; + return 1; + } + } + + // Xbox IR remote section + + match=0; + if (!remotekeyIsRepeat) { + /* We only grab the key event when the button is first pressed. + * If it's being held down, we ignore the multiple events this + * generates */ + + switch (selected_Button) { + case TRIGGER_XPAD_KEY_A: + if (current_remote_key == RC_KEY_SELECT) match=1; + break; + case TRIGGER_XPAD_PAD_UP: + if (current_remote_key == RC_KEY_UP) match=1; + break; + case TRIGGER_XPAD_PAD_DOWN: + if (current_remote_key == RC_KEY_DOWN) match=1; + break; + case TRIGGER_XPAD_PAD_LEFT: + if (current_remote_key == RC_KEY_LEFT) match=1; + break; + case TRIGGER_XPAD_PAD_RIGHT: + if (current_remote_key == RC_KEY_RIGHT) match=1; + break; + case TRIGGER_XPAD_KEY_BACK: + if (current_remote_key == RC_KEY_BACK) match=1; + break; + } + if (match) { + //A match occurred, so the event has now been processed + //Clear it, and return success + current_remote_key=0; + remotekeyIsRepeat=0; + return 1; + } + } + + // Xbox controller section + if (selected_Button < 6) { + + unsigned char Button; + + Button = XPAD_current[0].keys[selected_Button]; + + if ((Button>0x30)&&(xpad_button_history[selected_Button]==0)) { + // Button Rising Edge + xpad_button_history[selected_Button] = 1; + return 1; + } + + if ((Button==0x00)&&(xpad_button_history[selected_Button]==1)) { + // Button Falling Edge + xpad_button_history[selected_Button] = 0; + return -1; + } + } + + if ((selected_Button > 5) & (selected_Button < 10) ) { + + unsigned char Buttonmask; + + switch (selected_Button) { + case TRIGGER_XPAD_PAD_UP : + Buttonmask = XPAD_PAD_UP; + break; + case TRIGGER_XPAD_PAD_DOWN : + Buttonmask = XPAD_PAD_DOWN; + break; + case TRIGGER_XPAD_PAD_LEFT : + Buttonmask = XPAD_PAD_LEFT; + break; + case TRIGGER_XPAD_PAD_RIGHT : + Buttonmask = XPAD_PAD_RIGHT; + break; + } + + // Rising Edge + if (((XPAD_current[0].pad&Buttonmask) != 0) & ((xpad_button_history[6]&Buttonmask) == 0)) { + xpad_button_history[6] ^= Buttonmask; // Flip the Bit + return 1; + } + // Falling Edge + if (((XPAD_current[0].pad&Buttonmask) == 0) & ((xpad_button_history[6]&Buttonmask) != 0)) { + xpad_button_history[6] ^= Buttonmask; // Flip the Bit + return -1; + } + } + return 0; +} diff --git a/reactos/drivers/usb/cromwell/sys/ros_wrapper.c b/reactos/drivers/usb/cromwell/sys/ros_wrapper.c index d97f1c6aa40..9a27f77ff44 100644 --- a/reactos/drivers/usb/cromwell/sys/ros_wrapper.c +++ b/reactos/drivers/usb/cromwell/sys/ros_wrapper.c @@ -1,10 +1,10 @@ -#include "../usb_wrapper.h" - - -void wait_ms(int mils) -{ - LARGE_INTEGER Interval; - - Interval.QuadPart = -mils*10; - KeDelayExecutionThread(KernelMode, FALSE, &Interval); -} +#include "../usb_wrapper.h" + + +void wait_ms(int mils) +{ + LARGE_INTEGER Interval; + + Interval.QuadPart = -mils*10; + KeDelayExecutionThread(KernelMode, FALSE, &Interval); +} diff --git a/reactos/drivers/usb/cromwell/sys/usbkey.c b/reactos/drivers/usb/cromwell/sys/usbkey.c index efb237d49a9..cab2d1e591d 100644 --- a/reactos/drivers/usb/cromwell/sys/usbkey.c +++ b/reactos/drivers/usb/cromwell/sys/usbkey.c @@ -1,123 +1,123 @@ -#include "../usb_wrapper.h" - -#define keyboarddebug 0 - -#if keyboarddebug -extern int printe(const char *szFormat, ...); -int ycoffset = 0; -#endif - -unsigned int current_keyboard_key; - -struct usb_kbd_info { - struct urb *urb; - unsigned char kbd_pkt[8]; - unsigned char old[8]; - - /* - struct input_dev dev; - struct usb_device *usbdev; - struct urb irq, led; - struct usb_ctrlrequest dr; - unsigned char leds, newleds; - char name[128]; - int open; - */ -}; - -static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs) -{ - struct usb_kbd_info *kbd = urb->context; - int i; - - if (urb->status) return; - - memcpy(kbd->kbd_pkt, urb->transfer_buffer, 8); - - current_keyboard_key = kbd->kbd_pkt[2]; - - - #if keyboarddebug - ycoffset += 15; - ycoffset = ycoffset % 600; - VIDEO_CURSOR_POSX=20; - VIDEO_CURSOR_POSY=ycoffset; - printe(" -%02x %02x %02x %02x %02x %02x\n",kbd->kbd_pkt[0],kbd->kbd_pkt[1],kbd->kbd_pkt[2],kbd->kbd_pkt[3],kbd->kbd_pkt[4],kbd->kbd_pkt[5]); - #endif - - usb_submit_urb(urb,GFP_ATOMIC); - -} - -static int usb_kbd_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct urb *urb; - struct usb_device *udev = interface_to_usbdev (intf); - struct usb_endpoint_descriptor *ep_irq_in; - struct usb_endpoint_descriptor *ep_irq_out; - struct usb_kbd_info *usbk; - - int i, pipe, maxp; - char *buf; - - usbk=(struct usb_kbd_info *)kmalloc(sizeof(struct usb_kbd_info),0); - if (!usbk) return -1; - - urb=usb_alloc_urb(0,0); - if (!urb) return -1; - - usbk->urb=urb; - - ep_irq_in = &intf->altsetting[0].endpoint[0].desc; - usb_fill_int_urb(urb, udev, - usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), - usbk->kbd_pkt, 8, usb_kbd_irq, - usbk, 8); - - usb_submit_urb(urb,GFP_ATOMIC); - usb_set_intfdata(intf,usbk); - #if keyboarddebug - printe("USB Keyboard Connected\n"); - #endif -} - - -static void usb_kbd_disconnect(struct usb_interface *intf) -{ - struct usb_kbd_info *usbk = usb_get_intfdata (intf); - usbprintk("Keyboard disconnected\n "); - usb_unlink_urb(usbk->urb); - usb_free_urb(usbk->urb); - kfree(usbk); -} - -static struct usb_device_id usb_kbd_id_table [] = { - { USB_INTERFACE_INFO(3, 1, 1) }, - { } /* Terminating entry */ -}; - - -static struct usb_driver usb_kbd_driver = { - .owner = THIS_MODULE, - .name = "keyboard", - .probe = usb_kbd_probe, - .disconnect = usb_kbd_disconnect, - .id_table = usb_kbd_id_table, -}; - -void UsbKeyBoardInit(void) -{ - - //current_remote_key=0; - //sbprintk("Keyboard probe %p ",xremote_probe); - if (usb_register(&usb_kbd_driver) < 0) { - #if keyboarddebug - printe("Unable to register Keyboard driver"); - #endif - return; - } -} - -void UsbKeyBoardRemove(void) { - usb_deregister(&usb_kbd_driver); -} +#include "../usb_wrapper.h" + +#define keyboarddebug 0 + +#if keyboarddebug +extern int printe(const char *szFormat, ...); +int ycoffset = 0; +#endif + +unsigned int current_keyboard_key; + +struct usb_kbd_info { + struct urb *urb; + unsigned char kbd_pkt[8]; + unsigned char old[8]; + + /* + struct input_dev dev; + struct usb_device *usbdev; + struct urb irq, led; + struct usb_ctrlrequest dr; + unsigned char leds, newleds; + char name[128]; + int open; + */ +}; + +static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs) +{ + struct usb_kbd_info *kbd = urb->context; + int i; + + if (urb->status) return; + + memcpy(kbd->kbd_pkt, urb->transfer_buffer, 8); + + current_keyboard_key = kbd->kbd_pkt[2]; + + + #if keyboarddebug + ycoffset += 15; + ycoffset = ycoffset % 600; + VIDEO_CURSOR_POSX=20; + VIDEO_CURSOR_POSY=ycoffset; + printe(" -%02x %02x %02x %02x %02x %02x\n",kbd->kbd_pkt[0],kbd->kbd_pkt[1],kbd->kbd_pkt[2],kbd->kbd_pkt[3],kbd->kbd_pkt[4],kbd->kbd_pkt[5]); + #endif + + usb_submit_urb(urb,GFP_ATOMIC); + +} + +static int usb_kbd_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct urb *urb; + struct usb_device *udev = interface_to_usbdev (intf); + struct usb_endpoint_descriptor *ep_irq_in; + struct usb_endpoint_descriptor *ep_irq_out; + struct usb_kbd_info *usbk; + + int i, pipe, maxp; + char *buf; + + usbk=(struct usb_kbd_info *)kmalloc(sizeof(struct usb_kbd_info),0); + if (!usbk) return -1; + + urb=usb_alloc_urb(0,0); + if (!urb) return -1; + + usbk->urb=urb; + + ep_irq_in = &intf->altsetting[0].endpoint[0].desc; + usb_fill_int_urb(urb, udev, + usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), + usbk->kbd_pkt, 8, usb_kbd_irq, + usbk, 8); + + usb_submit_urb(urb,GFP_ATOMIC); + usb_set_intfdata(intf,usbk); + #if keyboarddebug + printe("USB Keyboard Connected\n"); + #endif +} + + +static void usb_kbd_disconnect(struct usb_interface *intf) +{ + struct usb_kbd_info *usbk = usb_get_intfdata (intf); + usbprintk("Keyboard disconnected\n "); + usb_unlink_urb(usbk->urb); + usb_free_urb(usbk->urb); + kfree(usbk); +} + +static struct usb_device_id usb_kbd_id_table [] = { + { USB_INTERFACE_INFO(3, 1, 1) }, + { } /* Terminating entry */ +}; + + +static struct usb_driver usb_kbd_driver = { + .owner = THIS_MODULE, + .name = "keyboard", + .probe = usb_kbd_probe, + .disconnect = usb_kbd_disconnect, + .id_table = usb_kbd_id_table, +}; + +void UsbKeyBoardInit(void) +{ + + //current_remote_key=0; + //sbprintk("Keyboard probe %p ",xremote_probe); + if (usb_register(&usb_kbd_driver) < 0) { + #if keyboarddebug + printe("Unable to register Keyboard driver"); + #endif + return; + } +} + +void UsbKeyBoardRemove(void) { + usb_deregister(&usb_kbd_driver); +} diff --git a/reactos/drivers/usb/cromwell/sys/usbwrapper.c b/reactos/drivers/usb/cromwell/sys/usbwrapper.c index f2de2204543..ce952e4ab4a 100644 --- a/reactos/drivers/usb/cromwell/sys/usbwrapper.c +++ b/reactos/drivers/usb/cromwell/sys/usbwrapper.c @@ -1,65 +1,65 @@ -/* - * Interface calls to BIOS - * - * 2003-06-21 Georg Acher (georg@acher.org) - * - */ - -#include "boot.h" -#include -#include "video.h" - -/*------------------------------------------------------------------------*/ -// Output window for USB messages -int usb_curs_x=0; -int usb_curs_y=0; - -void zxprintf(char* fmt, ...) -{ - va_list ap; - char buffer[1024]; - int tmp_x, tmp_y; - tmp_x=VIDEO_CURSOR_POSX; - tmp_y=VIDEO_CURSOR_POSY; - - VIDEO_CURSOR_POSX=usb_curs_x; - VIDEO_CURSOR_POSY=usb_curs_y; - - if ((VIDEO_CURSOR_POSY==0) || (VIDEO_CURSOR_POSY > (vmode.height -16))) - { - BootVideoClearScreen(&jpegBackdrop, 3*vmode.height/4, - vmode.height); - VIDEO_CURSOR_POSY=3*vmode.height/4; - } - - va_start(ap, fmt); - vsprintf(buffer,fmt,ap); - //printk(buffer); - va_end(ap); - - usb_curs_x=VIDEO_CURSOR_POSX; - usb_curs_y=VIDEO_CURSOR_POSY; - VIDEO_CURSOR_POSX=tmp_x; - VIDEO_CURSOR_POSY=tmp_y; -} -/*------------------------------------------------------------------------*/ -int zxsnprintf(char *buffer, size_t s, char* fmt, ...) -{ - va_list ap; - int x; - va_start(ap, fmt); - x=vsprintf(buffer,fmt,ap); - va_end(ap); - return x; -} -/*------------------------------------------------------------------------*/ -int zxsprintf(char *buffer, char* fmt, ...) -{ - va_list ap; - int x; - va_start(ap, fmt); - x=vsprintf(buffer,fmt,ap); - va_end(ap); - return x; -} -/*------------------------------------------------------------------------*/ +/* + * Interface calls to BIOS + * + * 2003-06-21 Georg Acher (georg@acher.org) + * + */ + +#include "boot.h" +#include +#include "video.h" + +/*------------------------------------------------------------------------*/ +// Output window for USB messages +int usb_curs_x=0; +int usb_curs_y=0; + +void zxprintf(char* fmt, ...) +{ + va_list ap; + char buffer[1024]; + int tmp_x, tmp_y; + tmp_x=VIDEO_CURSOR_POSX; + tmp_y=VIDEO_CURSOR_POSY; + + VIDEO_CURSOR_POSX=usb_curs_x; + VIDEO_CURSOR_POSY=usb_curs_y; + + if ((VIDEO_CURSOR_POSY==0) || (VIDEO_CURSOR_POSY > (vmode.height -16))) + { + BootVideoClearScreen(&jpegBackdrop, 3*vmode.height/4, + vmode.height); + VIDEO_CURSOR_POSY=3*vmode.height/4; + } + + va_start(ap, fmt); + vsprintf(buffer,fmt,ap); + //printk(buffer); + va_end(ap); + + usb_curs_x=VIDEO_CURSOR_POSX; + usb_curs_y=VIDEO_CURSOR_POSY; + VIDEO_CURSOR_POSX=tmp_x; + VIDEO_CURSOR_POSY=tmp_y; +} +/*------------------------------------------------------------------------*/ +int zxsnprintf(char *buffer, size_t s, char* fmt, ...) +{ + va_list ap; + int x; + va_start(ap, fmt); + x=vsprintf(buffer,fmt,ap); + va_end(ap); + return x; +} +/*------------------------------------------------------------------------*/ +int zxsprintf(char *buffer, char* fmt, ...) +{ + va_list ap; + int x; + va_start(ap, fmt); + x=vsprintf(buffer,fmt,ap); + va_end(ap); + return x; +} +/*------------------------------------------------------------------------*/ diff --git a/reactos/drivers/usb/cromwell/sys/xpad.c b/reactos/drivers/usb/cromwell/sys/xpad.c index e6d3122c80f..55360369955 100644 --- a/reactos/drivers/usb/cromwell/sys/xpad.c +++ b/reactos/drivers/usb/cromwell/sys/xpad.c @@ -1,183 +1,183 @@ -/* - * Simple XPAD driver for XBOX - * - * (c) 2003-07-04, Georg Acher (georg@acher.org) - * - * Inspired by linux/drivers/usb/input/xpad.c - * by Marko Friedemann - * - */ - - - -#include "../usb_wrapper.h" -#include "config.h" - -// history for the Rising - falling events -unsigned char xpad_button_history[7]; - -/* Stores time and XPAD state */ -struct xpad_data XPAD_current[4]; -struct xpad_data XPAD_last[4]; - -struct xpad_info -{ - struct urb *urb; - int num; - unsigned char data[32]; -}; - -int xpad_num=0; -/*------------------------------------------------------------------------*/ -static void xpad_irq(struct urb *urb, struct pt_regs *regs) -{ - struct xpad_info *xpi = urb->context; - unsigned char* data= urb->transfer_buffer; - -// struct xpad_data *xp=&XPAD_current[xpi->num]; -// struct xpad_data *xpo=&XPAD_last[xpi->num]; - - /* This hack means the xpad event always gets posted to the - * first xpad - avoids problems iterating over multiple xpads - * as the xpi->num entries are not reused when xpads are - * connected, then removed */ - - struct xpad_data *xp=&XPAD_current[0]; - struct xpad_data *xpo=&XPAD_last[0]; - - if (xpi->num<0 || xpi->num>3) - return; - - memcpy(xpo,xp,sizeof(struct xpad_data)); - - xp->stick_left_x=(short) (((short)data[13] << 8) | data[12]); - xp->stick_left_y=(short) (((short)data[15] << 8) | data[14]); - xp->stick_right_x=(short) (((short)data[17] << 8) | data[16]); - xp->stick_right_y=(short) (((short)data[19] << 8) | data[18]); - xp->trig_left= data[10]; - xp->trig_right= data[11]; - xp->pad = data[2]&0xf; - xp->state = (data[2]>>4)&0xf; - xp->keys[0] = data[4]; // a - xp->keys[1] = data[5]; // b - xp->keys[2] = data[6]; // x - xp->keys[3] = data[7]; // y - xp->keys[4] = data[8]; // black - xp->keys[5] = data[9]; // white - xp->timestamp=jiffies; // FIXME: A more uniform flowing time would be better... - usb_submit_urb(urb,GFP_ATOMIC); - -} -/*------------------------------------------------------------------------*/ -static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct urb *urb; - struct usb_device *udev = interface_to_usbdev (intf); - struct usb_endpoint_descriptor *ep_irq_in; - struct usb_endpoint_descriptor *ep_irq_out; - struct xpad_info *xpi; - - xpi=kmalloc(sizeof(struct xpad_info),GFP_KERNEL); - if (!xpi) return -1; - - urb=usb_alloc_urb(0,0); - if (!urb) return -1; - - xpi->urb=urb; - xpi->num=xpad_num; - ep_irq_in = &intf->altsetting[0].endpoint[0].desc; - usb_fill_int_urb(urb, udev, - usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), - xpi->data, 32, xpad_irq, - xpi, 32); - - usb_submit_urb(urb,GFP_ATOMIC); - - usb_set_intfdata(intf,xpi); - usbprintk("XPAD #%i connected\n",xpad_num); - #ifdef XPAD_VIBRA_STARTUP - { - // Brum Brum - char data1[6]={0,6,0,120,0,120}; - char data2[6]={0,6,0,0,0,0}; - int dummy; - - usb_bulk_msg(udev, usb_sndbulkpipe(udev,2), - data1, 6, &dummy, 500); - wait_ms(500); - usb_bulk_msg(udev, usb_sndbulkpipe(udev,2), - data2, 6, &dummy, 500); - } - #endif - xpad_num++; - return 0; -} -/*------------------------------------------------------------------------*/ -static void xpad_disconnect(struct usb_interface *intf) -{ - struct xpad_info *xpi=usb_get_intfdata (intf); - usb_unlink_urb(xpi->urb); - usb_free_urb(xpi->urb); - kfree(xpi); - xpad_num--; -} -/*------------------------------------------------------------------------*/ -static struct usb_device_id xpad_ids [] = { - { USB_DEVICE(0x044f, 0x0f07) },//Thrustmaster, Inc. Controller - { USB_DEVICE(0x045e, 0x0202) },//Microsoft Xbox Controller - { USB_DEVICE(0x045e, 0x0285) },//Microsoft Xbox Controller S - { USB_DEVICE(0x045e, 0x0289) },//Microsoft Xbox Controller S - { USB_DEVICE(0x046d, 0xca88) },//Logitech Compact Controller for Xbox - { USB_DEVICE(0x05fd, 0x1007) },//???Mad Catz Controller??? - { USB_DEVICE(0x05fd, 0x107a) },//InterAct PowerPad Pro - { USB_DEVICE(0x0738, 0x4516) },//Mad Catz Control Pad - { USB_DEVICE(0x0738, 0x4522) },//Mad Catz LumiCON - { USB_DEVICE(0x0738, 0x4526) },//Mad Catz Control Pad Pro - { USB_DEVICE(0x0738, 0x4536) },//Mad Catz MicroCON - { USB_DEVICE(0x0738, 0x4556) },//Mad Catz Lynx Wireless Controller - { USB_DEVICE(0x0c12, 0x9902) },//HAMA VibraX - *FAULTY HARDWARE* - { USB_DEVICE(0x0e4c, 0x1097) },//Radica Gamester Controller - { USB_DEVICE(0x0e4c, 0x2390) },//Radica Games Jtech Controller - { USB_DEVICE(0x0e6f, 0x0003) },//Logic3 Freebird wireless Controller - { USB_DEVICE(0x0e6f, 0x0005) },//Eclipse wireless Controlle - { USB_DEVICE(0x0f30, 0x0202) },//Joytech Advanced Controller - { USB_DEVICE(0xffff, 0xffff) },//Chinese-made Xbox Controller - { USB_DEVICE(0x0000, 0x0000) }, // nothing detected - FAIL - { } /* Terminating entry */ -}; - - -static struct usb_driver xpad_driver = { - .owner = THIS_MODULE, - .name = "XPAD", - .probe = xpad_probe, - .disconnect = xpad_disconnect, - .id_table = xpad_ids, -}; - -/*------------------------------------------------------------------------*/ -void XPADInit(void) -{ - int n; - for(n=0;n<4;n++) - { - memset(&XPAD_current[n], 0, sizeof(struct xpad_data)); - memset(&XPAD_last[n], 0, sizeof(struct xpad_data)); - } - memset(&xpad_button_history, 0, sizeof(xpad_button_history)); - - usbprintk("XPAD probe %p ",xpad_probe); - if (usb_register(&xpad_driver) < 0) { - err("Unable to register XPAD driver"); - return; - } -} -/*------------------------------------------------------------------------*/ -void XPADRemove(void) { - usb_deregister(&xpad_driver); -} - -/*------------------------------------------------------------------------*/ - - - +/* + * Simple XPAD driver for XBOX + * + * (c) 2003-07-04, Georg Acher (georg@acher.org) + * + * Inspired by linux/drivers/usb/input/xpad.c + * by Marko Friedemann + * + */ + + + +#include "../usb_wrapper.h" +#include "config.h" + +// history for the Rising - falling events +unsigned char xpad_button_history[7]; + +/* Stores time and XPAD state */ +struct xpad_data XPAD_current[4]; +struct xpad_data XPAD_last[4]; + +struct xpad_info +{ + struct urb *urb; + int num; + unsigned char data[32]; +}; + +int xpad_num=0; +/*------------------------------------------------------------------------*/ +static void xpad_irq(struct urb *urb, struct pt_regs *regs) +{ + struct xpad_info *xpi = urb->context; + unsigned char* data= urb->transfer_buffer; + +// struct xpad_data *xp=&XPAD_current[xpi->num]; +// struct xpad_data *xpo=&XPAD_last[xpi->num]; + + /* This hack means the xpad event always gets posted to the + * first xpad - avoids problems iterating over multiple xpads + * as the xpi->num entries are not reused when xpads are + * connected, then removed */ + + struct xpad_data *xp=&XPAD_current[0]; + struct xpad_data *xpo=&XPAD_last[0]; + + if (xpi->num<0 || xpi->num>3) + return; + + memcpy(xpo,xp,sizeof(struct xpad_data)); + + xp->stick_left_x=(short) (((short)data[13] << 8) | data[12]); + xp->stick_left_y=(short) (((short)data[15] << 8) | data[14]); + xp->stick_right_x=(short) (((short)data[17] << 8) | data[16]); + xp->stick_right_y=(short) (((short)data[19] << 8) | data[18]); + xp->trig_left= data[10]; + xp->trig_right= data[11]; + xp->pad = data[2]&0xf; + xp->state = (data[2]>>4)&0xf; + xp->keys[0] = data[4]; // a + xp->keys[1] = data[5]; // b + xp->keys[2] = data[6]; // x + xp->keys[3] = data[7]; // y + xp->keys[4] = data[8]; // black + xp->keys[5] = data[9]; // white + xp->timestamp=jiffies; // FIXME: A more uniform flowing time would be better... + usb_submit_urb(urb,GFP_ATOMIC); + +} +/*------------------------------------------------------------------------*/ +static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct urb *urb; + struct usb_device *udev = interface_to_usbdev (intf); + struct usb_endpoint_descriptor *ep_irq_in; + struct usb_endpoint_descriptor *ep_irq_out; + struct xpad_info *xpi; + + xpi=kmalloc(sizeof(struct xpad_info),GFP_KERNEL); + if (!xpi) return -1; + + urb=usb_alloc_urb(0,0); + if (!urb) return -1; + + xpi->urb=urb; + xpi->num=xpad_num; + ep_irq_in = &intf->altsetting[0].endpoint[0].desc; + usb_fill_int_urb(urb, udev, + usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), + xpi->data, 32, xpad_irq, + xpi, 32); + + usb_submit_urb(urb,GFP_ATOMIC); + + usb_set_intfdata(intf,xpi); + usbprintk("XPAD #%i connected\n",xpad_num); + #ifdef XPAD_VIBRA_STARTUP + { + // Brum Brum + char data1[6]={0,6,0,120,0,120}; + char data2[6]={0,6,0,0,0,0}; + int dummy; + + usb_bulk_msg(udev, usb_sndbulkpipe(udev,2), + data1, 6, &dummy, 500); + wait_ms(500); + usb_bulk_msg(udev, usb_sndbulkpipe(udev,2), + data2, 6, &dummy, 500); + } + #endif + xpad_num++; + return 0; +} +/*------------------------------------------------------------------------*/ +static void xpad_disconnect(struct usb_interface *intf) +{ + struct xpad_info *xpi=usb_get_intfdata (intf); + usb_unlink_urb(xpi->urb); + usb_free_urb(xpi->urb); + kfree(xpi); + xpad_num--; +} +/*------------------------------------------------------------------------*/ +static struct usb_device_id xpad_ids [] = { + { USB_DEVICE(0x044f, 0x0f07) },//Thrustmaster, Inc. Controller + { USB_DEVICE(0x045e, 0x0202) },//Microsoft Xbox Controller + { USB_DEVICE(0x045e, 0x0285) },//Microsoft Xbox Controller S + { USB_DEVICE(0x045e, 0x0289) },//Microsoft Xbox Controller S + { USB_DEVICE(0x046d, 0xca88) },//Logitech Compact Controller for Xbox + { USB_DEVICE(0x05fd, 0x1007) },//???Mad Catz Controller??? + { USB_DEVICE(0x05fd, 0x107a) },//InterAct PowerPad Pro + { USB_DEVICE(0x0738, 0x4516) },//Mad Catz Control Pad + { USB_DEVICE(0x0738, 0x4522) },//Mad Catz LumiCON + { USB_DEVICE(0x0738, 0x4526) },//Mad Catz Control Pad Pro + { USB_DEVICE(0x0738, 0x4536) },//Mad Catz MicroCON + { USB_DEVICE(0x0738, 0x4556) },//Mad Catz Lynx Wireless Controller + { USB_DEVICE(0x0c12, 0x9902) },//HAMA VibraX - *FAULTY HARDWARE* + { USB_DEVICE(0x0e4c, 0x1097) },//Radica Gamester Controller + { USB_DEVICE(0x0e4c, 0x2390) },//Radica Games Jtech Controller + { USB_DEVICE(0x0e6f, 0x0003) },//Logic3 Freebird wireless Controller + { USB_DEVICE(0x0e6f, 0x0005) },//Eclipse wireless Controlle + { USB_DEVICE(0x0f30, 0x0202) },//Joytech Advanced Controller + { USB_DEVICE(0xffff, 0xffff) },//Chinese-made Xbox Controller + { USB_DEVICE(0x0000, 0x0000) }, // nothing detected - FAIL + { } /* Terminating entry */ +}; + + +static struct usb_driver xpad_driver = { + .owner = THIS_MODULE, + .name = "XPAD", + .probe = xpad_probe, + .disconnect = xpad_disconnect, + .id_table = xpad_ids, +}; + +/*------------------------------------------------------------------------*/ +void XPADInit(void) +{ + int n; + for(n=0;n<4;n++) + { + memset(&XPAD_current[n], 0, sizeof(struct xpad_data)); + memset(&XPAD_last[n], 0, sizeof(struct xpad_data)); + } + memset(&xpad_button_history, 0, sizeof(xpad_button_history)); + + usbprintk("XPAD probe %p ",xpad_probe); + if (usb_register(&xpad_driver) < 0) { + err("Unable to register XPAD driver"); + return; + } +} +/*------------------------------------------------------------------------*/ +void XPADRemove(void) { + usb_deregister(&xpad_driver); +} + +/*------------------------------------------------------------------------*/ + + + diff --git a/reactos/drivers/usb/cromwell/sys/xremote.c b/reactos/drivers/usb/cromwell/sys/xremote.c index 7f53f211cc7..3b98dec8572 100644 --- a/reactos/drivers/usb/cromwell/sys/xremote.c +++ b/reactos/drivers/usb/cromwell/sys/xremote.c @@ -1,142 +1,142 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* - * $Id: xremote.c,v 1.5 2004/11/22 19:10:57 davidmpye Exp $ - * - * Copyright (c) 2002 Steven Toth - * - * XBOX DVD dongle infrared device driver for the input driver suite. - * - * This work was derived from the usbkbd.c kernel module. - * - * History: - * - * 2002_08_31 - 0.1 - Initial release - * 2002_09_02 - 0.2 - Added IOCTL support enabling user space administration - * of the translation matrix. - * - */ - -#include "../usb_wrapper.h" - - -u16 current_remote_key; -u8 remotekeyIsRepeat; - -struct xremote_info -{ - struct urb *urb; - unsigned char irpkt[8]; -}; - -/* USB callback completion handler - * Code in transfer_buffer is received as six unsigned chars - * Example PLAY=00 06 ea 0a 40 00 - * The command is located in byte[2], the rest are ignored. - * Key position is byte[4] bit0 (7-0 format) 0=down, 1=up - * All other bits are unknown / now required. - */ - -static void xremote_irq(struct urb *urb, struct pt_regs *regs) -{ - struct xremote_info *xri = urb->context; - - if (urb->status) return; - if (urb->actual_length < 6) return; - - /* Messy/unnecessary, fix this */ - memcpy(xri->irpkt, urb->transfer_buffer, 6); - - /* Set the key action based in the sent action */ - current_remote_key = ((xri->irpkt[2] & 0xff)<<8) | (xri->irpkt[3] & 0xff); - - if (((xri->irpkt[4] & 0xff) + ((xri->irpkt[5] & 0xff ) << 8))>0x41) { - remotekeyIsRepeat=0; - } - else remotekeyIsRepeat=1; - - usb_submit_urb(urb,GFP_ATOMIC); -} - -static int xremote_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct urb *urb; - struct usb_device *udev = interface_to_usbdev (intf); - struct usb_endpoint_descriptor *ep_irq_in; - struct usb_endpoint_descriptor *ep_irq_out; - struct xremote_info *xri; - - xri=(struct xremote_info *)kmalloc(sizeof(struct xremote_info),0); - if (!xri) return -1; - - urb=usb_alloc_urb(0,0); - if (!urb) return -1; - - xri->urb=urb; - - ep_irq_in = &intf->altsetting[0].endpoint[0].desc; - usb_fill_int_urb(urb, udev, - usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), - xri->irpkt, 8, xremote_irq, - xri, 8); - - usb_submit_urb(urb,GFP_ATOMIC); - usb_set_intfdata(intf,xri); - - usbprintk("DVD Remote connected\n"); - return 0; -} - -static void xremote_disconnect(struct usb_interface *intf) -{ - struct xremote_info *xri = usb_get_intfdata (intf); - usbprintk("DVD Remote disconnected\n "); - usb_unlink_urb(xri->urb); - usb_free_urb(xri->urb); - kfree(xri); -} - -static struct usb_device_id xremote_id_table [] = { - { USB_DEVICE(0x040b, 0x6521) }, /* Gamester Xbox DVD Movie Playback Kit IR */ - { USB_DEVICE(0x045e, 0x0284) }, /* Microsoft Xbox DVD Movie Playback Kit IR */ - { USB_DEVICE(0x0000, 0x0000) }, // nothing detected - FAIL - { } /* Terminating entry */ -}; - -static struct usb_driver xremote_driver = { - .owner = THIS_MODULE, - .name = "XRemote", - .probe = xremote_probe, - .disconnect = xremote_disconnect, - .id_table = xremote_id_table, -}; - -void XRemoteInit(void) -{ - - current_remote_key=0; - usbprintk("XRemote probe %p ",xremote_probe); - if (usb_register(&xremote_driver) < 0) { - err("Unable to register XRemote driver"); - return; - } -} - -void XRemoteRemove(void) { - usb_deregister(&xremote_driver); -} +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * $Id$ + * + * Copyright (c) 2002 Steven Toth + * + * XBOX DVD dongle infrared device driver for the input driver suite. + * + * This work was derived from the usbkbd.c kernel module. + * + * History: + * + * 2002_08_31 - 0.1 - Initial release + * 2002_09_02 - 0.2 - Added IOCTL support enabling user space administration + * of the translation matrix. + * + */ + +#include "../usb_wrapper.h" + + +u16 current_remote_key; +u8 remotekeyIsRepeat; + +struct xremote_info +{ + struct urb *urb; + unsigned char irpkt[8]; +}; + +/* USB callback completion handler + * Code in transfer_buffer is received as six unsigned chars + * Example PLAY=00 06 ea 0a 40 00 + * The command is located in byte[2], the rest are ignored. + * Key position is byte[4] bit0 (7-0 format) 0=down, 1=up + * All other bits are unknown / now required. + */ + +static void xremote_irq(struct urb *urb, struct pt_regs *regs) +{ + struct xremote_info *xri = urb->context; + + if (urb->status) return; + if (urb->actual_length < 6) return; + + /* Messy/unnecessary, fix this */ + memcpy(xri->irpkt, urb->transfer_buffer, 6); + + /* Set the key action based in the sent action */ + current_remote_key = ((xri->irpkt[2] & 0xff)<<8) | (xri->irpkt[3] & 0xff); + + if (((xri->irpkt[4] & 0xff) + ((xri->irpkt[5] & 0xff ) << 8))>0x41) { + remotekeyIsRepeat=0; + } + else remotekeyIsRepeat=1; + + usb_submit_urb(urb,GFP_ATOMIC); +} + +static int xremote_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct urb *urb; + struct usb_device *udev = interface_to_usbdev (intf); + struct usb_endpoint_descriptor *ep_irq_in; + struct usb_endpoint_descriptor *ep_irq_out; + struct xremote_info *xri; + + xri=(struct xremote_info *)kmalloc(sizeof(struct xremote_info),0); + if (!xri) return -1; + + urb=usb_alloc_urb(0,0); + if (!urb) return -1; + + xri->urb=urb; + + ep_irq_in = &intf->altsetting[0].endpoint[0].desc; + usb_fill_int_urb(urb, udev, + usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), + xri->irpkt, 8, xremote_irq, + xri, 8); + + usb_submit_urb(urb,GFP_ATOMIC); + usb_set_intfdata(intf,xri); + + usbprintk("DVD Remote connected\n"); + return 0; +} + +static void xremote_disconnect(struct usb_interface *intf) +{ + struct xremote_info *xri = usb_get_intfdata (intf); + usbprintk("DVD Remote disconnected\n "); + usb_unlink_urb(xri->urb); + usb_free_urb(xri->urb); + kfree(xri); +} + +static struct usb_device_id xremote_id_table [] = { + { USB_DEVICE(0x040b, 0x6521) }, /* Gamester Xbox DVD Movie Playback Kit IR */ + { USB_DEVICE(0x045e, 0x0284) }, /* Microsoft Xbox DVD Movie Playback Kit IR */ + { USB_DEVICE(0x0000, 0x0000) }, // nothing detected - FAIL + { } /* Terminating entry */ +}; + +static struct usb_driver xremote_driver = { + .owner = THIS_MODULE, + .name = "XRemote", + .probe = xremote_probe, + .disconnect = xremote_disconnect, + .id_table = xremote_id_table, +}; + +void XRemoteInit(void) +{ + + current_remote_key=0; + usbprintk("XRemote probe %p ",xremote_probe); + if (usb_register(&xremote_driver) < 0) { + err("Unable to register XRemote driver"); + return; + } +} + +void XRemoteRemove(void) { + usb_deregister(&xremote_driver); +} diff --git a/reactos/drivers/usb/cromwell/uhci/makefile b/reactos/drivers/usb/cromwell/uhci/makefile index b1170524da6..02196fed0a2 100644 --- a/reactos/drivers/usb/cromwell/uhci/makefile +++ b/reactos/drivers/usb/cromwell/uhci/makefile @@ -1,16 +1,16 @@ -PATH_TO_TOP = ../../../.. - -TARGET_TYPE = export_driver - -TARGET_NAME = uhci - -TARGET_DDKLIBS = ntoskrnl.a usbcore.a - -TARGET_CFLAGS = -Wall -I$(PATH_TO_TOP)/ntoskrnl/include -DDEBUG_MODE - -TARGET_OBJECTS = \ - uhci-hcd.o uhci_main.o ../sys/ros_wrapper.o ../sys/linuxwrapper.o - -include $(PATH_TO_TOP)/rules.mak - -include $(TOOLS_PATH)/helper.mk +PATH_TO_TOP = ../../../.. + +TARGET_TYPE = export_driver + +TARGET_NAME = uhci + +TARGET_DDKLIBS = ntoskrnl.a usbcore.a + +TARGET_CFLAGS = -Wall -I$(PATH_TO_TOP)/ntoskrnl/include -DDEBUG_MODE + +TARGET_OBJECTS = \ + uhci-hcd.o uhci_main.o ../sys/ros_wrapper.o ../sys/linuxwrapper.o + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk diff --git a/reactos/drivers/usb/cromwell/uhci/uhci-hcd.c b/reactos/drivers/usb/cromwell/uhci/uhci-hcd.c index 5960d58a720..99674c43e58 100644 --- a/reactos/drivers/usb/cromwell/uhci/uhci-hcd.c +++ b/reactos/drivers/usb/cromwell/uhci/uhci-hcd.c @@ -42,11 +42,15 @@ #include #include #include +#endif + #ifdef CONFIG_USB_DEBUG #define DEBUG #else #undef DEBUG #endif + +#if 0 #include #include @@ -79,9 +83,9 @@ * debug = 3, show all TD's in URB's when dumping */ #ifdef DEBUG -static int debug = 1; +static int debug = 3; #else -static int debug = 0; +static int debug = 2; #endif MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug level"); @@ -1873,7 +1877,7 @@ static void uhci_remove_pending_qhs(struct uhci_hcd *uhci) spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); } -static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) +static int uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned int io_addr = uhci->io_addr; @@ -1886,7 +1890,7 @@ static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) */ status = inw(io_addr + USBSTS); if (!status) /* shared interrupt, not mine */ - return; + return 0; outw(status, io_addr + USBSTS); /* Clear it */ if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { @@ -1925,6 +1929,8 @@ static void uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) spin_unlock(&uhci->urb_list_lock); uhci_finish_completion(hcd, regs); + + return 0; } static void reset_hc(struct uhci_hcd *uhci) @@ -2271,6 +2277,7 @@ static int __devinit uhci_start(struct usb_hcd *hcd) err("unable to allocate root hub"); goto err_alloc_root_hub; } + hcd->pdev->bus = (struct pci_bus *)udev; /* Fix bus pointer for initial device */ uhci->term_td = uhci_alloc_td(uhci, udev); if (!uhci->term_td) { @@ -2484,7 +2491,7 @@ static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) static const char hcd_name[] = "uhci-hcd"; -static const struct hc_driver uhci_driver = { +static struct hc_driver uhci_driver = { .description = hcd_name, /* Generic hardware linkage */ diff --git a/reactos/drivers/usb/cromwell/uhci/uhci.def b/reactos/drivers/usb/cromwell/uhci/uhci.def index b0ec75808f2..320634a6a47 100644 --- a/reactos/drivers/usb/cromwell/uhci/uhci.def +++ b/reactos/drivers/usb/cromwell/uhci/uhci.def @@ -1,2 +1,2 @@ -LIBRARY uhci.sys -EXPORTS +LIBRARY uhci.sys +EXPORTS diff --git a/reactos/drivers/usb/cromwell/uhci/uhci.rc b/reactos/drivers/usb/cromwell/uhci/uhci.rc index d5eb940f114..5acdfd37517 100644 --- a/reactos/drivers/usb/cromwell/uhci/uhci.rc +++ b/reactos/drivers/usb/cromwell/uhci/uhci.rc @@ -1,5 +1,5 @@ -#define REACTOS_VERSION_DLL -#define REACTOS_STR_FILE_DESCRIPTION "USB UHCI Device Driver\0" -#define REACTOS_STR_INTERNAL_NAME "uhci\0" -#define REACTOS_STR_ORIGINAL_FILENAME "uhci.sys\0" -#include +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "USB UHCI Device Driver\0" +#define REACTOS_STR_INTERNAL_NAME "uhci\0" +#define REACTOS_STR_ORIGINAL_FILENAME "uhci.sys\0" +#include diff --git a/reactos/drivers/usb/cromwell/uhci/uhci_config.h b/reactos/drivers/usb/cromwell/uhci/uhci_config.h index cd59c84d5b7..207aa328174 100644 --- a/reactos/drivers/usb/cromwell/uhci/uhci_config.h +++ b/reactos/drivers/usb/cromwell/uhci/uhci_config.h @@ -1,5 +1,5 @@ -/* - * Configs for UHCI - */ - -#define CONFIG_PCI +/* + * Configs for UHCI + */ + +#define CONFIG_PCI diff --git a/reactos/drivers/usb/cromwell/uhci/uhci_main.c b/reactos/drivers/usb/cromwell/uhci/uhci_main.c index be10f686fa6..b19cb498e3a 100644 --- a/reactos/drivers/usb/cromwell/uhci/uhci_main.c +++ b/reactos/drivers/usb/cromwell/uhci/uhci_main.c @@ -1,309 +1,337 @@ -/* - ReactOS specific functions for UHCI module - by Aleksey Bragin (aleksey@reactos.com) - Some parts of code are inspired (or even just copied) from ReactOS Videoport driver -*/ - -#include -#include -#include "../linux/linux_wrapper.h" -#include "../host/ohci_main.h" - -// declare basic init funcs -void init_wrapper(struct pci_dev *probe_dev); -int uhci_hcd_init(void); -void uhci_hcd_cleanup(void); -int STDCALL usb_init(void); -void STDCALL usb_exit(void); -extern struct pci_driver uhci_pci_driver; -extern const struct pci_device_id uhci_pci_ids[]; - - - -// This should be removed, but for testing purposes it's here -struct pci_dev *dev; -//struct pci_device_id *dev_id; - - -#define USB_UHCI_TAG TAG('u','s','b','u') - -NTSTATUS STDCALL AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo) -{ - PDEVICE_OBJECT fdo; - NTSTATUS Status; - WCHAR DeviceBuffer[20]; - UNICODE_STRING DeviceName; - POHCI_DRIVER_EXTENSION DriverExtension; - POHCI_DEVICE_EXTENSION DeviceExtension; - ULONG Size, DeviceNumber; - - DPRINT1("uhci: AddDevice called\n"); - - // Allocate driver extension now - DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); - if (DriverExtension == NULL) - { - Status = IoAllocateDriverObjectExtension( - DriverObject, - DriverObject, - sizeof(OHCI_DRIVER_EXTENSION), - (PVOID *)&DriverExtension); - - if (!NT_SUCCESS(Status)) - { - DPRINT1("Allocating DriverObjectExtension failed.\n"); - return Status; - } - } - - // Create a unicode device name - DeviceNumber = 0; //TODO: Allocate new device number every time - swprintf(DeviceBuffer, L"\\Device\\USBFDO-%lu", DeviceNumber); - RtlInitUnicodeString(&DeviceName, DeviceBuffer); - - Status = IoCreateDevice(DriverObject, - sizeof(OHCI_DEVICE_EXTENSION)/* + DriverExtension->InitializationData.HwDeviceExtensionSize*/, - &DeviceName, - FILE_DEVICE_CONTROLLER, - 0, - FALSE, - &fdo); - - if (!NT_SUCCESS(Status)) - { - DPRINT("IoCreateDevice call failed with status 0x%08x\n", Status); - return Status; - } - - // zerofill device extension - DeviceExtension = (POHCI_DEVICE_EXTENSION)pdo->DeviceExtension; - RtlZeroMemory(DeviceExtension, sizeof(OHCI_DEVICE_EXTENSION)); - DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo); - - fdo->Flags &= ~DO_DEVICE_INITIALIZING; - - // Initialize device extension - DeviceExtension->DeviceNumber = DeviceNumber; - DeviceExtension->PhysicalDeviceObject = pdo; - DeviceExtension->FunctionalDeviceObject = fdo; - DeviceExtension->DriverExtension = DriverExtension; - - /* Get bus number from the upper level bus driver. */ - Size = sizeof(ULONG); - Status = IoGetDeviceProperty( - pdo, - DevicePropertyBusNumber, - Size, - &DeviceExtension->SystemIoBusNumber, - &Size); - - if (!NT_SUCCESS(Status)) - { - DPRINT("Couldn't get an information from bus driver. Panic!!!\n"); - return Status; - } - - DPRINT("Done AddDevice\n"); - return STATUS_SUCCESS; -} - -VOID STDCALL DriverUnload(PDRIVER_OBJECT DriverObject) -{ - DPRINT1("DriverUnload()\n"); - - // Exit usb device - usb_exit(); - - // Remove device (ohci_pci_driver.remove) - uhci_pci_driver.remove(dev); - - ExFreePool(dev->slot_name); - ExFreePool(dev); - - // Perform some cleanup - uhci_hcd_cleanup(); -} - -NTSTATUS InitLinuxWrapper(PDEVICE_OBJECT DeviceObject) -{ - NTSTATUS Status; - POHCI_DEVICE_EXTENSION DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension; - - // Fill generic linux structs - dev = ExAllocatePoolWithTag(PagedPool, sizeof(struct pci_dev), USB_UHCI_TAG); - - init_wrapper(dev); - dev->irq = DeviceExtension->InterruptLevel; - dev->dev_ext = (PVOID)DeviceExtension; - dev->slot_name = ExAllocatePoolWithTag(NonPagedPool, 128, USB_UHCI_TAG); // 128 max len for slot name - - strcpy(dev->dev.name, "UnivHCI PCI-USB Controller"); - strcpy(dev->slot_name, "UHCD PCI Slot"); - - // Init the OHCI HCD. Probe will be called automatically, but will fail because id=NULL - Status = uhci_hcd_init(); - //FIXME: Check status returned value - - // Init core usb - usb_init(); - - // Probe device with real id now - uhci_pci_driver.probe(dev, uhci_pci_ids); - - DPRINT("InitLinuxWrapper() done\n"); - - return STATUS_SUCCESS; -} - -NTSTATUS STDCALL -OHCD_PnPStartDevice(IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp) -{ - PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); - PDRIVER_OBJECT DriverObject; - POHCI_DRIVER_EXTENSION DriverExtension; - POHCI_DEVICE_EXTENSION DeviceExtension; - PCM_RESOURCE_LIST AllocatedResources; - - /* - * Get the initialization data we saved in VideoPortInitialize. - */ - DriverObject = DeviceObject->DriverObject; - DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); - DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension; - - /* - * Store some resources in the DeviceExtension. - */ - AllocatedResources = Stack->Parameters.StartDevice.AllocatedResources; - if (AllocatedResources != NULL) - { - CM_FULL_RESOURCE_DESCRIPTOR *FullList; - CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor; - ULONG ResourceCount; - ULONG ResourceListSize; - - /* Save the resource list */ - ResourceCount = AllocatedResources->List[0].PartialResourceList.Count; - ResourceListSize = - FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList. - PartialDescriptors[ResourceCount]); - DeviceExtension->AllocatedResources = ExAllocatePool(PagedPool, ResourceListSize); - if (DeviceExtension->AllocatedResources == NULL) - { - return STATUS_INSUFFICIENT_RESOURCES; - } - - RtlCopyMemory(DeviceExtension->AllocatedResources, - AllocatedResources, - ResourceListSize); - - /* Get the interrupt level/vector - needed by HwFindAdapter sometimes */ - for (FullList = AllocatedResources->List; - FullList < AllocatedResources->List + AllocatedResources->Count; - FullList++) - { - /* FIXME: Is this ASSERT ok for resources from the PNP manager? */ - /*ASSERT(FullList->InterfaceType == PCIBus && - FullList->BusNumber == DeviceExtension->SystemIoBusNumber && - 1 == FullList->PartialResourceList.Version && - 1 == FullList->PartialResourceList.Revision);*/ - for (Descriptor = FullList->PartialResourceList.PartialDescriptors; - Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count; - Descriptor++) - { - if (Descriptor->Type == CmResourceTypeInterrupt) - { - DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level; - DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector; - } - else if (Descriptor->Type == CmResourceTypeMemory) - { - DeviceExtension->BaseAddress = Descriptor->u.Memory.Start; - DeviceExtension->BaseAddrLength = Descriptor->u.Memory.Length; - } - } - } - } - DPRINT1("Interrupt level: 0x%x Interrupt Vector: 0x%x\n", - DeviceExtension->InterruptLevel, - DeviceExtension->InterruptVector); - - /* - * Init wrapper with this object - */ - return InitLinuxWrapper(DeviceObject); -} - -// Dispatch PNP -NTSTATUS STDCALL DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - PIO_STACK_LOCATION IrpSp; - NTSTATUS Status; - - IrpSp = IoGetCurrentIrpStackLocation(Irp); - - switch (IrpSp->MinorFunction) - { - case IRP_MN_START_DEVICE: - //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp); - //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status)) - - Status = OHCD_PnPStartDevice(DeviceObject, Irp); - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - break; - - - case IRP_MN_REMOVE_DEVICE: - case IRP_MN_QUERY_REMOVE_DEVICE: - case IRP_MN_CANCEL_REMOVE_DEVICE: - case IRP_MN_SURPRISE_REMOVAL: - - case IRP_MN_STOP_DEVICE: - //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp); - //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status)) - Status = STATUS_SUCCESS; - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - - IoDeleteDevice(DeviceObject); // just delete device for now - break; - - case IRP_MN_QUERY_STOP_DEVICE: - case IRP_MN_CANCEL_STOP_DEVICE: - Status = STATUS_SUCCESS; - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - break; - - default: - return STATUS_NOT_IMPLEMENTED; - break; - } - - return Status; -} - -NTSTATUS STDCALL DispatchPower(PDEVICE_OBJECT fido, PIRP Irp) -{ - DbgPrint("IRP_MJ_POWER dispatch\n"); - return STATUS_SUCCESS; -} - -/* - * Standard DriverEntry method. - */ -NTSTATUS STDCALL -DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegPath) -{ - DriverObject->DriverUnload = DriverUnload; - DriverObject->DriverExtension->AddDevice = AddDevice; - DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp; - DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower; - - return STATUS_SUCCESS; -} +/* + ReactOS specific functions for UHCI module + by Aleksey Bragin (aleksey@reactos.com) + Some parts of code are inspired (or even just copied) from ReactOS Videoport driver +*/ + +#include +#include + +// config and include core/hcd.h, for hc_device struct +#include "../usb_wrapper.h" +#include "../core/hcd.h" + +#include "../host/ohci_main.h" + + +// declare basic init funcs +void init_wrapper(struct pci_dev *probe_dev); +int uhci_hcd_init(void); +void uhci_hcd_cleanup(void); +int STDCALL usb_init(void); +void STDCALL usb_exit(void); +extern struct pci_driver uhci_pci_driver; +extern struct pci_device_id uhci_pci_ids[]; + + +// This should be removed, but for testing purposes it's here +struct pci_dev *dev; +//struct pci_device_id *dev_id; + +#define USB_UHCI_TAG TAG('u','s','b','u') + +NTSTATUS STDCALL AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo) +{ + PDEVICE_OBJECT fdo; + NTSTATUS Status; + WCHAR DeviceBuffer[20]; + UNICODE_STRING DeviceName; + POHCI_DRIVER_EXTENSION DriverExtension; + POHCI_DEVICE_EXTENSION DeviceExtension; + ULONG Size, DeviceNumber; + + DPRINT1("uhci: AddDevice called\n"); + + // Allocate driver extension now + DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); + if (DriverExtension == NULL) + { + Status = IoAllocateDriverObjectExtension( + DriverObject, + DriverObject, + sizeof(OHCI_DRIVER_EXTENSION), + (PVOID *)&DriverExtension); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("Allocating DriverObjectExtension failed.\n"); + return Status; + } + } + + // Create a unicode device name + DeviceNumber = 0; //TODO: Allocate new device number every time + swprintf(DeviceBuffer, L"\\Device\\USBFDO-%lu", DeviceNumber); + RtlInitUnicodeString(&DeviceName, DeviceBuffer); + + Status = IoCreateDevice(DriverObject, + sizeof(OHCI_DEVICE_EXTENSION)/* + DriverExtension->InitializationData.HwDeviceExtensionSize*/, + &DeviceName, + FILE_DEVICE_CONTROLLER, + 0, + FALSE, + &fdo); + + if (!NT_SUCCESS(Status)) + { + DPRINT("IoCreateDevice call failed with status 0x%08x\n", Status); + return Status; + } + + // zerofill device extension + DeviceExtension = (POHCI_DEVICE_EXTENSION)pdo->DeviceExtension; + RtlZeroMemory(DeviceExtension, sizeof(OHCI_DEVICE_EXTENSION)); + DeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo); + + fdo->Flags &= ~DO_DEVICE_INITIALIZING; + + // Initialize device extension + DeviceExtension->DeviceNumber = DeviceNumber; + DeviceExtension->PhysicalDeviceObject = pdo; + DeviceExtension->FunctionalDeviceObject = fdo; + DeviceExtension->DriverExtension = DriverExtension; + + /* Get bus number from the upper level bus driver. */ + Size = sizeof(ULONG); + Status = IoGetDeviceProperty( + pdo, + DevicePropertyBusNumber, + Size, + &DeviceExtension->SystemIoBusNumber, + &Size); + + if (!NT_SUCCESS(Status)) + { + DPRINT("Couldn't get an information from bus driver. Panic!!!\n"); + return Status; + } + + DPRINT("Done AddDevice\n"); + return STATUS_SUCCESS; +} + +VOID STDCALL DriverUnload(PDRIVER_OBJECT DriverObject) +{ + DPRINT1("DriverUnload()\n"); + + // Exit usb device + usb_exit(); + + // Remove device (ohci_pci_driver.remove) + uhci_pci_driver.remove(dev); + + ExFreePool(dev->slot_name); + ExFreePool(dev); + + // Perform some cleanup + uhci_hcd_cleanup(); +} + +NTSTATUS InitLinuxWrapper(PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS Status; + POHCI_DEVICE_EXTENSION DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // Fill generic linux structs + dev = ExAllocatePoolWithTag(PagedPool, sizeof(struct pci_dev), USB_UHCI_TAG); + + init_wrapper(dev); + dev->irq = DeviceExtension->InterruptVector; + dev->dev_ext = (PVOID)DeviceExtension; + dev->slot_name = ExAllocatePoolWithTag(NonPagedPool, 128, USB_UHCI_TAG); // 128 max len for slot name + + strcpy(dev->dev.name, "UnivHCI PCI-USB Controller"); + strcpy(dev->slot_name, "UHCD PCI Slot"); + + // Init the OHCI HCD. Probe will be called automatically, but will fail because id=NULL + Status = uhci_hcd_init(); + //FIXME: Check status returned value + + // Init core usb + usb_init(); + + // Probe device with real id now + uhci_pci_driver.probe(dev, uhci_pci_ids); + + DPRINT("InitLinuxWrapper() done\n"); + + return STATUS_SUCCESS; +} + +NTSTATUS STDCALL +OHCD_PnPStartDevice(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); + PDRIVER_OBJECT DriverObject; + POHCI_DRIVER_EXTENSION DriverExtension; + POHCI_DEVICE_EXTENSION DeviceExtension; + PCM_RESOURCE_LIST AllocatedResources; + + /* + * Get the initialization data we saved in VideoPortInitialize. + */ + DriverObject = DeviceObject->DriverObject; + DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); + DeviceExtension = (POHCI_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* + * Store some resources in the DeviceExtension. + */ + AllocatedResources = Stack->Parameters.StartDevice.AllocatedResources; + if (AllocatedResources != NULL) + { + CM_FULL_RESOURCE_DESCRIPTOR *FullList; + CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor; + ULONG ResourceCount; + ULONG ResourceListSize; + + /* Save the resource list */ + ResourceCount = AllocatedResources->List[0].PartialResourceList.Count; + ResourceListSize = + FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList. + PartialDescriptors[ResourceCount]); + DeviceExtension->AllocatedResources = ExAllocatePool(PagedPool, ResourceListSize); + if (DeviceExtension->AllocatedResources == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory(DeviceExtension->AllocatedResources, + AllocatedResources, + ResourceListSize); + + /* Get the interrupt level/vector - needed by HwFindAdapter sometimes */ + for (FullList = AllocatedResources->List; + FullList < AllocatedResources->List + AllocatedResources->Count; + FullList++) + { + /* FIXME: Is this ASSERT ok for resources from the PNP manager? */ + /*ASSERT(FullList->InterfaceType == PCIBus && + FullList->BusNumber == DeviceExtension->SystemIoBusNumber && + 1 == FullList->PartialResourceList.Version && + 1 == FullList->PartialResourceList.Revision);*/ + DPRINT1("AllocRess->Count: %d, PartResList.Count: %d\n", + AllocatedResources->Count, FullList->PartialResourceList.Count); + + for (Descriptor = FullList->PartialResourceList.PartialDescriptors; + Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count; + Descriptor++) + { + if (Descriptor->Type == CmResourceTypeInterrupt) + { + DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level; + DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector; + + DPRINT1("Interrupt level: 0x%x Interrupt Vector: 0x%x\n", + DeviceExtension->InterruptLevel, + DeviceExtension->InterruptVector); + } + else if (Descriptor->Type == CmResourceTypePort) + { + DeviceExtension->BaseAddress = Descriptor->u.Port.Start; + DeviceExtension->BaseAddrLength = Descriptor->u.Port.Length; + DeviceExtension->Flags = Descriptor->Flags; + + ((struct hc_driver *)uhci_pci_ids->driver_data)->flags &= ~HCD_MEMORY; + + DPRINT1("I/O resource: start=0x%x, length=0x%x\n", + DeviceExtension->BaseAddress.u.LowPart, DeviceExtension->BaseAddrLength); + } + else if (Descriptor->Type == CmResourceTypeMemory) + { + DeviceExtension->BaseAddress = Descriptor->u.Memory.Start; + DeviceExtension->BaseAddrLength = Descriptor->u.Memory.Length; + DeviceExtension->Flags = Descriptor->Flags; + + ((struct hc_driver *)uhci_pci_ids->driver_data)->flags |= HCD_MEMORY; + + DPRINT1("Memory resource: start=0x%x, length=0x%x\n", + DeviceExtension->BaseAddress.u.LowPart, DeviceExtension->BaseAddrLength); + } + else + DPRINT1("Get resource type: %d, Generic start=0x%x Generic length=0x%x\n", + Descriptor->Type, Descriptor->u.Generic.Start.u.LowPart, Descriptor->u.Generic.Length); + + } + } + } + + /* + * Init wrapper with this object + */ + return InitLinuxWrapper(DeviceObject); +} + +// Dispatch PNP +NTSTATUS STDCALL DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + PIO_STACK_LOCATION IrpSp; + NTSTATUS Status; + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + switch (IrpSp->MinorFunction) + { + case IRP_MN_START_DEVICE: + //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp); + //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status)) + + Status = OHCD_PnPStartDevice(DeviceObject, Irp); + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + break; + + + case IRP_MN_REMOVE_DEVICE: + case IRP_MN_QUERY_REMOVE_DEVICE: + case IRP_MN_CANCEL_REMOVE_DEVICE: + case IRP_MN_SURPRISE_REMOVAL: + + case IRP_MN_STOP_DEVICE: + //Status = IntVideoPortForwardIrpAndWait(DeviceObject, Irp); + //if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status)) + Status = STATUS_SUCCESS; + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + IoDeleteDevice(DeviceObject); // just delete device for now + break; + + case IRP_MN_QUERY_STOP_DEVICE: + case IRP_MN_CANCEL_STOP_DEVICE: + Status = STATUS_SUCCESS; + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + break; + + default: + return STATUS_NOT_IMPLEMENTED; + break; + } + + return Status; +} + +NTSTATUS STDCALL DispatchPower(PDEVICE_OBJECT fido, PIRP Irp) +{ + DbgPrint("IRP_MJ_POWER dispatch\n"); + return STATUS_SUCCESS; +} + +/* + * Standard DriverEntry method. + */ +NTSTATUS STDCALL +DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegPath) +{ + DriverObject->DriverUnload = DriverUnload; + DriverObject->DriverExtension->AddDevice = AddDevice; + DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp; + DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower; + + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/usb/cromwell/usb_wrapper.h b/reactos/drivers/usb/cromwell/usb_wrapper.h index 4b810cad0cb..f454f2f069d 100644 --- a/reactos/drivers/usb/cromwell/usb_wrapper.h +++ b/reactos/drivers/usb/cromwell/usb_wrapper.h @@ -1,15 +1,16 @@ -//#include -//#include -//#include -#include -#include - -void wait_ms(int mils); - -#include "linux/linux_wrapper.h" -#define __KERNEL__ -#undef CONFIG_PCI -#define CONFIG_PCI - -#include "linux/usb.h" -#include "linux/pci_ids.h" \ No newline at end of file +//#include +//#include +//#include +#include +#include + +void wait_ms(int mils); + +#include "linux/linux_wrapper.h" +#define __KERNEL__ +#undef CONFIG_PCI +#define CONFIG_PCI + +#include "linux/usb.h" +#include "linux/pci_ids.h" + diff --git a/reactos/drivers/video/displays/framebuf/screen.c b/reactos/drivers/video/displays/framebuf/screen.c index bbf07ef75bd..6b8557f2a41 100644 --- a/reactos/drivers/video/displays/framebuf/screen.c +++ b/reactos/drivers/video/displays/framebuf/screen.c @@ -158,7 +158,6 @@ IntInitScreenInfo( ModeInfoPtr = ModeInfo; while (ModeCount-- > 0) { - if (ModeInfoPtr->Length > 0 && pDevMode->dmPelsWidth == ModeInfoPtr->VisScreenWidth && pDevMode->dmPelsHeight == ModeInfoPtr->VisScreenHeight && @@ -170,7 +169,8 @@ IntInitScreenInfo( break; } - ModeInfoPtr++; + ModeInfoPtr = (PVIDEO_MODE_INFORMATION) + (((PUCHAR)ModeInfoPtr) + ModeInfoSize); } } @@ -383,6 +383,7 @@ DrvGetModes( { if (ModeInfoPtr->Length == 0) { + ModeInfoPtr = (PVIDEO_MODE_INFORMATION)(((ULONG_PTR)ModeInfoPtr) + ModeInfoSize); continue; } diff --git a/reactos/drivers/video/miniport/vbe/vbemp.c b/reactos/drivers/video/miniport/vbe/vbemp.c index 9c52de7d91f..6e9bae4972d 100644 --- a/reactos/drivers/video/miniport/vbe/vbemp.c +++ b/reactos/drivers/video/miniport/vbe/vbemp.c @@ -885,6 +885,14 @@ VBEQueryMode( VideoMode->YMillimeter = 0; /* FIXME */ if (VBEMode->BitsPerPixel > 8) { + /* + * Always report 16bpp modes and not 15bpp mode... + */ + if (VBEMode->BitsPerPixel == 15 && VBEMode->NumberOfPlanes == 1) + { + VideoMode->BitsPerPlane = 16; + } + if (DeviceExtension->VbeInfo.Version < 0x300) { VideoMode->NumberRedBits = VBEMode->RedMaskSize; diff --git a/reactos/drivers/video/miniport/vbe/vbemp.h b/reactos/drivers/video/miniport/vbe/vbemp.h index 0bed245e568..bd64ff0c4ee 100644 --- a/reactos/drivers/video/miniport/vbe/vbemp.h +++ b/reactos/drivers/video/miniport/vbe/vbemp.h @@ -32,7 +32,7 @@ #include #ifdef DBG -#define DPRINT(arg) DbgPrint arg; +#define DPRINT(arg) DbgPrint(arg) #else #define DPRINT(arg) #endif diff --git a/reactos/hal/halx86/mp/mpconfig.c b/reactos/hal/halx86/mp/mpconfig.c index e624887843c..fe1bb3e8904 100644 --- a/reactos/hal/halx86/mp/mpconfig.c +++ b/reactos/hal/halx86/mp/mpconfig.c @@ -16,7 +16,7 @@ #include #include -//#define NDEBUG +#define NDEBUG #include /* GLOBALS ******************************************************************/ @@ -58,7 +58,7 @@ HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m) IRQCount++; } -static PCHAR +PCHAR HaliMPFamily(ULONG Family, ULONG Model) { @@ -275,9 +275,9 @@ HaliReadMPConfigTable(PMP_CONFIGURATION_TABLE Table) { PUCHAR pc = (PUCHAR)&Table->Signature; - DPRINT1("Bad MP configuration block signature: %c%c%c%c\n", + DPRINT1("Bad MP configuration block signature: %c%c%c%c\n", pc[0], pc[1], pc[2], pc[3]); - KEBUGCHECK(0); + KEBUGCHECKEX(0, pc[0], pc[1], pc[2], pc[3]); return FALSE; } diff --git a/reactos/include/ddk/obfuncs.h b/reactos/include/ddk/obfuncs.h index f4e2afda280..8edf62bcf6c 100644 --- a/reactos/include/ddk/obfuncs.h +++ b/reactos/include/ddk/obfuncs.h @@ -63,6 +63,43 @@ typedef NTSTATUS STDCALL_FUNC PSECURITY_DESCRIPTOR SecurityDescriptor, PULONG BufferLength); +typedef struct _OBJECT_HANDLE_COUNT_ENTRY +{ + struct _EPROCESS *Process; + ULONG HandleCount; +} OBJECT_HANDLE_COUNT_ENTRY, *POBJECT_HANDLE_COUNT_ENTRY; + +typedef struct _OBJECT_HANDLE_COUNT_DATABASE +{ + ULONG CountEntries; + POBJECT_HANDLE_COUNT_ENTRY HandleCountEntries[1]; +} OBJECT_HANDLE_COUNT_DATABASE, *POBJECT_HANDLE_COUNT_DATABASE; + +typedef struct _OBJECT_HEADER_HANDLE_INFO +{ + union { + POBJECT_HANDLE_COUNT_DATABASE HandleCountDatabase; + OBJECT_HANDLE_COUNT_ENTRY SingleEntry; + }; +} OBJECT_HEADER_HANDLE_INFO, *POBJECT_HEADER_HANDLE_INFO; + +typedef struct _OBJECT_HEADER_CREATOR_INFO +{ + LIST_ENTRY TypeList; + PVOID CreatorUniqueProcess; + USHORT CreatorBackTraceIndex; + USHORT Reserved; +} OBJECT_HEADER_CREATOR_INFO, *POBJECT_HEADER_CREATOR_INFO; + +typedef struct _OBJECT_HEADER_NAME_INFO +{ + struct _DIRECTORY_OBJECT *Directory; + UNICODE_STRING Name; + ULONG QueryReferences; + ULONG Reserved2; + ULONG DbgReferenceCount; +} OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO; + typedef struct _OBJECT_CREATE_INFORMATION { ULONG Attributes; diff --git a/reactos/include/debug.h b/reactos/include/debug.h index 47a1f1513e9..23b75e515d9 100644 --- a/reactos/include/debug.h +++ b/reactos/include/debug.h @@ -48,11 +48,19 @@ #endif #endif - /* TODO: Make the output of file/line and the debug message atomic */ +#ifdef DBG #define DPRINT1 DbgPrint("(%s:%d) ",__FILE__,__LINE__), DbgPrint #define CHECKPOINT1 do { DbgPrint("%s:%d\n",__FILE__,__LINE__); } while(0); - +#else +#ifdef __GNUC__ +#define DPRINT1(args...) +#define CHECKPOINT1 +#else +#define DPRINT1 +#define CHECKPOINT1 +#endif /* __GNUC__ */ +#endif #ifndef NDEBUG #define DPRINT(args...) do { DbgPrint("(%s:%d) ",__FILE__,__LINE__); DbgPrint(args); } while(0); diff --git a/reactos/include/ntdll/ntdll.h b/reactos/include/ntdll/ntdll.h index 5a4004f658b..bd7aeac7ff6 100644 --- a/reactos/include/ntdll/ntdll.h +++ b/reactos/include/ntdll/ntdll.h @@ -29,12 +29,17 @@ #define CHECKPOINT do { DbgPrint("(NTDLL:%s:%d) Checkpoint\n",__FILE__,__LINE__); } while(0) #endif +#ifdef DBG #if defined(__GNUC__) #define DPRINT1(args...) do { DbgPrint("(NTDLL:%s:%d) ",__FILE__,__LINE__); DbgPrint(args); } while(0) #else #define DPRINT1 DbgPrint("(NTDLL:%s:%d) ",__FILE__,__LINE__); DbgPrint #endif #define CHECKPOINT1 do { DbgPrint("(NTDLL:%s:%d) Checkpoint\n",__FILE__,__LINE__); } while(0) +#else +#define DPRINT1(args...) +#define CHECKPOINT1(args...) +#endif #define ROUNDUP(a,b) ((((a)+(b)-1)/(b))*(b)) #define ROUNDDOWN(a,b) (((a)/(b))*(b)) diff --git a/reactos/include/ntos/zwtypes.h b/reactos/include/ntos/zwtypes.h index 1402dee2380..d523d84dab8 100755 --- a/reactos/include/ntos/zwtypes.h +++ b/reactos/include/ntos/zwtypes.h @@ -326,7 +326,7 @@ typedef struct _SYSTEM_PERFORMANCE_INFORMATION { ULONG SystemCalls; } SYSTEM_PERFORMANCE_INFORMATION, *PSYSTEM_PERFORMANCE_INFORMATION; -#ifndef __USE_W32API +/*#ifndef __USE_W32API*/ // SystemProcessThreadInfo (5) typedef struct _SYSTEM_THREAD_INFORMATION @@ -391,7 +391,7 @@ typedef struct _SYSTEM_PROCESS_INFORMATION SYSTEM_THREAD_INFORMATION TH[1]; } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; -#endif +/*#endif */ // SystemModuleInformation (11) typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY { diff --git a/reactos/include/win32k/debug1.h b/reactos/include/win32k/debug1.h index 44badb7808b..c314e796cf2 100644 --- a/reactos/include/win32k/debug1.h +++ b/reactos/include/win32k/debug1.h @@ -39,9 +39,13 @@ #endif #endif +#ifdef DBG #define DPRINT1 DbgPrint("(%s:%d) ",__FILE__,__LINE__), DbgPrint #define CHECKPOINT1 DbgPrint("%s:%d\n",__FILE__,__LINE__); - +#else +#define DPRINT1(args...) +#define CHECKPOINT1(args...) +#endif #ifdef __NTOSKRNL__ #define DPRINT_CHECKS diff --git a/reactos/include/wine/debug.h b/reactos/include/wine/debug.h index 3af86979922..51f24ab834f 100644 --- a/reactos/include/wine/debug.h +++ b/reactos/include/wine/debug.h @@ -12,7 +12,11 @@ unsigned long DbgPrint(char *Format,...); +#ifdef DBG #define DPRINT1 DbgPrint("(%s:%d:%s) ",__FILE__,__LINE__,__FUNCTION__), DbgPrint +#else +#define DPRINT1(args...) +#endif #if !defined(DBG) || !defined(YDEBUG) #ifdef __GNUC__ diff --git a/reactos/include/wine/exception.h b/reactos/include/wine/exception.h index 594fd338c09..7bfc1c93d55 100644 --- a/reactos/include/wine/exception.h +++ b/reactos/include/wine/exception.h @@ -24,6 +24,7 @@ #include #include #include +#include /* The following definitions allow using exceptions in Wine and Winelib code * @@ -75,6 +76,10 @@ #else /* USE_COMPILER_EXCEPTIONS */ +#ifndef __GNUC__ +#define __attribute__(x) /* nothing */ +#endif + #define __TRY \ do { __WINE_FRAME __f; \ int __first = 1; \ @@ -91,7 +96,7 @@ __f.u.filter = (func); \ __wine_push_frame( &__f.frame ); \ if (sigsetjmp( __f.jmp, 1 )) { \ - const __WINE_FRAME * const __eptr WINE_UNUSED = &__f; \ + const __WINE_FRAME * const __eptr __attribute__((unused)) = &__f; \ do { #define __ENDTRY \ @@ -125,10 +130,7 @@ typedef void (CALLBACK *__WINE_FINALLY)(BOOL); #define GetExceptionInformation() (__eptr) #define GetExceptionCode() (__eptr->ExceptionRecord->ExceptionCode) -#if defined(AbnormalTermination) && defined(__REACTOS__) #undef AbnormalTermination -#endif - #define AbnormalTermination() (!__normal) typedef struct __tagWINE_FRAME @@ -175,8 +177,6 @@ static inline EXCEPTION_REGISTRATION_RECORD *__wine_pop_frame( EXCEPTION_REGISTR { #if defined(__GNUC__) && defined(__i386__) __asm__ __volatile__(".byte 0x64\n\tmovl %0,(0)" - //: : "r" (frame->Prev) : "memory" ); - //return frame->Prev; : : "r" (frame->prev) : "memory" ); return frame->prev; diff --git a/reactos/include/wine/msidefs.h b/reactos/include/wine/msidefs.h index f266b32172c..71b054b80ca 100644 --- a/reactos/include/wine/msidefs.h +++ b/reactos/include/wine/msidefs.h @@ -23,6 +23,17 @@ extern "C" { #endif +enum msidbFileAttributes { + msidbFileAttributesReadOnly = 0x00000001, + msidbFileAttributesHidden = 0x00000002, + msidbFileAttributesSystem = 0x00000004, + msidbFileAttributesVital = 0x00000200, + msidbFileAttributesChecksum = 0x00000400, + msidbFileAttributesPatchAdded = 0x00001000, + msidbFileAttributesNoncompressed = 0x00002000, + msidbFileAttributesCompressed = 0x00004000 +}; + enum msidbDialogAttributes { msidbDialogAttributesVisible = 0x00000001, msidbDialogAttributesModal = 0x00000002, @@ -103,6 +114,22 @@ enum msidbComponentAttributes msidbComponentAttributes64bit = 0x00000100 }; +enum msidbRegistryRoot +{ + msidbRegistryRootClassesRoot = 0, + msidbRegistryRootCurrentUser = 1, + msidbRegistryRootLocalMachine = 2, + msidbRegistryRootUsers = 3, +}; + +enum msidbLocatorType +{ + msidbLocatorTypeDirectory = 0x000, + msidbLocatorTypeFileName = 0x001, + msidbLocatorTypeRawValue = 0x002, + msidbLocatorType64bit = 0x010, +}; + /* * Windows SDK braindamage alert * diff --git a/reactos/include/wine/setupapi.h b/reactos/include/wine/setupapi.h index d7deaa7f21a..ee03767d3cd 100644 --- a/reactos/include/wine/setupapi.h +++ b/reactos/include/wine/setupapi.h @@ -669,6 +669,7 @@ LONG WINAPI AddTagToGroupOrderList(PCWSTR lpGroupName, DWORD dwUnknown2, DWO VOID WINAPI AssertFail(LPSTR, UINT, LPSTR); DWORD WINAPI CaptureAndConvertAnsiArg(PCSTR lpSrc, PWSTR *lpDst); DWORD WINAPI CaptureStringArg(PCWSTR lpSrc, PWSTR *lpDst); +BOOL WINAPI ConcatenatePaths(LPWSTR, LPCWSTR, DWORD, LPDWORD); BOOL WINAPI DelayedMove(PCWSTR lpExistingFileName, PCWSTR lpNewFileName); BOOL WINAPI DoesUserHavePrivilege(PCWSTR lpPrivilegeName); PWSTR WINAPI DuplicateString(PCWSTR lpSrc); @@ -681,6 +682,7 @@ void WINAPI InstallHinfSectionW( HWND hwnd, HINSTANCE handle, PCWSTR cmdline BOOL WINAPI IsUserAdmin(VOID); PWSTR WINAPI MultiByteToUnicode(PCSTR lpMultiByteStr, UINT uCodePage); VOID WINAPI MyFree(PVOID lpMem); +PWSTR WINAPI MyGetFileTitle(PCWSTR); PVOID WINAPI MyMalloc(DWORD dwSize); PVOID WINAPI MyRealloc(PVOID lpSrc, DWORD dwSize); DWORD WINAPI OpenAndMapForRead(PCWSTR, PDWORD, PHANDLE, PHANDLE, PVOID *); diff --git a/reactos/lib/cabinet/Makefile.in b/reactos/lib/cabinet/Makefile.in index 618aa04d5dc..9dbc9139d76 100644 --- a/reactos/lib/cabinet/Makefile.in +++ b/reactos/lib/cabinet/Makefile.in @@ -3,6 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = cabinet.dll +IMPORTLIB = libcabinet.$(IMPLIBEXT) IMPORTS = kernel32 C_SRCS = \ diff --git a/reactos/lib/cabinet/cabinet.h b/reactos/lib/cabinet/cabinet.h index 3ef0dc25d4a..c5b5e60b44a 100644 --- a/reactos/lib/cabinet/cabinet.h +++ b/reactos/lib/cabinet/cabinet.h @@ -2,6 +2,7 @@ * cabinet.h * * Copyright 2002 Greg Turner + * Copyright 2005 Gerold Jens Wucherpfennig * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -292,6 +293,19 @@ typedef struct cds_forward { typedef struct { unsigned int FCI_Intmagic; + PERF perf; + PFNFCIFILEPLACED pfnfiledest; + PFNFCIALLOC pfnalloc; + PFNFCIFREE pfnfree; + PFNFCIOPEN pfnopen; + PFNFCIREAD pfnread; + PFNFCIWRITE pfnwrite; + PFNFCICLOSE pfnclose; + PFNFCISEEK pfnseek; + PFNFCIDELETE pfndelete; + PFNFCIGETTEMPFILE pfnfcigtf; + PCCAB pccab; + void *pv; } FCI_Int, *PFCI_Int; typedef struct { @@ -307,7 +321,7 @@ typedef struct { } FDI_Int, *PFDI_Int; /* cast an HFCI into a PFCI_Int */ -#define PFCI_INT(hfci) ((PFDI_Int)(hfci)) +#define PFCI_INT(hfci) ((PFCI_Int)(hfci)) /* cast an HFDI into a PFDI_Int */ #define PFDI_INT(hfdi) ((PFDI_Int)(hfdi)) diff --git a/reactos/lib/cabinet/fci.c b/reactos/lib/cabinet/fci.c index 4fd9476c66c..88310c2a3b0 100644 --- a/reactos/lib/cabinet/fci.c +++ b/reactos/lib/cabinet/fci.c @@ -2,6 +2,7 @@ * File Compression Interface * * Copyright 2002 Patrik Stridvall + * Copyright 2005 Gerold Jens Wucherpfennig * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,6 +27,7 @@ #include "winbase.h" #include "winerror.h" #include "fci.h" +#include "cabinet.h" #include "wine/debug.h" @@ -33,12 +35,55 @@ WINE_DEFAULT_DEBUG_CHANNEL(cabinet); /*********************************************************************** * FCICreate (CABINET.10) + * + * Provided with several callbacks, + * returns a handle which can be used to perform operations + * on cabinet files. + * + * PARAMS + * perf [IO] A pointer to an ERF structure. When FCICreate + * returns an error condition, error information may + * be found here as well as from GetLastError. + * pfnfiledest [I] A pointer to a function which is called when a file + * is placed. Only useful for subsequent cabinet files. + * pfnalloc [I] A pointer to a function which allocates ram. Uses + * the same interface as malloc. + * pfnfree [I] A pointer to a function which frees ram. Uses the + * same interface as free. + * pfnopen [I] A pointer to a function which opens a file. Uses + * the same interface as _open. + * pfnread [I] A pointer to a function which reads from a file into + * a caller-provided buffer. Uses the same interface + * as _read + * pfnwrite [I] A pointer to a function which writes to a file from + * a caller-provided buffer. Uses the same interface + * as _write. + * pfnclose [I] A pointer to a function which closes a file handle. + * Uses the same interface as _close. + * pfnseek [I] A pointer to a function which seeks in a file. + * Uses the same interface as _lseek. + * pfndelete [I] A pointer to a function which deletes a file. + * pfnfcigtf [I] A pointer to a function which gets the name of a + * temporary file; ignored in wine + * pccab [I] A pointer to an initialized CCAB structure + * pv [I] A pointer to an application-defined notification + * function which will be passed to other FCI functions + * as a parameter. + * + * RETURNS + * On success, returns an FCI handle of type HFCI. + * On failure, the NULL file handle is returned. Error + * info can be retrieved from perf. + * + * INCLUDES + * fci.h + * */ HFCI __cdecl FCICreate( PERF perf, - PFNFCIFILEPLACED pfnfcifp, - PFNFCIALLOC pfna, - PFNFCIFREE pfnf, + PFNFCIFILEPLACED pfnfiledest, + PFNFCIALLOC pfnalloc, + PFNFCIFREE pfnfree, PFNFCIOPEN pfnopen, PFNFCIREAD pfnread, PFNFCIWRITE pfnwrite, @@ -49,17 +94,57 @@ HFCI __cdecl FCICreate( PCCAB pccab, void *pv) { - FIXME("(%p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p): stub\n", - perf, pfnfcifp, pfna, pfnf, pfnopen, pfnread, pfnwrite, pfnclose, - pfnseek, pfndelete, pfnfcigtf, pccab, pv); + HFCI rv; + if ((!pfnalloc) || (!pfnfree)) { perf->erfOper = FCIERR_NONE; - perf->erfType = 0; + perf->erfType = ERROR_BAD_ARGUMENTS; perf->fError = TRUE; - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - + SetLastError(ERROR_BAD_ARGUMENTS); return NULL; + } + + if (!(rv = (HFCI) (*pfnalloc)(sizeof(FCI_Int)))) { + perf->erfOper = FCIERR_ALLOC_FAIL; + perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + perf->fError = TRUE; + + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + + PFCI_INT(rv)->FCI_Intmagic = FCI_INT_MAGIC; + PFCI_INT(rv)->perf = perf; + PFCI_INT(rv)->pfnfiledest = pfnfiledest; + PFCI_INT(rv)->pfnalloc = pfnalloc; + PFCI_INT(rv)->pfnfree = pfnfree; + PFCI_INT(rv)->pfnopen = pfnopen; + PFCI_INT(rv)->pfnread = pfnread; + PFCI_INT(rv)->pfnwrite = pfnwrite; + PFCI_INT(rv)->pfnclose = pfnclose; + PFCI_INT(rv)->pfnseek = pfnseek; + PFCI_INT(rv)->pfndelete = pfndelete; + PFCI_INT(rv)->pfnfcigtf = pfnfcigtf; + PFCI_INT(rv)->pccab = pccab; + PFCI_INT(rv)->pv = pv; + + /* Still mark as incomplete, because of other missing FCI* APIs */ + + PFCI_INT(rv)->FCI_Intmagic = 0; + PFDI_FREE(rv, rv); + FIXME("(%p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p): stub\n", + perf, pfnfiledest, pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, + pfnseek, pfndelete, pfnfcigtf, pccab, pv); + + perf->erfOper = FCIERR_NONE; + perf->erfType = 0; + perf->fError = TRUE; + + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + + return NULL; + } /*********************************************************************** @@ -116,12 +201,30 @@ BOOL __cdecl FCIFlushFolder( /*********************************************************************** * FCIDestroy (CABINET.14) + * + * Frees a handle created by FCICreate. + * Only reason for failure would be an invalid handle. + * + * PARAMS + * hfci [I] The HFCI to free + * + * RETURNS + * TRUE for success + * FALSE for failure */ BOOL __cdecl FCIDestroy(HFCI hfci) { - FIXME("(%p): stub\n", hfci); - - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - + if (REALLY_IS_FCI(hfci)) { + PFCI_INT(hfci)->FCI_Intmagic = 0; + PFDI_FREE(hfci, hfci); + /*return TRUE; */ + } else { + SetLastError(ERROR_INVALID_HANDLE); return FALSE; + } + + /* Still mark as incomplete, because of other missing FCI* APIs */ + FIXME("(%p): stub\n", hfci); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; } diff --git a/reactos/lib/comctl32/Makefile.in b/reactos/lib/comctl32/Makefile.in index c966efff43c..1d117b8cf4d 100644 --- a/reactos/lib/comctl32/Makefile.in +++ b/reactos/lib/comctl32/Makefile.in @@ -4,6 +4,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = comctl32.dll +IMPORTLIB = libcomctl32.$(IMPLIBEXT) IMPORTS = user32 gdi32 advapi32 kernel32 DELAYIMPORTS = winmm EXTRALIBS = $(LIBUNICODE) diff --git a/reactos/lib/comctl32/comboex.c b/reactos/lib/comctl32/comboex.c index 5037365db13..f23caca7ede 100644 --- a/reactos/lib/comctl32/comboex.c +++ b/reactos/lib/comctl32/comboex.c @@ -283,6 +283,26 @@ static void COMBOEX_FreeText (CBE_ITEMDATA *item) } +static INT COMBOEX_GetIndex(COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item) +{ + CBE_ITEMDATA *moving; + INT index; + + moving = infoPtr->items; + index = infoPtr->nb_items - 1; + + while (moving && (moving != item)) { + moving = moving->next; + index--; + } + if (!moving || (index < 0)) { + ERR("COMBOBOXEX item structures broken. Please report!\n"); + return -1; + } + return index; +} + + static LPCWSTR COMBOEX_GetText(COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item) { NMCOMBOBOXEXW nmce; @@ -295,6 +315,7 @@ static LPCWSTR COMBOEX_GetText(COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item) ZeroMemory(&nmce, sizeof(nmce)); nmce.ceItem.mask = CBEIF_TEXT; nmce.ceItem.lParam = item->lParam; + nmce.ceItem.iItem = COMBOEX_GetIndex(infoPtr, item); COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); if (is_textW(nmce.ceItem.pszText)) { @@ -1389,6 +1410,7 @@ static LRESULT COMBOEX_DrawItem (COMBOEX_INFO *infoPtr, DRAWITEMSTRUCT *dis) ZeroMemory(&nmce, sizeof(nmce)); nmce.ceItem.mask = CBEIF_INDENT; nmce.ceItem.lParam = item->lParam; + nmce.ceItem.iItem = dis->itemID; COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); if (nmce.ceItem.mask & CBEIF_DI_SETITEM) item->iIndent = nmce.ceItem.iIndent; @@ -1453,6 +1475,7 @@ static LRESULT COMBOEX_DrawItem (COMBOEX_INFO *infoPtr, DRAWITEMSTRUCT *dis) ZeroMemory(&nmce, sizeof(nmce)); nmce.ceItem.mask = (drawstate == ILD_NORMAL) ? CBEIF_IMAGE : CBEIF_SELECTEDIMAGE; nmce.ceItem.lParam = item->lParam; + nmce.ceItem.iItem = dis->itemID; COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); if (drawstate == ILD_NORMAL) { if (nmce.ceItem.mask & CBEIF_DI_SETITEM) item->iImage = nmce.ceItem.iImage; @@ -1468,6 +1491,7 @@ static LRESULT COMBOEX_DrawItem (COMBOEX_INFO *infoPtr, DRAWITEMSTRUCT *dis) ZeroMemory(&nmce, sizeof(nmce)); nmce.ceItem.mask = CBEIF_OVERLAY; nmce.ceItem.lParam = item->lParam; + nmce.ceItem.iItem = dis->itemID; COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); if (nmce.ceItem.mask & CBEIF_DI_SETITEM) item->iOverlay = nmce.ceItem.iOverlay; diff --git a/reactos/lib/comctl32/comctl32undoc.c b/reactos/lib/comctl32/comctl32undoc.c index e86c0a4885c..4e671b04e3e 100644 --- a/reactos/lib/comctl32/comctl32undoc.c +++ b/reactos/lib/comctl32/comctl32undoc.c @@ -588,7 +588,7 @@ static void MRU_SaveChanged ( LPWINEMRULIST mp ) if ((err = RegOpenKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, 0, KEY_WRITE, &newkey))) { /* not present - what to do ??? */ - ERR("Can not open key, error=%d, attempting to create\n", + ERR("Could not open key, error=%d, attempting to create\n", err); if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, 0, @@ -980,7 +980,7 @@ static HANDLE CreateMRUListLazy_common(LPWINEMRULIST mp) &newkey, &dwdisp))) { /* error - what to do ??? */ - ERR("(%lu %lu %lx %lx \"%s\" %p): Can not open key, error=%d\n", + ERR("(%lu %lu %lx %lx \"%s\" %p): Could not open key, error=%d\n", mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags, (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), mp->extview.lpfnCompare, err); diff --git a/reactos/lib/comctl32/datetime.c b/reactos/lib/comctl32/datetime.c index 5fed3f7bda1..7e25903eb15 100644 --- a/reactos/lib/comctl32/datetime.c +++ b/reactos/lib/comctl32/datetime.c @@ -607,7 +607,7 @@ DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc) RECT *checkbox = &infoPtr->checkbox; SIZE size; COLORREF oldTextColor; - SHORT fieldWidth; + SHORT fieldWidth = 0; /* draw control edge */ TRACE("\n"); diff --git a/reactos/lib/comctl32/header.c b/reactos/lib/comctl32/header.c index 56d0b747ff8..f22651c3a3d 100644 --- a/reactos/lib/comctl32/header.c +++ b/reactos/lib/comctl32/header.c @@ -163,7 +163,7 @@ HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack) HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); HEADER_ITEM *phdi = &infoPtr->items[iItem]; RECT r; - INT oldBkMode; + INT oldBkMode, cxEdge = GetSystemMetrics(SM_CXEDGE); TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem, bHotTrack, infoPtr->bUnicode); @@ -188,6 +188,9 @@ HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack) else DrawEdge (hdc, &r, EDGE_ETCHED, BF_BOTTOM | BF_RIGHT | BF_ADJUST); + r.left -= cxEdge; + r.right += cxEdge; + if (phdi->fmt & HDF_OWNERDRAW) { DRAWITEMSTRUCT dis; dis.CtlType = ODT_HEADER; @@ -206,149 +209,117 @@ HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack) SetBkMode(hdc, oldBkMode); } else { - UINT uTextJustify = DT_LEFT; + UINT rw, rh, /* width and height of r */ + *x = NULL, *w = NULL; /* x and width of the pic (bmp or img) which is part of cnt */ + /* cnt,txt,img,bmp */ + UINT cx, tx, ix, bx, + cw, tw, iw, bw; + BITMAP bmp; - if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_CENTER) - uTextJustify = DT_CENTER; - else if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_RIGHT) - uTextJustify = DT_RIGHT; + cw = tw = iw = bw = 0; + rw = r.right - r.left; + rh = r.bottom - r.top; - if ((phdi->fmt & HDF_BITMAP) && !(phdi->fmt & HDF_BITMAP_ON_RIGHT) && (phdi->hbm)) { - BITMAP bmp; - HDC hdcBitmap; - INT yD, yS, cx, cy, rx, ry; - - GetObjectW (phdi->hbm, sizeof(BITMAP), (LPVOID)&bmp); - - ry = r.bottom - r.top; - rx = r.right - r.left; - - if (ry >= bmp.bmHeight) { - cy = bmp.bmHeight; - yD = r.top + (ry - bmp.bmHeight) / 2; - yS = 0; - } - else { - cy = ry; - yD = r.top; - yS = (bmp.bmHeight - ry) / 2; - - } - - if (rx >= bmp.bmWidth + infoPtr->iMargin) { - cx = bmp.bmWidth; - } - else { - cx = rx - infoPtr->iMargin; - } - - hdcBitmap = CreateCompatibleDC (hdc); - SelectObject (hdcBitmap, phdi->hbm); - BitBlt (hdc, r.left + infoPtr->iMargin, yD, cx, cy, hdcBitmap, 0, yS, SRCCOPY); - DeleteDC (hdcBitmap); - - r.left += (bmp.bmWidth + infoPtr->iMargin); - } - - - if ((phdi->fmt & HDF_BITMAP) && (phdi->fmt & HDF_BITMAP_ON_RIGHT) && (phdi->hbm)) { - BITMAP bmp; - HDC hdcBitmap; - INT xD, yD, yS, cx, cy, rx, ry, tx; - RECT textRect; - - GetObjectW (phdi->hbm, sizeof(BITMAP), (LPVOID)&bmp); - - textRect = r; - if (phdi->fmt & HDF_STRING) { - DrawTextW (hdc, phdi->pszText, -1, - &textRect, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_CALCRECT); - tx = textRect.right - textRect.left; - } - else - tx = 0; - ry = r.bottom - r.top; - rx = r.right - r.left; - - if (ry >= bmp.bmHeight) { - cy = bmp.bmHeight; - yD = r.top + (ry - bmp.bmHeight) / 2; - yS = 0; - } - else { - cy = ry; - yD = r.top; - yS = (bmp.bmHeight - ry) / 2; - - } - - if (r.left + tx + bmp.bmWidth + 2*infoPtr->iMargin <= r.right) { - cx = bmp.bmWidth; - xD = r.left + tx + infoPtr->iMargin; - } - else { - if (rx >= bmp.bmWidth + infoPtr->iMargin ) { - cx = bmp.bmWidth; - xD = r.right - bmp.bmWidth - infoPtr->iMargin; - r.right = xD - infoPtr->iMargin; - } - else { - cx = rx - infoPtr->iMargin; - xD = r.left; - r.right = r.left; - } - } - - hdcBitmap = CreateCompatibleDC (hdc); - SelectObject (hdcBitmap, phdi->hbm); - BitBlt (hdc, xD, yD, cx, cy, hdcBitmap, 0, yS, SRCCOPY); - DeleteDC (hdcBitmap); - } - - if ((phdi->fmt & HDF_IMAGE) && !(phdi->fmt & HDF_BITMAP_ON_RIGHT) && (infoPtr->himl)) { - r.left += infoPtr->iMargin; - ImageList_DrawEx(infoPtr->himl, phdi->iImage, hdc, r.left, r.top + (r.bottom-r.top- infoPtr->himl->cy)/2, - infoPtr->himl->cx, r.bottom-r.top, CLR_DEFAULT, CLR_DEFAULT, 0); - r.left += infoPtr->himl->cx; - } - - if ((phdi->fmt & HDF_IMAGE) && (phdi->fmt & HDF_BITMAP_ON_RIGHT) && (infoPtr->himl)) { + if (phdi->fmt & HDF_STRING) { RECT textRect; - INT tx; - textRect = r; - if (phdi->fmt & HDF_STRING) { - DrawTextW (hdc, phdi->pszText, -1, - &textRect, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_CALCRECT); - tx = textRect.right - textRect.left; - } - else - tx = 0; + DrawTextW (hdc, phdi->pszText, -1, + &textRect, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_CALCRECT); + cw = textRect.right - textRect.left + 2 * infoPtr->iMargin; + } - if (tx < (r.right-r.left - infoPtr->himl->cx - GetSystemMetrics(SM_CXEDGE))) - ImageList_DrawEx(infoPtr->himl, phdi->iImage, hdc, r.left + tx + 2*infoPtr->iMargin, - r.top + (r.bottom-r.top-infoPtr->himl->cy)/2, infoPtr->himl->cx, r.bottom-r.top, - CLR_DEFAULT, CLR_DEFAULT, 0); - else { - INT x = max(r.right - infoPtr->iMargin - infoPtr->himl->cx, r.left); - INT cx = min(infoPtr->himl->cx, r.right-r.left - GetSystemMetrics(SM_CXEDGE)); - ImageList_DrawEx(infoPtr->himl, phdi->iImage, hdc, x , - r.top + (r.bottom-r.top-infoPtr->himl->cy)/2, cx, r.bottom-r.top, - CLR_DEFAULT, CLR_DEFAULT, 0); - r.right -= infoPtr->himl->cx - infoPtr->iMargin; + if ((phdi->fmt & HDF_IMAGE) && (infoPtr->himl)) { + iw = infoPtr->himl->cx + 2 * infoPtr->iMargin; + x = &ix; + w = &iw; + } + + if ((phdi->fmt & HDF_BITMAP) && (phdi->hbm)) { + GetObjectW (phdi->hbm, sizeof(BITMAP), (LPVOID)&bmp); + bw = bmp.bmWidth + 2 * infoPtr->iMargin; + if (!iw) { + x = &bx; + w = &bw; } - } + } - if (((phdi->fmt & HDF_STRING) + if (bw || iw) + cw += *w; + + /* align cx using the unclipped cw */ + if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_LEFT) + cx = r.left; + else if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_CENTER) + cx = r.left + rw / 2 - cw / 2; + else /* HDF_RIGHT */ + cx = r.right - cw; + + /* clip cx & cw */ + if (cx < r.left) + cx = r.left; + if (cx + cw > r.right) + cw = r.right - cx; + + tx = cx + infoPtr->iMargin; + /* since cw might have changed we have to recalculate tw */ + tw = cw - infoPtr->iMargin * 2; + + if (iw || bw) { + tw -= *w; + if (phdi->fmt & HDF_BITMAP_ON_RIGHT) { + /* put pic behind text */ + *x = cx + tw + infoPtr->iMargin * 3; + } else { + *x = cx + infoPtr->iMargin; + /* move text behind pic */ + tx += *w; + } + } + + if (iw && bw) { + /* since we're done with the layout we can + now calculate the position of bmp which + has no influence on alignment and layout + because of img */ + if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_RIGHT) + bx = cx - bw + infoPtr->iMargin; + else + bx = cx + cw + infoPtr->iMargin; + } + + if (iw || bw) { + HDC hClipDC = GetDC(hwnd); + HRGN hClipRgn = CreateRectRgn(r.left, r.top, r.right, r.bottom); + SelectClipRgn(hClipDC, hClipRgn); + + if (bw) { + HDC hdcBitmap = CreateCompatibleDC (hClipDC); + SelectObject (hdcBitmap, phdi->hbm); + BitBlt (hClipDC, bx, r.top + ((INT)rh - bmp.bmHeight) / 2, + bmp.bmWidth, bmp.bmHeight, hdcBitmap, 0, 0, SRCCOPY); + DeleteDC (hdcBitmap); + } + + if (iw) { + ImageList_DrawEx (infoPtr->himl, phdi->iImage, hClipDC, + ix, r.top + ((INT)rh - infoPtr->himl->cy) / 2, + infoPtr->himl->cx, infoPtr->himl->cy, CLR_DEFAULT, CLR_DEFAULT, 0); + } + + DeleteObject(hClipRgn); + DeleteDC(hClipDC); + } + + if (((phdi->fmt & HDF_STRING) || (!(phdi->fmt & (HDF_OWNERDRAW|HDF_STRING|HDF_BITMAP| HDF_BITMAP_ON_RIGHT|HDF_IMAGE)))) /* no explicit format specified? */ && (phdi->pszText)) { - oldBkMode = SetBkMode(hdc, TRANSPARENT); - r.left += infoPtr->iMargin; - r.right -= infoPtr->iMargin; + oldBkMode = SetBkMode(hdc, TRANSPARENT); SetTextColor (hdc, (bHotTrack) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT); + r.left = tx; + r.right = tx + tw; DrawTextW (hdc, phdi->pszText, -1, - &r, uTextJustify|DT_END_ELLIPSIS|DT_VCENTER|DT_SINGLELINE); + &r, DT_LEFT|DT_END_ELLIPSIS|DT_VCENTER|DT_SINGLELINE); if (oldBkMode != TRANSPARENT) SetBkMode(hdc, oldBkMode); } diff --git a/reactos/lib/comctl32/hotkey.c b/reactos/lib/comctl32/hotkey.c index 8957d9678d6..3861dde6e16 100644 --- a/reactos/lib/comctl32/hotkey.c +++ b/reactos/lib/comctl32/hotkey.c @@ -54,7 +54,7 @@ typedef struct tagHOTKEY_INFO BYTE CurrMod; INT CaretPos; DWORD ScanCode; - WCHAR strNone[15]; /* hope its long enough ... */ + WCHAR strNone[15]; /* hope it's long enough ... */ } HOTKEY_INFO; static const WCHAR HOTKEY_plussep[] = { ' ', '+', ' ' }; diff --git a/reactos/lib/comctl32/imagelist.c b/reactos/lib/comctl32/imagelist.c index f392f131ba2..80b7980074a 100644 --- a/reactos/lib/comctl32/imagelist.c +++ b/reactos/lib/comctl32/imagelist.c @@ -98,7 +98,7 @@ static inline BOOL is_valid(HIMAGELIST himl) * nothing * * NOTES - * This function can NOT be used to reduce the number of images. + * This function CANNOT be used to reduce the number of images. */ static void IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy) diff --git a/reactos/lib/comctl32/ipaddress.c b/reactos/lib/comctl32/ipaddress.c index a229e124d34..1e0f50c7b4c 100644 --- a/reactos/lib/comctl32/ipaddress.c +++ b/reactos/lib/comctl32/ipaddress.c @@ -62,6 +62,7 @@ typedef struct { HWND Self; HWND Notify; + BOOL Enabled; IPPART_INFO Part[4]; } IPADDRESS_INFO; @@ -127,12 +128,26 @@ static LRESULT IPADDRESS_Draw (IPADDRESS_INFO *infoPtr, HDC hdc) static const WCHAR dotW[] = { '.', 0 }; RECT rect, rcPart; POINT pt; + COLORREF bgCol, fgCol; int i; TRACE("\n"); GetClientRect (infoPtr->Self, &rect); + + if (infoPtr->Enabled) { + bgCol = COLOR_WINDOW; + fgCol = COLOR_WINDOWTEXT; + } else { + bgCol = COLOR_3DFACE; + fgCol = COLOR_GRAYTEXT; + } + + FillRect (hdc, &rect, (HBRUSH) (bgCol+1)); DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + + SetBkColor (hdc, GetSysColor(bgCol)); + SetTextColor(hdc, GetSysColor(fgCol)); for (i = 0; i < 3; i++) { GetWindowRect (infoPtr->Part[i].EditHwnd, &rcPart); @@ -174,6 +189,7 @@ static LRESULT IPADDRESS_Create (HWND hwnd, LPCREATESTRUCTA lpCreate) edit.bottom = rcClient.bottom - 2; infoPtr->Self = hwnd; + infoPtr->Enabled = FALSE; infoPtr->Notify = lpCreate->hwndParent; for (i = 0; i < 4; i++) { @@ -215,6 +231,20 @@ static LRESULT IPADDRESS_Destroy (IPADDRESS_INFO *infoPtr) } +static LRESULT IPADDRESS_Enable (IPADDRESS_INFO *infoPtr, BOOL enabled) +{ + int i; + + infoPtr->Enabled = enabled; + + for (i = 0; i < 4; i++) + EnableWindow(infoPtr->Part[i].EditHwnd, enabled); + + InvalidateRgn(infoPtr->Self, NULL, FALSE); + return 0; +} + + static LRESULT IPADDRESS_Paint (IPADDRESS_INFO *infoPtr, HDC hdc) { PAINTSTRUCT ps; @@ -517,6 +547,10 @@ IPADDRESS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_DESTROY: return IPADDRESS_Destroy (infoPtr); + case WM_ENABLE: + return IPADDRESS_Enable (infoPtr, (BOOL)wParam); + break; + case WM_PAINT: return IPADDRESS_Paint (infoPtr, (HDC)wParam); diff --git a/reactos/lib/comctl32/listview.c b/reactos/lib/comctl32/listview.c index df00d220e50..8bd2d9f0b1e 100644 --- a/reactos/lib/comctl32/listview.c +++ b/reactos/lib/comctl32/listview.c @@ -24,7 +24,7 @@ * NOTES * * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Oct. 21, 2002, by Dimitrie O. Paun. + * of Comctl32.dll version 6.0 on May. 20, 2005, by James Hawkins. * * Unless otherwise noted, we believe this code to be complete, as per * the specification mentioned above. @@ -32,6 +32,17 @@ * * TODO: * + * Default Message Processing + * -- EN_KILLFOCUS should be handled in WM_COMMAND + * -- WM_CREATE: create the icon and small icon image lists at this point only if + * the LVS_SHAREIMAGELISTS style is not specified. + * -- WM_ERASEBKGND: forward this message to the parent window if the bkgnd + * color is CLR_NONE. + * -- WM_WINDOWPOSCHANGED: arrange the list items if the current view is icon + * or small icon and the LVS_AUTOARRANGE style is specified. + * -- WM_TIMER + * -- WM_WININICHANGE + * * Features * -- Hot item handling, mouse hovering * -- Workareas support @@ -74,6 +85,8 @@ * -- LVS_NOLABELWRAP * -- LVS_NOSCROLL (see Q137520) * -- LVS_SORTASCENDING, LVS_SORTDESCENDING + * -- LVS_ALIGNTOP + * -- LVS_TYPESTYLEMASK * * Extended Styles * -- LVS_EX_BORDERSELECT @@ -99,6 +112,7 @@ * -- LVN_ODFINDITEM * -- LVN_SETDISPINFO * -- NM_HOVER + * -- LVN_BEGINRDRAG * * Messages: * -- LVM_CANCELEDITLABEL @@ -130,6 +144,20 @@ * -- LVM_SORTGROUPS * -- LVM_SORTITEMSEX * + * Macros: + * -- ListView_GetCheckSate, ListView_SetCheckState + * -- ListView_GetHoverTime, ListView_SetHoverTime + * -- ListView_GetISearchString + * -- ListView_GetNumberOfWorkAreas + * -- ListView_GetOrigin + * -- ListView_GetTextBkColor + * -- ListView_GetUnicodeFormat, ListView_SetUnicodeFormat + * -- ListView_GetWorkAreas, ListView_SetWorkAreas + * -- ListView_SortItemsEx + * + * Functions: + * -- LVGroupComparE + * * Known differences in message stream from native control (not known if * these differences cause problems): * LVM_INSERTITEM issues LVM_SETITEMSTATE and LVM_SETITEM in certain cases. @@ -225,6 +253,7 @@ typedef struct tagLISTVIEW_INFO HIMAGELIST himlState; BOOL bLButtonDown; BOOL bRButtonDown; + POINT ptClickPos; /* point where the user clicked */ BOOL bNoItemMetrics; /* flags if item metrics are not yet computed */ INT nItemHeight; INT nItemWidth; @@ -394,6 +423,7 @@ static INT LISTVIEW_GetTopIndex(LISTVIEW_INFO *); static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *, INT, BOOL); static HWND CreateEditLabelT(LISTVIEW_INFO *, LPCWSTR, DWORD, INT, INT, INT, INT, BOOL); static HIMAGELIST LISTVIEW_SetImageList(LISTVIEW_INFO *, INT, HIMAGELIST); +static INT LISTVIEW_HitTest(LISTVIEW_INFO *, LPLVHITTESTINFO, BOOL, BOOL); /******** Text handling functions *************************************/ @@ -3143,6 +3173,22 @@ static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *infoPtr, INT nItem) return bResult; } +static BOOL LISTVIEW_GetItemAtPt(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, POINT pt) +{ + LVHITTESTINFO lvHitTestInfo; + + ZeroMemory(&lvHitTestInfo, sizeof(lvHitTestInfo)); + lvHitTestInfo.pt.x = pt.x; + lvHitTestInfo.pt.y = pt.y; + + LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE); + + lpLVItem->mask = LVIF_PARAM; + lpLVItem->iItem = lvHitTestInfo.iItem; + lpLVItem->iSubItem = 0; + + return LISTVIEW_GetItemT(infoPtr, lpLVItem, TRUE); +} /*** * DESCRIPTION: @@ -3164,9 +3210,17 @@ static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *infoPtr, INT nItem) */ static LRESULT LISTVIEW_MouseHover(LISTVIEW_INFO *infoPtr, WORD fwKyes, INT x, INT y) { - if(infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT) - /* FIXME: select the item!!! */ - /*LISTVIEW_GetItemAtPt(infoPtr, pt)*/; + if (infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT) + { + LVITEMW item; + POINT pt; + + pt.x = x; + pt.y = y; + + if (LISTVIEW_GetItemAtPt(infoPtr, &item, pt)) + LISTVIEW_SetSelection(infoPtr, item.iItem); + } return 0; } @@ -3185,7 +3239,24 @@ static LRESULT LISTVIEW_MouseHover(LISTVIEW_INFO *infoPtr, WORD fwKyes, INT x, I */ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, INT y) { - TRACKMOUSEEVENT trackinfo; + TRACKMOUSEEVENT trackinfo; + + if (infoPtr->bLButtonDown && DragDetect(infoPtr->hwndSelf, infoPtr->ptClickPos)) + { + LVHITTESTINFO lvHitTestInfo; + NMLISTVIEW nmlv; + + lvHitTestInfo.pt = infoPtr->ptClickPos; + LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE); + + ZeroMemory(&nmlv, sizeof(nmlv)); + nmlv.iItem = lvHitTestInfo.iItem; + nmlv.ptAction = infoPtr->ptClickPos; + + notify_listview(infoPtr, LVN_BEGINDRAG, &nmlv); + + return 0; + } /* see if we are supposed to be tracking mouse hovering */ if(infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT) { @@ -7490,6 +7561,25 @@ fail: return -1; } +/*** + * DESCRIPTION: + * Enables the listview control. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] bEnable : specifies whether to enable or disable the window + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_Enable(LISTVIEW_INFO *infoPtr, BOOL bEnable) +{ + if (infoPtr->dwStyle & LVS_OWNERDRAWFIXED) + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + return TRUE; +} + /*** * DESCRIPTION: * Erases the background of the listview control. @@ -7905,68 +7995,6 @@ static LRESULT LISTVIEW_KillFocus(LISTVIEW_INFO *infoPtr) return 0; } - -/*** - * DESCRIPTION: - * Track mouse/dragging - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] pt : mouse coordinate - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_TrackMouse(LISTVIEW_INFO *infoPtr, POINT pt) -{ - INT cxDrag = GetSystemMetrics(SM_CXDRAG); - INT cyDrag = GetSystemMetrics(SM_CYDRAG); - RECT r; - MSG msg; - - TRACE("\n"); - - r.top = pt.y - cyDrag; - r.left = pt.x - cxDrag; - r.bottom = pt.y + cyDrag; - r.right = pt.x + cxDrag; - - SetCapture(infoPtr->hwndSelf); - - while (1) - { - if (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) - { - if (msg.message == WM_MOUSEMOVE) - { - pt.x = (short)LOWORD(msg.lParam); - pt.y = (short)HIWORD(msg.lParam); - if (PtInRect(&r, pt)) - continue; - else - { - ReleaseCapture(); - return 1; - } - } - else if (msg.message >= WM_LBUTTONDOWN && - msg.message <= WM_RBUTTONDBLCLK) - { - break; - } - - DispatchMessageW(&msg); - } - - if (GetCapture() != infoPtr->hwndSelf) - return 0; - } - - ReleaseCapture(); - return 0; -} - - /*** * DESCRIPTION: * Processes double click messages (left mouse button). @@ -8027,8 +8055,9 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, IN if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf); - /* set left button down flag */ + /* set left button down flag and record the click position */ infoPtr->bLButtonDown = TRUE; + infoPtr->ptClickPos = pt; lvHitTestInfo.pt.x = x; lvHitTestInfo.pt.y = y; @@ -8051,19 +8080,6 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, IN } return 0; } - if (LISTVIEW_TrackMouse(infoPtr, lvHitTestInfo.pt)) - { - NMLISTVIEW nmlv; - - ZeroMemory(&nmlv, sizeof(nmlv)); - nmlv.iItem = nItem; - nmlv.ptAction.x = lvHitTestInfo.pt.x; - nmlv.ptAction.y = lvHitTestInfo.pt.y; - - notify_listview(infoPtr, LVN_BEGINDRAG, &nmlv); - - return 0; - } if (infoPtr->dwStyle & LVS_SINGLESEL) { @@ -8292,6 +8308,11 @@ static LRESULT LISTVIEW_HeaderNotification(LISTVIEW_INFO *infoPtr, const NMHEADE notify_listview(infoPtr, LVN_COLUMNCLICK, &nmlv); } break; + + case HDN_DIVIDERDBLCLICKW: + case HDN_DIVIDERDBLCLICKA: + LISTVIEW_SetColumnWidth(infoPtr, lpnmh->iItem, LVSCW_AUTOSIZE); + break; } return 0; @@ -8621,7 +8642,7 @@ static LRESULT LISTVIEW_SetRedraw(LISTVIEW_INFO *infoPtr, BOOL bRedraw) { TRACE("infoPtr->bRedraw=%d, bRedraw=%d\n", infoPtr->bRedraw, bRedraw); - /* we can not use straight equality here because _any_ non-zero value is TRUE */ + /* we cannot use straight equality here because _any_ non-zero value is TRUE */ if ((infoPtr->bRedraw && bRedraw) || (!infoPtr->bRedraw && !bRedraw)) return 0; infoPtr->bRedraw = bRedraw; @@ -9194,6 +9215,9 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_CREATE: return LISTVIEW_Create(hwnd, (LPCREATESTRUCTW)lParam); + case WM_ENABLE: + return LISTVIEW_Enable(infoPtr, (BOOL)wParam); + case WM_ERASEBKGND: return LISTVIEW_EraseBkgnd(infoPtr, (HDC)wParam); diff --git a/reactos/lib/comctl32/monthcal.c b/reactos/lib/comctl32/monthcal.c index 84aa1dbca6e..75fa4e47039 100644 --- a/reactos/lib/comctl32/monthcal.c +++ b/reactos/lib/comctl32/monthcal.c @@ -473,29 +473,23 @@ static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, PAINTSTRUCT* ps) SetTextColor(hdc, infoPtr->titletxt); currentFont = SelectObject(hdc, infoPtr->hBoldFont); - /* titlemonth->left and right are set in MONTHCAL_UpdateSize */ - titlemonth->left = title->left; - titlemonth->right = title->right; - GetLocaleInfoW( LOCALE_USER_DEFAULT,LOCALE_SMONTHNAME1+infoPtr->currentMonth -1, buf1,countof(buf1)); wsprintfW(buf, fmt1W, buf1, infoPtr->currentYear); - if(IntersectRect(&rcTemp, &(ps->rcPaint), titlemonth)) + if(IntersectRect(&rcTemp, &(ps->rcPaint), title)) { - DrawTextW(hdc, buf, strlenW(buf), titlemonth, + DrawTextW(hdc, buf, strlenW(buf), title, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } - SelectObject(hdc, infoPtr->hFont); - /* titlemonth left/right contained rect for whole titletxt('June 1999') * MCM_HitTestInfo wants month & year rects, so prepare these now. *(no, we can't draw them separately; the whole text is centered) */ GetTextExtentPoint32W(hdc, buf, strlenW(buf), &size); - titlemonth->left = title->right / 2 - size.cx / 2; - titleyear->right = title->right / 2 + size.cx / 2; + titlemonth->left = title->right / 2 + title->left / 2 - size.cx / 2; + titleyear->right = title->right / 2 + title->left / 2 + size.cx / 2; GetTextExtentPoint32W(hdc, buf1, strlenW(buf1), &size); titlemonth->right = titlemonth->left + size.cx; titleyear->left = titlemonth->right; @@ -524,6 +518,7 @@ static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, PAINTSTRUCT* ps) infoPtr->wdays.left = infoPtr->days.left = infoPtr->weeknums.right; /* draw day abbreviations */ + SelectObject(hdc, infoPtr->hFont); SetBkColor(hdc, infoPtr->monthbk); SetTextColor(hdc, infoPtr->trailingtxt); @@ -673,9 +668,9 @@ static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, PAINTSTRUCT* ps) wsprintfW(buf, fmt2W, buf1, buf2); SelectObject(hdc, infoPtr->hBoldFont); + DrawTextW(hdc, buf, -1, &rtoday, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE); if(IntersectRect(&rcTemp, &(ps->rcPaint), &rtoday)) { - DrawTextW(hdc, buf, -1, &rtoday, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE); DrawTextW(hdc, buf, -1, &rtoday, DT_LEFT | DT_VCENTER | DT_SINGLELINE); } SelectObject(hdc, infoPtr->hFont); @@ -1424,18 +1419,19 @@ MONTHCAL_LButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam) 0, WS_VISIBLE | WS_CHILD |UDS_SETBUDDYINT, infoPtr->titleyear.left+3,infoPtr->titlebtnnext.top, - infoPtr->titleyear.right-infoPtr->titleyear.left, + infoPtr->titleyear.right-infoPtr->titleyear.left+4, infoPtr->textHeight, infoPtr->hwndSelf, NULL, NULL, NULL); + SendMessageW( infoPtr->hWndYearEdit, WM_SETFONT, (WPARAM) infoPtr->hBoldFont, (LPARAM)TRUE); infoPtr->hWndYearUpDown=CreateWindowExW(0, UPDOWN_CLASSW, 0, WS_VISIBLE | WS_CHILD |UDS_SETBUDDYINT|UDS_NOTHOUSANDS|UDS_ARROWKEYS, - infoPtr->titleyear.right+6,infoPtr->titlebtnnext.top, - 20, + infoPtr->titleyear.right+7,infoPtr->titlebtnnext.top, + 18, infoPtr->textHeight, infoPtr->hwndSelf, NULL, @@ -1733,7 +1729,7 @@ static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr) xdiv = (dwStyle & MCS_WEEKNUMBERS) ? 8 : 7; - infoPtr->width_increment = size.cx * 2; + infoPtr->width_increment = size.cx * 2 + 4; infoPtr->height_increment = infoPtr->textHeight; left_offset = (rcClient.right - rcClient.left) - (infoPtr->width_increment * xdiv); @@ -1852,7 +1848,7 @@ MONTHCAL_Create(HWND hwnd, WPARAM wParam, LPARAM lParam) /* initialize info structure */ /* FIXME: calculate systemtime ->> localtime(substract timezoneinfo) */ - GetSystemTime(&infoPtr->todaysDate); + GetLocalTime(&infoPtr->todaysDate); MONTHCAL_SetFirstDayOfWeek(infoPtr, (LPARAM)-1); infoPtr->currentMonth = infoPtr->todaysDate.wMonth; infoPtr->currentYear = infoPtr->todaysDate.wYear; diff --git a/reactos/lib/comctl32/tab.c b/reactos/lib/comctl32/tab.c index 3287b573cb4..9f4f280819b 100644 --- a/reactos/lib/comctl32/tab.c +++ b/reactos/lib/comctl32/tab.c @@ -1727,12 +1727,12 @@ TAB_DrawItemInterior else drawRect->bottom-=center_offset_h; - center_offset_v = ((drawRect->right - drawRect->left) - ((rcText.bottom - rcText.top) + infoPtr->uVItemPadding)) / 2; + center_offset_v = ((drawRect->right - drawRect->left) - (rcText.bottom - rcText.top) + infoPtr->uVItemPadding) / 2; } else { drawRect->left += center_offset_h; - center_offset_v = ((drawRect->bottom - drawRect->top) - ((rcText.bottom - rcText.top) + infoPtr->uVItemPadding)) / 2; + center_offset_v = ((drawRect->bottom - drawRect->top) - (rcText.bottom - rcText.top) + infoPtr->uVItemPadding) / 2; } if (center_offset_v < 0) @@ -2961,9 +2961,16 @@ TAB_Destroy (TAB_INFO *infoPtr) return 0; } +static LRESULT TAB_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + if (!wParam) + return 0; + return WVR_ALIGNTOP; +} + static inline LRESULT TAB_SetItemExtra (TAB_INFO *infoPtr, INT cbInfo) -{ +{ if (!infoPtr || cbInfo <= 0) return FALSE; @@ -3143,6 +3150,9 @@ TAB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_NCHITTEST: return TAB_NCHitTest(infoPtr, lParam); + case WM_NCCALCSIZE: + return TAB_NCCalcSize(hwnd, wParam, lParam); + default: if (uMsg >= WM_USER && uMsg < WM_APP) WARN("unknown msg %04x wp=%08x lp=%08lx\n", diff --git a/reactos/lib/comctl32/toolbar.c b/reactos/lib/comctl32/toolbar.c index b11ea510d01..b7406736dc6 100644 --- a/reactos/lib/comctl32/toolbar.c +++ b/reactos/lib/comctl32/toolbar.c @@ -6233,7 +6233,7 @@ TOOLBAR_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam) * forgets to specify TBSTYLE_TRANSPARENT but does specify either * CCS_TOP or CCS_BOTTOM (_NOMOVEY and _TOP), then the control * does *not* set TBSTYLE_TRANSPARENT even though it should!!!! - * Some how, the only cases of this seem to be MFC programs. + * Somehow, the only cases of this seem to be MFC programs. * * Note also that the addition of _TRANSPARENT occurs *only* here. It * does not occur in the WM_STYLECHANGING routine. diff --git a/reactos/lib/comctl32/updown.c b/reactos/lib/comctl32/updown.c index 9dc705aad42..da2dcc19418 100644 --- a/reactos/lib/comctl32/updown.c +++ b/reactos/lib/comctl32/updown.c @@ -775,9 +775,12 @@ static LRESULT WINAPI UpDownWindowProc(HWND hwnd, UINT message, WPARAM wParam, L break; case WM_ENABLE: - infoPtr->dwStyle &= ~WS_DISABLED; - infoPtr->dwStyle |= (wParam ? 0 : WS_DISABLED); - if (infoPtr->dwStyle & WS_DISABLED) UPDOWN_CancelMode (infoPtr); + if (wParam) { + infoPtr->dwStyle &= ~WS_DISABLED; + } else { + infoPtr->dwStyle |= WS_DISABLED; + UPDOWN_CancelMode (infoPtr); + } InvalidateRect (infoPtr->Self, NULL, FALSE); break; diff --git a/reactos/lib/comdlg32/Makefile.in b/reactos/lib/comdlg32/Makefile.in index 7a34e9d1a3e..13851c30559 100644 --- a/reactos/lib/comdlg32/Makefile.in +++ b/reactos/lib/comdlg32/Makefile.in @@ -3,6 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = comdlg32.dll +IMPORTLIB = libcomdlg32.$(IMPLIBEXT) IMPORTS = shell32 shlwapi comctl32 winspool user32 gdi32 kernel32 ntdll EXTRALIBS = -luuid @@ -22,7 +23,6 @@ C_SRCS16 = \ filedlg16.c \ finddlg.c \ fontdlg16.c \ - generic.c \ printdlg16.c SPEC_SRCS16 = commdlg.spec diff --git a/reactos/lib/comdlg32/commdlg.spec b/reactos/lib/comdlg32/commdlg.spec index 283ac4b5920..165c64ac02e 100644 --- a/reactos/lib/comdlg32/commdlg.spec +++ b/reactos/lib/comdlg32/commdlg.spec @@ -24,4 +24,3 @@ #29 pascal DWLBSUBCLASS exported, shared data #30 pascal DWUPARROWHACK exported, shared data #31 pascal DWOKSUBCLASS exported, shared data -32 pascal DllEntryPoint(long word word word long word) COMMDLG_DllEntryPoint diff --git a/reactos/lib/comdlg32/filedlg.c b/reactos/lib/comdlg32/filedlg.c index 41dd83ffde0..e1722de3ab2 100644 --- a/reactos/lib/comdlg32/filedlg.c +++ b/reactos/lib/comdlg32/filedlg.c @@ -1835,7 +1835,13 @@ BOOL FILEDLG95_OnOpen(HWND hwnd) TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf); - if(lstrlenW(lpwstrTemp)==2) PathAddBackslashW(lpwstrTemp); + /* append a backslash to drive letters */ + if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' && + ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') || + (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z'))) + { + PathAddBackslashW(lpwstrTemp); + } dwAttributes = SFGAO_FOLDER; if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes))) diff --git a/reactos/lib/comdlg32/filedlgbrowser.c b/reactos/lib/comdlg32/filedlgbrowser.c index e4ae8bd2704..51bca31262b 100644 --- a/reactos/lib/comdlg32/filedlgbrowser.c +++ b/reactos/lib/comdlg32/filedlgbrowser.c @@ -776,7 +776,8 @@ HRESULT WINAPI IShellBrowserImpl_ICommDlgBrowser_OnDefaultCommand(ICommDlgBrowse else { /* Tell the dialog that the user selected a file */ - hRes = PostMessageA(This->hwndOwner, WM_COMMAND, IDOK, 0L); + PostMessageA(This->hwndOwner, WM_COMMAND, IDOK, 0L); + hRes = S_OK; } /* Free memory used by pidl */ diff --git a/reactos/lib/comdlg32/fontdlg.c b/reactos/lib/comdlg32/fontdlg.c index 8237f1edae9..829c89bcc4e 100644 --- a/reactos/lib/comdlg32/fontdlg.c +++ b/reactos/lib/comdlg32/fontdlg.c @@ -1024,18 +1024,15 @@ LRESULT CFn_WMCommand(HWND hDlg, WPARAM wParam, LPARAM lParam, LRESULT CFn_WMDestroy(HWND hwnd, WPARAM wParam, LPARAM lParam, LPCHOOSEFONTW lpcfw) { LPCHOOSEFONTA lpcfa; - LPCSTR lpTemplateName; LPSTR lpszStyle; LPLOGFONTA lpLogFonta; int len; lpcfa = GetPropW(hwnd, strWineFontData_a); lpLogFonta = lpcfa->lpLogFont; - lpTemplateName = lpcfa->lpTemplateName; lpszStyle = lpcfa->lpszStyle; memcpy(lpcfa, lpcfw, sizeof(CHOOSEFONTA)); lpcfa->lpLogFont = lpLogFonta; - lpcfa->lpTemplateName = lpTemplateName; lpcfa->lpszStyle = lpszStyle; memcpy(lpcfa->lpLogFont, lpcfw->lpLogFont, sizeof(LOGFONTA)); WideCharToMultiByte(CP_ACP, 0, lpcfw->lpLogFont->lfFaceName, @@ -1047,9 +1044,9 @@ LRESULT CFn_WMDestroy(HWND hwnd, WPARAM wParam, LPARAM lParam, LPCHOOSEFONTW lpc HeapFree(GetProcessHeap(), 0, lpcfw->lpszStyle); } - HeapFree(GetProcessHeap(), 0, (LPBYTE)lpcfw->lpTemplateName); HeapFree(GetProcessHeap(), 0, lpcfw->lpLogFont); HeapFree(GetProcessHeap(), 0, lpcfw); + SetPropW(hwnd, strWineFontData, 0); return TRUE; } @@ -1141,13 +1138,6 @@ INT_PTR CALLBACK FormatCharDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam, MultiByteToWideChar(CP_ACP, 0, lpcfa->lpszStyle, -1, lpcfw->lpszStyle, len); } - if((lpcfa->Flags & CF_ENABLETEMPLATE) && lpcfa->lpTemplateName) { - len = MultiByteToWideChar(CP_ACP, 0, lpcfa->lpTemplateName, -1, NULL, 0); - lpcfw->lpTemplateName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpcfa->lpTemplateName, - -1, (LPWSTR)lpcfw->lpTemplateName, len); - } - if (!CFn_WMInitDialog(hDlg, wParam, lParam, lpcfw)) { TRACE("CFn_WMInitDialog returned FALSE\n"); diff --git a/reactos/lib/comdlg32/generic.c b/reactos/lib/comdlg32/generic.c deleted file mode 100644 index e54df203041..00000000000 --- a/reactos/lib/comdlg32/generic.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * COMMDLG/COMDLG32 functions - * - * Copyright 1994 Martin Ayotte - * Copyright 1996 Albrecht Kleine - * Copyright 1998,1999 Bertho Stultiens - * Copyright 1999 Klaas van Gend - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "commdlg.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -#include "cdlg.h" -#include "cdlg16.h" - -/*********************************************************************** - * DllEntryPoint [COMMDLG.32] - * - * Initialization code for the COMMDLG DLL - * - * RETURNS: - */ -BOOL WINAPI COMMDLG_DllEntryPoint(DWORD Reason, HINSTANCE16 hInst, WORD ds, WORD HeapSize, DWORD res1, WORD res2) -{ - TRACE("(%08lx, %04x, %04x, %04x, %08lx, %04x)\n", Reason, hInst, ds, HeapSize, res1, res2); - return TRUE; -} - - -/*********************************************************************** - * CommDlgExtendedError16 [COMMDLG.26] - * - * Get the last error value if a commdlg function fails. - * RETURNS - * Current error value which might not be valid - * if a previous call succeeded. - */ -DWORD WINAPI CommDlgExtendedError16(void) -{ - return CommDlgExtendedError(); -} diff --git a/reactos/lib/cpl/desk/en.rc b/reactos/lib/cpl/desk/en.rc index 8e8c8cad024..a4c4c4fbb9c 100644 --- a/reactos/lib/cpl/desk/en.rc +++ b/reactos/lib/cpl/desk/en.rc @@ -98,7 +98,7 @@ BEGIN IDS_COLOR_4BIT "16 Colors" IDS_COLOR_8BIT "256 Colors" IDS_COLOR_16BIT "High Color (16 Bit)" - IDS_COLOR_32BIT "True Color (24 Bit)" + IDS_COLOR_24BIT "True Color (24 Bit)" IDS_COLOR_32BIT "True Color (32 Bit)" IDS_PIXEL "%lux%lu Pixel" END diff --git a/reactos/lib/cpl/desk/resource.h b/reactos/lib/cpl/desk/resource.h index 3a9f6696481..988dd019073 100644 --- a/reactos/lib/cpl/desk/resource.h +++ b/reactos/lib/cpl/desk/resource.h @@ -61,6 +61,7 @@ #define IDS_COLOR_4BIT 2904 #define IDS_COLOR_8BIT 2908 #define IDS_COLOR_16BIT 2916 +#define IDS_COLOR_24BIT 2924 #define IDS_COLOR_32BIT 2932 #endif /* __CPL_DESK_RESOURCE_H__ */ diff --git a/reactos/lib/cpl/desk/settings.c b/reactos/lib/cpl/desk/settings.c index 0b0597701cd..cc908925757 100644 --- a/reactos/lib/cpl/desk/settings.c +++ b/reactos/lib/cpl/desk/settings.c @@ -62,14 +62,18 @@ UpdateDisplay(IN HWND hwndDlg) LoadString(hApplet, IDS_PIXEL, Pixel, sizeof(Pixel) / sizeof(TCHAR)); _stprintf(Buffer, Pixel, CurrentDisplayDevice->CurrentSettings->dmPelsWidth, CurrentDisplayDevice->CurrentSettings->dmPelsHeight, Pixel); SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION_TEXT, WM_SETTEXT, 0, (LPARAM)Buffer); - + + for (index = 0; index < CurrentDisplayDevice->ResolutionsCount; index++) + { + if (CurrentDisplayDevice->Resolutions[index].dmPelsWidth == CurrentDisplayDevice->CurrentSettings->dmPelsWidth && CurrentDisplayDevice->Resolutions[index].dmPelsHeight == CurrentDisplayDevice->CurrentSettings->dmPelsHeight) { SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_SETPOS, TRUE, index); break; } + } if (LoadString(hApplet, (2900 + CurrentDisplayDevice->CurrentSettings->dmBitsPerPel), Buffer, sizeof(Buffer) / sizeof(TCHAR))) SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_SELECTSTRING, -1, (LPARAM)Buffer); } @@ -84,7 +88,7 @@ GetPossibleSettings(IN LPTSTR DeviceName, OUT DWORD* pSettingsCount, OUT PSETTIN PSETTINGS_ENTRY Settings = NULL; HDC hDC; PSETTINGS_ENTRY Current; - DWORD bpp, xres, yres; + DWORD bpp, xres, yres, checkbpp; /* Get current settings */ *CurrentSettings = NULL; @@ -101,13 +105,16 @@ GetPossibleSettings(IN LPTSTR DeviceName, OUT DWORD* pSettingsCount, OUT PSETTIN while (EnumDisplaySettingsEx(DeviceName, iMode, &devmode, dwFlags)) { + if (devmode.dmBitsPerPel==8 || devmode.dmBitsPerPel==16 || devmode.dmBitsPerPel==24 || devmode.dmBitsPerPel==32) checkbpp=1; + else checkbpp=0; + if (devmode.dmPelsWidth < 640 || - devmode.dmPelsHeight < 480) + devmode.dmPelsHeight < 480 || checkbpp == 0) { iMode++; continue; } - + Current = HeapAlloc(GetProcessHeap(), 0, sizeof(SETTINGS_ENTRY)); if (Current != NULL) { diff --git a/reactos/lib/cpl/desk/sv.rc b/reactos/lib/cpl/desk/sv.rc index 8cd3b1e259d..172d4c63afb 100644 --- a/reactos/lib/cpl/desk/sv.rc +++ b/reactos/lib/cpl/desk/sv.rc @@ -76,7 +76,7 @@ BEGIN IDS_COLOR_4BIT "16 färger" IDS_COLOR_8BIT "256 färger" IDS_COLOR_16BIT "65 536 färger (16 Bit)" - IDS_COLOR_32BIT "16,7 miljoner färger (24 Bit)" + IDS_COLOR_24BIT "16,7 miljoner färger (24 Bit)" IDS_COLOR_32BIT "16,7 miljoner färger (32 Bit)" IDS_PIXEL "%lux%lu Pixlar" END diff --git a/reactos/lib/dinput/Makefile.in b/reactos/lib/dinput/Makefile.in index ab300725a72..1b36151b174 100644 --- a/reactos/lib/dinput/Makefile.in +++ b/reactos/lib/dinput/Makefile.in @@ -11,7 +11,7 @@ C_SRCS = \ device.c \ dinput_main.c \ joystick_linux.c \ - joystick_linuxinput.c \ + joystick_linuxinput.c \ keyboard.c \ mouse.c \ regsvr.c diff --git a/reactos/lib/dinput/data_formats.c b/reactos/lib/dinput/data_formats.c index 9edaaab3631..7962a67b187 100644 --- a/reactos/lib/dinput/data_formats.c +++ b/reactos/lib/dinput/data_formats.c @@ -16,6 +16,10 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* TODO: + * add keyboard + */ + #include #include "windef.h" @@ -23,7 +27,7 @@ #define numObjects(x) (sizeof(x) / sizeof(x[0])) -static const DIOBJECTDATAFORMAT dfDIJoystick[] = { +DIOBJECTDATAFORMAT dfDIJoystick[] = { { &GUID_XAxis,DIJOFS_X,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, { &GUID_YAxis,DIJOFS_Y,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, { &GUID_ZAxis,DIJOFS_Z,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, @@ -76,10 +80,10 @@ const DIDATAFORMAT c_dfDIJoystick = { DIDF_ABSAXIS, sizeof(DIJOYSTATE2), numObjects(dfDIJoystick), - (LPDIOBJECTDATAFORMAT)dfDIJoystick + dfDIJoystick }; -static const DIOBJECTDATAFORMAT dfDIJoystick2[] = { +DIOBJECTDATAFORMAT dfDIJoystick2[] = { { &GUID_XAxis,DIJOFS_X,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, { &GUID_YAxis,DIJOFS_Y,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, { &GUID_ZAxis,DIJOFS_Z,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, @@ -252,10 +256,10 @@ const DIDATAFORMAT c_dfDIJoystick2 = { DIDF_ABSAXIS, sizeof(DIJOYSTATE2), numObjects(dfDIJoystick2), - (LPDIOBJECTDATAFORMAT)dfDIJoystick2 + dfDIJoystick2 }; -static const DIOBJECTDATAFORMAT dfDIMouse[] = { +DIOBJECTDATAFORMAT dfDIMouse[] = { { &GUID_XAxis, DIMOFS_X, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, { &GUID_YAxis, DIMOFS_Y, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, { &GUID_ZAxis, DIMOFS_Z, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, @@ -271,10 +275,10 @@ const DIDATAFORMAT c_dfDIMouse = { DIDF_RELAXIS, sizeof(DIMOUSESTATE), numObjects(dfDIMouse), - (LPDIOBJECTDATAFORMAT)dfDIMouse + dfDIMouse }; -static const DIOBJECTDATAFORMAT dfDIMouse2[] = { +DIOBJECTDATAFORMAT dfDIMouse2[] = { { &GUID_XAxis, DIMOFS_X, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, { &GUID_YAxis, DIMOFS_Y, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, { &GUID_ZAxis, DIMOFS_Z, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, @@ -294,273 +298,5 @@ const DIDATAFORMAT c_dfDIMouse2 = { DIDF_RELAXIS, sizeof(DIMOUSESTATE2), numObjects(dfDIMouse2), - (LPDIOBJECTDATAFORMAT)dfDIMouse2 -}; - -static const DIOBJECTDATAFORMAT dfDIKeyboard[] = { - { &GUID_Key,0,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(0),0}, - { &GUID_Key,1,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(1),0}, - { &GUID_Key,2,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(2),0}, - { &GUID_Key,3,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(3),0}, - { &GUID_Key,4,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(4),0}, - { &GUID_Key,5,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(5),0}, - { &GUID_Key,6,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(6),0}, - { &GUID_Key,7,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(7),0}, - { &GUID_Key,8,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(8),0}, - { &GUID_Key,9,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(9),0}, - { &GUID_Key,10,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(10),0}, - { &GUID_Key,11,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(11),0}, - { &GUID_Key,12,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(12),0}, - { &GUID_Key,13,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(13),0}, - { &GUID_Key,14,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(14),0}, - { &GUID_Key,15,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(15),0}, - { &GUID_Key,16,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(16),0}, - { &GUID_Key,17,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(17),0}, - { &GUID_Key,18,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(18),0}, - { &GUID_Key,19,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(19),0}, - { &GUID_Key,20,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(20),0}, - { &GUID_Key,21,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(21),0}, - { &GUID_Key,22,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(22),0}, - { &GUID_Key,23,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(23),0}, - { &GUID_Key,24,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(24),0}, - { &GUID_Key,25,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(25),0}, - { &GUID_Key,26,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(26),0}, - { &GUID_Key,27,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(27),0}, - { &GUID_Key,28,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(28),0}, - { &GUID_Key,29,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(29),0}, - { &GUID_Key,30,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(30),0}, - { &GUID_Key,31,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(31),0}, - { &GUID_Key,32,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(32),0}, - { &GUID_Key,33,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(33),0}, - { &GUID_Key,34,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(34),0}, - { &GUID_Key,35,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(35),0}, - { &GUID_Key,36,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(36),0}, - { &GUID_Key,37,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(37),0}, - { &GUID_Key,38,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(38),0}, - { &GUID_Key,39,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(39),0}, - { &GUID_Key,40,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(40),0}, - { &GUID_Key,41,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(41),0}, - { &GUID_Key,42,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(42),0}, - { &GUID_Key,43,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(43),0}, - { &GUID_Key,44,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(44),0}, - { &GUID_Key,45,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(45),0}, - { &GUID_Key,46,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(46),0}, - { &GUID_Key,47,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(47),0}, - { &GUID_Key,48,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(48),0}, - { &GUID_Key,49,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(49),0}, - { &GUID_Key,50,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(50),0}, - { &GUID_Key,51,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(51),0}, - { &GUID_Key,52,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(52),0}, - { &GUID_Key,53,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(53),0}, - { &GUID_Key,54,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(54),0}, - { &GUID_Key,55,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(55),0}, - { &GUID_Key,56,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(56),0}, - { &GUID_Key,57,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(57),0}, - { &GUID_Key,58,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(58),0}, - { &GUID_Key,59,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(59),0}, - { &GUID_Key,60,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(60),0}, - { &GUID_Key,61,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(61),0}, - { &GUID_Key,62,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(62),0}, - { &GUID_Key,63,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(63),0}, - { &GUID_Key,64,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(64),0}, - { &GUID_Key,65,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(65),0}, - { &GUID_Key,66,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(66),0}, - { &GUID_Key,67,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(67),0}, - { &GUID_Key,68,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(68),0}, - { &GUID_Key,69,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(69),0}, - { &GUID_Key,70,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(70),0}, - { &GUID_Key,71,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(71),0}, - { &GUID_Key,72,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(72),0}, - { &GUID_Key,73,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(73),0}, - { &GUID_Key,74,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(74),0}, - { &GUID_Key,75,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(75),0}, - { &GUID_Key,76,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(76),0}, - { &GUID_Key,77,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(77),0}, - { &GUID_Key,78,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(78),0}, - { &GUID_Key,79,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(79),0}, - { &GUID_Key,80,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(80),0}, - { &GUID_Key,81,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(81),0}, - { &GUID_Key,82,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(82),0}, - { &GUID_Key,83,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(83),0}, - { &GUID_Key,84,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(84),0}, - { &GUID_Key,85,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(85),0}, - { &GUID_Key,86,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(86),0}, - { &GUID_Key,87,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(87),0}, - { &GUID_Key,88,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(88),0}, - { &GUID_Key,89,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(89),0}, - { &GUID_Key,90,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(90),0}, - { &GUID_Key,91,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(91),0}, - { &GUID_Key,92,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(92),0}, - { &GUID_Key,93,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(93),0}, - { &GUID_Key,94,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(94),0}, - { &GUID_Key,95,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(95),0}, - { &GUID_Key,96,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(96),0}, - { &GUID_Key,97,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(97),0}, - { &GUID_Key,98,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(98),0}, - { &GUID_Key,99,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(99),0}, - { &GUID_Key,100,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(100),0}, - { &GUID_Key,101,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(101),0}, - { &GUID_Key,102,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(102),0}, - { &GUID_Key,103,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(103),0}, - { &GUID_Key,104,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(104),0}, - { &GUID_Key,105,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(105),0}, - { &GUID_Key,106,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(106),0}, - { &GUID_Key,107,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(107),0}, - { &GUID_Key,108,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(108),0}, - { &GUID_Key,109,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(109),0}, - { &GUID_Key,110,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(110),0}, - { &GUID_Key,111,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(111),0}, - { &GUID_Key,112,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(112),0}, - { &GUID_Key,113,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(113),0}, - { &GUID_Key,114,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(114),0}, - { &GUID_Key,115,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(115),0}, - { &GUID_Key,116,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(116),0}, - { &GUID_Key,117,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(117),0}, - { &GUID_Key,118,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(118),0}, - { &GUID_Key,119,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(119),0}, - { &GUID_Key,120,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(120),0}, - { &GUID_Key,121,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(121),0}, - { &GUID_Key,122,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(122),0}, - { &GUID_Key,123,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(123),0}, - { &GUID_Key,124,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(124),0}, - { &GUID_Key,125,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(125),0}, - { &GUID_Key,126,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(126),0}, - { &GUID_Key,127,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(127),0}, - { &GUID_Key,128,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(128),0}, - { &GUID_Key,129,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(129),0}, - { &GUID_Key,130,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(130),0}, - { &GUID_Key,131,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(131),0}, - { &GUID_Key,132,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(132),0}, - { &GUID_Key,133,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(133),0}, - { &GUID_Key,134,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(134),0}, - { &GUID_Key,135,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(135),0}, - { &GUID_Key,136,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(136),0}, - { &GUID_Key,137,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(137),0}, - { &GUID_Key,138,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(138),0}, - { &GUID_Key,139,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(139),0}, - { &GUID_Key,140,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(140),0}, - { &GUID_Key,141,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(141),0}, - { &GUID_Key,142,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(142),0}, - { &GUID_Key,143,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(143),0}, - { &GUID_Key,144,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(144),0}, - { &GUID_Key,145,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(145),0}, - { &GUID_Key,146,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(146),0}, - { &GUID_Key,147,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(147),0}, - { &GUID_Key,148,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(148),0}, - { &GUID_Key,149,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(149),0}, - { &GUID_Key,150,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(150),0}, - { &GUID_Key,151,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(151),0}, - { &GUID_Key,152,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(152),0}, - { &GUID_Key,153,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(153),0}, - { &GUID_Key,154,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(154),0}, - { &GUID_Key,155,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(155),0}, - { &GUID_Key,156,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(156),0}, - { &GUID_Key,157,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(157),0}, - { &GUID_Key,158,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(158),0}, - { &GUID_Key,159,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(159),0}, - { &GUID_Key,160,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(160),0}, - { &GUID_Key,161,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(161),0}, - { &GUID_Key,162,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(162),0}, - { &GUID_Key,163,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(163),0}, - { &GUID_Key,164,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(164),0}, - { &GUID_Key,165,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(165),0}, - { &GUID_Key,166,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(166),0}, - { &GUID_Key,167,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(167),0}, - { &GUID_Key,168,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(168),0}, - { &GUID_Key,169,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(169),0}, - { &GUID_Key,170,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(170),0}, - { &GUID_Key,171,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(171),0}, - { &GUID_Key,172,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(172),0}, - { &GUID_Key,173,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(173),0}, - { &GUID_Key,174,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(174),0}, - { &GUID_Key,175,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(175),0}, - { &GUID_Key,176,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(176),0}, - { &GUID_Key,177,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(177),0}, - { &GUID_Key,178,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(178),0}, - { &GUID_Key,179,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(179),0}, - { &GUID_Key,180,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(180),0}, - { &GUID_Key,181,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(181),0}, - { &GUID_Key,182,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(182),0}, - { &GUID_Key,183,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(183),0}, - { &GUID_Key,184,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(184),0}, - { &GUID_Key,185,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(185),0}, - { &GUID_Key,186,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(186),0}, - { &GUID_Key,187,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(187),0}, - { &GUID_Key,188,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(188),0}, - { &GUID_Key,189,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(189),0}, - { &GUID_Key,190,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(190),0}, - { &GUID_Key,191,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(191),0}, - { &GUID_Key,192,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(192),0}, - { &GUID_Key,193,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(193),0}, - { &GUID_Key,194,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(194),0}, - { &GUID_Key,195,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(195),0}, - { &GUID_Key,196,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(196),0}, - { &GUID_Key,197,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(197),0}, - { &GUID_Key,198,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(198),0}, - { &GUID_Key,199,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(199),0}, - { &GUID_Key,200,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(200),0}, - { &GUID_Key,201,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(201),0}, - { &GUID_Key,202,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(202),0}, - { &GUID_Key,203,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(203),0}, - { &GUID_Key,204,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(204),0}, - { &GUID_Key,205,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(205),0}, - { &GUID_Key,206,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(206),0}, - { &GUID_Key,207,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(207),0}, - { &GUID_Key,208,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(208),0}, - { &GUID_Key,209,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(209),0}, - { &GUID_Key,210,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(210),0}, - { &GUID_Key,211,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(211),0}, - { &GUID_Key,212,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(212),0}, - { &GUID_Key,213,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(213),0}, - { &GUID_Key,214,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(214),0}, - { &GUID_Key,215,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(215),0}, - { &GUID_Key,216,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(216),0}, - { &GUID_Key,217,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(217),0}, - { &GUID_Key,218,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(218),0}, - { &GUID_Key,219,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(219),0}, - { &GUID_Key,220,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(220),0}, - { &GUID_Key,221,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(221),0}, - { &GUID_Key,222,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(222),0}, - { &GUID_Key,223,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(223),0}, - { &GUID_Key,224,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(224),0}, - { &GUID_Key,225,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(225),0}, - { &GUID_Key,226,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(226),0}, - { &GUID_Key,227,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(227),0}, - { &GUID_Key,228,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(228),0}, - { &GUID_Key,229,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(229),0}, - { &GUID_Key,230,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(230),0}, - { &GUID_Key,231,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(231),0}, - { &GUID_Key,232,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(232),0}, - { &GUID_Key,233,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(233),0}, - { &GUID_Key,234,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(234),0}, - { &GUID_Key,235,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(235),0}, - { &GUID_Key,236,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(236),0}, - { &GUID_Key,237,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(237),0}, - { &GUID_Key,238,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(238),0}, - { &GUID_Key,239,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(239),0}, - { &GUID_Key,240,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(240),0}, - { &GUID_Key,241,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(241),0}, - { &GUID_Key,242,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(242),0}, - { &GUID_Key,243,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(243),0}, - { &GUID_Key,244,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(244),0}, - { &GUID_Key,245,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(245),0}, - { &GUID_Key,246,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(246),0}, - { &GUID_Key,247,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(247),0}, - { &GUID_Key,248,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(248),0}, - { &GUID_Key,249,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(249),0}, - { &GUID_Key,250,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(250),0}, - { &GUID_Key,251,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(251),0}, - { &GUID_Key,252,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(252),0}, - { &GUID_Key,253,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(253),0}, - { &GUID_Key,254,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(254),0}, - { &GUID_Key,255,DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(255),0} -}; - -const DIDATAFORMAT c_dfDIKeyboard = { - sizeof(DIDATAFORMAT), - sizeof(DIOBJECTDATAFORMAT), - DIDF_RELAXIS, - 256, - numObjects(dfDIKeyboard), - (LPDIOBJECTDATAFORMAT)dfDIKeyboard + dfDIMouse2 }; diff --git a/reactos/lib/dinput/device.c b/reactos/lib/dinput/device.c index b9c8790269a..2980c3c00d1 100644 --- a/reactos/lib/dinput/device.c +++ b/reactos/lib/dinput/device.c @@ -290,12 +290,12 @@ DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT a int index = 0; DWORD next = 0; - ret = HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat)); + ret = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat)); - done = HeapAlloc(GetProcessHeap(), 0, sizeof(int) * asked_format->dwNumObjs); + done = (int *) HeapAlloc(GetProcessHeap(), 0, sizeof(int) * asked_format->dwNumObjs); memset(done, 0, sizeof(int) * asked_format->dwNumObjs); - dt = HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform)); + dt = (DataTransform *) HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform)); TRACE("Creating DataTransform : \n"); diff --git a/reactos/lib/dinput/dinput_main.c b/reactos/lib/dinput/dinput_main.c index 527333e746e..bd003d07e6a 100644 --- a/reactos/lib/dinput/dinput_main.c +++ b/reactos/lib/dinput/dinput_main.c @@ -53,14 +53,10 @@ static IDirectInput7WVtbl ddi7wvt; static IDirectInput8AVtbl ddi8avt; static IDirectInput8WVtbl ddi8wvt; -static const struct dinput_device *dinput_devices[] = -{ - &mouse_device, - &keyboard_device, - &joystick_linuxinput_device, - &joystick_linux_device -}; -#define NB_DINPUT_DEVICES (sizeof(dinput_devices)/sizeof(dinput_devices[0])) +/* This array will be filled a dinput.so loading */ +#define MAX_WINE_DINPUT_DEVICES 4 +static dinput_device * dinput_devices[MAX_WINE_DINPUT_DEVICES]; +static int nrof_dinput_devices = 0; HINSTANCE DINPUT_instance = NULL; @@ -78,7 +74,28 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserv) return TRUE; } +/* register a direct draw driver. We better not use malloc for we are in + * the ELF startup initialisation at this point. + */ +void dinput_register_device(dinput_device *device) { + int i; + /* insert according to priority */ + for (i=0;ipref <= device->pref) { + memcpy(dinput_devices+i+1,dinput_devices+i,sizeof(dinput_devices[0])*(nrof_dinput_devices-i)); + dinput_devices[i] = device; + break; + } + } + if (i==nrof_dinput_devices) /* not found, or too low priority */ + dinput_devices[nrof_dinput_devices] = device; + + nrof_dinput_devices++; + + /* increase MAX_DDRAW_DRIVERS if the line below triggers */ + assert(nrof_dinput_devices <= MAX_WINE_DINPUT_DEVICES); +} /****************************************************************************** * DirectInputCreateEx (DINPUT.@) @@ -94,7 +111,7 @@ HRESULT WINAPI DirectInputCreateEx( if (IsEqualGUID(&IID_IDirectInputA,riid) || IsEqualGUID(&IID_IDirectInput2A,riid) || IsEqualGUID(&IID_IDirectInput7A,riid)) { - This = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); This->lpVtbl = &ddi7avt; This->ref = 1; This->version = 1; @@ -106,7 +123,7 @@ HRESULT WINAPI DirectInputCreateEx( if (IsEqualGUID(&IID_IDirectInputW,riid) || IsEqualGUID(&IID_IDirectInput2W,riid) || IsEqualGUID(&IID_IDirectInput7W,riid)) { - This = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); This->lpVtbl = &ddi7wvt; This->ref = 1; This->version = 1; @@ -116,7 +133,7 @@ HRESULT WINAPI DirectInputCreateEx( } if (IsEqualGUID(&IID_IDirectInput8A,riid)) { - This = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); This->lpVtbl = &ddi8avt; This->ref = 1; This->version = 8; @@ -126,7 +143,7 @@ HRESULT WINAPI DirectInputCreateEx( } if (IsEqualGUID(&IID_IDirectInput8W,riid)) { - This = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); This->lpVtbl = &ddi8wvt; This->ref = 1; This->version = 8; @@ -147,7 +164,7 @@ HRESULT WINAPI DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPU TRACE("(0x%08lx,%04lx,%p,%p)\n", (DWORD)hinst,dwVersion,ppDI,punkOuter); //trace:dinput:DirectInputCreateA (0x00400000,0500,0x42bafc54,(nil)) - This = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); This->lpVtbl = &ddi7avt; This->ref = 1; if (dwVersion > 0x0700) { @@ -168,7 +185,7 @@ HRESULT WINAPI DirectInputCreateW(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPU { IDirectInputImpl* This; TRACE("(0x%08lx,%04lx,%p,%p)\n", (DWORD)hinst,dwVersion,ppDI,punkOuter); - This = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); This->lpVtbl = &ddi7wvt; This->ref = 1; if (dwVersion >= 0x0800) { @@ -185,7 +202,7 @@ static const char *_dump_DIDEVTYPE_value(DWORD dwDevType) { switch (dwDevType) { case 0: return "All devices"; case DIDEVTYPE_MOUSE: return "DIDEVTYPE_MOUSE"; - case DIDEVTYPE_KEYBOARD: return "DIDEVTYPE_KEYBOARD"; + case DIDEVTYPE_KEYBOARD: return "DIDEVTYPE_KEYBOARD"; case DIDEVTYPE_JOYSTICK: return "DIDEVTYPE_JOYSTICK"; case DIDEVTYPE_DEVICE: return "DIDEVTYPE_DEVICE"; default: return "Unkown"; @@ -231,22 +248,16 @@ static HRESULT WINAPI IDirectInputAImpl_EnumDevices( TRACE("(this=%p,0x%04lx '%s',%p,%p,%04lx)\n", This, dwDevType, _dump_DIDEVTYPE_value(dwDevType), lpCallback, pvRef, dwFlags); -#ifdef __REACTOS__ - /* hack geting keyboard and mouse working */ - if (NB_DINPUT_DEVICES==0){ + + if (nrof_dinput_devices==0){ scan_mouse(); scan_keyboard(); } -#endif + TRACE(" flags: "); _dump_EnumDevices_dwFlags(dwFlags); TRACE("\n"); - for (i = 0; i < NB_DINPUT_DEVICES; i++) { -#ifndef __REACTOS__ - /* Wine Dinput does not support windows enum - we need a hack here */ - if (!dinput_devices[i]->enum_deviceA) continue; -#endif + for (i = 0; i < nrof_dinput_devices; i++) { for (j = 0, r = -1; r != 0; j++) { devInstance.dwSize = sizeof(devInstance); TRACE(" - checking device %d ('%s')\n", i, dinput_devices[i]->name); @@ -272,13 +283,10 @@ static HRESULT WINAPI IDirectInputWImpl_EnumDevices( DIDEVICEINSTANCEW devInstance; int i, j, r; -#ifdef __REACTOS__ - /* hack geting keyboard and mouse working */ - if (NB_DINPUT_DEVICES==0){ + if (nrof_dinput_devices==0){ scan_mouse(); scan_keyboard(); } -#endif TRACE("(this=%p,0x%04lx '%s',%p,%p,%04lx)\n", This, dwDevType, _dump_DIDEVTYPE_value(dwDevType), @@ -286,13 +294,7 @@ static HRESULT WINAPI IDirectInputWImpl_EnumDevices( TRACE(" flags: "); _dump_EnumDevices_dwFlags(dwFlags); TRACE("\n"); - for (i = 0; i < NB_DINPUT_DEVICES; i++) { -#ifndef __REACTOS__ - /* Wine Dinput does not support windows enum - we need a hack here */ - if (!dinput_devices[i]->enum_deviceW) continue; -#endif - + for (i = 0; i < nrof_dinput_devices; i++) { for (j = 0, r = -1; r != 0; j++) { devInstance.dwSize = sizeof(devInstance); TRACE(" - checking device %d ('%s')\n", i, dinput_devices[i]->name); @@ -364,18 +366,14 @@ static HRESULT WINAPI IDirectInputAImpl_CreateDevice( TRACE("(this=%p,%s,%p,%p)\n",This,debugstr_guid(rguid),pdev,punk); -#ifdef __REACTOS__ - /* hack geting keyboard and mouse working */ - if (NB_DINPUT_DEVICES==0){ + if (nrof_dinput_devices==0){ scan_mouse(); scan_keyboard(); } -#endif /* Loop on all the devices to see if anyone matches the given GUID */ - for (i = 0; i < NB_DINPUT_DEVICES; i++) { + for (i = 0; i < nrof_dinput_devices; i++) { HRESULT ret; - if (!dinput_devices[i]->create_deviceA) continue; if ((ret = dinput_devices[i]->create_deviceA(This, rguid, NULL, pdev)) == DI_OK) return DI_OK; @@ -394,18 +392,14 @@ static HRESULT WINAPI IDirectInputWImpl_CreateDevice(LPDIRECTINPUT7A iface, TRACE("(this=%p,%s,%p,%p)\n",This,debugstr_guid(rguid),pdev,punk); -#ifdef __REACTOS__ - /* hack geting keyboard and mouse working */ - if (NB_DINPUT_DEVICES==0){ + if (nrof_dinput_devices==0){ scan_mouse(); scan_keyboard(); } -#endif /* Loop on all the devices to see if anyone matches the given GUID */ - for (i = 0; i < NB_DINPUT_DEVICES; i++) { + for (i = 0; i < nrof_dinput_devices; i++) { HRESULT ret; - if (!dinput_devices[i]->create_deviceW) continue; if ((ret = dinput_devices[i]->create_deviceW(This, rguid, NULL, pdev)) == DI_OK) return DI_OK; @@ -463,18 +457,14 @@ static HRESULT WINAPI IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface, R TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter); -#ifdef __REACTOS__ - /* hack geting keyboard and mouse working */ - if (NB_DINPUT_DEVICES==0){ - scan_mouse(); - scan_keyboard(); - } -#endif + if (nrof_dinput_devices==0){ + scan_mouse(); + scan_keyboard(); + } /* Loop on all the devices to see if anyone matches the given GUID */ - for (i = 0; i < NB_DINPUT_DEVICES; i++) { + for (i = 0; i < nrof_dinput_devices; i++) { HRESULT ret; - if (!dinput_devices[i]->create_deviceA) continue; if ((ret = dinput_devices[i]->create_deviceA(This, rguid, riid, (LPDIRECTINPUTDEVICEA*) pvOut)) == DI_OK) return DI_OK; @@ -494,7 +484,7 @@ static HRESULT WINAPI IDirectInput7WImpl_CreateDeviceEx(LPDIRECTINPUT7W iface, R TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter); - if (NB_DINPUT_DEVICES==0){ + if (nrof_dinput_devices==0){ scan_mouse(); scan_keyboard(); } @@ -502,9 +492,8 @@ static HRESULT WINAPI IDirectInput7WImpl_CreateDeviceEx(LPDIRECTINPUT7W iface, R /* Loop on all the devices to see if anyone matches the given GUID */ - for (i = 0; i < NB_DINPUT_DEVICES; i++) { + for (i = 0; i < nrof_dinput_devices; i++) { HRESULT ret; - if (!dinput_devices[i]->create_deviceW) continue; if ((ret = dinput_devices[i]->create_deviceW(This, rguid, riid, (LPDIRECTINPUTDEVICEW*) pvOut)) == DI_OK) return DI_OK; diff --git a/reactos/lib/dinput/dinput_private.h b/reactos/lib/dinput/dinput_private.h index 92e92ca88e7..ce7b54a9577 100644 --- a/reactos/lib/dinput/dinput_private.h +++ b/reactos/lib/dinput/dinput_private.h @@ -39,18 +39,16 @@ struct IDirectInputImpl }; /* Function called by all devices that Wine supports */ -struct dinput_device { +typedef struct dinput_device { + INT pref; const char *name; BOOL (*enum_deviceA)(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id); BOOL (*enum_deviceW)(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id); HRESULT (*create_deviceA)(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev); HRESULT (*create_deviceW)(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev); -}; +} dinput_device; -extern const struct dinput_device mouse_device; -extern const struct dinput_device keyboard_device; -extern const struct dinput_device joystick_linux_device; -extern const struct dinput_device joystick_linuxinput_device; +extern void dinput_register_device(dinput_device *device); extern HINSTANCE DINPUT_instance; diff --git a/reactos/lib/dinput/joystick_linux.c b/reactos/lib/dinput/joystick_linux.c index 99834e63d2e..138ded7caf8 100644 --- a/reactos/lib/dinput/joystick_linux.c +++ b/reactos/lib/dinput/joystick_linux.c @@ -28,6 +28,8 @@ #include "config.h" #include "wine/port.h" +#ifdef HAVE_LINUX_22_JOYSTICK_API + #include #include #include @@ -53,6 +55,7 @@ #ifdef HAVE_LINUX_JOYSTICK_H # include #endif +#define JOYDEV "/dev/js" #include "wine/debug.h" #include "wine/unicode.h" @@ -67,10 +70,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); -#ifdef HAVE_LINUX_22_JOYSTICK_API - -#define JOYDEV "/dev/js" - typedef struct { LONG lMin; LONG lMax; @@ -647,7 +646,8 @@ static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, RE return DIERR_DEVICENOTREG; } -const struct dinput_device joystick_linux_device = { +static dinput_device joydev = { + 10, "Wine Linux joystick driver", joydev_enum_deviceA, joydev_enum_deviceW, @@ -655,6 +655,8 @@ const struct dinput_device joystick_linux_device = { joydev_create_deviceW }; +DECL_GLOBAL_CONSTRUCTOR(joydev_register) { dinput_register_device(&joydev); } + /****************************************************************************** @@ -1695,14 +1697,4 @@ static IDirectInputDevice8WVtbl SysJoystickWvt = }; #undef XCAST -#else /* HAVE_LINUX_22_JOYSTICK_API */ - -const struct dinput_device joystick_linux_device = { - "Wine Linux joystick driver", - NULL, - NULL, - NULL, - NULL -}; - #endif /* HAVE_LINUX_22_JOYSTICK_API */ diff --git a/reactos/lib/dinput/joystick_linuxinput.c b/reactos/lib/dinput/joystick_linuxinput.c index 563897a4454..673cc3852fc 100644 --- a/reactos/lib/dinput/joystick_linuxinput.c +++ b/reactos/lib/dinput/joystick_linuxinput.c @@ -22,6 +22,8 @@ #include "config.h" #include "wine/port.h" +#ifdef HAVE_LINUX_INPUT_H + #include #include #include @@ -41,10 +43,16 @@ #ifdef HAVE_SYS_ERRNO_H # include #endif + +#ifdef HAVE_CORRECT_LINUXINPUT_H + #ifdef HAVE_LINUX_INPUT_H # include #endif + +#define EVDEVPREFIX "/dev/input/event" + #include "wine/debug.h" #include "wine/unicode.h" #include "windef.h" @@ -57,10 +65,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); -#ifdef HAVE_CORRECT_LINUXINPUT_H - -#define EVDEVPREFIX "/dev/input/event" - /* Wine joystick driver object instances */ #define WINE_JOYSTICK_AXIS_BASE 0 #define WINE_JOYSTICK_BUTTON_BASE 8 @@ -318,7 +322,8 @@ static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, RE return DIERR_DEVICENOTREG; } -const struct dinput_device joystick_linuxinput_device = { +static dinput_device joydev = { + 20, "Wine Linux-input joystick driver", joydev_enum_deviceA, joydev_enum_deviceW, @@ -326,6 +331,8 @@ const struct dinput_device joystick_linuxinput_device = { joydev_create_deviceW }; +DECL_GLOBAL_CONSTRUCTOR(joydev_register) { dinput_register_device(&joydev); } + /****************************************************************************** * Joystick */ @@ -971,7 +978,7 @@ static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, { JoystickImpl *This = (JoystickImpl *)iface; - TRACE("(this=%p,%s,%p)\n", + TRACE("(this=%p,%s,%p): stub!\n", iface, debugstr_guid(rguid), pdiph); if (TRACE_ON(dinput)) @@ -1087,14 +1094,6 @@ static IDirectInputDevice8WVtbl JoystickWvt = }; #undef XCAST -#else /* HAVE_CORRECT_LINUXINPUT_H */ +#endif /* HAVE_LINUX_INPUT_H */ -const struct dinput_device joystick_linuxinput_device = { - "Wine Linux-input joystick driver", - NULL, - NULL, - NULL, - NULL -}; - -#endif /* HAVE_CORRECT_LINUXINPUT_H */ +#endif diff --git a/reactos/lib/dinput/keyboard.c b/reactos/lib/dinput/keyboard.c index f6164ac8c11..08acc185ebf 100644 --- a/reactos/lib/dinput/keyboard.c +++ b/reactos/lib/dinput/keyboard.c @@ -3,7 +3,6 @@ * Copyright 1998 Marcus Meissner * Copyright 1998,1999 Lionel Ulmer * Copyright 2000-2001 TransGaming Technologies Inc. - * Copyright 2005 Raphael Junqueira * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -38,7 +37,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); -#define WINE_DINPUT_KEYBOARD_MAX_KEYS 256 +//fast fix misning from mingw headers +#ifdef __REACTOS__ +#define LLKHF_INJECTED 0x00000010 +#endif static IDirectInputDevice8AVtbl SysKeyboardAvt; static IDirectInputDevice8WVtbl SysKeyboardWvt; @@ -68,15 +70,14 @@ struct SysKeyboardImpl CRITICAL_SECTION crit; }; -static SysKeyboardImpl* current_lock = NULL; -/* Today's acquired device - * FIXME: currently this can be only one. - * Maybe this should be a linked list or st. - * I don't know what the rules are for multiple acquired keyboards, - * but 'DI_LOSTFOCUS' and 'DI_UNACQUIRED' exist for a reason. +SysKeyboardImpl *current; /* Today's acquired device +FIXME: currently this can be only one. +Maybe this should be a linked list or st. +I don't know what the rules are for multiple acquired keyboards, +but 'DI_LOSTFOCUS' and 'DI_UNACQUIRED' exist for a reason. */ -static BYTE DInputKeyState[WINE_DINPUT_KEYBOARD_MAX_KEYS]; /* array for 'GetDeviceState' */ +static BYTE DInputKeyState[256]; /* array for 'GetDeviceState' */ static CRITICAL_SECTION keyboard_crit; static CRITICAL_SECTION_DEBUG critsect_debug = @@ -90,8 +91,7 @@ static CRITICAL_SECTION keyboard_crit = { &critsect_debug, -1, 0, 0, 0, 0 }; static DWORD keyboard_users; #ifndef __REACTOS__ -static DWORD keyboard_users = 0; -static HHOOK keyboard_hook = NULL; +static HHOOK keyboard_hook; #endif #ifdef __REACTOS__ @@ -116,24 +116,24 @@ void reactos_input_keyboard() if (disk_code!=-1) { - if (current_lock->buffer != NULL) + if (current->buffer != NULL) { int n; - n = (current_lock->start + current_lock->count) % current_lock->buffersize; + n = (current->start + current->count) % current->buffersize; - current_lock->buffer[n].dwOfs = (BYTE) disk_code; - current_lock->buffer[n].dwData = DInputKeyState[disk_code]; - current_lock->buffer[n].dwTimeStamp = 10; - current_lock->buffer[n].dwSequence = current_lock->dinput->evsequence++; + current->buffer[n].dwOfs = (BYTE) disk_code; + current->buffer[n].dwData = DInputKeyState[disk_code]; + current->buffer[n].dwTimeStamp = 10; + current->buffer[n].dwSequence = current->dinput->evsequence++; - if (current_lock->count == current_lock->buffersize) + if (current->count == current->buffersize) { - current_lock->start = ++current_lock->start % current_lock->buffersize; - current_lock->overflow = TRUE; + current->start = ++current->start % current->buffersize; + current->overflow = TRUE; } else - current_lock->count++; + current->count++; } } @@ -144,58 +144,59 @@ void reactos_input_keyboard() #ifndef __REACTOS__ LRESULT CALLBACK KeyboardCallback( int code, WPARAM wparam, LPARAM lparam ) { - BYTE dik_code; - BOOL down; - DWORD timestamp; - KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam; - BYTE new_diks; - TRACE("(%d,%d,%ld)\n", code, wparam, lparam); - /** returns now if not HC_ACTION */ - if (code != HC_ACTION) return CallNextHookEx(keyboard_hook, code, wparam, lparam); - - { - dik_code = hook->scanCode; - if (hook->flags & LLKHF_EXTENDED) dik_code |= 0x80; - down = !(hook->flags & LLKHF_UP); - timestamp = hook->time; - } + if (code == HC_ACTION) + { + BYTE dik_code; + BOOL down; + DWORD timestamp; + + { + KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam; + dik_code = hook->scanCode; + if (hook->flags & LLKHF_EXTENDED) dik_code |= 0x80; + down = !(hook->flags & LLKHF_UP); + timestamp = hook->time; + } - /** returns now if key event already known */ - new_diks = (down ? 0x80 : 0); - /*if (new_diks != DInputKeyState[dik_code]) return CallNextHookEx(keyboard_hook, code, wparam, lparam); TO BE FIXED */ + DInputKeyState[dik_code] = (down ? 0x80 : 0); + TRACE(" setting %02X to %02X\n", dik_code, DInputKeyState[dik_code]); + + if (current != NULL) + { + if (current->hEvent) + SetEvent(current->hEvent); - DInputKeyState[dik_code] = new_diks; - TRACE(" setting %02X to %02X\n", dik_code, DInputKeyState[dik_code]); - - if (current_lock != NULL) { - if (current_lock->hEvent) SetEvent(current_lock->hEvent); - - if (current_lock->buffer != NULL) { - int n; - - EnterCriticalSection(&(current_lock->crit)); - - n = (current_lock->start + current_lock->count) % current_lock->buffersize; - - current_lock->buffer[n].dwOfs = dik_code; - current_lock->buffer[n].dwData = down ? 0x80 : 0; - current_lock->buffer[n].dwTimeStamp = timestamp; - current_lock->buffer[n].dwSequence = current_lock->dinput->evsequence++; - - TRACE("Adding event at offset %d : %ld - %ld - %ld - %ld\n", n, - current_lock->buffer[n].dwOfs, current_lock->buffer[n].dwData, current_lock->buffer[n].dwTimeStamp, current_lock->buffer[n].dwSequence); - - if (current_lock->count == current_lock->buffersize) { - current_lock->start = ++current_lock->start % current_lock->buffersize; - current_lock->overflow = TRUE; - } else - current_lock->count++; - - LeaveCriticalSection(&(current_lock->crit)); + if (current->buffer != NULL) + { + int n; + + EnterCriticalSection(&(current->crit)); + + n = (current->start + current->count) % current->buffersize; + + current->buffer[n].dwOfs = dik_code; + current->buffer[n].dwData = down ? 0x80 : 0; + current->buffer[n].dwTimeStamp = timestamp; + current->buffer[n].dwSequence = current->dinput->evsequence++; + + TRACE("Adding event at offset %d : %ld - %ld - %ld - %ld\n", n, + current->buffer[n].dwOfs, current->buffer[n].dwData, current->buffer[n].dwTimeStamp, current->buffer[n].dwSequence); + + if (current->count == current->buffersize) + { + current->start = ++current->start % current->buffersize; + current->overflow = TRUE; + } + else + current->count++; + + LeaveCriticalSection(&(current->crit)); + } + } } - } + return CallNextHookEx(keyboard_hook, code, wparam, lparam); } #endif @@ -294,27 +295,17 @@ static BOOL keyboarddev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEI static SysKeyboardImpl *alloc_device_keyboard(REFGUID rguid, LPVOID kvt, IDirectInputImpl *dinput) { SysKeyboardImpl* newDevice; - DWORD kbd_users; - newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboardImpl)); newDevice->lpVtbl = kvt; newDevice->ref = 1; memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); newDevice->dinput = dinput; - InitializeCriticalSection(&(newDevice->crit)); #ifndef __REACTOS__ EnterCriticalSection(&keyboard_crit); -<<<<<<< .working if (!keyboard_users++) keyboard_hook = SetWindowsHookExW( WH_KEYBOARD_LL, KeyboardCallback, DINPUT_instance, 0 ); -======= - kbd_users = InterlockedIncrement(&keyboard_users); - if (1 == kbd_users) { - keyboard_hook = SetWindowsHookExW( WH_KEYBOARD_LL, KeyboardCallback, DINPUT_instance, 0 ); - } ->>>>>>> .merge-right.r14821 LeaveCriticalSection(&keyboard_crit); #endif @@ -358,7 +349,8 @@ static HRESULT keyboarddev_create_deviceW(IDirectInputImpl *dinput, REFGUID rgui return DIERR_DEVICENOTREG; } -const struct dinput_device keyboard_device = { +dinput_device keyboarddev = { + 100, "Wine keyboard driver", keyboarddev_enum_deviceA, keyboarddev_enum_deviceW, @@ -366,20 +358,25 @@ const struct dinput_device keyboard_device = { keyboarddev_create_deviceW }; +void scan_keyboard() +{ + dinput_register_device(&keyboarddev); +} + +DECL_GLOBAL_CONSTRUCTOR(keyboarddev_register) { dinput_register_device(&keyboarddev); } + static ULONG WINAPI SysKeyboardAImpl_Release(LPDIRECTINPUTDEVICE8A iface) { SysKeyboardImpl *This = (SysKeyboardImpl *)iface; ULONG ref; - DWORD kbd_users; ref = InterlockedDecrement(&(This->ref)); if (ref) return ref; #ifndef __REACTOS__ - EnterCriticalSection(&keyboard_crit); - kbd_users = InterlockedDecrement(&keyboard_users); - if (0 == kbd_users) { + EnterCriticalSection(&keyboard_crit); + if (!--keyboard_users) { UnhookWindowsHookEx( keyboard_hook ); keyboard_hook = 0; } @@ -426,68 +423,33 @@ static HRESULT WINAPI SysKeyboardAImpl_SetProperty( return DI_OK; } -static HRESULT WINAPI SysKeyboardAImpl_GetProperty( - LPDIRECTINPUTDEVICE8A iface,REFGUID rguid,LPDIPROPHEADER ph -) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); - TRACE("(size=%ld,headersize=%ld,obj=%ld,how=%ld\n", - ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow); - if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPDIPROPDWORD pd = (LPDIPROPDWORD)ph; - - TRACE("(buffersize=%ld)\n",pd->dwData); - - if (This->acquired) - return DIERR_INVALIDPARAM; - - pd->dwData = This->buffersize; - - break; - } - default: - WARN("Unknown type %ld\n",(DWORD)rguid); - break; - } - } - return DI_OK; -} static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState( LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr ) { - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - TRACE("(%p)->(%ld,%p)\n", This, len, ptr); + TRACE("(%p)->(%ld,%p)\n", iface, len, ptr); #ifdef __REACTOS__ reactos_input_keyboard(); #endif /* Note: device does not need to be acquired */ - if (len != WINE_DINPUT_KEYBOARD_MAX_KEYS) + if (len != 256) return DIERR_INVALIDPARAM; - MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, 0); - - EnterCriticalSection(&(This->crit)); + MsgWaitForMultipleObjectsEx(0, NULL, 0, 0, 0); if (TRACE_ON(dinput)) { int i; - for (i = 0; i < WINE_DINPUT_KEYBOARD_MAX_KEYS; i++) { + for (i = 0; i < 256; i++) { if (DInputKeyState[i] != 0x00) { TRACE(" - %02X: %02x\n", i, DInputKeyState[i]); } } } - memcpy(ptr, DInputKeyState, WINE_DINPUT_KEYBOARD_MAX_KEYS); - LeaveCriticalSection(&(This->crit)); - + memcpy(ptr, DInputKeyState, 256); return DI_OK; } @@ -515,7 +477,7 @@ static HRESULT WINAPI SysKeyboardAImpl_GetDeviceData( if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) return DIERR_INVALIDPARAM; - MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, 0); + MsgWaitForMultipleObjectsEx(0, NULL, 0, 0, 0); EnterCriticalSection(&(This->crit)); @@ -576,7 +538,7 @@ static HRESULT WINAPI SysKeyboardAImpl_EnumObjects( memset(&ddoi, 0, sizeof(ddoi)); ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); - for (i = 0; i < WINE_DINPUT_KEYBOARD_MAX_KEYS; i++) { + for (i = 0; i < 256; i++) { /* Report 255 keys :-) */ ddoi.guidType = GUID_Key; ddoi.dwOfs = i; @@ -617,24 +579,26 @@ static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) This->acquired = 1; - if (current_lock != NULL) { - FIXME("Not more than one keyboard can be acquired at the same time.\n"); - SysKeyboardAImpl_Unacquire(iface); - } - - current_lock = This; + if (current != NULL) + { + FIXME("Not more than one keyboard can be acquired at the same time.\n"); + SysKeyboardAImpl_Unacquire(iface); + } - if (This->buffersize > 0) { - This->buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - This->buffersize * sizeof(*(This->buffer))); - This->start = 0; - This->count = 0; - This->overflow = FALSE; - } else { + current = This; + + if (This->buffersize > 0) + { + This->buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + This->buffersize * sizeof(*(This->buffer))); + This->start = 0; + This->count = 0; + This->overflow = FALSE; + InitializeCriticalSection(&(This->crit)); + } + else This->buffer = NULL; - } - /*keyboard_hook = SetWindowsHookExW( WH_KEYBOARD_LL, KeyboardCallback, DINPUT_instance, 0 );*/ return DI_OK; } @@ -647,19 +611,19 @@ static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) if (This->acquired == 0) return DI_NOEFFECT; - /* No more locks */ - if (current_lock == This) - current_lock = NULL; + if (current == This) + current = NULL; else - ERR("this != current_lock\n"); + ERR("this != current\n"); - /* Unacquire device */ This->acquired = 0; - if (This->buffersize >= 0) { - HeapFree(GetProcessHeap(), 0, This->buffer); - This->buffer = NULL; - } + if (This->buffersize >= 0) + { + HeapFree(GetProcessHeap(), 0, This->buffer); + This->buffer = NULL; + DeleteCriticalSection(&(This->crit)); + } return DI_OK; } @@ -698,7 +662,7 @@ static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities( else devcaps.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8); devcaps.dwAxes = 0; - devcaps.dwButtons = WINE_DINPUT_KEYBOARD_MAX_KEYS; + devcaps.dwButtons = 256; devcaps.dwPOVs = 0; devcaps.dwFFSamplePeriod = 0; devcaps.dwFFMinTimeResolution = 0; @@ -794,7 +758,7 @@ static HRESULT WINAPI SysKeyboardAImpl_GetDeviceInfo( TRACE("(this=%p,%p)\n", This, pdidi); if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) { - WARN(" dinput3 not supported yet...\n"); + WARN(" dinput3 not supporte yet...\n"); return DI_OK; } @@ -809,7 +773,7 @@ static HRESULT WINAPI SysKeyboardWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface TRACE("(this=%p,%p)\n", This, pdidi); if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)) { - WARN(" dinput3 not supported yet...\n"); + WARN(" dinput3 not supporte yet...\n"); return DI_OK; } @@ -825,7 +789,7 @@ static IDirectInputDevice8AVtbl SysKeyboardAvt = SysKeyboardAImpl_Release, SysKeyboardAImpl_GetCapabilities, SysKeyboardAImpl_EnumObjects, - SysKeyboardAImpl_GetProperty, + IDirectInputDevice2AImpl_GetProperty, SysKeyboardAImpl_SetProperty, SysKeyboardAImpl_Acquire, SysKeyboardAImpl_Unacquire, @@ -867,7 +831,7 @@ static IDirectInputDevice8WVtbl SysKeyboardWvt = XCAST(Release)SysKeyboardAImpl_Release, XCAST(GetCapabilities)SysKeyboardAImpl_GetCapabilities, SysKeyboardWImpl_EnumObjects, - XCAST(GetProperty)SysKeyboardAImpl_GetProperty, + XCAST(GetProperty)IDirectInputDevice2AImpl_GetProperty, XCAST(SetProperty)SysKeyboardAImpl_SetProperty, XCAST(Acquire)SysKeyboardAImpl_Acquire, XCAST(Unacquire)SysKeyboardAImpl_Unacquire, diff --git a/reactos/lib/dinput/mouse.c b/reactos/lib/dinput/mouse.c index 47dc282f51a..104951c182b 100644 --- a/reactos/lib/dinput/mouse.c +++ b/reactos/lib/dinput/mouse.c @@ -41,6 +41,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); + /* Wine mouse driver object instances */ #define WINE_MOUSE_X_AXIS_INSTANCE 0 #define WINE_MOUSE_Y_AXIS_INSTANCE 1 @@ -264,7 +265,7 @@ static SysMouseImpl *alloc_device_mouse(REFGUID rguid, LPVOID mvt, IDirectInputI /* Per default, Wine uses its internal data format */ newDevice->df = (DIDATAFORMAT *) &Wine_InternalMouseFormat; memcpy(newDevice->offset_array, offset_array, WINE_INTERNALMOUSE_NUM_OBJS * sizeof(int)); - newDevice->wine_df = HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat)); + newDevice->wine_df = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat)); newDevice->wine_df->size = 0; newDevice->wine_df->internal_format_size = Wine_InternalMouseFormat.dwDataSize; newDevice->wine_df->dt = NULL; @@ -311,7 +312,8 @@ static HRESULT mousedev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, return DIERR_DEVICENOTREG; } -const struct dinput_device mouse_device = { +static dinput_device mousedev = { + 100, "Wine mouse driver", mousedev_enum_deviceA, mousedev_enum_deviceW, @@ -319,6 +321,15 @@ const struct dinput_device mouse_device = { mousedev_create_deviceW }; +#ifdef __REACTOS__ +void scan_mouse() +{ + dinput_register_device(&mousedev); +} + +DECL_GLOBAL_CONSTRUCTOR(mousedev_register) { dinput_register_device(&mousedev); } +#endif + /****************************************************************************** * SysMouseA (DInput Mouse support) */ @@ -338,21 +349,17 @@ static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE8A iface) /* Free the data queue */ HeapFree(GetProcessHeap(),0,This->data_queue); -#ifndef __REACTOS__ + if (This->hook) { UnhookWindowsHookEx( This->hook ); if (This->dwCoopLevel & DISCL_EXCLUSIVE) ShowCursor(TRUE); /* show cursor */ } +#ifndef __REACTOS__ DeleteCriticalSection(&(This->crit)); #endif -#ifdef __REACTOS__ -if (This->dwCoopLevel & DISCL_EXCLUSIVE) - ShowCursor(TRUE); /* show cursor */ - -#endif - /* Free the DataFormat */ + /* Free the DataFormat */ if (This->df != &(Wine_InternalMouseFormat)) { HeapFree(GetProcessHeap(), 0, This->df->rgodf); HeapFree(GetProcessHeap(), 0, This->df); @@ -436,7 +443,10 @@ static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lpara if (code != HC_ACTION) return CallNextHookEx( This->hook, code, wparam, lparam ); +#ifndef __REACTOS__ EnterCriticalSection(&(This->crit)); +#endif + dwCoop = This->dwCoopLevel; /* Only allow mouse events every 10 ms. @@ -553,7 +563,9 @@ static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lpara This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]); end: +#ifndef __REACTOS__ LeaveCriticalSection(&(This->crit)); +#endif if (dwCoop & DISCL_NONEXCLUSIVE) { /* Pass the events down to previous handlers (e.g. win32 input) */ @@ -590,63 +602,66 @@ static void dinput_window_check(SysMouseImpl* This) { static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) { SysMouseImpl *This = (SysMouseImpl *)iface; - RECT rect; - POINT point; + RECT rect; TRACE("(this=%p)\n",This); - if (This->acquired) - return S_FALSE; - - This->acquired = 1; - - /* Store (in a global variable) the current lock */ - current_lock = (IDirectInputDevice8A*)This; - - /* Init the mouse state */ - GetCursorPos( &point ); - if (This->absolute) { - This->m_state.lX = point.x; - This->m_state.lY = point.y; - This->prevX = point.x; - This->prevY = point.y; - } else { - This->m_state.lX = 0; - This->m_state.lY = 0; - This->org_coords = point; - } - This->m_state.lZ = 0; - This->m_state.rgbButtons[0] = ((GetKeyState(VK_LBUTTON) & 0x80) ? 0xFF : 0x00); - This->m_state.rgbButtons[1] = ((GetKeyState(VK_RBUTTON) & 0x80) ? 0xFF : 0x00); - This->m_state.rgbButtons[2] = ((GetKeyState(VK_MBUTTON) & 0x80) ? 0xFF : 0x00); - - /* Install our mouse hook */ - if (This->dwCoopLevel & DISCL_EXCLUSIVE) - ShowCursor(FALSE); /* hide cursor */ -#ifndef __REACTOS__ - This->hook = SetWindowsHookExA( WH_MOUSE_LL, dinput_mouse_hook, DINPUT_instance, 0 ); -#endif - - /* Get the window dimension and find the center */ - GetWindowRect(This->win, &rect); - This->win_centerX = (rect.right - rect.left) / 2; - This->win_centerY = (rect.bottom - rect.top ) / 2; - - /* Warp the mouse to the center of the window */ - if (This->absolute == 0) { - This->mapped_center.x = This->win_centerX; - This->mapped_center.y = This->win_centerY; - MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1); - TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); - SetCursorPos( This->mapped_center.x, This->mapped_center.y ); -#ifdef MOUSE_HACK - This->need_warp = WARP_DONE; -#else - This->need_warp = WARP_STARTED; -#endif - } - return DI_OK; + + if (This->acquired == 0) { + POINT point; + + + + /* Store (in a global variable) the current lock */ + current_lock = (IDirectInputDevice8A*)This; + + /* Init the mouse state */ + GetCursorPos( &point ); + if (This->absolute) { + This->m_state.lX = point.x; + This->m_state.lY = point.y; + This->prevX = point.x; + This->prevY = point.y; + } else { + This->m_state.lX = 0; + This->m_state.lY = 0; + This->org_coords = point; + } + This->m_state.lZ = 0; + This->m_state.rgbButtons[0] = ((GetKeyState(VK_LBUTTON) & 0x80) ? 0xFF : 0x00); + This->m_state.rgbButtons[1] = ((GetKeyState(VK_RBUTTON) & 0x80) ? 0xFF : 0x00); + This->m_state.rgbButtons[2] = ((GetKeyState(VK_MBUTTON) & 0x80) ? 0xFF : 0x00); + + /* Install our mouse hook */ + if (This->dwCoopLevel & DISCL_EXCLUSIVE) + ShowCursor(FALSE); /* hide cursor */ + + This->hook = SetWindowsHookExA( WH_MOUSE_LL, dinput_mouse_hook, DINPUT_instance, 0 ); + + /* Get the window dimension and find the center */ + GetWindowRect(This->win, &rect); + This->win_centerX = (rect.right - rect.left) / 2; + This->win_centerY = (rect.bottom - rect.top ) / 2; + + /* Warp the mouse to the center of the window */ + if (This->absolute == 0) { + This->mapped_center.x = This->win_centerX; + This->mapped_center.y = This->win_centerY; + MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1); + TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); + SetCursorPos( This->mapped_center.x, This->mapped_center.y ); +#ifdef MOUSE_HACK + This->need_warp = WARP_DONE; +#else + This->need_warp = WARP_STARTED; +#endif + } + + This->acquired = 1; + return DI_OK; + } + return S_FALSE; } /****************************************************************************** @@ -658,38 +673,31 @@ static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) TRACE("(this=%p)\n",This); - if (0 == This->acquired) { - return DI_NOEFFECT; - } + if (This->acquired) { + /* Reinstall previous mouse event handler */ - /* Reinstall previous mouse event handler */ - if (This->hook) { -#ifndef __REACTOS__ - UnhookWindowsHookEx( This->hook ); - This->hook = 0; - - if (This->dwCoopLevel & DISCL_EXCLUSIVE) - ShowCursor(TRUE); /* show cursor */ -#endif -#ifdef __REACTOS__ - if (This->dwCoopLevel & DISCL_EXCLUSIVE) - ShowCursor(TRUE); /* show cursor */ -#endif - } + + if (This->hook) { + UnhookWindowsHookEx( This->hook ); + This->hook = 0; + + if (This->dwCoopLevel & DISCL_EXCLUSIVE) + ShowCursor(TRUE); /* show cursor */ + } + + /* No more locks */ + current_lock = NULL; - /* No more locks */ - if (current_lock == (IDirectInputDevice8A*) This) - current_lock = NULL; - else - ERR("this(%p) != current_lock(%p)\n", This, current_lock); + /* Unacquire device */ + This->acquired = 0; - /* Unacquire device */ - This->acquired = 0; - - /* And put the mouse cursor back where it was at acquire time */ - if (This->absolute == 0) { - TRACE(" warping mouse back to (%ld , %ld)\n", This->org_coords.x, This->org_coords.y); - SetCursorPos(This->org_coords.x, This->org_coords.y); + /* And put the mouse cursor back where it was at acquire time */ + if (This->absolute == 0) { + TRACE(" warping mouse back to (%ld , %ld)\n", This->org_coords.x, This->org_coords.y); + SetCursorPos(This->org_coords.x, This->org_coords.y); + } + } else { + return DI_NOEFFECT; } return DI_OK; @@ -781,15 +789,12 @@ static HRESULT WINAPI SysMouseAImpl_GetDeviceState( EnterCriticalSection(&(This->crit)); #endif -#ifdef __REACTOS__ -getmousesvalue(iface); -#endif TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr); /* Copy the current mouse state */ fill_DataFormat(ptr, &(This->m_state), This->wine_df); - +#ifdef __REACTOS__ // this fix windows bugs when // some program calling on mouse poll if (poll_mouse==1) poll_mouse=0; @@ -800,7 +805,7 @@ getmousesvalue(iface); This->m_state.lZ = 0; } } - +#endif /* Check if we need to do a mouse warping */ if (This->need_warp == WARP_NEEDED) { @@ -843,168 +848,32 @@ static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface, SysMouseImpl *This = (SysMouseImpl *)iface; DWORD len; int nqtail; -#ifdef __REACTOS__ -static int last_event=0; -const int size = sizeof(DIDEVICEOBJECTDATA) * 1; -int count=0; -DWORD count_ent=0; -static DWORD time=0; -static POINT save_point; -static int save_b[5]; -static int b[5]; -static POINT point; -int calc; -int count_button; -int add = 0; -#endif TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags); - -#ifdef __REACTOS__ - -if (flags != DIGDD_PEEK) -{ -b[0] = ((GetKeyState(VK_LBUTTON) & 0x80) ? 0xFF : 0x00); -b[1] = ((GetKeyState(VK_RBUTTON) & 0x80) ? 0xFF : 0x00); -b[2] = ((GetKeyState(VK_MBUTTON) & 0x80) ? 0xFF : 0x00); -b[3] = ((GetKeyState(VK_XBUTTON1) & 0x80) ? 0xFF : 0x00); -b[4] = ((GetKeyState(VK_XBUTTON2) & 0x80) ? 0xFF : 0x00); -GetCursorPos( &point ); -} - -#endif - - - - - - + if (This->acquired == 0) { WARN(" application tries to get data from an unacquired device !\n"); - return DIERR_NOTACQUIRED; + //return DIERR_NOTACQUIRED; // windows does not get any data if // we do not call manual to mouse Acquire // this is only need if some apps calling on getdevice data direcly // in windows GetdeviceData does always update first the data // then return it. + SysMouseAImpl_Acquire(iface); } -#ifdef __REACTOS__ - if (*entries == 0) return DIERR_INVALIDPARAM; - - if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) { - ERR("Wrong structure size !\n"); - return DIERR_INVALIDPARAM; - } - if (This->data_queue==NULL) { - WARN("No buffer have been set up !\n"); - return DIERR_NOTINITIALIZED; - } - -/* this code are not need it but if we want 100% compatible - with ms we should keep it. but the mouse will be choppy - in Unreal 2004 Demo - - if (GetTickCount()-time <50) { - *entries=0; - return DI_OK; - } - time = GetTickCount(); -*/ - if (GetTickCount()-time <50) - { - add=0; - } - else - { - add=1; - time = GetTickCount(); - } - - - for (count=0;count<*entries;count++) { - - - if (save_point.x != point.x) { - dod[count_ent].dwOfs = DIMOFS_X; - - dod[count_ent].dwData = point.x - save_point.x; - dod[count_ent].dwTimeStamp = GetTickCount(); - dod[count_ent].dwSequence = last_event+=add; - count_ent++; - save_point.x = point.x; - } - - else if (save_point.y != point.y) { - dod[count_ent].dwOfs = DIMOFS_Y; - dod[count_ent].dwData = point.y - save_point.y; - - dod[count_ent].dwTimeStamp = GetTickCount(); - dod[count_ent].dwSequence = last_event+=add; - count_ent++; - save_point.y = point.y; - } - - else if (save_b[0] != b[0]) { - dod[count_ent].dwOfs = DIMOFS_BUTTON0; - - dod[count_ent].dwData = b[0]; - dod[count_ent].dwTimeStamp = GetTickCount(); - dod[count_ent].dwSequence = last_event+=add; - count_ent++; - save_b[0] = b[0]; - } - - else if (save_b[1] != b[1]) { - dod[count_ent].dwOfs = DIMOFS_BUTTON1; - - dod[count_ent].dwData = b[1]; - dod[count_ent].dwTimeStamp = GetTickCount(); - dod[count_ent].dwSequence = last_event+=add; - count_ent++; - save_b[1] = b[1]; - } - - else if (save_b[2] != b[2]) { - dod[count_ent].dwOfs = DIMOFS_BUTTON2; - - dod[count_ent].dwData = b[2]; - dod[count_ent].dwTimeStamp = GetTickCount(); - dod[count_ent].dwSequence = last_event+=add; - count_ent++; - save_b[2] = b[2]; - } - - else if (save_b[3] != b[3]) { - dod[count_ent].dwOfs = DIMOFS_BUTTON3; - - dod[count_ent].dwData = b[3]; - dod[count_ent].dwTimeStamp = GetTickCount(); - dod[count_ent].dwSequence = last_event+=add; - count_ent++; - save_b[3] = b[3]; - } - - - } // end for - - -SetCursorPos(point.x, point.y); -*entries = count_ent; -#endif - #ifndef __REACTOS__ EnterCriticalSection(&(This->crit)); - +#endif // FIXME mouse are bit choppy here. @@ -1047,9 +916,9 @@ SetCursorPos(point.x, point.y); } if (!(flags & DIGDD_PEEK)) This->queue_tail = nqtail; - +#ifndef __REACTOS__ LeaveCriticalSection(&(This->crit)); - +#endif /* Check if we need to do a mouse warping */ @@ -1066,8 +935,7 @@ SetCursorPos(point.x, point.y); #else This->need_warp = WARP_STARTED; #endif - } -#endif + } return DI_OK; } @@ -1089,7 +957,8 @@ static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, TRACE("buffersize = %ld\n",pd->dwData); - This->data_queue = HeapAlloc(GetProcessHeap(),0, pd->dwData * sizeof(DIDEVICEOBJECTDATA)); + This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0, + pd->dwData * sizeof(DIDEVICEOBJECTDATA)); This->queue_head = 0; This->queue_tail = 0; This->queue_len = pd->dwData; @@ -1120,7 +989,7 @@ static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, { SysMouseImpl *This = (SysMouseImpl *)iface; - TRACE("(this=%p,%s,%p)\n", + TRACE("(this=%p,%s,%p): stub!\n", iface, debugstr_guid(rguid), pdiph); if (TRACE_ON(dinput)) diff --git a/reactos/lib/dinput8/Makefile.in b/reactos/lib/dinput8/Makefile.in index 271545360eb..c434023b5c7 100644 --- a/reactos/lib/dinput8/Makefile.in +++ b/reactos/lib/dinput8/Makefile.in @@ -3,6 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = dinput8.dll +IMPORTLIB = libdinput8.$(IMPLIBEXT) IMPORTS = dinput EXTRALIBS = -luuid diff --git a/reactos/lib/dxdiagn/dxdiagn.xml b/reactos/lib/dxdiagn/dxdiagn.xml index 33531ca0ef4..332b8ad2254 100644 --- a/reactos/lib/dxdiagn/dxdiagn.xml +++ b/reactos/lib/dxdiagn/dxdiagn.xml @@ -1,4 +1,4 @@ - + . include/wine diff --git a/reactos/lib/icmp/Makefile.in b/reactos/lib/icmp/Makefile.in index 1f4fe10766f..c836679f86e 100644 --- a/reactos/lib/icmp/Makefile.in +++ b/reactos/lib/icmp/Makefile.in @@ -3,6 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = icmp.dll +IMPORTLIB = libicmp.$(IMPLIBEXT) IMPORTS = kernel32 EXTRALIBS = @SOCKETLIBS@ diff --git a/reactos/lib/iphlpapi/ifenum_reactos.c b/reactos/lib/iphlpapi/ifenum_reactos.c index 603f6fee89a..350a1492c68 100644 --- a/reactos/lib/iphlpapi/ifenum_reactos.c +++ b/reactos/lib/iphlpapi/ifenum_reactos.c @@ -129,15 +129,15 @@ NTSTATUS tdiGetSetOfThings( HANDLE tcpFile, DWORD allocationSizeForEntityArray = entrySize * MAX_TDI_ENTITIES, arraySize = entrySize * MAX_TDI_ENTITIES; - DbgPrint("TdiGetSetOfThings(tcpFile %x,toiClass %x,toiType %x,toiId %x," - "teiEntity %x,fixedPart %d,entrySize %d)\n", - (int)tcpFile, - (int)toiClass, - (int)toiType, - (int)toiId, - (int)teiEntity, - (int)fixedPart, - (int)entrySize ); + TRACE("TdiGetSetOfThings(tcpFile %x,toiClass %x,toiType %x,toiId %x," + "teiEntity %x,fixedPart %d,entrySize %d)\n", + (int)tcpFile, + (int)toiClass, + (int)toiType, + (int)toiId, + (int)teiEntity, + (int)fixedPart, + (int)entrySize ); req.ID.toi_class = toiClass; req.ID.toi_type = toiType; diff --git a/reactos/lib/kernel32/mem/section.c b/reactos/lib/kernel32/mem/section.c index e2fc7376ceb..d6734e8422d 100644 --- a/reactos/lib/kernel32/mem/section.c +++ b/reactos/lib/kernel32/mem/section.c @@ -77,7 +77,7 @@ CreateFileMappingA(HANDLE hFile, InitializeObjectAttributes(&ObjectAttributes, (lpName ? &UnicodeName : NULL), 0, - hBaseDir, + (lpName ? hBaseDir : NULL), SecurityDescriptor); Status = NtCreateSection(&SectionHandle, @@ -155,7 +155,7 @@ CreateFileMappingW(HANDLE hFile, InitializeObjectAttributes(&ObjectAttributes, (lpName ? &UnicodeName : NULL), 0, - hBaseDir, + (lpName ? hBaseDir : NULL), SecurityDescriptor); Status = NtCreateSection(&SectionHandle, diff --git a/reactos/lib/kernel32/misc/lang.c b/reactos/lib/kernel32/misc/lang.c index e4fb9d71639..c030e8cab49 100644 --- a/reactos/lib/kernel32/misc/lang.c +++ b/reactos/lib/kernel32/misc/lang.c @@ -25,7 +25,6 @@ //static RTL_CRITICAL_SECTION LocalesListLock; - /****************************************************************************** * @implemented * RIPPED FROM WINE's dlls\kernel\locale.c rev 1.42 @@ -849,6 +848,85 @@ CompareStringA ( } +static int compare_unicode_string( + PUNICODE_STRING String1, + PUNICODE_STRING String2, + DWORD Flags + ) +{ + ULONG len1, len2; + PWCHAR s1, s2; + WCHAR c1, c2; + + if (String1 && String2) + { + len1 = String1->Length / sizeof(WCHAR); + len2 = String2->Length / sizeof(WCHAR); + s1 = String1->Buffer; + s2 = String2->Buffer; + + while (len1 > 0 && len2 > 0) + { + if (Flags & NORM_IGNORESYMBOLS) + { + int skip = 0; + /* FIXME: not tested */ + if (iswctype(*s1, _SPACE | _PUNCT)) + { + s1++; + len1--; + skip = 1; + } + if (iswctype(*s2, _SPACE | _PUNCT)) + { + s2++; + len2--; + skip = 1; + } + if (skip) continue; + } + + /* hyphen and apostrophe are treated differently depending on + * whether SORT_STRINGSORT specified or not + */ + if (!(Flags & SORT_STRINGSORT)) + { + if (*s1 == '-' || *s1 == '\'') + { + if (*s2 != '-' && *s2 != '\'') + { + s1++; + len1--; + continue; + } + } + else if (*s2 == '-' || *s2 == '\'') + { + s2++; + len2--; + continue; + } + } + if (Flags & NORM_IGNORECASE) + { + c1 = len1-- ? RtlUpcaseUnicodeChar(*s1++) : 0; + c2 = len2-- ? RtlUpcaseUnicodeChar(*s2++) : 0; + if (!c1 || !c2 || c1 != c2) + return c1 - c2; + } + else + { + c1 = len1-- ? *s1++ : 0; + c2 = len2-- ? *s2++ : 0; + if (!c1 || !c2 || c1 != c2) + return c1 - c2; + } + } + } + return 0; +} + + /* * @unimplemented */ @@ -880,12 +958,6 @@ CompareStringW ( return 0; } - if (dwCmpFlags & ~NORM_IGNORECASE) - { - DPRINT1("CompareString: STUB flags - 0x%x\n", - dwCmpFlags & ~NORM_IGNORECASE); - } - if (cchCount1 < 0) cchCount1 = lstrlenW(lpString1); if (cchCount2 < 0) cchCount2 = lstrlenW(lpString2); @@ -894,9 +966,17 @@ CompareStringW ( String2.Length = String2.MaximumLength = cchCount2 * sizeof(WCHAR); String2.Buffer = (LPWSTR)lpString2; - Result = RtlCompareUnicodeString( - &String1, &String2, dwCmpFlags & NORM_IGNORECASE); + if (dwCmpFlags & ~NORM_IGNORECASE) + { + DPRINT1("CompareString: STUB flags - 0x%x\n", dwCmpFlags); + Result = compare_unicode_string(&String1, &String2, dwCmpFlags); + } + else + Result = RtlCompareUnicodeString( + &String1, &String2, dwCmpFlags & NORM_IGNORECASE); + + if (Result) /* need to translate result */ return (Result < 0) ? CSTR_LESS_THAN : CSTR_GREATER_THAN; diff --git a/reactos/lib/kernel32/synch/event.c b/reactos/lib/kernel32/synch/event.c index 6f8d80baf46..f5da06033cb 100644 --- a/reactos/lib/kernel32/synch/event.c +++ b/reactos/lib/kernel32/synch/event.c @@ -77,7 +77,7 @@ CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, InitializeObjectAttributes(&ObjectAttributes, (lpName ? &UnicodeName : NULL), 0, - hBaseDir, + (lpName ? hBaseDir : NULL), NULL); if (lpEventAttributes != NULL) diff --git a/reactos/lib/kernel32/synch/mutex.c b/reactos/lib/kernel32/synch/mutex.c index 20c3293da1d..854901d3a9e 100644 --- a/reactos/lib/kernel32/synch/mutex.c +++ b/reactos/lib/kernel32/synch/mutex.c @@ -76,7 +76,7 @@ CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes, InitializeObjectAttributes(&ObjectAttributes, (lpName ? &UnicodeName : NULL), 0, - hBaseDir, + (lpName ? hBaseDir : NULL), NULL); if (lpMutexAttributes != NULL) diff --git a/reactos/lib/kernel32/synch/sem.c b/reactos/lib/kernel32/synch/sem.c index aa5124d92f6..0e39f1cbeb0 100644 --- a/reactos/lib/kernel32/synch/sem.c +++ b/reactos/lib/kernel32/synch/sem.c @@ -77,7 +77,7 @@ CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, InitializeObjectAttributes(&ObjectAttributes, (lpName ? &UnicodeName : NULL), 0, - hBaseDir, + (lpName ? hBaseDir : NULL), NULL); if (lpSemaphoreAttributes != NULL) diff --git a/reactos/lib/kernel32/synch/timer.c b/reactos/lib/kernel32/synch/timer.c index ebfdaa31413..fd28a112d1a 100644 --- a/reactos/lib/kernel32/synch/timer.c +++ b/reactos/lib/kernel32/synch/timer.c @@ -38,7 +38,7 @@ CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes, InitializeObjectAttributes(&ObjectAttributes, (lpTimerName ? &UnicodeName : NULL), 0, - hBaseDir, + (lpTimerName ? hBaseDir : NULL), NULL); if (lpTimerAttributes != NULL) diff --git a/reactos/lib/mmdrv/wave.c b/reactos/lib/mmdrv/wave.c index 5816d245cc8..ed690a2a5d1 100644 --- a/reactos/lib/mmdrv/wave.c +++ b/reactos/lib/mmdrv/wave.c @@ -275,7 +275,7 @@ APIENTRY DWORD wodMessage(DWORD dwId, DWORD dwMessage, DWORD dwUser, DWORD dwPar case WODM_GETVOLUME: DPRINT("WODM_GETVOLUME"); { - WAVE_DD_VOLUME Vol; + WAVE_DD_VOLUME Vol = {}; DWORD res; res = soundGetData(WaveOutDevice, dwId, sizeof(Vol), diff --git a/reactos/lib/mpr/Makefile.in b/reactos/lib/mpr/Makefile.in index 87005abd05f..988a58b4f87 100644 --- a/reactos/lib/mpr/Makefile.in +++ b/reactos/lib/mpr/Makefile.in @@ -3,6 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = mpr.dll +IMPORTLIB = libmpr.$(IMPLIBEXT) IMPORTS = user32 advapi32 kernel32 EXTRALIBS = $(LIBUNICODE) diff --git a/reactos/lib/mpr/mpr.rc b/reactos/lib/mpr/mpr.rc index aed47a53e24..412bc61f318 100644 --- a/reactos/lib/mpr/mpr.rc +++ b/reactos/lib/mpr/mpr.rc @@ -33,4 +33,5 @@ #include "mpr_Ja.rc" #include "mpr_Nl.rc" #include "mpr_Pt.rc" +#include "mpr_Ru.rc" #include "mpr_Sv.rc" diff --git a/reactos/lib/mpr/mpr_Ru.rc b/reactos/lib/mpr/mpr_Ru.rc new file mode 100644 index 00000000000..a81051b0350 --- /dev/null +++ b/reactos/lib/mpr/mpr_Ru.rc @@ -0,0 +1,46 @@ +/* + * MPR dll resources + * + * Copyright (C) 2005 Mikhail Y. Zvyozdochkin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + IDS_ENTIRENETWORK "Âñÿ ñåòü" +} + +IDD_PROXYDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 250, 154 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Ââåäèòå Ñåòåâîé Ïàðîëü" +FONT 8, "MS Shell Dlg" +{ + LTEXT "Ïîæàëóéñòà, ââåäèòå Âàøè èìÿ è ïàðîëü:", IDC_EXPLAIN, 40, 6, 150, 15 + LTEXT "Ïðîêñè-ñåðâåð", -1, 40, 26, 50, 10 +/* LTEXT "Realm", -1, 40, 46, 50, 10 */ + LTEXT "Èìÿ ïîëüçîâàòåëÿ", -1, 40, 66, 50, 10 + LTEXT "Ïàðîëü", -1, 40, 86, 50, 10 + LTEXT "" IDC_PROXY, 80, 26, 150, 14, 0 + LTEXT "" IDC_REALM, 80, 46, 150, 14, 0 + EDITTEXT IDC_USERNAME, 80, 66, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP + EDITTEXT IDC_PASSWORD, 80, 86, 150, 14, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP | ES_PASSWORD + CHECKBOX "&Ñîõðàíèòü ïàðîëü (íåáåçîïàñíî)", IDC_SAVEPASSWORD, + 80, 106, 150, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP + PUSHBUTTON "OK", IDOK, 98, 126, 56, 14, WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON + PUSHBUTTON "Îòìåíà", IDCANCEL, 158, 126, 56, 14, WS_GROUP | WS_TABSTOP +} diff --git a/reactos/lib/msacm/msacm.rc b/reactos/lib/msacm/msacm.rc index 186ab00b7de..1b0f2c03531 100644 --- a/reactos/lib/msacm/msacm.rc +++ b/reactos/lib/msacm/msacm.rc @@ -30,3 +30,5 @@ #include "msacm_Ja.rc" #include "msacm_Nl.rc" #include "msacm_Pt.rc" +#include "msacm_Ru.rc" +#include "msacm_Sv.rc" diff --git a/reactos/lib/msacm/msacm_Ru.rc b/reactos/lib/msacm/msacm_Ru.rc new file mode 100644 index 00000000000..0f02617ea70 --- /dev/null +++ b/reactos/lib/msacm/msacm_Ru.rc @@ -0,0 +1,57 @@ +/* + * Russian resource file for MS ACM + * + * Copyright 2005 Mikhail Y. Zvyozdochkin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT + +DLG_ACMFORMATCHOOSE_ID DIALOG DISCARDABLE 10, 20, 225, 100 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Âûáîð çâóêà" +FONT 8, "MS Shell Dlg" +BEGIN + + LTEXT "&Èìÿ:", -1, 5, 5, 115, 8, NOT WS_GROUP + + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_CUSTOM, 5, 15, 115, 60, + CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + + PUSHBUTTON "Ñîõð&àíèòü êàê...", IDD_ACMFORMATCHOOSE_BTN_SETNAME, 125, 14, 45, 14 + PUSHBUTTON "&Óäàëèòü", IDD_ACMFORMATCHOOSE_BTN_DELNAME, 175, 14, 45, 14 + + LTEXT "&Ôîðìàò:", -1, 5, 41, 44, 8, NOT WS_GROUP + + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_FORMATTAG, 50, 39, 170, 60, + CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + + LTEXT "&Ñâîéñòâà:", -1, 5, 59, 44, 8, NOT WS_GROUP + +#if 0 + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_FORMAT, 50, 57, 170, 60, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP | + CBS_OWNERDRAWFIXED | CBS_HASSTRINGS +#else + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_FORMAT, 50, 57, 170, 60, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +#endif + DEFPUSHBUTTON "OK", IDOK, 48, 80, 40, 14 + PUSHBUTTON "Îòìåíà", IDCANCEL, 92, 80, 40, 14 + PUSHBUTTON "Ñ&ïðàâêà", IDD_ACMFORMATCHOOSE_BTN_HELP, 136, 80, 40, 14 + +END + diff --git a/reactos/lib/msacm/msacm_Sv.rc b/reactos/lib/msacm/msacm_Sv.rc new file mode 100644 index 00000000000..4f08d5493f8 --- /dev/null +++ b/reactos/lib/msacm/msacm_Sv.rc @@ -0,0 +1,56 @@ +/* + * Swedish resource file for MS ACM + * + * Copyright 2005 Anders Bergh + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_SWEDISH, SUBLANG_DEFAULT + +DLG_ACMFORMATCHOOSE_ID DIALOG DISCARDABLE 10, 20, 225, 100 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Ljudval" +FONT 8, "MS Shell Dlg" +BEGIN + + LTEXT "&Namn:", -1, 5, 5, 115, 8, NOT WS_GROUP + + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_CUSTOM, 5, 15, 115, 60, + CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + + PUSHBUTTON "&Spara som...", IDD_ACMFORMATCHOOSE_BTN_SETNAME, 125, 14, 45, 14 + PUSHBUTTON "&Ta bort", IDD_ACMFORMATCHOOSE_BTN_DELNAME, 175, 14, 45, 14 + + LTEXT "&Format:", -1, 5, 41, 44, 8, NOT WS_GROUP + + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_FORMATTAG, 50, 39, 170, 60, + CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + + LTEXT "&Attribut:", -1, 5, 59, 44, 8, NOT WS_GROUP + +#if 0 + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_FORMAT, 50, 57, 170, 60, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP | + CBS_OWNERDRAWFIXED | CBS_HASSTRINGS +#else + COMBOBOX IDD_ACMFORMATCHOOSE_CMB_FORMAT, 50, 57, 170, 60, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +#endif + DEFPUSHBUTTON "OK", IDOK, 48, 80, 40, 14 + PUSHBUTTON "Avbryt", IDCANCEL, 92, 80, 40, 14 + PUSHBUTTON "&Hjälp", IDD_ACMFORMATCHOOSE_BTN_HELP, 136, 80, 40, 14 + +END diff --git a/reactos/lib/msi/Makefile.in b/reactos/lib/msi/Makefile.in index 85c1eee55e3..12f85fdf719 100644 --- a/reactos/lib/msi/Makefile.in +++ b/reactos/lib/msi/Makefile.in @@ -3,6 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = msi.dll +IMPORTLIB = libmsi.$(IMPLIBEXT) IMPORTS = shell32 cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32 EXTRALIBS = -luuid $(LIBUNICODE) diff --git a/reactos/lib/msi/action.c b/reactos/lib/msi/action.c index ae48e3bcf75..caa26868694 100644 --- a/reactos/lib/msi/action.c +++ b/reactos/lib/msi/action.c @@ -99,6 +99,7 @@ static UINT ACTION_ForceReboot(MSIPACKAGE *package); static UINT ACTION_ResolveSource(MSIPACKAGE *package); static UINT ACTION_ExecuteAction(MSIPACKAGE *package); static UINT ACTION_RegisterFonts(MSIPACKAGE *package); +static UINT ACTION_PublishComponents(MSIPACKAGE *package); /* @@ -324,7 +325,7 @@ static struct _actions StandardActions[] = { { szInstallServices, NULL}, { szPatchFiles, NULL}, { szProcessComponents, ACTION_ProcessComponents }, - { szPublishComponents, NULL}, + { szPublishComponents, ACTION_PublishComponents }, { szPublishFeatures, ACTION_PublishFeatures }, { szPublishProduct, ACTION_PublishProduct }, { szRegisterClassInfo, ACTION_RegisterClassInfo }, @@ -380,6 +381,13 @@ inline static void reduce_to_longfilename(WCHAR* filename) memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR)); } +inline static void reduce_to_shortfilename(WCHAR* filename) +{ + LPWSTR p = strchrW(filename,'|'); + if (p) + *p = 0; +} + WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index) { UINT rc; @@ -598,6 +606,7 @@ void ACTION_free_package_structures( MSIPACKAGE* package) { HeapFree(GetProcessHeap(),0,package->files[i].File); HeapFree(GetProcessHeap(),0,package->files[i].FileName); + HeapFree(GetProcessHeap(),0,package->files[i].ShortName); HeapFree(GetProcessHeap(),0,package->files[i].Version); HeapFree(GetProcessHeap(),0,package->files[i].Language); HeapFree(GetProcessHeap(),0,package->files[i].SourcePath); @@ -630,15 +639,16 @@ static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d ) MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row); msiobj_release(&row->hdr); - msi_dialog_check_messages(package->dialog, NULL); + msi_dialog_check_messages(NULL); } static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record) { static const WCHAR Query_t[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'A','c','t','i','o', 'n','T','e','x','t',' ','W','H','E','R','E',' ', - 'A','c','t','i','o','n',' ','=', ' ','\'','%','s','\'',0}; + '`','A','c','t','i','o', 'n','T','e','x','t','`',' ', + 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=', + ' ','\'','%','s','\'',0}; WCHAR message[1024]; UINT rc; MSIQUERY * view; @@ -655,12 +665,14 @@ static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * recor if (rc != ERROR_SUCCESS) { MSI_ViewClose(view); + msiobj_release(&view->hdr); return; } rc = MSI_ViewFetch(view,&row); if (rc != ERROR_SUCCESS) { MSI_ViewClose(view); + msiobj_release(&view->hdr); return; } @@ -705,8 +717,9 @@ static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action) {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0}; static const WCHAR Query_t[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'A','c','t','i','o', 'n','T','e','x','t',' ','W','H','E','R','E', ' ', - 'A','c','t','i','o','n',' ','=', ' ','\'','%','s','\'',0}; + '`','A','c','t','i','o', 'n','T','e','x','t','`',' ', + 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=', + ' ','\'','%','s','\'',0}; WCHAR message[1024]; WCHAR timet[0x100]; UINT rc; @@ -1005,14 +1018,14 @@ static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI) MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'I','n','s','t','a','l','l','E','x','e','c','u','t','e', - 'S','e','q','u','e','n','c','e',' ', 'W','H','E','R','E',' ', - 'S','e','q','u','e','n','c','e',' ', '=',' ','%','i',0}; + '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e', + 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ', + '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0}; static const WCHAR UISeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e', - ' ', 'W','H','E','R','E',' ', 'S','e','q','u','e','n','c','e', + '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e', + '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`', ' ', '=',' ','%','i',0}; if (UI) @@ -1090,18 +1103,19 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) UINT rc; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - 'I','n','s','t','a','l','l','E','x','e','c','u','t','e', - 'S','e','q','u','e','n','c','e',' ', 'W','H','E','R','E',' ', - 'S','e','q','u','e','n','c','e',' ', '>',' ','%','i',' ', + '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e', + 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ', + '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ', 'O','R','D','E','R',' ', 'B','Y',' ', - 'S','e','q','u','e','n','c','e',0 }; + '`','S','e','q','u','e','n','c','e','`',0 }; MSIRECORD * row = 0; static const WCHAR IVQuery[] = - {'S','E','L','E','C','T',' ','S','e','q','u','e','n','c','e',' ', - 'F','R','O','M',' ','I','n','s','t','a','l','l', - 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ', - 'W','H','E','R','E',' ','A','c','t','i','o','n',' ','=',' ','`', - 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`', 0}; + {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`', + ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l', + 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ', + 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=', + ' ','\'', 'I','n','s','t','a','l','l', + 'V','a','l','i','d','a','t','e','\'', 0}; INT seq = 0; @@ -1225,10 +1239,12 @@ static UINT ACTION_ProcessUISequence(MSIPACKAGE *package) UINT rc; static const WCHAR ExecSeqQuery [] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e', - ' ','W','H','E','R','E',' ', 'S','e','q','u','e','n','c','e',' ', + '`','I','n','s','t','a','l','l', + 'U','I','S','e','q','u','e','n','c','e','`', + ' ','W','H','E','R','E',' ', + '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ', - 'S','e','q','u','e','n','c','e',0}; + '`','S','e','q','u','e','n','c','e','`',0}; rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); @@ -1420,7 +1436,7 @@ UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action) if (!handled) handled = ACTION_HandleDialogBox(package, action, &rc); - msi_dialog_check_messages( package->dialog, NULL ); + msi_dialog_check_messages( NULL ); if (!handled) { @@ -1493,9 +1509,10 @@ static BOOL create_full_pathW(const WCHAR *path) static UINT ACTION_CreateFolders(MSIPACKAGE *package) { static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','D','i','r','e','c','t','o','r','y','_', + {'S','E','L','E','C','T',' ', + '`','D','i','r','e','c','t','o','r','y','_','`', ' ','F','R','O','M',' ', - 'C','r','e','a','t','e','F','o','l','d','e','r',0 }; + '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 }; UINT rc; MSIQUERY *view; MSIFOLDER *folder; @@ -1606,7 +1623,7 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row) sz = 96; MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz); - package->components[index].Installed = INSTALLSTATE_UNKNOWN; + package->components[index].Installed = INSTALLSTATE_ABSENT; package->components[index].Action = INSTALLSTATE_UNKNOWN; package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN; @@ -1620,14 +1637,18 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) int index = package->loaded_features; DWORD sz; static const WCHAR Query1[] = - {'S','E','L','E','C','T',' ','C','o','m','p','o','n','e','n','t','_', - ' ','F','R','O','M',' ','F','e','a','t','u','r','e', - 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ', - 'F','e', 'a','t','u','r','e','_','=','\'','%','s','\'',0}; + {'S','E','L','E','C','T',' ', + '`','C','o','m','p','o','n','e','n','t','_','`', + ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e', + 'C','o','m','p','o','n','e','n','t','s','`',' ', + 'W','H','E','R','E',' ', + '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0}; static const WCHAR Query2[] = {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', - 'C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ', - 'C','o','m','p','o','n','e','n','t','=','\'','%','s','\'',0}; + '`','C','o','m','p','o','n','e','n','t','`',' ', + 'W','H','E','R','E',' ', + '`','C','o','m','p','o','n','e','n','t','`',' ', + '=','\'','%','s','\'',0}; MSIQUERY * view; MSIQUERY * view2; MSIRECORD * row2; @@ -1673,7 +1694,7 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) package->features[index].Attributes= MSI_RecordGetInteger(row,8); - package->features[index].Installed = INSTALLSTATE_UNKNOWN; + package->features[index].Installed = INSTALLSTATE_ABSENT; package->features[index].Action = INSTALLSTATE_UNKNOWN; package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN; @@ -1712,6 +1733,7 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) c_indx); package->features[index].Components[cnt] = c_indx; package->features[index].ComponentCount ++; + msiobj_release( &row2->hdr ); continue; } @@ -1751,61 +1773,6 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) msiobj_release(&view->hdr); } -/* - * I am not doing any of the costing functionality yet. - * Mostly looking at doing the Component and Feature loading - * - * The native MSI does A LOT of modification to tables here. Mostly adding - * a lot of temporary columns to the Feature and Component tables. - * - * note: Native msi also tracks the short filename. But I am only going to - * track the long ones. Also looking at this directory table - * it appears that the directory table does not get the parents - * resolved base on property only based on their entries in the - * directory table. - */ -static UINT ACTION_CostInitialize(MSIPACKAGE *package) -{ - MSIQUERY * view; - MSIRECORD * row; - UINT rc; - static const WCHAR Query_all[] = - {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - 'F','e','a','t','u','r','e',0}; - static const WCHAR szCosting[] = - {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 }; - static const WCHAR szZero[] = { '0', 0 }; - - MSI_SetPropertyW(package, szCosting, szZero); - MSI_SetPropertyW(package, cszRootDrive , c_colon); - - rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view); - if (rc != ERROR_SUCCESS) - return rc; - rc = MSI_ViewExecute(view,0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - while (1) - { - DWORD rc; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - break; - - load_feature(package,row); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - - return ERROR_SUCCESS; -} - static UINT load_file(MSIPACKAGE* package, MSIRECORD * row) { DWORD index = package->loaded_files; @@ -1838,8 +1805,10 @@ static UINT load_file(MSIPACKAGE* package, MSIRECORD * row) HeapFree(GetProcessHeap(), 0, buffer); package->files[index].FileName = load_dynamic_stringW(row,3); - reduce_to_longfilename(package->files[index].FileName); + + package->files[index].ShortName = load_dynamic_stringW(row,3); + reduce_to_shortfilename(package->files[index].ShortName); package->files[index].FileSize = MSI_RecordGetInteger(row,4); package->files[index].Version = load_dynamic_stringW(row, 5); @@ -1855,15 +1824,15 @@ static UINT load_file(MSIPACKAGE* package, MSIRECORD * row) return ERROR_SUCCESS; } -static UINT ACTION_FileCost(MSIPACKAGE *package) +static UINT load_all_files(MSIPACKAGE *package) { MSIQUERY * view; MSIRECORD * row; UINT rc; static const WCHAR Query[] = {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - 'F','i','l','e',' ', 'O','R','D','E','R',' ','B','Y',' ', - 'S','e','q','u','e','n','c','e', 0}; + '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ', + '`','S','e','q','u','e','n','c','e','`', 0}; if (!package) return ERROR_INVALID_HANDLE; @@ -1897,16 +1866,88 @@ static UINT ACTION_FileCost(MSIPACKAGE *package) return ERROR_SUCCESS; } + +/* + * I am not doing any of the costing functionality yet. + * Mostly looking at doing the Component and Feature loading + * + * The native MSI does A LOT of modification to tables here. Mostly adding + * a lot of temporary columns to the Feature and Component tables. + * + * note: Native msi also tracks the short filename. But I am only going to + * track the long ones. Also looking at this directory table + * it appears that the directory table does not get the parents + * resolved base on property only based on their entries in the + * directory table. + */ +static UINT ACTION_CostInitialize(MSIPACKAGE *package) +{ + MSIQUERY * view; + MSIRECORD * row; + UINT rc; + static const WCHAR Query_all[] = + {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', + '`','F','e','a','t','u','r','e','`',0}; + static const WCHAR szCosting[] = + {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 }; + static const WCHAR szZero[] = { '0', 0 }; + WCHAR buffer[3]; + DWORD sz = 3; + + MSI_GetPropertyW(package, szCosting, buffer, &sz); + if (buffer[0]=='1') + return ERROR_SUCCESS; + + MSI_SetPropertyW(package, szCosting, szZero); + MSI_SetPropertyW(package, cszRootDrive , c_colon); + + rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view); + if (rc != ERROR_SUCCESS) + return rc; + rc = MSI_ViewExecute(view,0); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return rc; + } + while (1) + { + DWORD rc; + + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + break; + + load_feature(package,row); + msiobj_release(&row->hdr); + } + MSI_ViewClose(view); + msiobj_release(&view->hdr); + + load_all_files(package); + + return ERROR_SUCCESS; +} + +static UINT ACTION_FileCost(MSIPACKAGE *package) +{ + return ERROR_SUCCESS; +} + + static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) { static const WCHAR Query[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'D','i','r','e','c', 't','o','r','y',' ','W','H','E','R','E',' ','`', - 'D','i','r','e','c','t', 'o','r','y','`',' ','=',' ','`','%','s','`', + '`','D','i','r','e','c', 't','o','r','y','`',' ', + 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`', + ' ','=',' ','\'','%','s','\'', 0}; UINT rc; MSIQUERY * view; LPWSTR ptargetdir, targetdir, parent, srcdir; + LPWSTR shortname = NULL; MSIRECORD * row = 0; INT index = -1; DWORD i; @@ -1972,15 +2013,16 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) /* for now only pick long filename versions */ if (strchrW(targetdir,'|')) { + shortname = targetdir; targetdir = strchrW(targetdir,'|'); *targetdir = 0; targetdir ++; } + /* for the sourcedir pick the short filename */ if (srcdir && strchrW(srcdir,'|')) { - srcdir= strchrW(srcdir,'|'); - *srcdir= 0; - srcdir ++; + LPWSTR p = strchrW(srcdir,'|'); + *p = 0; } /* now check for root dirs */ @@ -1999,9 +2041,12 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) if (srcdir) package->folders[index].SourceDefault = strdupW(srcdir); + else if (shortname) + package->folders[index].SourceDefault = strdupW(shortname); else if (targetdir) package->folders[index].SourceDefault = strdupW(targetdir); HeapFree(GetProcessHeap(), 0, ptargetdir); + TRACE(" SourceDefault = %s\n",debugstr_w(package->folders[index].SourceDefault)); parent = load_dynamic_stringW(row,2); if (parent) @@ -2105,6 +2150,7 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, else if (source && package->folders[i].ResolvedSource) { path = strdupW(package->folders[i].ResolvedSource); + TRACE(" (source)already resolved to %s\n",debugstr_w(path)); return path; } else if (!source && package->folders[i].Property) @@ -2136,6 +2182,7 @@ LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, else { path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL); + TRACE(" (source)resolved into %s\n",debugstr_w(path)); package->folders[i].ResolvedSource = strdupW(path); } HeapFree(GetProcessHeap(),0,p); @@ -2201,17 +2248,25 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature) { MSICOMPONENT* component = &package->components[feature->Components[i]]; + TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n", + newstate, debugstr_w(component->Component), component->Installed, + component->Action, component->ActionRequest); + if (!component->Enabled) continue; else { if (newstate == INSTALLSTATE_LOCAL) + { component->ActionRequest = INSTALLSTATE_LOCAL; + component->Action = INSTALLSTATE_LOCAL; + } else { int j,k; component->ActionRequest = newstate; + component->Action = newstate; /*if any other feature wants is local we need to set it local*/ for (j = 0; @@ -2225,12 +2280,19 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature) { if (package->features[j].ActionRequest == INSTALLSTATE_LOCAL) + { + TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature)); component->ActionRequest = INSTALLSTATE_LOCAL; + component->Action = INSTALLSTATE_LOCAL; + } break; } } } } + TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n", + newstate, debugstr_w(component->Component), component->Installed, + component->Action, component->ActionRequest); } } @@ -2344,10 +2406,26 @@ static UINT SetFeatureStates(MSIPACKAGE *package) BOOL feature_state = ((package->features[i].Level > 0) && (package->features[i].Level <= install_level)); - if (feature_state) + if ((feature_state) && + (package->features[i].Action == INSTALLSTATE_UNKNOWN)) { - package->features[i].ActionRequest = INSTALLSTATE_LOCAL; - package->features[i].Action = INSTALLSTATE_LOCAL; + if (package->features[i].Attributes & + msidbFeatureAttributesFavorSource) + { + package->features[i].ActionRequest = INSTALLSTATE_SOURCE; + package->features[i].Action = INSTALLSTATE_SOURCE; + } + else if (package->features[i].Attributes & + msidbFeatureAttributesFavorAdvertise) + { + package->features[i].ActionRequest =INSTALLSTATE_ADVERTISED; + package->features[i].Action =INSTALLSTATE_ADVERTISED; + } + else + { + package->features[i].ActionRequest = INSTALLSTATE_LOCAL; + package->features[i].Action = INSTALLSTATE_LOCAL; + } } } } @@ -2380,6 +2458,27 @@ static UINT SetFeatureStates(MSIPACKAGE *package) component->Action = INSTALLSTATE_LOCAL; component->ActionRequest = INSTALLSTATE_LOCAL; } + else if (feature->ActionRequest == INSTALLSTATE_SOURCE) + { + if ((component->Action == INSTALLSTATE_UNKNOWN) || + (component->Action == INSTALLSTATE_ABSENT) || + (component->Action == INSTALLSTATE_ADVERTISED)) + + { + component->Action = INSTALLSTATE_SOURCE; + component->ActionRequest = INSTALLSTATE_SOURCE; + } + } + else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED) + { + if ((component->Action == INSTALLSTATE_UNKNOWN) || + (component->Action == INSTALLSTATE_ABSENT)) + + { + component->Action = INSTALLSTATE_ADVERTISED; + component->ActionRequest = INSTALLSTATE_ADVERTISED; + } + } else if (feature->ActionRequest == INSTALLSTATE_ABSENT) { if (component->Action == INSTALLSTATE_UNKNOWN) @@ -2415,10 +2514,10 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) { static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'D','i','r','e','c','t','o','r','y',0}; + '`','D','i','r','e','c','t','o','r','y','`',0}; static const WCHAR ConditionQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'C','o','n','d','i','t','i','o','n',0}; + '`','C','o','n','d','i','t','i','o','n','`',0}; static const WCHAR szCosting[] = {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 }; static const WCHAR szlevel[] = @@ -2428,6 +2527,12 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) MSIQUERY * view; DWORD i; LPWSTR level; + DWORD sz = 3; + WCHAR buffer[3]; + + MSI_GetPropertyW(package, szCosting, buffer, &sz); + if (buffer[0]=='1') + return ERROR_SUCCESS; TRACE("Building Directory properties\n"); @@ -2669,6 +2774,7 @@ static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name, if (the_file == INVALID_HANDLE_VALUE) { + ERR("Unable to create file %s\n",debugstr_w(source)); rc = ERROR_FUNCTION_FAILED; goto end; } @@ -2771,7 +2877,7 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) LPWSTR tracknametmp; static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0}; - if (data->file_name && strcmp(data->file_name,pfdin->psz1)) + if (data->file_name && lstrcmpiA(data->file_name,pfdin->psz1)) return 0; file = cabinet_alloc((len+1)*sizeof(char)); @@ -2884,8 +2990,8 @@ static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, return ret; } -static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, - WCHAR* path, WCHAR* file) +static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path, + MSIFILE* file) { UINT rc; MSIQUERY * view; @@ -2893,24 +2999,30 @@ static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, static WCHAR source[MAX_PATH]; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - 'M','e','d','i','a',' ','W','H','E','R','E',' ', - 'L','a','s','t','S','e','q','u','e','n','c','e',' ','>','=',' ','%', - 'i',' ','O','R','D','E','R',' ','B','Y',' ', - 'L','a','s','t','S','e','q','u','e','n','c','e',0}; + '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ', + '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=', + ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ', + '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0}; WCHAR Query[1024]; WCHAR cab[0x100]; DWORD sz=0x100; INT seq; static UINT last_sequence = 0; - if (sequence <= last_sequence) + if (file->Attributes & msidbFileAttributesNoncompressed) { - TRACE("Media already ready (%u, %u)\n",sequence,last_sequence); - /*extract_a_cabinet_file(package, source,path,file); */ + TRACE("Uncompressed File, no media to ready.\n"); return ERROR_SUCCESS; } - sprintfW(Query,ExecSeqQuery,sequence); + if (file->Sequence <= last_sequence) + { + TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence); + /*extract_a_cabinet_file(package, source,path,file->File); */ + return ERROR_SUCCESS; + } + + sprintfW(Query,ExecSeqQuery,file->Sequence); rc = MSI_DatabaseOpenViewW(package->db, Query, &view); if (rc != ERROR_SUCCESS) @@ -3038,12 +3150,10 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package) if ((file->State == 1) || (file->State == 2)) { LPWSTR p; - INT len; MSICOMPONENT* comp = NULL; TRACE("Installing %s\n",debugstr_w(file->File)); - rc = ready_media_for_file(package,file->Sequence,path_to_source, - file->File); + rc = ready_media_for_file(package, path_to_source, file); /* * WARNING! * our file table could change here because a new temp file @@ -3068,11 +3178,18 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package) HeapFree(GetProcessHeap(),0,file->TargetPath); file->TargetPath = build_directory_name(2, p, file->FileName); + HeapFree(GetProcessHeap(),0,p); + + if (file->Attributes & msidbFileAttributesNoncompressed) + { + p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL); + file->SourcePath = build_directory_name(2, p, file->ShortName); + HeapFree(GetProcessHeap(),0,p); + } + else + file->SourcePath = build_directory_name(2, path_to_source, + file->File); - len = strlenW(path_to_source) + strlenW(file->File) + 2; - file->SourcePath = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); - strcpyW(file->SourcePath, path_to_source); - strcatW(file->SourcePath, file->File); TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath), debugstr_w(file->TargetPath)); @@ -3088,16 +3205,26 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package) msiobj_release( &uirow->hdr ); ui_progress(package,2,file->FileSize,0,0); - if (!MoveFileW(file->SourcePath,file->TargetPath)) + + if (file->Attributes & msidbFileAttributesNoncompressed) + rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE); + else + rc = MoveFileW(file->SourcePath, file->TargetPath); + + if (!rc) { rc = GetLastError(); - ERR("Unable to move file (%s -> %s) (error %d)\n", + ERR("Unable to move/copy file (%s -> %s) (error %d)\n", debugstr_w(file->SourcePath), debugstr_w(file->TargetPath), rc); if (rc == ERROR_ALREADY_EXISTS && file->State == 2) { - CopyFileW(file->SourcePath,file->TargetPath,FALSE); - DeleteFileW(file->SourcePath); + if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE)) + ERR("Unable to copy file (%s -> %s) (error %ld)\n", + debugstr_w(file->SourcePath), + debugstr_w(file->TargetPath), GetLastError()); + if (!(file->Attributes & msidbFileAttributesNoncompressed)) + DeleteFileW(file->SourcePath); rc = 0; } else if (rc == ERROR_FILE_NOT_FOUND) @@ -3105,14 +3232,17 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package) ERR("Source File Not Found! Continuing\n"); rc = 0; } - else + else if (file->Attributes & msidbFileAttributesVital) { - ERR("Ignoring Error and continuing...\n"); + ERR("Ignoring Error and continuing (nonvital file)...\n"); rc = 0; } } else + { file->State = 4; + rc = ERROR_SUCCESS; + } } } @@ -3151,7 +3281,7 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'D','u','p','l','i','c','a','t','e','F','i','l','e',0}; + '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0}; if (!package) return ERROR_INVALID_HANDLE; @@ -3304,21 +3434,35 @@ static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, { LPWSTR ptr; CHAR byte[5]; - LPWSTR deformated; + LPWSTR deformated = NULL; int count; deformat_string(package, &value[2], &deformated); /* binary value type */ - ptr = deformated; - *type=REG_BINARY; - *size = strlenW(ptr)/2; + ptr = deformated; + *type = REG_BINARY; + if (strlenW(ptr)%2) + *size = (strlenW(ptr)/2)+1; + else + *size = strlenW(ptr)/2; + data = HeapAlloc(GetProcessHeap(),0,*size); - + byte[0] = '0'; byte[1] = 'x'; byte[4] = 0; count = 0; + /* if uneven pad with a zero in front */ + if (strlenW(ptr)%2) + { + byte[2]= '0'; + byte[3]= *ptr; + ptr++; + data[count] = (BYTE)strtol(byte,NULL,0); + count ++; + TRACE("Uneven byte count\n"); + } while (*ptr) { byte[2]= *ptr; @@ -3395,7 +3539,7 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'R','e','g','i','s','t','r','y',0 }; + '`','R','e','g','i','s','t','r','y','`',0 }; if (!package) return ERROR_INVALID_HANDLE; @@ -3438,6 +3582,7 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) MSIRECORD * uirow; LPWSTR uikey; INT root; + BOOL check_first = FALSE; rc = MSI_ViewFetch(view,&row); if (rc != ERROR_SUCCESS) @@ -3483,6 +3628,7 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) { HeapFree(GetProcessHeap(),0,name); name = NULL; + check_first = TRUE; } } @@ -3545,8 +3691,32 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) deformat_string(package, name, &deformated); - TRACE("Setting value %s\n",debugstr_w(deformated)); - RegSetValueExW(hkey, deformated, 0, type, value_data, size); + /* get the double nulls to terminate SZ_MULTI */ + if (type == REG_MULTI_SZ) + size +=sizeof(WCHAR); + + if (!check_first) + { + TRACE("Setting value %s of %s\n",debugstr_w(deformated), + debugstr_w(uikey)); + RegSetValueExW(hkey, deformated, 0, type, value_data, size); + } + else + { + DWORD sz = 0; + rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz); + if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA) + { + TRACE("value %s of %s checked already exists\n", + debugstr_w(deformated), debugstr_w(uikey)); + } + else + { + TRACE("Checked and setting value %s of %s\n", + debugstr_w(deformated), debugstr_w(uikey)); + RegSetValueExW(hkey, deformated, 0, type, value_data, size); + } + } uirow = MSI_CreateRecord(3); MSI_RecordSetStringW(uirow,2,deformated); @@ -3589,7 +3759,7 @@ static UINT ACTION_InstallValidate(MSIPACKAGE *package) DWORD total = 0; static const WCHAR q1[]= {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - 'R','e','g','i','s','t','r','y',0}; + '`','R','e','g','i','s','t','r','y','`',0}; UINT rc; MSIQUERY * view; MSIRECORD * row = 0; @@ -3629,6 +3799,14 @@ static UINT ACTION_InstallValidate(MSIPACKAGE *package) total += package->files[i].FileSize; ui_progress(package,0,total,0,0); + for(i = 0; i < package->loaded_features; i++) + { + MSIFEATURE* feature = &package->features[i]; + TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n", + debugstr_w(feature->Feature), feature->Installed, feature->Action, + feature->ActionRequest); + } + return ERROR_SUCCESS; } @@ -3639,7 +3817,7 @@ static UINT ACTION_LaunchConditions(MSIPACKAGE *package) MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n',0}; + '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0}; static const WCHAR title[]= {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0}; @@ -3708,8 +3886,9 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT LPWSTR key,deformated,buffer,name,deformated_name; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'R','e','g','i','s','t','r','y',' ','W','H','E','R','E',' ', - 'R','e','g','i','s','t','r','y',' ','=',' ' ,'`','%','s','`',0 }; + '`','R','e','g','i','s','t','r','y','`',' ', + 'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`', + ' ','=',' ' ,'\'','%','s','\'',0 }; static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0}; static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0}; @@ -3941,9 +4120,6 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) MSIRECORD * uirow; squash_guid(package->components[i].ComponentId,squished_cc); - rc = RegCreateKeyW(hkey,squished_cc,&hkey2); - if (rc != ERROR_SUCCESS) - continue; keypath = resolve_keypath(package,i); package->components[i].FullKeypath = keypath; @@ -3951,8 +4127,9 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) /* do the refcounting */ ACTION_RefCountComponent( package, i); - TRACE("Component %s, Keypath=%s, RefCount=%i\n", - debugstr_w(package->components[i].Component), + TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n", + debugstr_w(package->components[i].Component), + debugstr_w(squished_cc), debugstr_w(package->components[i].FullKeypath), package->components[i].RefCount); /* @@ -3962,6 +4139,10 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) if (ACTION_VerifyComponentForAction(package, i, INSTALLSTATE_LOCAL)) { + rc = RegCreateKeyW(hkey,squished_cc,&hkey2); + if (rc != ERROR_SUCCESS) + continue; + if (keypath) { RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath, @@ -3996,6 +4177,11 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) INSTALLSTATE_ABSENT)) { DWORD res; + + rc = RegOpenKeyW(hkey,squished_cc,&hkey2); + if (rc != ERROR_SUCCESS) + continue; + RegDeleteValueW(hkey2,squished_pc); /* if the key is empty delete it */ @@ -4088,7 +4274,7 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) MSIRECORD * row = 0; static const WCHAR Query[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'T','y','p','e','L','i','b',0}; + '`','T','y','p','e','L','i','b','`',0}; if (!package) return ERROR_INVALID_HANDLE; @@ -4217,8 +4403,8 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app ) MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'A','p','p','I' ,'d',' ','w','h','e','r','e',' ', - 'A','p','p','I','d','=','`','%','s','`',0}; + '`','A','p','p','I' ,'d','`',' ','W','H','E','R','E',' ', + '`','A','p','p','I','d','`',' ','=','\'','%','s','\'',0}; HKEY hkey2,hkey3; LPWSTR buffer=0; @@ -4347,7 +4533,7 @@ static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'C','l','a','s','s',0}; + '`','C','l','a','s','s','`',0}; static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 }; static const WCHAR szAppID[] = { 'A','p','p','I','D',0 }; @@ -4404,8 +4590,10 @@ static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) continue; } - if (!ACTION_VerifyComponentForAction(package, index, - INSTALLSTATE_LOCAL)) + if ((!ACTION_VerifyComponentForAction(package, index, + INSTALLSTATE_LOCAL)) && + (!ACTION_VerifyComponentForAction(package, index, + INSTALLSTATE_ADVERTISED))) { TRACE("Skipping class reg due to disabled component\n"); msiobj_release(&row->hdr); @@ -4662,8 +4850,8 @@ static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent, MSIRECORD * row = 0; static const WCHAR Query_t[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'P','r','o','g' ,'I','d',' ','W','H','E','R','E',' ', - 'P','r','o','g','I','d',' ','=',' ','`' ,'%','s','`',0}; + '`','P','r','o','g' ,'I','d','`',' ','W','H','E','R','E',' ', + '`','P','r','o','g','I','d','`',' ','=',' ','\'' ,'%','s','\'',0}; if (!package) return ERROR_INVALID_HANDLE; @@ -4776,7 +4964,7 @@ static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package) MSIRECORD * row = 0; static const WCHAR Query[] = {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - 'P','r','o','g','I','d',0}; + '`','P','r','o','g','I','d','`',0}; if (!package) return ERROR_INVALID_HANDLE; @@ -4851,8 +5039,8 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) MSIQUERY * view; MSIRECORD * row = 0; static const WCHAR Query[] = - {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ', - 'S','h','o','r','t','c','u','t',0}; + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','S','h','o','r','t','c','u','t','`',0}; IShellLinkW *sl; IPersistFile *pf; HRESULT res; @@ -5054,7 +5242,7 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) MSIRECORD * row = 0; static const WCHAR Query[]= {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'I','c','o','n',0}; + '`','I','c','o','n','`',0}; DWORD sz; /* for registry stuff */ LPWSTR productcode; @@ -5215,7 +5403,7 @@ static UINT ACTION_WriteIniValues(MSIPACKAGE *package) MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'I','n','i','F','i','l','e',0}; + '`','I','n','i','F','i','l','e','`',0}; static const WCHAR szWindowsFolder[] = {'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; @@ -5357,10 +5545,11 @@ static UINT ACTION_SelfRegModules(MSIPACKAGE *package) MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'S','e','l','f','R','e','g',0}; + '`','S','e','l','f','R','e','g','`',0}; static const WCHAR ExeStr[] = - {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','s',' ',0}; + {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0}; + static const WCHAR close[] = {'\"',0}; STARTUPINFOW si; PROCESS_INFORMATION info; BOOL brc; @@ -5414,13 +5603,14 @@ static UINT ACTION_SelfRegModules(MSIPACKAGE *package) filename = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); strcpyW(filename,ExeStr); strcatW(filename,package->files[index].TargetPath); + strcatW(filename,close); TRACE("Registering %s\n",debugstr_w(filename)); brc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &info); if (brc) - msi_dialog_check_messages(package->dialog, info.hProcess); + msi_dialog_check_messages(info.hProcess); HeapFree(GetProcessHeap(),0,filename); msiobj_release(&row->hdr); @@ -5460,9 +5650,12 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package) GUID clsid; int j; INT size; + BOOL absent = FALSE; - if (!ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_LOCAL)) - continue; + if (!ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_LOCAL) && + !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_SOURCE) && + !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_ADVERTISED)) + absent = TRUE; size = package->features[i].ComponentCount*21; size +=1; @@ -5476,14 +5669,18 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package) { WCHAR buf[21]; memset(buf,0,sizeof(buf)); - TRACE("From %s\n",debugstr_w(package->components + if (package->components + [package->features[i].Components[j]].ComponentId[0]!=0) + { + TRACE("From %s\n",debugstr_w(package->components [package->features[i].Components[j]].ComponentId)); - CLSIDFromString(package->components + CLSIDFromString(package->components [package->features[i].Components[j]].ComponentId, &clsid); - encode_base85_guid(&clsid,buf); - TRACE("to %s\n",debugstr_w(buf)); - strcatW(data,buf); + encode_base85_guid(&clsid,buf); + TRACE("to %s\n",debugstr_w(buf)); + strcatW(data,buf); + } } if (package->features[i].Feature_Parent[0]) { @@ -5497,9 +5694,23 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package) (LPSTR)data,size); HeapFree(GetProcessHeap(),0,data); - size = strlenW(package->features[i].Feature_Parent)*sizeof(WCHAR); - RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ, + if (!absent) + { + size = strlenW(package->features[i].Feature_Parent)*sizeof(WCHAR); + RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ, (LPSTR)package->features[i].Feature_Parent,size); + } + else + { + size = (strlenW(package->features[i].Feature_Parent)+2)* + sizeof(WCHAR); + data = HeapAlloc(GetProcessHeap(),0,size); + data[0] = 0x6; + strcpyW(&data[1],package->features[i].Feature_Parent); + RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ, + (LPSTR)data,size); + HeapFree(GetProcessHeap(),0,data); + } } end: @@ -5625,7 +5836,10 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) snprintfW(path,sizeof(path)/sizeof(path[0]),installerPathFmt,windir); create_full_pathW(path); TRACE("Copying to local package %s\n",debugstr_w(packagefile)); - CopyFileW(package->PackagePath,packagefile,FALSE); + if (!CopyFileW(package->PackagePath,packagefile,FALSE)) + ERR("Unable to copy package (%s -> %s) (error %ld)\n", + debugstr_w(package->PackagePath), debugstr_w(packagefile), + GetLastError()); size = strlenW(packagefile)*sizeof(WCHAR); RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size); @@ -5793,7 +6007,7 @@ static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package) MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'E','x','t','e','n','s','i','o','n',0}; + '`','E','x','t','e','n','s','i','o','n','`',0}; static const WCHAR szContentType[] = {'C','o','n','t','e','n','t',' ','T','y','p','e',0 }; HKEY hkey; @@ -5842,8 +6056,10 @@ static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package) continue; } - if (!ACTION_VerifyComponentForAction(package, index, - INSTALLSTATE_LOCAL)) + if ((!ACTION_VerifyComponentForAction(package, index, + INSTALLSTATE_LOCAL)) && + (!ACTION_VerifyComponentForAction(package, index, + INSTALLSTATE_ADVERTISED))) { TRACE("Skipping extension reg due to disabled component\n"); msiobj_release(&row->hdr); @@ -5916,7 +6132,7 @@ static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package) MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'M','I','M','E',0}; + '`','M','I','M','E','`',0}; static const WCHAR szExten[] = {'E','x','t','e','n','s','i','o','n',0 }; HKEY hkey; @@ -6042,6 +6258,8 @@ static UINT ACTION_RegisterUser(MSIPACKAGE *package) size = strlenW(buffer)*sizeof(WCHAR); RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size); } + else + RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,NULL,0); i++; } @@ -6057,7 +6275,7 @@ end: static UINT ACTION_ExecuteAction(MSIPACKAGE *package) { UINT rc; - rc = ACTION_ProcessExecSequence(package,TRUE); + rc = ACTION_ProcessExecSequence(package,FALSE); return rc; } @@ -6187,6 +6405,8 @@ static LPWSTR load_ttfname_from(LPCWSTR filename) } CloseHandle(handle); } + else + ERR("Unable to open font file %s\n", debugstr_w(filename)); TRACE("Returning fontname %s\n",debugstr_w(ret)); return ret; @@ -6199,7 +6419,7 @@ static UINT ACTION_RegisterFonts(MSIPACKAGE *package) MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'F','o','n','t',0}; + '`','F','o','n','t','`',0}; static const WCHAR regfont1[] = {'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', @@ -6215,16 +6435,22 @@ static UINT ACTION_RegisterFonts(MSIPACKAGE *package) HKEY hkey1; HKEY hkey2; + TRACE("%p\n", package); + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); if (rc != ERROR_SUCCESS) - return rc; + { + TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc); + return ERROR_SUCCESS; + } rc = MSI_ViewExecute(view, 0); if (rc != ERROR_SUCCESS) { MSI_ViewClose(view); msiobj_release(&view->hdr); - return rc; + TRACE("MSI_ViewExecute returned %d\n", rc); + return ERROR_SUCCESS; } RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1); @@ -6289,10 +6515,143 @@ static UINT ACTION_RegisterFonts(MSIPACKAGE *package) RegCloseKey(hkey1); RegCloseKey(hkey2); + TRACE("returning %d\n", rc); + return rc; +} + +static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPWSTR productid=NULL, compgroupid=NULL; + LPWSTR feature=NULL; + LPWSTR text = NULL; + LPWSTR qualifier = NULL; + LPWSTR component = NULL; + GUID clsid; + WCHAR productid_85[21]; + WCHAR component_85[21]; + HKEY hkey; + UINT rc = ERROR_SUCCESS; + UINT index; + /* + * I have a fair bit of confusion as to when a < is used and when a > is + * used. I do not think i have it right... + * + * Ok it appears that the > is used if there is a guid for the compoenent + * and the < is used if not. + */ + static WCHAR fmt1[] = {'%','s','%','s','<',0,0}; + static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0}; + LPWSTR output = NULL; + DWORD sz = 0; + INT component_index; + + component = load_dynamic_stringW(rec,3); + component_index = get_loaded_component(package,component); + + if (!ACTION_VerifyComponentForAction(package, component_index, + INSTALLSTATE_LOCAL) && + !ACTION_VerifyComponentForAction(package, component_index, + INSTALLSTATE_SOURCE) && + !ACTION_VerifyComponentForAction(package, component_index, + INSTALLSTATE_ADVERTISED)) + { + TRACE("Skipping: Component %s not scheduled for install\n", + debugstr_w(component)); + HeapFree(GetProcessHeap(),0,component); + return ERROR_SUCCESS; + } + + memset(productid_85,0,sizeof(productid_85)); + memset(component_85,0,sizeof(component_85)); + compgroupid = load_dynamic_stringW(rec,1); + + rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE); + if (rc != ERROR_SUCCESS) + goto end; + + productid = load_dynamic_property(package,szProductCode,NULL); + CLSIDFromString(productid, &clsid); + + encode_base85_guid(&clsid,productid_85); + + text = load_dynamic_stringW(rec,4); + qualifier = load_dynamic_stringW(rec,2); + + feature = load_dynamic_stringW(rec,5); + + index = get_loaded_component(package, component); + CLSIDFromString(package->components[index].ComponentId, &clsid); + encode_base85_guid(&clsid,component_85); + + TRACE("Doing something with this... %s = %s %s %s %s\n", + debugstr_w(qualifier), debugstr_w(productid_85), + debugstr_w(feature), debugstr_w(text), debugstr_w(component_85)); + + sz = lstrlenW(productid_85) + lstrlenW(feature); + if (text) + sz += lstrlenW(text); + if (component && index >= 0) + sz += lstrlenW(component_85); + + sz+=3; + sz *= sizeof(WCHAR); + + output = HeapAlloc(GetProcessHeap(),0,sz); + memset(output,0,sz); + + if (component && index >= 0) + sprintfW(output,fmt2,productid_85,feature,component_85); + else + sprintfW(output,fmt1,productid_85,feature); + + if (text) + strcatW(output,text); + + sz = (lstrlenW(output)+2) * sizeof(WCHAR); + RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz); + +end: + RegCloseKey(hkey); + HeapFree(GetProcessHeap(),0,output); + HeapFree(GetProcessHeap(),0,compgroupid); + HeapFree(GetProcessHeap(),0,component); + HeapFree(GetProcessHeap(),0,productid); + HeapFree(GetProcessHeap(),0,feature); + HeapFree(GetProcessHeap(),0,text); + HeapFree(GetProcessHeap(),0,qualifier); + + return rc; +} + +/* + * At present I am ignorning the advertised components part of this and only + * focusing on the qualified component sets + */ +static UINT ACTION_PublishComponents(MSIPACKAGE *package) +{ + UINT rc; + MSIQUERY * view; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','P','u','b','l','i','s','h', + 'C','o','m','p','o','n','e','n','t','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package); + msiobj_release(&view->hdr); + return rc; } /* Msi functions that seem appropriate here */ + +/*********************************************************************** + * MsiDoActionA (MSI.@) + */ UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction ) { LPWSTR szwAction; @@ -6316,6 +6675,9 @@ UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction ) return rc; } +/*********************************************************************** + * MsiDoActionW (MSI.@) + */ UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction ) { MSIPACKAGE *package; @@ -6461,6 +6823,9 @@ UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR } +/*********************************************************************** + * MsiSetTargetPathA (MSI.@) + */ UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder, LPCSTR szFolderPath) { @@ -6519,7 +6884,7 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, HeapFree(GetProcessHeap(),0,folder->Property); folder->Property = build_directory_name(2, szFolderPath, NULL); - if (strcmpiW(path, folder->Property) == 0) + if (lstrcmpiW(path, folder->Property) == 0) { /* * Resolved Target has not really changed, so just @@ -6550,6 +6915,9 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, return ERROR_SUCCESS; } +/*********************************************************************** + * MsiSetTargetPathW (MSI.@) + */ UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, LPCWSTR szFolderPath) { @@ -6604,7 +6972,9 @@ BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode) return TRUE; } -/* +/*********************************************************************** + * MsiSetFeatureStateA (MSI.@) + * * According to the docs, when this is called it immediately recalculates * all the component states as well */ @@ -6626,11 +6996,42 @@ UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature, return rc; } + + +UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature, + INSTALLSTATE iState) +{ + INT index, i; + UINT rc = ERROR_SUCCESS; + + TRACE(" %s to %i\n",debugstr_w(szFeature), iState); + + index = get_loaded_feature(package,szFeature); + if (index < 0) + return ERROR_UNKNOWN_FEATURE; + + package->features[index].ActionRequest= iState; + package->features[index].Action= iState; + + ACTION_UpdateComponentStates(package,szFeature); + + /* update all the features that are children of this feature */ + for (i = 0; i < package->loaded_features; i++) + { + if (strcmpW(szFeature, package->features[i].Feature_Parent) == 0) + MSI_SetFeatureStateW(package, package->features[i].Feature, iState); + } + + return rc; +} + +/*********************************************************************** + * MsiSetFeatureStateW (MSI.@) + */ UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature, INSTALLSTATE iState) { MSIPACKAGE* package; - INT index; UINT rc = ERROR_SUCCESS; TRACE(" %s to %i\n",debugstr_w(szFeature), iState); @@ -6639,17 +7040,8 @@ UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature, if (!package) return ERROR_INVALID_HANDLE; - index = get_loaded_feature(package,szFeature); - if (index < 0) - { - rc = ERROR_UNKNOWN_FEATURE; - goto end; - } + rc = MSI_SetFeatureStateW(package,szFeature,iState); - package->features[index].ActionRequest= iState; - ACTION_UpdateComponentStates(package,szFeature); - -end: msiobj_release( &package->hdr ); return rc; } @@ -6706,6 +7098,9 @@ piAction); return ret; } +/*********************************************************************** + * MsiGetComponentStateA (MSI.@) + */ UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent, INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) { @@ -6745,6 +7140,9 @@ piAction); return ERROR_SUCCESS; } +/*********************************************************************** + * MsiGetComponentStateW (MSI.@) + */ UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent, INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) { diff --git a/reactos/lib/msi/action.h b/reactos/lib/msi/action.h index af718bee464..a88a07f5e15 100644 --- a/reactos/lib/msi/action.h +++ b/reactos/lib/msi/action.h @@ -82,6 +82,7 @@ typedef struct tagMSIFILE LPWSTR File; INT ComponentIndex; LPWSTR FileName; + LPWSTR ShortName; INT FileSize; LPWSTR Version; LPWSTR Language; diff --git a/reactos/lib/msi/appsearch.c b/reactos/lib/msi/appsearch.c index ca9fc65a305..f499caa43c0 100644 --- a/reactos/lib/msi/appsearch.c +++ b/reactos/lib/msi/appsearch.c @@ -23,8 +23,10 @@ #include "windef.h" #include "winbase.h" +#include "winreg.h" #include "msi.h" #include "msiquery.h" +#include "msidefs.h" #include "winver.h" #include "wine/unicode.h" #include "wine/debug.h" @@ -243,6 +245,9 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound, 'R','e','g','L','o','c','a','t','o','r',' ', 'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e','_',' ','=',' ', '\'','%','s','\'',0}; + static const WCHAR dwordFmt[] = { '#','%','d','\0' }; + static const WCHAR expandSzFmt[] = { '#','%','%','%','s','\0' }; + static const WCHAR binFmt[] = { '#','x','%','x','\0' }; TRACE("(package %p, appFound %p, sig %p)\n", package, appFound, sig); *appFound = FALSE; @@ -250,7 +255,11 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound, if (rc == ERROR_SUCCESS) { MSIRECORD *row = 0; - LPWSTR keyPath; + LPWSTR keyPath = NULL, valueName = NULL, propertyValue = NULL; + int root, type; + HKEY rootKey, key = NULL; + DWORD sz = 0, regType, i; + LPBYTE value = NULL; rc = MSI_ViewExecute(view, 0); if (rc != ERROR_SUCCESS) @@ -266,13 +275,121 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound, goto end; } - /* get key path */ + root = MSI_RecordGetInteger(row,2); keyPath = load_dynamic_stringW(row,3); - FIXME("AppSearch unimplemented for RegLocator (key path %s)\n", - debugstr_w(keyPath)); - HeapFree(GetProcessHeap(), 0, keyPath); + /* FIXME: keyPath needs to be expanded for properties */ + valueName = load_dynamic_stringW(row,4); + /* FIXME: valueName probably does too */ + type = MSI_RecordGetInteger(row,5); + + if ((type & 0x0f) != msidbLocatorTypeRawValue) + { + FIXME("AppSearch unimplemented for type %d (key path %s, value %s)\n", + type, debugstr_w(keyPath), debugstr_w(valueName)); + goto end; + } + + switch (root) + { + case msidbRegistryRootClassesRoot: + rootKey = HKEY_CLASSES_ROOT; + break; + case msidbRegistryRootCurrentUser: + rootKey = HKEY_CURRENT_USER; + break; + case msidbRegistryRootLocalMachine: + rootKey = HKEY_LOCAL_MACHINE; + break; + case msidbRegistryRootUsers: + rootKey = HKEY_USERS; + break; + default: + WARN("Unknown root key %d\n", root); + goto end; + } + + rc = RegCreateKeyW(rootKey, keyPath, &key); + if (rc) + { + TRACE("RegCreateKeyW returned %d\n", rc); + rc = ERROR_SUCCESS; + goto end; + } + rc = RegQueryValueExW(key, valueName, NULL, NULL, NULL, &sz); + if (rc) + { + TRACE("RegQueryValueExW returned %d\n", rc); + rc = ERROR_SUCCESS; + goto end; + } + /* FIXME: sanity-check sz before allocating (is there an upper-limit + * on the value of a property?) + */ + value = HeapAlloc(GetProcessHeap(), 0, sz); + rc = RegQueryValueExW(key, valueName, NULL, ®Type, value, &sz); + if (rc) + { + TRACE("RegQueryValueExW returned %d\n", rc); + rc = ERROR_SUCCESS; + goto end; + } + + switch (regType) + { + case REG_SZ: + if (*(LPWSTR)value == '#') + { + /* escape leading pound with another */ + propertyValue = HeapAlloc(GetProcessHeap(), 0, + sz + sizeof(WCHAR)); + propertyValue[0] = '#'; + strcpyW(propertyValue + 1, (LPWSTR)value); + } + else + { + propertyValue = HeapAlloc(GetProcessHeap(), 0, sz); + strcpyW(propertyValue, (LPWSTR)value); + } + break; + case REG_DWORD: + /* 7 chars for digits, 1 for NULL, 1 for #, and 1 for sign + * char if needed + */ + propertyValue = HeapAlloc(GetProcessHeap(), 0, + 10 * sizeof(WCHAR)); + sprintfW(propertyValue, dwordFmt, *(DWORD *)value); + break; + case REG_EXPAND_SZ: + /* space for extra #% characters in front */ + propertyValue = HeapAlloc(GetProcessHeap(), 0, + sz + 2 * sizeof(WCHAR)); + sprintfW(propertyValue, expandSzFmt, (LPWSTR)value); + break; + case REG_BINARY: + /* 3 == length of "#x" */ + propertyValue = HeapAlloc(GetProcessHeap(), 0, + (sz * 3 + 1) * sizeof(WCHAR)); + for (i = 0; i < sz; i++) + sprintfW(propertyValue + i * 3, binFmt, value[i]); + break; + default: + WARN("unimplemented for values of type %ld\n", regType); + goto end; + } + + TRACE("found registry value, setting %s to %s\n", + debugstr_w(sig->Property), debugstr_w(propertyValue)); + rc = MSI_SetPropertyW(package, sig->Property, propertyValue); + *appFound = TRUE; end: + HeapFree(GetProcessHeap(), 0, propertyValue); + HeapFree(GetProcessHeap(), 0, value); + RegCloseKey(key); + + HeapFree(GetProcessHeap(), 0, keyPath); + HeapFree(GetProcessHeap(), 0, valueName); + msiobj_release(&row->hdr); MSI_ViewClose(view); msiobj_release(&view->hdr); diff --git a/reactos/lib/msi/cond.tab.c b/reactos/lib/msi/cond.tab.c index 56af92f32e5..72fe698b431 100644 --- a/reactos/lib/msi/cond.tab.c +++ b/reactos/lib/msi/cond.tab.c @@ -1,2230 +1,2031 @@ -/* A Bison parser, made by GNU Bison 1.875c. */ - -/* Skeleton parser for Yacc-like parsing with Bison, - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* Written by Richard Stallman by simplifying the original so called - ``semantic'' parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 1 - -/* Using locations. */ -#define YYLSP_NEEDED 0 - -/* If NAME_PREFIX is specified substitute the variables and functions - names. */ -#define yyparse COND_parse -#define yylex COND_lex -#define yyerror COND_error -#define yylval COND_lval -#define yychar COND_char -#define yydebug COND_debug -#define yynerrs COND_nerrs - - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - COND_SPACE = 258, - COND_EOF = 259, - COND_OR = 260, - COND_AND = 261, - COND_NOT = 262, - COND_LT = 263, - COND_GT = 264, - COND_EQ = 265, - COND_LPAR = 266, - COND_RPAR = 267, - COND_TILDA = 268, - COND_PERCENT = 269, - COND_DOLLARS = 270, - COND_QUESTION = 271, - COND_AMPER = 272, - COND_EXCLAM = 273, - COND_IDENT = 274, - COND_NUMBER = 275, - COND_LITER = 276, - COND_ERROR = 277 - }; -#endif -#define COND_SPACE 258 -#define COND_EOF 259 -#define COND_OR 260 -#define COND_AND 261 -#define COND_NOT 262 -#define COND_LT 263 -#define COND_GT 264 -#define COND_EQ 265 -#define COND_LPAR 266 -#define COND_RPAR 267 -#define COND_TILDA 268 -#define COND_PERCENT 269 -#define COND_DOLLARS 270 -#define COND_QUESTION 271 -#define COND_AMPER 272 -#define COND_EXCLAM 273 -#define COND_IDENT 274 -#define COND_NUMBER 275 -#define COND_LITER 276 -#define COND_ERROR 277 - - - - -/* Copy the first part of user declarations. */ -#line 1 "./cond.y" - - -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2003 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -#include "msi.h" -#include "msiquery.h" -#include "msipriv.h" - -#define YYLEX_PARAM info -#define YYPARSE_PARAM info - -static int COND_error(char *str); - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -typedef struct tag_yyinput -{ - MSIPACKAGE *package; - LPCWSTR str; - INT n; - MSICONDITION result; -} COND_input; - -struct cond_str { - LPCWSTR data; - INT len; -}; - -static LPWSTR COND_GetString( struct cond_str *str ); -static LPWSTR COND_GetLiteral( struct cond_str *str ); -static int COND_lex( void *COND_lval, COND_input *info); - -typedef INT (*comp_int)(INT a, INT b); -typedef INT (*comp_str)(LPWSTR a, LPWSTR b, BOOL caseless); -typedef INT (*comp_m1)(LPWSTR a,int b); -typedef INT (*comp_m2)(int a,LPWSTR b); - -static INT comp_lt_i(INT a, INT b); -static INT comp_gt_i(INT a, INT b); -static INT comp_le_i(INT a, INT b); -static INT comp_ge_i(INT a, INT b); -static INT comp_eq_i(INT a, INT b); -static INT comp_ne_i(INT a, INT b); -static INT comp_bitand(INT a, INT b); -static INT comp_highcomp(INT a, INT b); -static INT comp_lowcomp(INT a, INT b); - -static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless); - -static INT comp_eq_m1(LPWSTR a, INT b); -static INT comp_ne_m1(LPWSTR a, INT b); -static INT comp_lt_m1(LPWSTR a, INT b); -static INT comp_gt_m1(LPWSTR a, INT b); -static INT comp_le_m1(LPWSTR a, INT b); -static INT comp_ge_m1(LPWSTR a, INT b); - -static INT comp_eq_m2(INT a, LPWSTR b); -static INT comp_ne_m2(INT a, LPWSTR b); -static INT comp_lt_m2(INT a, LPWSTR b); -static INT comp_gt_m2(INT a, LPWSTR b); -static INT comp_le_m2(INT a, LPWSTR b); -static INT comp_ge_m2(INT a, LPWSTR b); - - - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) -#line 106 "./cond.y" -typedef union YYSTYPE { - struct cond_str str; - LPWSTR string; - INT value; - comp_int fn_comp_int; - comp_str fn_comp_str; - comp_m1 fn_comp_m1; - comp_m2 fn_comp_m2; -} YYSTYPE; -/* Line 191 of yacc.c. */ -#line 241 "cond.tab.c" -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - - - -/* Copy the second part of user declarations. */ - - -/* Line 214 of yacc.c. */ -#line 253 "cond.tab.c" - -#if ! defined (yyoverflow) || YYERROR_VERBOSE - -# ifndef YYFREE -# define YYFREE free -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# endif - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# define YYSTACK_ALLOC alloca -# endif -# else -# if defined (alloca) || defined (_ALLOCA_H) -# define YYSTACK_ALLOC alloca -# else -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# else -# if defined (__STDC__) || defined (__cplusplus) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# endif -#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ - - -#if (! defined (yyoverflow) \ - && (! defined (__cplusplus) \ - || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - short yyss; - YYSTYPE yyvs; - }; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined (__GNUC__) && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - register YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (0) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) - -#endif - -#if defined (__STDC__) || defined (__cplusplus) - typedef signed char yysigned_char; -#else - typedef short yysigned_char; -#endif - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 30 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 146 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 23 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 17 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 65 -/* YYNRULES -- Number of states. */ -#define YYNSTATES 74 - -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 277 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ -static const unsigned char yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22 -}; - -#if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const unsigned char yyprhs[] = -{ - 0, 0, 3, 5, 7, 11, 13, 17, 19, 22, - 24, 26, 30, 34, 39, 43, 47, 51, 53, 56, - 58, 60, 63, 66, 69, 72, 75, 77, 80, 82, - 84, 87, 90, 93, 96, 99, 101, 104, 106, 108, - 111, 114, 117, 120, 123, 125, 128, 130, 132, 135, - 138, 141, 144, 147, 149, 151, 153, 155, 157, 160, - 163, 166, 169, 171, 174, 176 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const yysigned_char yyrhs[] = -{ - 24, 0, -1, 25, -1, 26, -1, 26, 5, 25, - -1, 27, -1, 26, 6, 27, -1, 28, -1, 7, - 28, -1, 33, -1, 34, -1, 33, 29, 33, -1, - 34, 30, 34, -1, 34, 13, 30, 34, -1, 34, - 31, 33, -1, 33, 32, 34, -1, 11, 25, 12, - -1, 10, -1, 8, 9, -1, 8, -1, 9, -1, - 8, 10, -1, 9, 10, -1, 9, 8, -1, 8, - 8, -1, 9, 9, -1, 10, -1, 8, 9, -1, - 8, -1, 9, -1, 8, 10, -1, 9, 10, -1, - 9, 8, -1, 8, 8, -1, 9, 9, -1, 10, - -1, 8, 9, -1, 8, -1, 9, -1, 8, 10, - -1, 9, 10, -1, 9, 8, -1, 8, 8, -1, - 9, 9, -1, 10, -1, 8, 9, -1, 8, -1, - 9, -1, 8, 10, -1, 9, 10, -1, 9, 8, - -1, 8, 8, -1, 9, 9, -1, 36, -1, 39, - -1, 37, -1, 35, -1, 21, -1, 15, 38, -1, - 16, 38, -1, 17, 38, -1, 18, 38, -1, 38, - -1, 14, 38, -1, 19, -1, 20, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const unsigned short yyrline[] = -{ - 0, 136, 136, 144, 148, 155, 159, 166, 170, 178, - 182, 186, 190, 194, 198, 202, 206, 214, 218, 222, - 226, 230, 234, 239, 243, 247, 255, 259, 263, 267, - 271, 275, 280, 284, 288, 296, 300, 304, 308, 312, - 316, 321, 325, 329, 337, 341, 345, 349, 353, 357, - 362, 366, 370, 377, 381, 388, 392, 399, 408, 417, - 426, 435, 447, 470, 484, 493 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE -/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "$end", "error", "$undefined", "COND_SPACE", "COND_EOF", "COND_OR", - "COND_AND", "COND_NOT", "COND_LT", "COND_GT", "COND_EQ", "COND_LPAR", - "COND_RPAR", "COND_TILDA", "COND_PERCENT", "COND_DOLLARS", - "COND_QUESTION", "COND_AMPER", "COND_EXCLAM", "COND_IDENT", - "COND_NUMBER", "COND_LITER", "COND_ERROR", "$accept", "condition", - "expression", "boolean_term", "boolean_factor", "term", "comp_op_i", - "comp_op_s", "comp_op_m1", "comp_op_m2", "value_i", "value_s", "literal", - "symbol_i", "symbol_s", "identifier", "integer", 0 -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ -static const unsigned short yytoknum[] = -{ - 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277 -}; -# endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const unsigned char yyr1[] = -{ - 0, 23, 24, 25, 25, 26, 26, 27, 27, 28, - 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 33, 33, 34, 34, 35, 36, 36, - 36, 36, 37, 37, 38, 39 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const unsigned char yyr2[] = -{ - 0, 2, 1, 1, 3, 1, 3, 1, 2, 1, - 1, 3, 3, 4, 3, 3, 3, 1, 2, 1, - 1, 2, 2, 2, 2, 2, 1, 2, 1, 1, - 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, - 2, 2, 2, 2, 1, 2, 1, 1, 2, 2, - 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, - 2, 2, 1, 2, 1, 1 -}; - -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ -static const unsigned char yydefact[] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 64, 65, - 57, 0, 2, 3, 5, 7, 9, 10, 56, 53, - 55, 62, 54, 8, 0, 63, 58, 59, 60, 61, - 1, 0, 0, 19, 20, 17, 0, 0, 37, 38, - 35, 0, 0, 0, 16, 4, 6, 24, 18, 21, - 23, 25, 22, 11, 15, 42, 36, 39, 41, 43, - 40, 28, 29, 26, 0, 12, 14, 33, 27, 30, - 32, 34, 31, 13 -}; - -/* YYDEFGOTO[NTERM-NUM]. */ -static const yysigned_char yydefgoto[] = -{ - -1, 11, 12, 13, 14, 15, 36, 42, 43, 37, - 16, 17, 18, 19, 20, 21, 22 -}; - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -37 -static const short yypact[] = -{ - -4, 51, -4, -11, -11, -11, -11, -11, -37, -37, - -37, 18, -37, -1, -37, -37, 49, 14, -37, -37, - -37, -37, -37, -37, 19, -37, -37, -37, -37, -37, - -37, -4, -4, 11, 25, 34, 111, 59, 28, 42, - 60, 130, 59, 111, -37, -37, -37, 63, 69, 72, - 73, 81, 82, -37, -37, 85, 91, 94, 95, 103, - 104, 133, 136, -37, 59, -37, -37, -37, -37, -37, - -37, -37, -37, -37 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const short yypgoto[] = -{ - -37, -37, -2, -37, -6, 39, -37, 0, -37, -37, - -34, -36, -37, -37, -37, 129, -37 -}; - -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -53 -static const yysigned_char yytable[] = -{ - 24, 54, 53, 1, 31, 32, 65, 2, 8, 66, - 3, 4, 5, 6, 7, 8, 9, 10, 30, 47, - 48, 49, 38, 39, 40, -46, 46, 41, 73, 45, - -46, 44, -46, 50, 51, 52, 55, 56, 57, -47, - 23, 64, -28, 0, -47, 0, -47, -28, -44, -28, - 58, 59, 60, -44, 0, -44, -29, 33, 34, 35, - 0, -29, 2, -29, 0, 3, 4, 5, 6, 7, - 8, 9, 10, 3, -26, 0, 0, -51, 8, -26, - 10, -26, -51, -45, -51, 0, -48, -50, -45, 0, - -45, -48, -50, -48, -50, -52, -49, 0, 0, -33, - -52, -49, -52, -49, -33, -27, -33, 0, -30, -32, - -27, 0, -27, -30, -32, -30, -32, -34, -31, 0, - 0, 0, -34, -31, -34, -31, 4, 5, 6, 7, - 0, 9, 25, 26, 27, 28, 29, 0, 61, 62, - 63, 67, 68, 69, 70, 71, 72 -}; - -static const yysigned_char yycheck[] = -{ - 2, 37, 36, 7, 5, 6, 42, 11, 19, 43, - 14, 15, 16, 17, 18, 19, 20, 21, 0, 8, - 9, 10, 8, 9, 10, 14, 32, 13, 64, 31, - 19, 12, 21, 8, 9, 10, 8, 9, 10, 14, - 1, 41, 14, -1, 19, -1, 21, 19, 14, 21, - 8, 9, 10, 19, -1, 21, 14, 8, 9, 10, - -1, 19, 11, 21, -1, 14, 15, 16, 17, 18, - 19, 20, 21, 14, 14, -1, -1, 14, 19, 19, - 21, 21, 19, 14, 21, -1, 14, 14, 19, -1, - 21, 19, 19, 21, 21, 14, 14, -1, -1, 14, - 19, 19, 21, 21, 19, 14, 21, -1, 14, 14, - 19, -1, 21, 19, 19, 21, 21, 14, 14, -1, - -1, -1, 19, 19, 21, 21, 15, 16, 17, 18, - -1, 20, 3, 4, 5, 6, 7, -1, 8, 9, - 10, 8, 9, 10, 8, 9, 10 -}; - -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const unsigned char yystos[] = -{ - 0, 7, 11, 14, 15, 16, 17, 18, 19, 20, - 21, 24, 25, 26, 27, 28, 33, 34, 35, 36, - 37, 38, 39, 28, 25, 38, 38, 38, 38, 38, - 0, 5, 6, 8, 9, 10, 29, 32, 8, 9, - 10, 13, 30, 31, 12, 25, 27, 8, 9, 10, - 8, 9, 10, 33, 34, 8, 9, 10, 8, 9, - 10, 8, 9, 10, 30, 34, 33, 8, 9, 10, - 8, 9, 10, 34 -}; - -#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) -# define YYSIZE_T __SIZE_TYPE__ -#endif -#if ! defined (YYSIZE_T) && defined (size_t) -# define YYSIZE_T size_t -#endif -#if ! defined (YYSIZE_T) -# if defined (__STDC__) || defined (__cplusplus) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -#endif -#if ! defined (YYSIZE_T) -# define YYSIZE_T unsigned int -#endif - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ - -#define YYFAIL goto yyerrlab - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ - YYPOPSTACK; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror ("syntax error: cannot back up");\ - YYERROR; \ - } \ -while (0) - -#define YYTERROR 1 -#define YYERRCODE 256 - -/* YYLLOC_DEFAULT -- Compute the default location (before the actions - are run). */ - -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - ((Current).first_line = (Rhs)[1].first_line, \ - (Current).first_column = (Rhs)[1].first_column, \ - (Current).last_line = (Rhs)[N].last_line, \ - (Current).last_column = (Rhs)[N].last_column) -#endif - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#ifdef YYLEX_PARAM -# define YYLEX yylex (&yylval, YYLEX_PARAM) -#else -# define YYLEX yylex (&yylval) -#endif - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) - -# define YYDSYMPRINT(Args) \ -do { \ - if (yydebug) \ - yysymprint Args; \ -} while (0) - -# define YYDSYMPRINTF(Title, Token, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yysymprint (stderr, \ - Token, Value); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (0) - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yy_stack_print (short *bottom, short *top) -#else -static void -yy_stack_print (bottom, top) - short *bottom; - short *top; -#endif -{ - YYFPRINTF (stderr, "Stack now"); - for (/* Nothing. */; bottom <= top; ++bottom) - YYFPRINTF (stderr, " %d", *bottom); - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (0) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yy_reduce_print (int yyrule) -#else -static void -yy_reduce_print (yyrule) - int yyrule; -#endif -{ - int yyi; - unsigned int yylno = yyrline[yyrule]; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", - yyrule - 1, yylno); - /* Print the symbols being reduced, and their result. */ - for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) - YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); - YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]); -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (Rule); \ -} while (0) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YYDSYMPRINT(Args) -# define YYDSYMPRINTF(Title, Token, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#if defined (YYMAXDEPTH) && YYMAXDEPTH == 0 -# undef YYMAXDEPTH -#endif - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined (__GLIBC__) && defined (_STRING_H) -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -static YYSIZE_T -# if defined (__STDC__) || defined (__cplusplus) -yystrlen (const char *yystr) -# else -yystrlen (yystr) - const char *yystr; -# endif -{ - register const char *yys = yystr; - - while (*yys++ != '\0') - continue; - - return yys - yystr - 1; -} -# endif -# endif - -# ifndef yystpcpy -# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -static char * -# if defined (__STDC__) || defined (__cplusplus) -yystpcpy (char *yydest, const char *yysrc) -# else -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -# endif -{ - register char *yyd = yydest; - register const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -#endif /* !YYERROR_VERBOSE */ - - - -#if YYDEBUG -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) -#else -static void -yysymprint (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - /* Pacify ``unused variable'' warnings. */ - (void) yyvaluep; - - if (yytype < YYNTOKENS) - { - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); -# ifdef YYPRINT - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# endif - } - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - - switch (yytype) - { - default: - break; - } - YYFPRINTF (yyoutput, ")"); -} - -#endif /* ! YYDEBUG */ -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yydestruct (int yytype, YYSTYPE *yyvaluep) -#else -static void -yydestruct (yytype, yyvaluep) - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - /* Pacify ``unused variable'' warnings. */ - (void) yyvaluep; - - switch (yytype) - { - - default: - break; - } -} - - -/* Prevent warnings from -Wmissing-prototypes. */ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -int yyparse (void *YYPARSE_PARAM); -# else -int yyparse (); -# endif -#else /* ! YYPARSE_PARAM */ -#if defined (__STDC__) || defined (__cplusplus) -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - - - - - - -/*----------. -| yyparse. | -`----------*/ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -int yyparse (void *YYPARSE_PARAM) -# else -int yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -# endif -#else /* ! YYPARSE_PARAM */ -#if defined (__STDC__) || defined (__cplusplus) -int -yyparse (void) -#else -int -yyparse () - -#endif -#endif -{ - /* The lookahead symbol. */ -int yychar; - -/* The semantic value of the lookahead symbol. */ -YYSTYPE yylval; - -/* Number of syntax errors so far. */ -int yynerrs; - - register int yystate; - register int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Lookahead token as an internal (translated) token number. */ - int yytoken = 0; - - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - short yyssa[YYINITDEPTH]; - short *yyss = yyssa; - register short *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - register YYSTYPE *yyvsp; - - - -#define YYPOPSTACK (yyvsp--, yyssp--) - - YYSIZE_T yystacksize = YYINITDEPTH; - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - - - /* When reducing, the number of symbols on the RHS of the reduced - rule. */ - int yylen; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss; - yyvsp = yyvs; - - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. so pushing a state here evens the stacks. - */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - short *yyss1 = yyss; - - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyoverflowlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyoverflowlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - short *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyoverflowlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); - -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - -/* Do appropriate processing given the current state. */ -/* Read a lookahead token if we need one and don't already have one. */ -/* yyresume: */ - - /* First try to decide what to do without reference to lookahead token. */ - - yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - if (yyn == YYFINAL) - YYACCEPT; - - /* Shift the lookahead token. */ - YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken])); - - /* Discard the token being shifted unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - *++yyvsp = yylval; - - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - yystate = yyn; - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 2: -#line 137 "./cond.y" - { - COND_input* cond = (COND_input*) info; - cond->result = yyvsp[0].value; - ;} - break; - - case 3: -#line 145 "./cond.y" - { - yyval.value = yyvsp[0].value; - ;} - break; - - case 4: -#line 149 "./cond.y" - { - yyval.value = yyvsp[-2].value || yyvsp[0].value; - ;} - break; - - case 5: -#line 156 "./cond.y" - { - yyval.value = yyvsp[0].value; - ;} - break; - - case 6: -#line 160 "./cond.y" - { - yyval.value = yyvsp[-2].value && yyvsp[0].value; - ;} - break; - - case 7: -#line 167 "./cond.y" - { - yyval.value = yyvsp[0].value; - ;} - break; - - case 8: -#line 171 "./cond.y" - { - yyval.value = ! yyvsp[0].value; - ;} - break; - - case 9: -#line 179 "./cond.y" - { - yyval.value = yyvsp[0].value; - ;} - break; - - case 10: -#line 183 "./cond.y" - { - yyval.value = yyvsp[0].string[0] ? MSICONDITION_TRUE : MSICONDITION_FALSE; - ;} - break; - - case 11: -#line 187 "./cond.y" - { - yyval.value = yyvsp[-1].fn_comp_int( yyvsp[-2].value, yyvsp[0].value ); - ;} - break; - - case 12: -#line 191 "./cond.y" - { - yyval.value = yyvsp[-1].fn_comp_str( yyvsp[-2].string, yyvsp[0].string, FALSE ); - ;} - break; - - case 13: -#line 195 "./cond.y" - { - yyval.value = yyvsp[-1].fn_comp_str( yyvsp[-3].string, yyvsp[0].string, TRUE ); - ;} - break; - - case 14: -#line 199 "./cond.y" - { - yyval.value = yyvsp[-1].fn_comp_m1( yyvsp[-2].string, yyvsp[0].value ); - ;} - break; - - case 15: -#line 203 "./cond.y" - { - yyval.value = yyvsp[-1].fn_comp_m2( yyvsp[-2].value, yyvsp[0].string ); - ;} - break; - - case 16: -#line 207 "./cond.y" - { - yyval.value = yyvsp[-1].value; - ;} - break; - - case 17: -#line 215 "./cond.y" - { - yyval.fn_comp_int = comp_eq_i; - ;} - break; - - case 18: -#line 219 "./cond.y" - { - yyval.fn_comp_int = comp_ne_i; - ;} - break; - - case 19: -#line 223 "./cond.y" - { - yyval.fn_comp_int = comp_lt_i; - ;} - break; - - case 20: -#line 227 "./cond.y" - { - yyval.fn_comp_int = comp_gt_i; - ;} - break; - - case 21: -#line 231 "./cond.y" - { - yyval.fn_comp_int = comp_le_i; - ;} - break; - - case 22: -#line 235 "./cond.y" - { - yyval.fn_comp_int = comp_ge_i; - ;} - break; - - case 23: -#line 240 "./cond.y" - { - yyval.fn_comp_int = comp_bitand; - ;} - break; - - case 24: -#line 244 "./cond.y" - { - yyval.fn_comp_int = comp_highcomp; - ;} - break; - - case 25: -#line 248 "./cond.y" - { - yyval.fn_comp_int = comp_lowcomp; - ;} - break; - - case 26: -#line 256 "./cond.y" - { - yyval.fn_comp_str = comp_eq_s; - ;} - break; - - case 27: -#line 260 "./cond.y" - { - yyval.fn_comp_str = comp_ne_s; - ;} - break; - - case 28: -#line 264 "./cond.y" - { - yyval.fn_comp_str = comp_lt_s; - ;} - break; - - case 29: -#line 268 "./cond.y" - { - yyval.fn_comp_str = comp_gt_s; - ;} - break; - - case 30: -#line 272 "./cond.y" - { - yyval.fn_comp_str = comp_le_s; - ;} - break; - - case 31: -#line 276 "./cond.y" - { - yyval.fn_comp_str = comp_ge_s; - ;} - break; - - case 32: -#line 281 "./cond.y" - { - yyval.fn_comp_str = comp_substring; - ;} - break; - - case 33: -#line 285 "./cond.y" - { - yyval.fn_comp_str = comp_start; - ;} - break; - - case 34: -#line 289 "./cond.y" - { - yyval.fn_comp_str = comp_end; - ;} - break; - - case 35: -#line 297 "./cond.y" - { - yyval.fn_comp_m1 = comp_eq_m1; - ;} - break; - - case 36: -#line 301 "./cond.y" - { - yyval.fn_comp_m1 = comp_ne_m1; - ;} - break; - - case 37: -#line 305 "./cond.y" - { - yyval.fn_comp_m1 = comp_lt_m1; - ;} - break; - - case 38: -#line 309 "./cond.y" - { - yyval.fn_comp_m1 = comp_gt_m1; - ;} - break; - - case 39: -#line 313 "./cond.y" - { - yyval.fn_comp_m1 = comp_le_m1; - ;} - break; - - case 40: -#line 317 "./cond.y" - { - yyval.fn_comp_m1 = comp_ge_m1; - ;} - break; - - case 41: -#line 322 "./cond.y" - { - yyval.fn_comp_m1 = 0; - ;} - break; - - case 42: -#line 326 "./cond.y" - { - yyval.fn_comp_m1 = 0; - ;} - break; - - case 43: -#line 330 "./cond.y" - { - yyval.fn_comp_m1 = 0; - ;} - break; - - case 44: -#line 338 "./cond.y" - { - yyval.fn_comp_m2 = comp_eq_m2; - ;} - break; - - case 45: -#line 342 "./cond.y" - { - yyval.fn_comp_m2 = comp_ne_m2; - ;} - break; - - case 46: -#line 346 "./cond.y" - { - yyval.fn_comp_m2 = comp_lt_m2; - ;} - break; - - case 47: -#line 350 "./cond.y" - { - yyval.fn_comp_m2 = comp_gt_m2; - ;} - break; - - case 48: -#line 354 "./cond.y" - { - yyval.fn_comp_m2 = comp_le_m2; - ;} - break; - - case 49: -#line 358 "./cond.y" - { - yyval.fn_comp_m2 = comp_ge_m2; - ;} - break; - - case 50: -#line 363 "./cond.y" - { - yyval.fn_comp_m2 = 0; - ;} - break; - - case 51: -#line 367 "./cond.y" - { - yyval.fn_comp_m2 = 0; - ;} - break; - - case 52: -#line 371 "./cond.y" - { - yyval.fn_comp_m2 = 0; - ;} - break; - - case 53: -#line 378 "./cond.y" - { - yyval.value = yyvsp[0].value; - ;} - break; - - case 54: -#line 382 "./cond.y" - { - yyval.value = yyvsp[0].value; - ;} - break; - - case 55: -#line 389 "./cond.y" - { - yyval.string = yyvsp[0].string; - ;} - break; - - case 56: -#line 393 "./cond.y" - { - yyval.string = yyvsp[0].string; - ;} - break; - - case 57: -#line 400 "./cond.y" - { - yyval.string = COND_GetLiteral(&yyvsp[0].str); - if( !yyval.string ) - YYABORT; - ;} - break; - - case 58: -#line 409 "./cond.y" - { - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetComponentStateW(cond->package, yyvsp[0].string, &install, &action ); - yyval.value = action; - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ;} - break; - - case 59: -#line 418 "./cond.y" - { - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetComponentStateW(cond->package, yyvsp[0].string, &install, &action ); - yyval.value = install; - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ;} - break; - - case 60: -#line 427 "./cond.y" - { - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetFeatureStateW(cond->package, yyvsp[0].string, &install, &action ); - yyval.value = action; - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ;} - break; - - case 61: -#line 436 "./cond.y" - { - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetFeatureStateW(cond->package, yyvsp[0].string, &install, &action ); - yyval.value = install; - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ;} - break; - - case 62: -#line 448 "./cond.y" - { - DWORD sz; - COND_input* cond = (COND_input*) info; - - sz = 0; - MSI_GetPropertyW(cond->package, yyvsp[0].string, NULL, &sz); - if (sz == 0) - { - yyval.string = HeapAlloc( GetProcessHeap(), 0 ,sizeof(WCHAR)); - yyval.string[0] = 0; - } - else - { - sz ++; - yyval.string = HeapAlloc( GetProcessHeap(), 0, sz*sizeof (WCHAR) ); - - /* Lookup the identifier */ - - MSI_GetPropertyW(cond->package,yyvsp[0].string,yyval.string,&sz); - } - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ;} - break; - - case 63: -#line 471 "./cond.y" - { - UINT len = GetEnvironmentVariableW( yyvsp[0].string, NULL, 0 ); - if( len++ ) - { - yyval.string = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) ); - if( yyval.string ) - GetEnvironmentVariableW( yyvsp[0].string, yyval.string, len ); - } - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ;} - break; - - case 64: -#line 485 "./cond.y" - { - yyval.string = COND_GetString(&yyvsp[0].str); - if( !yyval.string ) - YYABORT; - ;} - break; - - case 65: -#line 494 "./cond.y" - { - LPWSTR szNum = COND_GetString(&yyvsp[0].str); - if( !szNum ) - YYABORT; - yyval.value = atoiW( szNum ); - HeapFree( GetProcessHeap(), 0, szNum ); - ;} - break; - - - } - -/* Line 1000 of yacc.c. */ -#line 1726 "cond.tab.c" - - yyvsp -= yylen; - yyssp -= yylen; - - - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if YYERROR_VERBOSE - yyn = yypact[yystate]; - - if (YYPACT_NINF < yyn && yyn < YYLAST) - { - YYSIZE_T yysize = 0; - int yytype = YYTRANSLATE (yychar); - const char* yyprefix; - char *yymsg; - int yyx; - - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yycount = 0; - - yyprefix = ", expecting "; - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]); - yycount += 1; - if (yycount == 5) - { - yysize = 0; - break; - } - } - yysize += (sizeof ("syntax error, unexpected ") - + yystrlen (yytname[yytype])); - yymsg = (char *) YYSTACK_ALLOC (yysize); - if (yymsg != 0) - { - char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); - yyp = yystpcpy (yyp, yytname[yytype]); - - if (yycount < 5) - { - yyprefix = ", expecting "; - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - yyp = yystpcpy (yyp, yyprefix); - yyp = yystpcpy (yyp, yytname[yyx]); - yyprefix = " or "; - } - } - yyerror (yymsg); - YYSTACK_FREE (yymsg); - } - else - yyerror ("syntax error; also virtual memory exhausted"); - } - else -#endif /* YYERROR_VERBOSE */ - yyerror ("syntax error"); - } - - - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* If at end of input, pop the error token, - then the rest of the stack, then return failure. */ - if (yychar == YYEOF) - for (;;) - { - YYPOPSTACK; - if (yyssp == yyss) - YYABORT; - YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); - yydestruct (yystos[*yyssp], yyvsp); - } - } - else - { - YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc); - yydestruct (yytoken, &yylval); - yychar = YYEMPTY; - - } - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - -#ifdef __GNUC__ - /* Pacify GCC when the user code never invokes YYERROR and the label - yyerrorlab therefore never appears in user code. */ - if (0) - goto yyerrorlab; -#endif - - yyvsp -= yylen; - yyssp -= yylen; - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); - yydestruct (yystos[yystate], yyvsp); - YYPOPSTACK; - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - if (yyn == YYFINAL) - YYACCEPT; - - YYDPRINTF ((stderr, "Shifting error token, ")); - - *++yyvsp = yylval; - - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#ifndef yyoverflow -/*----------------------------------------------. -| yyoverflowlab -- parser overflow comes here. | -`----------------------------------------------*/ -yyoverflowlab: - yyerror ("parser stack overflow"); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif - return yyresult; -} - - -#line 503 "./cond.y" - - - -static int COND_IsAlpha( WCHAR x ) -{ - return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) || - ( ( x >= 'a' ) && ( x <= 'z' ) ) || - ( ( x == '_' ) ) ); -} - -static int COND_IsNumber( WCHAR x ) -{ - return( (( x >= '0' ) && ( x <= '9' )) || (x =='-') || (x =='.') ); -} - - -/* the mess of comparison functions */ - -static INT comp_lt_i(INT a, INT b) -{ return (a < b); } -static INT comp_gt_i(INT a, INT b) -{ return (a > b); } -static INT comp_le_i(INT a, INT b) -{ return (a <= b); } -static INT comp_ge_i(INT a, INT b) -{ return (a >= b); } -static INT comp_eq_i(INT a, INT b) -{ return (a == b); } -static INT comp_ne_i(INT a, INT b) -{ return (a != b); } -static INT comp_bitand(INT a, INT b) -{ return a & b;} -static INT comp_highcomp(INT a, INT b) -{ return HIWORD(a)==b; } -static INT comp_lowcomp(INT a, INT b) -{ return LOWORD(a)==b; } - -static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return !strcmpiW(a,b); else return !strcmpW(a,b);} -static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b); else return strcmpW(a,b);} -static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)<0; else return strcmpW(a,b)<0;} -static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)>0; else return strcmpW(a,b)>0;} -static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)<=0; else return strcmpW(a,b)<=0;} -static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)>=0; else return strcmpW(a,b)>=0;} -static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless) -/* ERROR NOT WORKING REWRITE */ -{ if (casless) return strstrW(a,b)!=NULL; else return strstrW(a,b)!=NULL;} -static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strncmpiW(a,b,strlenW(b))==0; - else return strncmpW(a,b,strlenW(b))==0;} -static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless) -{ - int i = strlenW(a); - int j = strlenW(b); - if (j>i) - return 0; - if (casless) return (!strcmpiW(&a[i-j-1],b)); - else return (!strcmpW(&a[i-j-1],b)); -} - - -static INT comp_eq_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)==b; else return 0;} -static INT comp_ne_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)!=b; else return 1;} -static INT comp_lt_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)b; else return 0;} -static INT comp_le_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)<=b; else return 0;} -static INT comp_ge_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)>=b; else return 0;} - -static INT comp_eq_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a == atoiW(b); else return 0;} -static INT comp_ne_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a != atoiW(b); else return 1;} -static INT comp_lt_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a < atoiW(b); else return 0;} -static INT comp_gt_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a > atoiW(b); else return 0;} -static INT comp_le_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a <= atoiW(b); else return 0;} -static INT comp_ge_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a >= atoiW(b); else return 0;} - - - -static int COND_IsIdent( WCHAR x ) -{ - return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) - || ( x == '#' ) || (x == '.') ); -} - -static int COND_GetOne( struct cond_str *str, COND_input *cond ) -{ - static const WCHAR szNot[] = {'N','O','T',0}; - static const WCHAR szAnd[] = {'A','N','D',0}; - static const WCHAR szOr[] = {'O','R',0}; - WCHAR ch; - int rc, len = 1; - - str->data = &cond->str[cond->n]; - - ch = str->data[0]; - switch( ch ) - { - case 0: return 0; - case '(': rc = COND_LPAR; break; - case ')': rc = COND_RPAR; break; - case '&': rc = COND_AMPER; break; - case '!': rc = COND_EXCLAM; break; - case '$': rc = COND_DOLLARS; break; - case '?': rc = COND_QUESTION; break; - case '%': rc = COND_PERCENT; break; - case ' ': rc = COND_SPACE; break; - case '=': rc = COND_EQ; break; - case '~': rc = COND_TILDA; break; - case '<': rc = COND_LT; break; - case '>': rc = COND_GT; break; - case '"': - { - const WCHAR *ch2 = str->data + 1; - - - while ( *ch2 && *ch2 != '"' ) - ++ch2; - if (*ch2 == '"') - { - len = ch2 - str->data + 1; - rc = COND_LITER; - break; - } - } - ERR("Unterminated string\n"); - rc = COND_ERROR; - break; - default: - if( COND_IsAlpha( ch ) ) - { - while( COND_IsIdent( str->data[len] ) ) - len++; - rc = COND_IDENT; - break; - } - - if( COND_IsNumber( ch ) ) - { - while( COND_IsNumber( str->data[len] ) ) - len++; - rc = COND_NUMBER; - break; - } - - ERR("Got unknown character %c(%x)\n",ch,ch); - rc = COND_ERROR; - break; - } - - /* keyword identifiers */ - if( rc == COND_IDENT ) - { - if( (len==3) && (strncmpiW(str->data,szNot,len)==0) ) - rc = COND_NOT; - else if( (len==3) && (strncmpiW(str->data,szAnd,len)==0) ) - rc = COND_AND; - else if( (len==2) && (strncmpiW(str->data,szOr,len)==0) ) - rc = COND_OR; - } - - cond->n += len; - str->len = len; - - return rc; -} - -static int COND_lex( void *COND_lval, COND_input *cond ) -{ - int rc; - struct cond_str *str = COND_lval; - - do { - rc = COND_GetOne( str, cond ); - } while (rc == COND_SPACE); - - return rc; -} - -static LPWSTR COND_GetString( struct cond_str *str ) -{ - LPWSTR ret; - - ret = HeapAlloc( GetProcessHeap(), 0, (str->len+1) * sizeof (WCHAR) ); - if( ret ) - { - memcpy( ret, str->data, str->len * sizeof(WCHAR)); - ret[str->len]=0; - } - TRACE("Got identifier %s\n",debugstr_w(ret)); - return ret; -} - -static LPWSTR COND_GetLiteral( struct cond_str *str ) -{ - LPWSTR ret; - - ret = HeapAlloc( GetProcessHeap(), 0, (str->len-1) * sizeof (WCHAR) ); - if( ret ) - { - memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) ); - ret[str->len - 2]=0; - } - TRACE("Got literal %s\n",debugstr_w(ret)); - return ret; -} - -static int COND_error(char *str) -{ - return 0; -} - -MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) -{ - COND_input cond; - MSICONDITION r; - - cond.package = package; - cond.str = szCondition; - cond.n = 0; - cond.result = -1; - - TRACE("Evaluating %s\n",debugstr_w(szCondition)); - - if( szCondition && !COND_parse( &cond ) ) - r = cond.result; - else - r = MSICONDITION_ERROR; - - TRACE("Evaluates to %i\n",r); - return r; -} - -MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition ) -{ - MSIPACKAGE *package; - UINT ret; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); - if( !package) - return ERROR_INVALID_HANDLE; - ret = MSI_EvaluateConditionW( package, szCondition ); - msiobj_release( &package->hdr ); - return ret; -} - -MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition ) -{ - LPWSTR szwCond = NULL; - MSICONDITION r; - - if( szCondition ) - { - UINT len = MultiByteToWideChar( CP_ACP, 0, szCondition, -1, NULL, 0 ); - szwCond = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, szCondition, -1, szwCond, len ); - } - - r = MsiEvaluateConditionW( hInstall, szwCond ); - - HeapFree( GetProcessHeap(), 0, szwCond ); - - return r; -} - +/* A Bison parser, made from ./cond.y + by GNU bison 1.35. */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define yyparse COND_parse +#define yylex COND_lex +#define yyerror COND_error +#define yylval COND_lval +#define yychar COND_char +#define yydebug COND_debug +#define yynerrs COND_nerrs +# define COND_SPACE 257 +# define COND_EOF 258 +# define COND_OR 259 +# define COND_AND 260 +# define COND_NOT 261 +# define COND_LT 262 +# define COND_GT 263 +# define COND_EQ 264 +# define COND_LPAR 265 +# define COND_RPAR 266 +# define COND_TILDA 267 +# define COND_PERCENT 268 +# define COND_DOLLARS 269 +# define COND_QUESTION 270 +# define COND_AMPER 271 +# define COND_EXCLAM 272 +# define COND_IDENT 273 +# define COND_NUMBER 274 +# define COND_LITER 275 +# define COND_ERROR 276 + +#line 1 "./cond.y" + + +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2003 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#include "msi.h" +#include "msiquery.h" +#include "msipriv.h" + +#define YYLEX_PARAM info +#define YYPARSE_PARAM info + +static int COND_error(char *str); + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +typedef struct tag_yyinput +{ + MSIPACKAGE *package; + LPCWSTR str; + INT n; + MSICONDITION result; +} COND_input; + +struct cond_str { + LPCWSTR data; + INT len; +}; + +static LPWSTR COND_GetString( struct cond_str *str ); +static LPWSTR COND_GetLiteral( struct cond_str *str ); +static int COND_lex( void *COND_lval, COND_input *info); + +typedef INT (*comp_int)(INT a, INT b); +typedef INT (*comp_str)(LPWSTR a, LPWSTR b, BOOL caseless); +typedef INT (*comp_m1)(LPWSTR a,int b); +typedef INT (*comp_m2)(int a,LPWSTR b); + +static INT comp_lt_i(INT a, INT b); +static INT comp_gt_i(INT a, INT b); +static INT comp_le_i(INT a, INT b); +static INT comp_ge_i(INT a, INT b); +static INT comp_eq_i(INT a, INT b); +static INT comp_ne_i(INT a, INT b); +static INT comp_bitand(INT a, INT b); +static INT comp_highcomp(INT a, INT b); +static INT comp_lowcomp(INT a, INT b); + +static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless); + +static INT comp_eq_m1(LPWSTR a, INT b); +static INT comp_ne_m1(LPWSTR a, INT b); +static INT comp_lt_m1(LPWSTR a, INT b); +static INT comp_gt_m1(LPWSTR a, INT b); +static INT comp_le_m1(LPWSTR a, INT b); +static INT comp_ge_m1(LPWSTR a, INT b); + +static INT comp_eq_m2(INT a, LPWSTR b); +static INT comp_ne_m2(INT a, LPWSTR b); +static INT comp_lt_m2(INT a, LPWSTR b); +static INT comp_gt_m2(INT a, LPWSTR b); +static INT comp_le_m2(INT a, LPWSTR b); +static INT comp_ge_m2(INT a, LPWSTR b); + + +#line 105 "./cond.y" +#ifndef YYSTYPE +typedef union +{ + struct cond_str str; + LPWSTR string; + INT value; + comp_int fn_comp_int; + comp_str fn_comp_str; + comp_m1 fn_comp_m1; + comp_m2 fn_comp_m2; +} yystype; +# define YYSTYPE yystype +# define YYSTYPE_IS_TRIVIAL 1 +#endif +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + + + +#define YYFINAL 74 +#define YYFLAG -32768 +#define YYNTBASE 23 + +/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ +#define YYTRANSLATE(x) ((unsigned)(x) <= 276 ? yytranslate[x] : 39) + +/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ +static const char yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22 +}; + +#if YYDEBUG +static const short yyprhs[] = +{ + 0, 0, 2, 4, 8, 10, 14, 16, 19, 21, + 23, 27, 31, 36, 40, 44, 48, 50, 53, 55, + 57, 60, 63, 66, 69, 72, 74, 77, 79, 81, + 84, 87, 90, 93, 96, 98, 101, 103, 105, 108, + 111, 114, 117, 120, 122, 125, 127, 129, 132, 135, + 138, 141, 144, 146, 148, 150, 152, 154, 157, 160, + 163, 166, 168, 171, 173 +}; +static const short yyrhs[] = +{ + 24, 0, 25, 0, 25, 5, 24, 0, 26, 0, + 25, 6, 26, 0, 27, 0, 7, 27, 0, 32, + 0, 33, 0, 32, 28, 32, 0, 33, 29, 33, + 0, 33, 13, 29, 33, 0, 33, 30, 32, 0, + 32, 31, 33, 0, 11, 24, 12, 0, 10, 0, + 8, 9, 0, 8, 0, 9, 0, 8, 10, 0, + 9, 10, 0, 9, 8, 0, 8, 8, 0, 9, + 9, 0, 10, 0, 8, 9, 0, 8, 0, 9, + 0, 8, 10, 0, 9, 10, 0, 9, 8, 0, + 8, 8, 0, 9, 9, 0, 10, 0, 8, 9, + 0, 8, 0, 9, 0, 8, 10, 0, 9, 10, + 0, 9, 8, 0, 8, 8, 0, 9, 9, 0, + 10, 0, 8, 9, 0, 8, 0, 9, 0, 8, + 10, 0, 9, 10, 0, 9, 8, 0, 8, 8, + 0, 9, 9, 0, 35, 0, 38, 0, 36, 0, + 34, 0, 21, 0, 15, 37, 0, 16, 37, 0, + 17, 37, 0, 18, 37, 0, 37, 0, 14, 37, + 0, 19, 0, 20, 0 +}; + +#endif + +#if YYDEBUG +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const short yyrline[] = +{ + 0, 135, 143, 148, 154, 159, 165, 170, 177, 182, + 186, 190, 194, 198, 202, 206, 212, 218, 222, 226, + 230, 234, 239, 243, 247, 253, 259, 263, 267, 271, + 275, 280, 284, 288, 294, 300, 304, 308, 312, 316, + 321, 325, 329, 335, 341, 345, 349, 353, 357, 362, + 366, 370, 376, 381, 387, 392, 398, 407, 417, 426, + 435, 446, 470, 483, 492 +}; +#endif + + +#if (YYDEBUG) || defined YYERROR_VERBOSE + +/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ +static const char *const yytname[] = +{ + "$", "error", "$undefined.", "COND_SPACE", "COND_EOF", "COND_OR", + "COND_AND", "COND_NOT", "COND_LT", "COND_GT", "COND_EQ", "COND_LPAR", + "COND_RPAR", "COND_TILDA", "COND_PERCENT", "COND_DOLLARS", + "COND_QUESTION", "COND_AMPER", "COND_EXCLAM", "COND_IDENT", + "COND_NUMBER", "COND_LITER", "COND_ERROR", "condition", "expression", + "boolean_term", "boolean_factor", "term", "comp_op_i", "comp_op_s", + "comp_op_m1", "comp_op_m2", "value_i", "value_s", "literal", "symbol_i", + "symbol_s", "identifier", "integer", 0 +}; +#endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const short yyr1[] = +{ + 0, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 32, 32, 33, 33, 34, 35, 35, 35, + 35, 36, 36, 37, 38 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const short yyr2[] = +{ + 0, 1, 1, 3, 1, 3, 1, 2, 1, 1, + 3, 3, 4, 3, 3, 3, 1, 2, 1, 1, + 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, + 2, 2, 2, 2, 1, 2, 1, 1, 2, 2, + 2, 2, 2, 1, 2, 1, 1, 2, 2, 2, + 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, + 2, 1, 2, 1, 1 +}; + +/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE + doesn't specify something else to do. Zero means the default is an + error. */ +static const short yydefact[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, + 56, 1, 2, 4, 6, 8, 9, 55, 52, 54, + 61, 53, 7, 0, 62, 57, 58, 59, 60, 0, + 0, 18, 19, 16, 0, 0, 36, 37, 34, 0, + 0, 0, 15, 3, 5, 23, 17, 20, 22, 24, + 21, 10, 14, 41, 35, 38, 40, 42, 39, 27, + 28, 25, 0, 11, 13, 32, 26, 29, 31, 33, + 30, 12, 0, 0, 0 +}; + +static const short yydefgoto[] = +{ + 72, 11, 12, 13, 14, 34, 40, 41, 35, 15, + 16, 17, 18, 19, 20, 21 +}; + +static const short yypact[] = +{ + -5, 50, -5, -12, -12, -12, -12, -12,-32768,-32768, + -32768,-32768, -2,-32768,-32768, 48, 123,-32768,-32768,-32768, + -32768,-32768,-32768, -4,-32768,-32768,-32768,-32768,-32768, -5, + -5, 10, 24, 33, 110, 58, 27, 41, 59, 135, + 58, 110,-32768,-32768,-32768, 62, 68, 71, 72, 80, + 81,-32768,-32768, 84, 90, 93, 94, 102, 103, 138, + 141,-32768, 58,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768, 17, 21,-32768 +}; + +static const short yypgoto[] = +{ + -32768, -1,-32768, -8, 25,-32768, -14,-32768,-32768, -11, + -35,-32768,-32768,-32768, 134,-32768 +}; + + +#define YYLAST 151 + + +static const short yytable[] = +{ + 52, 23, 1, 29, 30, 63, 2, 8, 42, 3, + 4, 5, 6, 7, 8, 9, 10, 73, 45, 46, + 47, 74, 44, 51, -45, 62, 22, 71, 43, -45, + 64, -45, 48, 49, 50, 53, 54, 55, -46, 0, + 0, -27, 0, -46, 0, -46, -27, -43, -27, 56, + 57, 58, -43, 0, -43, -28, 31, 32, 33, 0, + -28, 2, -28, 0, 3, 4, 5, 6, 7, 8, + 9, 10, 3, -25, 0, 0, -50, 8, -25, 10, + -25, -50, -44, -50, 0, -47, -49, -44, 0, -44, + -47, -49, -47, -49, -51, -48, 0, 0, -32, -51, + -48, -51, -48, -32, -26, -32, 0, -29, -31, -26, + 0, -26, -29, -31, -29, -31, -33, -30, 0, 0, + 0, -33, -30, -33, -30, 4, 5, 6, 7, 0, + 9, 36, 37, 38, 0, 0, 39, 24, 25, 26, + 27, 28, 0, 59, 60, 61, 65, 66, 67, 68, + 69, 70 +}; + +static const short yycheck[] = +{ + 35, 2, 7, 5, 6, 40, 11, 19, 12, 14, + 15, 16, 17, 18, 19, 20, 21, 0, 8, 9, + 10, 0, 30, 34, 14, 39, 1, 62, 29, 19, + 41, 21, 8, 9, 10, 8, 9, 10, 14, -1, + -1, 14, -1, 19, -1, 21, 19, 14, 21, 8, + 9, 10, 19, -1, 21, 14, 8, 9, 10, -1, + 19, 11, 21, -1, 14, 15, 16, 17, 18, 19, + 20, 21, 14, 14, -1, -1, 14, 19, 19, 21, + 21, 19, 14, 21, -1, 14, 14, 19, -1, 21, + 19, 19, 21, 21, 14, 14, -1, -1, 14, 19, + 19, 21, 21, 19, 14, 21, -1, 14, 14, 19, + -1, 21, 19, 19, 21, 21, 14, 14, -1, -1, + -1, 19, 19, 21, 21, 15, 16, 17, 18, -1, + 20, 8, 9, 10, -1, -1, 13, 3, 4, 5, + 6, 7, -1, 8, 9, 10, 8, 9, 10, 8, + 9, 10 +}; +#define YYPURE 1 + +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/share/bison/bison.simple" + +/* Skeleton output parser for bison, + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser when + the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC malloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short yyss; + YYSTYPE yyvs; +# if YYLSP_NEEDED + YYLTYPE yyls; +# endif +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# if YYLSP_NEEDED +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAX) +# else +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAX) +# endif + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up"); \ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). + + When YYLLOC_DEFAULT is run, CURRENT is set the location of the + first token. By default, to implement support for ranges, extend + its range to the last symbol. */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#if YYPURE +# if YYLSP_NEEDED +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval, &yylloc) +# endif +# else /* !YYLSP_NEEDED */ +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval) +# endif +# endif /* !YYLSP_NEEDED */ +#else /* !YYPURE */ +# define YYLEX yylex () +#endif /* !YYPURE */ + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +#endif /* !YYDEBUG */ + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + +#ifdef YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif +#endif + +#line 315 "/usr/share/bison/bison.simple" + + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +# define YYPARSE_PARAM_DECL +# else +# define YYPARSE_PARAM_ARG YYPARSE_PARAM +# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +# endif +#else /* !YYPARSE_PARAM */ +# define YYPARSE_PARAM_ARG +# define YYPARSE_PARAM_DECL +#endif /* !YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +# ifdef YYPARSE_PARAM +int yyparse (void *); +# else +int yyparse (void); +# endif +#endif + +/* YY_DECL_VARIABLES -- depending whether we use a pure parser, + variables are global, or local to YYPARSE. */ + +#define YY_DECL_NON_LSP_VARIABLES \ +/* The lookahead symbol. */ \ +int yychar; \ + \ +/* The semantic value of the lookahead symbol. */ \ +YYSTYPE yylval; \ + \ +/* Number of parse errors so far. */ \ +int yynerrs; + +#if YYLSP_NEEDED +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES \ + \ +/* Location data for the lookahead symbol. */ \ +YYLTYPE yylloc; +#else +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES +#endif + + +/* If nonreentrant, generate the variables here. */ + +#if !YYPURE +YY_DECL_VARIABLES +#endif /* !YYPURE */ + +int +yyparse (YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + /* If reentrant, generate the variables here. */ +#if YYPURE + YY_DECL_VARIABLES +#endif /* !YYPURE */ + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int yychar1 = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short yyssa[YYINITDEPTH]; + short *yyss = yyssa; + register short *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + +#if YYLSP_NEEDED + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; +#endif + +#if YYLSP_NEEDED +# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +# define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + YYSIZE_T yystacksize = YYINITDEPTH; + + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; +#if YYLSP_NEEDED + YYLTYPE yyloc; +#endif + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; +#if YYLSP_NEEDED + yylsp = yyls; +#endif + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. */ +# if YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + yyls = yyls1; +# else + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); +# endif + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + goto yyoverflowlab; + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + + { + short *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); +# if YYLSP_NEEDED + YYSTACK_RELOCATE (yyls); +# endif +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; +#if YYLSP_NEEDED + yylsp = yyls + yysize - 1; +#endif + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yychar1 = YYTRANSLATE (yychar); + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables + which are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + YYFPRINTF (stderr, "Next token is %d (%s", + yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise + meaning of a token, for further debugging info. */ +# ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +# endif + YYFPRINTF (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %d (%s), ", + yychar, yytname[yychar1])); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to the semantic value of + the lookahead token. This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + +#if YYLSP_NEEDED + /* Similarly for the default location. Let the user run additional + commands if for instance locations are ranges. */ + yyloc = yylsp[1-yylen]; + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); +#endif + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables which + are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + int yyi; + + YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) + YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); + YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + switch (yyn) { + +case 1: +#line 137 "./cond.y" +{ + COND_input* cond = (COND_input*) info; + cond->result = yyvsp[0].value; + ; + break;} +case 2: +#line 145 "./cond.y" +{ + yyval.value = yyvsp[0].value; + ; + break;} +case 3: +#line 149 "./cond.y" +{ + yyval.value = yyvsp[-2].value || yyvsp[0].value; + ; + break;} +case 4: +#line 156 "./cond.y" +{ + yyval.value = yyvsp[0].value; + ; + break;} +case 5: +#line 160 "./cond.y" +{ + yyval.value = yyvsp[-2].value && yyvsp[0].value; + ; + break;} +case 6: +#line 167 "./cond.y" +{ + yyval.value = yyvsp[0].value; + ; + break;} +case 7: +#line 171 "./cond.y" +{ + yyval.value = ! yyvsp[0].value; + ; + break;} +case 8: +#line 179 "./cond.y" +{ + yyval.value = yyvsp[0].value; + ; + break;} +case 9: +#line 183 "./cond.y" +{ + yyval.value = (yyvsp[0].string && yyvsp[0].string[0]) ? MSICONDITION_TRUE : MSICONDITION_FALSE; + ; + break;} +case 10: +#line 187 "./cond.y" +{ + yyval.value = yyvsp[-1].fn_comp_int( yyvsp[-2].value, yyvsp[0].value ); + ; + break;} +case 11: +#line 191 "./cond.y" +{ + yyval.value = yyvsp[-1].fn_comp_str( yyvsp[-2].string, yyvsp[0].string, FALSE ); + ; + break;} +case 12: +#line 195 "./cond.y" +{ + yyval.value = yyvsp[-1].fn_comp_str( yyvsp[-3].string, yyvsp[0].string, TRUE ); + ; + break;} +case 13: +#line 199 "./cond.y" +{ + yyval.value = yyvsp[-1].fn_comp_m1( yyvsp[-2].string, yyvsp[0].value ); + ; + break;} +case 14: +#line 203 "./cond.y" +{ + yyval.value = yyvsp[-1].fn_comp_m2( yyvsp[-2].value, yyvsp[0].string ); + ; + break;} +case 15: +#line 207 "./cond.y" +{ + yyval.value = yyvsp[-1].value; + ; + break;} +case 16: +#line 215 "./cond.y" +{ + yyval.fn_comp_int = comp_eq_i; + ; + break;} +case 17: +#line 219 "./cond.y" +{ + yyval.fn_comp_int = comp_ne_i; + ; + break;} +case 18: +#line 223 "./cond.y" +{ + yyval.fn_comp_int = comp_lt_i; + ; + break;} +case 19: +#line 227 "./cond.y" +{ + yyval.fn_comp_int = comp_gt_i; + ; + break;} +case 20: +#line 231 "./cond.y" +{ + yyval.fn_comp_int = comp_le_i; + ; + break;} +case 21: +#line 235 "./cond.y" +{ + yyval.fn_comp_int = comp_ge_i; + ; + break;} +case 22: +#line 240 "./cond.y" +{ + yyval.fn_comp_int = comp_bitand; + ; + break;} +case 23: +#line 244 "./cond.y" +{ + yyval.fn_comp_int = comp_highcomp; + ; + break;} +case 24: +#line 248 "./cond.y" +{ + yyval.fn_comp_int = comp_lowcomp; + ; + break;} +case 25: +#line 256 "./cond.y" +{ + yyval.fn_comp_str = comp_eq_s; + ; + break;} +case 26: +#line 260 "./cond.y" +{ + yyval.fn_comp_str = comp_ne_s; + ; + break;} +case 27: +#line 264 "./cond.y" +{ + yyval.fn_comp_str = comp_lt_s; + ; + break;} +case 28: +#line 268 "./cond.y" +{ + yyval.fn_comp_str = comp_gt_s; + ; + break;} +case 29: +#line 272 "./cond.y" +{ + yyval.fn_comp_str = comp_le_s; + ; + break;} +case 30: +#line 276 "./cond.y" +{ + yyval.fn_comp_str = comp_ge_s; + ; + break;} +case 31: +#line 281 "./cond.y" +{ + yyval.fn_comp_str = comp_substring; + ; + break;} +case 32: +#line 285 "./cond.y" +{ + yyval.fn_comp_str = comp_start; + ; + break;} +case 33: +#line 289 "./cond.y" +{ + yyval.fn_comp_str = comp_end; + ; + break;} +case 34: +#line 297 "./cond.y" +{ + yyval.fn_comp_m1 = comp_eq_m1; + ; + break;} +case 35: +#line 301 "./cond.y" +{ + yyval.fn_comp_m1 = comp_ne_m1; + ; + break;} +case 36: +#line 305 "./cond.y" +{ + yyval.fn_comp_m1 = comp_lt_m1; + ; + break;} +case 37: +#line 309 "./cond.y" +{ + yyval.fn_comp_m1 = comp_gt_m1; + ; + break;} +case 38: +#line 313 "./cond.y" +{ + yyval.fn_comp_m1 = comp_le_m1; + ; + break;} +case 39: +#line 317 "./cond.y" +{ + yyval.fn_comp_m1 = comp_ge_m1; + ; + break;} +case 40: +#line 322 "./cond.y" +{ + yyval.fn_comp_m1 = 0; + ; + break;} +case 41: +#line 326 "./cond.y" +{ + yyval.fn_comp_m1 = 0; + ; + break;} +case 42: +#line 330 "./cond.y" +{ + yyval.fn_comp_m1 = 0; + ; + break;} +case 43: +#line 338 "./cond.y" +{ + yyval.fn_comp_m2 = comp_eq_m2; + ; + break;} +case 44: +#line 342 "./cond.y" +{ + yyval.fn_comp_m2 = comp_ne_m2; + ; + break;} +case 45: +#line 346 "./cond.y" +{ + yyval.fn_comp_m2 = comp_lt_m2; + ; + break;} +case 46: +#line 350 "./cond.y" +{ + yyval.fn_comp_m2 = comp_gt_m2; + ; + break;} +case 47: +#line 354 "./cond.y" +{ + yyval.fn_comp_m2 = comp_le_m2; + ; + break;} +case 48: +#line 358 "./cond.y" +{ + yyval.fn_comp_m2 = comp_ge_m2; + ; + break;} +case 49: +#line 363 "./cond.y" +{ + yyval.fn_comp_m2 = 0; + ; + break;} +case 50: +#line 367 "./cond.y" +{ + yyval.fn_comp_m2 = 0; + ; + break;} +case 51: +#line 371 "./cond.y" +{ + yyval.fn_comp_m2 = 0; + ; + break;} +case 52: +#line 378 "./cond.y" +{ + yyval.value = yyvsp[0].value; + ; + break;} +case 53: +#line 382 "./cond.y" +{ + yyval.value = yyvsp[0].value; + ; + break;} +case 54: +#line 389 "./cond.y" +{ + yyval.string = yyvsp[0].string; + ; + break;} +case 55: +#line 393 "./cond.y" +{ + yyval.string = yyvsp[0].string; + ; + break;} +case 56: +#line 400 "./cond.y" +{ + yyval.string = COND_GetLiteral(&yyvsp[0].str); + if( !yyval.string ) + YYABORT; + ; + break;} +case 57: +#line 409 "./cond.y" +{ + COND_input* cond = (COND_input*) info; + INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; + + MSI_GetComponentStateW(cond->package, yyvsp[0].string, &install, &action ); + yyval.value = action; + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ; + break;} +case 58: +#line 418 "./cond.y" +{ + COND_input* cond = (COND_input*) info; + INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; + + MSI_GetComponentStateW(cond->package, yyvsp[0].string, &install, &action ); + yyval.value = install; + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ; + break;} +case 59: +#line 427 "./cond.y" +{ + COND_input* cond = (COND_input*) info; + INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; + + MSI_GetFeatureStateW(cond->package, yyvsp[0].string, &install, &action ); + yyval.value = action; + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ; + break;} +case 60: +#line 436 "./cond.y" +{ + COND_input* cond = (COND_input*) info; + INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; + + MSI_GetFeatureStateW(cond->package, yyvsp[0].string, &install, &action ); + yyval.value = install; + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ; + break;} +case 61: +#line 448 "./cond.y" +{ + DWORD sz; + COND_input* cond = (COND_input*) info; + + sz = 0; + MSI_GetPropertyW(cond->package, yyvsp[0].string, NULL, &sz); + if (sz == 0) + { + yyval.string = HeapAlloc( GetProcessHeap(), 0 ,sizeof(WCHAR)); + yyval.string[0] = 0; + } + else + { + sz ++; + yyval.string = HeapAlloc( GetProcessHeap(), 0, sz*sizeof (WCHAR) ); + + /* Lookup the identifier */ + + MSI_GetPropertyW(cond->package,yyvsp[0].string,yyval.string,&sz); + } + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ; + break;} +case 62: +#line 471 "./cond.y" +{ + UINT len = GetEnvironmentVariableW( yyvsp[0].string, NULL, 0 ); + if( len++ ) + { + yyval.string = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) ); + if( yyval.string ) + GetEnvironmentVariableW( yyvsp[0].string, yyval.string, len ); + } + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ; + break;} +case 63: +#line 485 "./cond.y" +{ + yyval.string = COND_GetString(&yyvsp[0].str); + if( !yyval.string ) + YYABORT; + ; + break;} +case 64: +#line 494 "./cond.y" +{ + LPWSTR szNum = COND_GetString(&yyvsp[0].str); + if( !szNum ) + YYABORT; + yyval.value = atoiW( szNum ); + HeapFree( GetProcessHeap(), 0, szNum ); + ; + break;} +} + +#line 705 "/usr/share/bison/bison.simple" + + + yyvsp -= yylen; + yyssp -= yylen; +#if YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; +#if YYLSP_NEEDED + *++yylsp = yyloc; +#endif + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + char *yymsg; + int yyx, yycount; + + yycount = 0; + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) + if (yycheck[yyx + yyn] == yyx) + yysize += yystrlen (yytname[yyx]) + 15, yycount++; + yysize += yystrlen ("parse error, unexpected ") + 1; + yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "parse error, unexpected "); + yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); + + if (yycount < 5) + { + yycount = 0; + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); + yyx++) + if (yycheck[yyx + yyn] == yyx) + { + const char *yyq = ! yycount ? ", expecting " : " or "; + yyp = yystpcpy (yyp, yyq); + yyp = yystpcpy (yyp, yytname[yyx]); + yycount++; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("parse error; also virtual memory exhausted"); + } + else +#endif /* defined (YYERROR_VERBOSE) */ + yyerror ("parse error"); + } + goto yyerrlab1; + + +/*--------------------------------------------------. +| yyerrlab1 -- error raised explicitly by an action | +`--------------------------------------------------*/ +yyerrlab1: + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + YYDPRINTF ((stderr, "Discarding token %d (%s).\n", + yychar, yytname[yychar1])); + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + + +/*-------------------------------------------------------------------. +| yyerrdefault -- current state does not do anything special for the | +| error token. | +`-------------------------------------------------------------------*/ +yyerrdefault: +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + + /* If its default is to accept any token, ok. Otherwise pop it. */ + yyn = yydefact[yystate]; + if (yyn) + goto yydefault; +#endif + + +/*---------------------------------------------------------------. +| yyerrpop -- pop the current state because it cannot handle the | +| error token | +`---------------------------------------------------------------*/ +yyerrpop: + if (yyssp == yyss) + YYABORT; + yyvsp--; + yystate = *--yyssp; +#if YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "Error: state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + +/*--------------. +| yyerrhandle. | +`--------------*/ +yyerrhandle: + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +/*---------------------------------------------. +| yyoverflowab -- parser overflow comes here. | +`---------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} +#line 503 "./cond.y" + + + +static int COND_IsAlpha( WCHAR x ) +{ + return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) || + ( ( x >= 'a' ) && ( x <= 'z' ) ) || + ( ( x == '_' ) ) ); +} + +static int COND_IsNumber( WCHAR x ) +{ + return( (( x >= '0' ) && ( x <= '9' )) || (x =='-') || (x =='.') ); +} + + +/* the mess of comparison functions */ + +static INT comp_lt_i(INT a, INT b) +{ return (a < b); } +static INT comp_gt_i(INT a, INT b) +{ return (a > b); } +static INT comp_le_i(INT a, INT b) +{ return (a <= b); } +static INT comp_ge_i(INT a, INT b) +{ return (a >= b); } +static INT comp_eq_i(INT a, INT b) +{ return (a == b); } +static INT comp_ne_i(INT a, INT b) +{ return (a != b); } +static INT comp_bitand(INT a, INT b) +{ return a & b;} +static INT comp_highcomp(INT a, INT b) +{ return HIWORD(a)==b; } +static INT comp_lowcomp(INT a, INT b) +{ return LOWORD(a)==b; } + +static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return !strcmpiW(a,b); else return !strcmpW(a,b);} +static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b); else return strcmpW(a,b);} +static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b)<0; else return strcmpW(a,b)<0;} +static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b)>0; else return strcmpW(a,b)>0;} +static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b)<=0; else return strcmpW(a,b)<=0;} +static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b)>=0; else return strcmpW(a,b)>=0;} +static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless) +/* ERROR NOT WORKING REWRITE */ +{ if (casless) return strstrW(a,b)!=NULL; else return strstrW(a,b)!=NULL;} +static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strncmpiW(a,b,strlenW(b))==0; + else return strncmpW(a,b,strlenW(b))==0;} +static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless) +{ + int i = strlenW(a); + int j = strlenW(b); + if (j>i) + return 0; + if (casless) return (!strcmpiW(&a[i-j-1],b)); + else return (!strcmpW(&a[i-j-1],b)); +} + + +static INT comp_eq_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)==b; else return 0;} +static INT comp_ne_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)!=b; else return 1;} +static INT comp_lt_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)b; else return 0;} +static INT comp_le_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)<=b; else return 0;} +static INT comp_ge_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)>=b; else return 0;} + +static INT comp_eq_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a == atoiW(b); else return 0;} +static INT comp_ne_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a != atoiW(b); else return 1;} +static INT comp_lt_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a < atoiW(b); else return 0;} +static INT comp_gt_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a > atoiW(b); else return 0;} +static INT comp_le_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a <= atoiW(b); else return 0;} +static INT comp_ge_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a >= atoiW(b); else return 0;} + + + +static int COND_IsIdent( WCHAR x ) +{ + return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) + || ( x == '#' ) || (x == '.') ); +} + +static int COND_GetOne( struct cond_str *str, COND_input *cond ) +{ + static const WCHAR szNot[] = {'N','O','T',0}; + static const WCHAR szAnd[] = {'A','N','D',0}; + static const WCHAR szOr[] = {'O','R',0}; + WCHAR ch; + int rc, len = 1; + + str->data = &cond->str[cond->n]; + + ch = str->data[0]; + switch( ch ) + { + case 0: return 0; + case '(': rc = COND_LPAR; break; + case ')': rc = COND_RPAR; break; + case '&': rc = COND_AMPER; break; + case '!': rc = COND_EXCLAM; break; + case '$': rc = COND_DOLLARS; break; + case '?': rc = COND_QUESTION; break; + case '%': rc = COND_PERCENT; break; + case ' ': rc = COND_SPACE; break; + case '=': rc = COND_EQ; break; + case '~': rc = COND_TILDA; break; + case '<': rc = COND_LT; break; + case '>': rc = COND_GT; break; + case '"': + { + const WCHAR *ch2 = str->data + 1; + + + while ( *ch2 && *ch2 != '"' ) + ++ch2; + if (*ch2 == '"') + { + len = ch2 - str->data + 1; + rc = COND_LITER; + break; + } + } + ERR("Unterminated string\n"); + rc = COND_ERROR; + break; + default: + if( COND_IsAlpha( ch ) ) + { + while( COND_IsIdent( str->data[len] ) ) + len++; + rc = COND_IDENT; + break; + } + + if( COND_IsNumber( ch ) ) + { + while( COND_IsNumber( str->data[len] ) ) + len++; + rc = COND_NUMBER; + break; + } + + ERR("Got unknown character %c(%x)\n",ch,ch); + rc = COND_ERROR; + break; + } + + /* keyword identifiers */ + if( rc == COND_IDENT ) + { + if( (len==3) && (strncmpiW(str->data,szNot,len)==0) ) + rc = COND_NOT; + else if( (len==3) && (strncmpiW(str->data,szAnd,len)==0) ) + rc = COND_AND; + else if( (len==2) && (strncmpiW(str->data,szOr,len)==0) ) + rc = COND_OR; + } + + cond->n += len; + str->len = len; + + return rc; +} + +static int COND_lex( void *COND_lval, COND_input *cond ) +{ + int rc; + struct cond_str *str = COND_lval; + + do { + rc = COND_GetOne( str, cond ); + } while (rc == COND_SPACE); + + return rc; +} + +static LPWSTR COND_GetString( struct cond_str *str ) +{ + LPWSTR ret; + + ret = HeapAlloc( GetProcessHeap(), 0, (str->len+1) * sizeof (WCHAR) ); + if( ret ) + { + memcpy( ret, str->data, str->len * sizeof(WCHAR)); + ret[str->len]=0; + } + TRACE("Got identifier %s\n",debugstr_w(ret)); + return ret; +} + +static LPWSTR COND_GetLiteral( struct cond_str *str ) +{ + LPWSTR ret; + + ret = HeapAlloc( GetProcessHeap(), 0, (str->len-1) * sizeof (WCHAR) ); + if( ret ) + { + memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) ); + ret[str->len - 2]=0; + } + TRACE("Got literal %s\n",debugstr_w(ret)); + return ret; +} + +static int COND_error(char *str) +{ + return 0; +} + +MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) +{ + COND_input cond; + MSICONDITION r; + + cond.package = package; + cond.str = szCondition; + cond.n = 0; + cond.result = -1; + + TRACE("Evaluating %s\n",debugstr_w(szCondition)); + + if ( szCondition == NULL || szCondition[0] == 0) + r = MSICONDITION_NONE; + else if ( !COND_parse( &cond ) ) + r = cond.result; + else + r = MSICONDITION_ERROR; + + TRACE("Evaluates to %i\n",r); + return r; +} + +MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition ) +{ + MSIPACKAGE *package; + UINT ret; + + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); + if( !package) + return ERROR_INVALID_HANDLE; + ret = MSI_EvaluateConditionW( package, szCondition ); + msiobj_release( &package->hdr ); + return ret; +} + +MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition ) +{ + LPWSTR szwCond = NULL; + MSICONDITION r; + + if( szCondition ) + { + UINT len = MultiByteToWideChar( CP_ACP, 0, szCondition, -1, NULL, 0 ); + szwCond = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, szCondition, -1, szwCond, len ); + } + + r = MsiEvaluateConditionW( hInstall, szwCond ); + + HeapFree( GetProcessHeap(), 0, szwCond ); + + return r; +} diff --git a/reactos/lib/msi/cond.y b/reactos/lib/msi/cond.y index 8be1d2e6c04..fd995b8cb38 100644 --- a/reactos/lib/msi/cond.y +++ b/reactos/lib/msi/cond.y @@ -181,7 +181,7 @@ term: } | value_s { - $$ = $1[0] ? MSICONDITION_TRUE : MSICONDITION_FALSE; + $$ = ($1 && $1[0]) ? MSICONDITION_TRUE : MSICONDITION_FALSE; } | value_i comp_op_i value_i { @@ -739,7 +739,9 @@ MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) TRACE("Evaluating %s\n",debugstr_w(szCondition)); - if( szCondition && !COND_parse( &cond ) ) + if ( szCondition == NULL || szCondition[0] == 0) + r = MSICONDITION_NONE; + else if ( !COND_parse( &cond ) ) r = cond.result; else r = MSICONDITION_ERROR; diff --git a/reactos/lib/msi/create.c b/reactos/lib/msi/create.c index b22a2aac61f..bbf90425dca 100644 --- a/reactos/lib/msi/create.c +++ b/reactos/lib/msi/create.c @@ -201,20 +201,10 @@ static UINT CREATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, static UINT CREATE_delete( struct tagMSIVIEW *view ) { MSICREATEVIEW *cv = (MSICREATEVIEW*)view; - create_col_info *col; TRACE("%p\n", cv ); - col = cv->col_info; - while( col ) - { - create_col_info *t = col; - col = col->next; - HeapFree( GetProcessHeap(), 0, t->colname ); - HeapFree( GetProcessHeap(), 0, t ); - } msiobj_release( &cv->db->hdr ); - HeapFree( GetProcessHeap(), 0, cv->name ); HeapFree( GetProcessHeap(), 0, cv ); return ERROR_SUCCESS; @@ -250,7 +240,7 @@ UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, cv->view.ops = &create_ops; msiobj_addref( &db->hdr ); cv->db = db; - cv->name = table; /* FIXME: strdupW it? */ + cv->name = table; cv->col_info = col_info; cv->bIsTemp = temp; *view = (MSIVIEW*) cv; diff --git a/reactos/lib/msi/custom.c b/reactos/lib/msi/custom.c index b9e70cf9d6e..4465fc2ebf2 100644 --- a/reactos/lib/msi/custom.c +++ b/reactos/lib/msi/custom.c @@ -80,9 +80,10 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) MSIQUERY * view; MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = - {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','u','s','t','o' - ,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i' - ,'o','n','`',' ','=',' ','`','%','s','`',0}; + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','C','u','s','t','o' ,'m','A','c','t','i','o','n','`', + ' ','W','H','E','R','E',' ','`','A','c','t','i' ,'o','n','`',' ', + '=',' ','\'','%','s','\'',0}; UINT type; LPWSTR source; LPWSTR target; @@ -251,8 +252,9 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source, MSIQUERY * view; MSIRECORD * row = 0; static const WCHAR fmt[] = - {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','B','i' -,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`','%','s','`',0}; + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','B','i' ,'n','a','r','y','`',' ','W','H','E','R','E', + ' ','`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0}; HANDLE the_file; CHAR buffer[1024]; @@ -333,7 +335,7 @@ static void file_running_action(MSIPACKAGE* package, HANDLE Handle, static UINT process_action_return_value(UINT type, HANDLE ThreadHandle) { - DWORD rc; + DWORD rc=0; if (type == 2) { @@ -357,7 +359,8 @@ static UINT process_action_return_value(UINT type, HANDLE ThreadHandle) case ERROR_NO_MORE_ITEMS: return ERROR_SUCCESS; default: - return ERROR_FUNCTION_FAILED; + ERR("Invalid Return Code %lx\n",rc); + return ERROR_INSTALL_FAILURE; } } @@ -372,9 +375,9 @@ static UINT process_handle(MSIPACKAGE* package, UINT type, /* synchronous */ TRACE("Synchronous Execution of action %s\n",debugstr_w(Name)); if (ProcessHandle) - msi_dialog_check_messages(package->dialog, ProcessHandle); + msi_dialog_check_messages(ProcessHandle); else - msi_dialog_check_messages(package->dialog, ThreadHandle); + msi_dialog_check_messages(ThreadHandle); if (!(type & 0x40)) { @@ -479,7 +482,7 @@ static DWORD WINAPI DllThread(LPVOID info) stuff = (thread_struct*)info; rc = ACTION_CallDllFunction(stuff); - TRACE("MSI Thread (0x%lx) finished\n",GetCurrentThreadId()); + TRACE("MSI Thread (0x%lx) finished (rc %li)\n",GetCurrentThreadId(), rc); /* clse all handles for this thread */ MsiCloseAllHandles(); return rc; @@ -630,7 +633,8 @@ static UINT HANDLE_CustomType19(MSIPACKAGE *package, LPCWSTR source, static const WCHAR query[] = { 'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ', 'F','R','O','M',' ','`','E','r','r','o','r','`',' ', - 'W','H','E','R','E',' ','`','E','r','r','o','r','`',' ','=',' ','%','s',0 + 'W','H','E','R','E',' ','`','E','r','r','o','r','`',' ','=',' ', + '\'','%','s','\'',0 }; MSIQUERY *view = NULL; MSIRECORD *row = 0; @@ -685,7 +689,7 @@ static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source, prop = load_dynamic_property(package,source,&prc); if (!prop) - return prc; + return ERROR_SUCCESS; deformat_string(package,target,&deformated); len = strlenW(prop) + 2; @@ -782,8 +786,7 @@ void ACTION_FinishCustomActions(MSIPACKAGE* package) { TRACE("Waiting on action %s\n", debugstr_w(package->RunningAction[i].name)); - msi_dialog_check_messages(package->dialog, - package->RunningAction[i].handle); + msi_dialog_check_messages(package->RunningAction[i].handle); } HeapFree(GetProcessHeap(),0,package->RunningAction[i].name); diff --git a/reactos/lib/msi/database.c b/reactos/lib/msi/database.c index 6d7bd1b9e5b..800b1db2f57 100644 --- a/reactos/lib/msi/database.c +++ b/reactos/lib/msi/database.c @@ -65,6 +65,7 @@ VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) DWORD r; free_cached_tables( db ); + msi_destroy_stringtable( db->strings ); r = IStorage_Release( db->storage ); if( r ) ERR("database reference count was not zero (%ld)\n", r); @@ -213,7 +214,8 @@ UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB) r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB ); end: - HeapFree( GetProcessHeap(), 0, szwPersist ); + if( HIWORD(szPersist) ) + HeapFree( GetProcessHeap(), 0, szwPersist ); HeapFree( GetProcessHeap(), 0, szwDBPath ); return r; @@ -334,7 +336,7 @@ UINT WINAPI MsiDatabaseExportA( MSIHANDLE handle, LPCSTR szTable, goto end; } - r = MsiDatabaseImportW( handle, path, file ); + r = MsiDatabaseExportW( handle, table, path, file ); end: HeapFree( GetProcessHeap(), 0, table ); diff --git a/reactos/lib/msi/dialog.c b/reactos/lib/msi/dialog.c index 19ab2d5d402..4977329f471 100644 --- a/reactos/lib/msi/dialog.c +++ b/reactos/lib/msi/dialog.c @@ -44,6 +44,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); const WCHAR szMsiDialogClass[] = { 'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',0 }; +const WCHAR szMsiHiddenWindow[] = { + 'M','s','i','H','i','d','d','e','n','W','i','n','d','o','w',0 +}; const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 }; const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 }; @@ -106,6 +109,14 @@ static UINT msi_dialog_radiogroup_handler( msi_dialog *, msi_control *, WPARAM p static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +/* dialog sequencing */ + +#define WM_MSI_DIALOG_CREATE (WM_USER+0x100) +#define WM_MSI_DIALOG_DESTROY (WM_USER+0x101) + +static DWORD uiThreadId; +static HWND hMsiHiddenWindow; + INT msi_dialog_scale_unit( msi_dialog *dialog, INT val ) { return (dialog->scale * val + 5) / 10; @@ -725,41 +736,51 @@ static INT msi_dialog_get_sans_serif_height( HWND hwnd ) return height; } -static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs ) +/* fetch the associated record from the Dialog table */ +static MSIRECORD *msi_get_dialog_record( msi_dialog *dialog ) { static const WCHAR query[] = { 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ','D','i','a','l','o','g',' ', 'W','H','E','R','E',' ', '`','D','i','a','l','o','g','`',' ','=',' ','\'','%','s','\'',0}; - static const WCHAR df[] = { - 'D','e','f','a','u','l','t','U','I','F','o','n','t',0 }; - msi_dialog *dialog = (msi_dialog*) cs->lpCreateParams; MSIPACKAGE *package = dialog->package; MSIQUERY *view = NULL; MSIRECORD *rec = NULL; - DWORD width, height; - LPCWSTR text; - LPWSTR title = NULL; UINT r; - TRACE("%p %p\n", dialog, package); + TRACE("%p %s\n", dialog, debugstr_w(dialog->name) ); - dialog->hwnd = hwnd; - SetWindowLongPtrW( hwnd, GWLP_USERDATA, (LONG_PTR) dialog ); - - /* fetch the associated record from the Dialog table */ r = MSI_OpenQuery( package->db, &view, query, dialog->name ); if( r != ERROR_SUCCESS ) { ERR("query failed for dialog %s\n", debugstr_w(dialog->name)); - return -1; + return NULL; } MSI_ViewExecute( view, NULL ); MSI_ViewFetch( view, &rec ); MSI_ViewClose( view ); msiobj_release( &view->hdr ); + return rec; +} + +static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs ) +{ + static const WCHAR df[] = { + 'D','e','f','a','u','l','t','U','I','F','o','n','t',0 }; + msi_dialog *dialog = (msi_dialog*) cs->lpCreateParams; + MSIRECORD *rec = NULL; + DWORD width, height; + LPCWSTR text; + LPWSTR title = NULL; + + TRACE("%p %p\n", dialog, dialog->package); + + dialog->hwnd = hwnd; + SetWindowLongPtrW( hwnd, GWLP_USERDATA, (LONG_PTR) dialog ); + + rec = msi_get_dialog_record( dialog ); if( !rec ) { TRACE("No record found for dialog %s\n", debugstr_w(dialog->name)); @@ -1004,7 +1025,8 @@ static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg, { msi_dialog *dialog = (LPVOID) GetWindowLongPtrW( hwnd, GWLP_USERDATA ); - TRACE(" 0x%04x\n", msg); + TRACE("0x%04x\n", msg); + switch (msg) { case WM_CREATE: @@ -1020,13 +1042,43 @@ static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg, return DefWindowProcW(hwnd, msg, wParam, lParam); } +static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC oldproc = (WNDPROC) GetPropW(hWnd, szButtonData); + + TRACE("hWnd %p msg %04x wParam 0x%08x lParam 0x%08lx\n", hWnd, msg, wParam, lParam); + + if (msg == WM_COMMAND) /* Forward notifications to dialog */ + SendMessageW(GetParent(hWnd), msg, wParam, lParam); + + return CallWindowProcW(oldproc, hWnd, msg, wParam, lParam); +} + +static LRESULT WINAPI MSIHiddenWindowProc( HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam ) +{ + msi_dialog *dialog = (msi_dialog*) lParam; + + TRACE("%d %p\n", msg, dialog); + + switch (msg) + { + case WM_MSI_DIALOG_CREATE: + return msi_dialog_run_message_loop( dialog ); + case WM_MSI_DIALOG_DESTROY: + msi_dialog_destroy( dialog ); + return 0; + } + return DefWindowProcW( hwnd, msg, wParam, lParam ); +} + /* functions that interface to other modules within MSI */ msi_dialog *msi_dialog_create( MSIPACKAGE* package, LPCWSTR szDialogName, msi_dialog_event_handler event_handler ) { + MSIRECORD *rec = NULL; msi_dialog *dialog; - HWND hwnd; TRACE("%p %s\n", package, debugstr_w(szDialogName)); @@ -1036,44 +1088,101 @@ msi_dialog *msi_dialog_create( MSIPACKAGE* package, LPCWSTR szDialogName, if( !dialog ) return NULL; strcpyW( dialog->name, szDialogName ); + msiobj_addref( &package->hdr ); dialog->package = package; dialog->event_handler = event_handler; + dialog->finished = 0; - /* create the dialog window, don't show it yet */ - hwnd = CreateWindowW( szMsiDialogClass, szDialogName, WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - NULL, NULL, NULL, dialog ); - if( !hwnd ) + /* verify that the dialog exists */ + rec = msi_get_dialog_record( dialog ); + if( !rec ) { - ERR("Failed to create dialog %s\n", debugstr_w( szDialogName )); - msi_dialog_destroy( dialog ); + HeapFree( GetProcessHeap(), 0, dialog ); return NULL; } + dialog->attributes = MSI_RecordGetInteger( rec, 6 ); + msiobj_release( &rec->hdr ); return dialog; } +static void msi_process_pending_messages(void) +{ + MSG msg; + + while( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ) ) + { + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } +} + void msi_dialog_end_dialog( msi_dialog *dialog ) { + TRACE("%p\n", dialog); dialog->finished = 1; + PostMessageW(dialog->hwnd, WM_NULL, 0, 0); +} + +void msi_dialog_check_messages( HANDLE handle ) +{ + DWORD r; + + /* in threads other than the UI thread, block */ + if( uiThreadId != GetCurrentThreadId() ) + { + if( handle ) + WaitForSingleObject( handle, INFINITE ); + return; + } + + /* there's two choices for the UI thread */ + while (1) + { + msi_process_pending_messages(); + + if( !handle ) + break; + + /* + * block here until somebody creates a new dialog or + * the handle we're waiting on becomes ready + */ + r = MsgWaitForMultipleObjects( 1, &handle, 0, INFINITE, QS_ALLINPUT ); + if( r == WAIT_OBJECT_0 ) + break; + } } UINT msi_dialog_run_message_loop( msi_dialog *dialog ) { - MSG msg; + HWND hwnd; - if( dialog->attributes & msidbDialogAttributesVisible ) + if( !(dialog->attributes & msidbDialogAttributesVisible) ) + return ERROR_SUCCESS; + + if( uiThreadId != GetCurrentThreadId() ) + return SendMessageW( hMsiHiddenWindow, WM_MSI_DIALOG_CREATE, 0, (LPARAM) dialog ); + + /* create the dialog window, don't show it yet */ + hwnd = CreateWindowW( szMsiDialogClass, dialog->name, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, NULL, dialog ); + if( !hwnd ) { - ShowWindow( dialog->hwnd, SW_SHOW ); - UpdateWindow( dialog->hwnd ); + ERR("Failed to create dialog %s\n", debugstr_w( dialog->name )); + return ERROR_FUNCTION_FAILED; } + ShowWindow( hwnd, SW_SHOW ); + UpdateWindow( hwnd ); + if( dialog->attributes & msidbDialogAttributesModal ) { - while( !dialog->finished && GetMessageW( &msg, 0, 0, 0 ) ) + while( !dialog->finished ) { - TranslateMessage( &msg ); - DispatchMessageW( &msg ); + MsgWaitForMultipleObjects( 0, NULL, 0, INFINITE, QS_ALLEVENTS ); + msi_process_pending_messages(); } } else @@ -1082,27 +1191,9 @@ UINT msi_dialog_run_message_loop( msi_dialog *dialog ) return ERROR_SUCCESS; } -void msi_dialog_check_messages( msi_dialog *dialog, HANDLE handle ) -{ - MSG msg; - DWORD r; - - do - { - while( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ) ) - { - TranslateMessage( &msg ); - DispatchMessageW( &msg ); - } - if( !handle ) - break; - r = MsgWaitForMultipleObjects( 1, &handle, 0, INFINITE, QS_ALLEVENTS ); - } - while( WAIT_OBJECT_0 != r ); -} - void msi_dialog_do_preview( msi_dialog *dialog ) { + TRACE("\n"); dialog->attributes |= msidbDialogAttributesVisible; dialog->attributes &= ~msidbDialogAttributesModal; msi_dialog_run_message_loop( dialog ); @@ -1110,6 +1201,12 @@ void msi_dialog_do_preview( msi_dialog *dialog ) void msi_dialog_destroy( msi_dialog *dialog ) { + if( uiThreadId != GetCurrentThreadId() ) + { + SendMessageW( hMsiHiddenWindow, WM_MSI_DIALOG_DESTROY, 0, (LPARAM) dialog ); + return; + } + if( dialog->hwnd ) ShowWindow( dialog->hwnd, SW_HIDE ); @@ -1138,11 +1235,12 @@ void msi_dialog_destroy( msi_dialog *dialog ) if( dialog->hwnd ) DestroyWindow( dialog->hwnd ); + msiobj_release( &dialog->package->hdr ); dialog->package = NULL; HeapFree( GetProcessHeap(), 0, dialog ); } -void msi_dialog_register_class( void ) +BOOL msi_dialog_register_class( void ) { WNDCLASSW cls; @@ -1155,22 +1253,28 @@ void msi_dialog_register_class( void ) cls.lpszMenuName = NULL; cls.lpszClassName = szMsiDialogClass; - RegisterClassW( &cls ); + if( !RegisterClassW( &cls ) ) + return FALSE; + + cls.lpfnWndProc = MSIHiddenWindowProc; + cls.lpszClassName = szMsiHiddenWindow; + + if( !RegisterClassW( &cls ) ) + return FALSE; + + uiThreadId = GetCurrentThreadId(); + + hMsiHiddenWindow = CreateWindowW( szMsiHiddenWindow, NULL, WS_OVERLAPPED, + 0, 0, 100, 100, NULL, NULL, NULL, NULL ); + if( !hMsiHiddenWindow ) + return FALSE; + + return TRUE; } void msi_dialog_unregister_class( void ) { + DestroyWindow( hMsiHiddenWindow ); UnregisterClassW( szMsiDialogClass, NULL ); -} - -static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - WNDPROC oldproc = (WNDPROC) GetPropW(hWnd, szButtonData); - - TRACE("hWnd %p msg %04x wParam 0x%08x lParam 0x%08lx\n", hWnd, msg, wParam, lParam); - - if (msg == WM_COMMAND) /* Forward notifications to dialog */ - SendMessageW(GetParent(hWnd), msg, wParam, lParam); - - return CallWindowProcW(oldproc, hWnd, msg, wParam, lParam); + uiThreadId = 0; } diff --git a/reactos/lib/msi/insert.c b/reactos/lib/msi/insert.c index 40dba1a9d4f..b8e69980943 100644 --- a/reactos/lib/msi/insert.c +++ b/reactos/lib/msi/insert.c @@ -233,7 +233,6 @@ static UINT INSERT_delete( struct tagMSIVIEW *view ) sv = iv->sv; if( sv ) sv->ops->delete( sv ); - delete_value_list( iv->vals ); msiobj_release( &iv->db->hdr ); HeapFree( GetProcessHeap(), 0, iv ); diff --git a/reactos/lib/msi/msi.c b/reactos/lib/msi/msi.c index aabcd522e77..b1f3babf69d 100644 --- a/reactos/lib/msi/msi.c +++ b/reactos/lib/msi/msi.c @@ -35,6 +35,8 @@ #include "wincrypt.h" #include "winver.h" #include "winuser.h" +#include "wine/unicode.h" +#include "action.h" UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf); @@ -59,6 +61,8 @@ LPVOID gUIContext = NULL; WCHAR gszLogFile[MAX_PATH]; HINSTANCE msi_hInstance; +static const WCHAR installerW[] = {'\\','I','n','s','t','a','l','l','e','r',0}; + UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct) { UINT r; @@ -252,7 +256,7 @@ UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage, UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState, LPCWSTR szCommandLine) { - MSIHANDLE handle; + MSIHANDLE handle = -1; MSIPACKAGE* package; UINT rc; HKEY hkey=0,hkey1=0; @@ -330,6 +334,8 @@ UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel, HeapFree(GetProcessHeap(),0,commandline); end: RegCloseKey(hkey); + if (handle != -1) + MsiCloseHandle(handle); return rc; } @@ -420,11 +426,38 @@ UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer) UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer) { - FIXME("%s %p\n",debugstr_w(szComponent), szBuffer); + UINT rc; + HKEY hkey; + WCHAR szSquished[GUID_SIZE]; + DWORD sz = GUID_SIZE; + static const WCHAR szPermKey[] = + { '0','0','0','0','0','0','0','0','0','0','0','0', + '0','0','0','0','0','0','0', '0','0','0','0','0', + '0','0','0','0','0','0','0','0',0}; + + TRACE("%s %p\n",debugstr_w(szComponent), szBuffer); if (NULL == szComponent) return ERROR_INVALID_PARAMETER; - return ERROR_CALL_NOT_IMPLEMENTED; + + rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE); + if (rc != ERROR_SUCCESS) + return ERROR_UNKNOWN_COMPONENT; + + rc = RegEnumValueW(hkey, 0, szSquished, &sz, NULL, NULL, NULL, NULL); + if (rc == ERROR_SUCCESS && strcmpW(szSquished,szPermKey)==0) + { + sz = GUID_SIZE; + rc = RegEnumValueW(hkey, 1, szSquished, &sz, NULL, NULL, NULL, NULL); + } + + RegCloseKey(hkey); + + if (rc != ERROR_SUCCESS) + return ERROR_INSTALL_FAILURE; + + unsquash_guid(szSquished, szBuffer); + return ERROR_SUCCESS; } UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, @@ -475,6 +508,14 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, { MSIHANDLE hProduct; UINT r; + static const WCHAR szPackageCode[] = + {'P','a','c','k','a','g','e','C','o','d','e',0}; + static const WCHAR szVersionString[] = + {'V','e','r','s','i','o','n','S','t','r','i','n','g',0}; + static const WCHAR szProductVersion[] = + {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}; + static const WCHAR szAssignmentType[] = + {'A','s','s','i','g','n','m','e','n','t','T','y','p','e',0}; FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute), szBuffer, pcchValueBuf); @@ -483,13 +524,66 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, return ERROR_INVALID_PARAMETER; if (NULL == szProduct || NULL == szAttribute) return ERROR_INVALID_PARAMETER; + + /* check for special properties */ + if (strcmpW(szAttribute, szPackageCode)==0) + { + HKEY hkey; + WCHAR squished[GUID_SIZE]; + WCHAR package[200]; + DWORD sz = sizeof(squished); - r = MsiOpenProductW(szProduct, &hProduct); - if (ERROR_SUCCESS != r) - return r; + r = MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE); + if (r != ERROR_SUCCESS) + return ERROR_UNKNOWN_PRODUCT; + + r = RegQueryValueExW(hkey, szPackageCode, NULL, NULL, + (LPBYTE)squished, &sz); + if (r != ERROR_SUCCESS) + { + RegCloseKey(hkey); + return ERROR_UNKNOWN_PRODUCT; + } + + unsquash_guid(squished, package); + *pcchValueBuf = strlenW(package); + if (strlenW(package) > *pcchValueBuf) + { + RegCloseKey(hkey); + return ERROR_MORE_DATA; + } + else + strcpyW(szBuffer, package); + + RegCloseKey(hkey); + r = ERROR_SUCCESS; + } + else if (strcmpW(szAttribute, szVersionString)==0) + { + r = MsiOpenProductW(szProduct, &hProduct); + if (ERROR_SUCCESS != r) + return r; + + r = MsiGetPropertyW(hProduct, szProductVersion, szBuffer, pcchValueBuf); + MsiCloseHandle(hProduct); + } + else if (strcmpW(szAttribute, szAssignmentType)==0) + { + FIXME("0 (zero) if advertised, 1(one) if per machine.\n"); + if (szBuffer) + szBuffer[0] = 1; + r = ERROR_SUCCESS; + } + else + { + r = MsiOpenProductW(szProduct, &hProduct); + if (ERROR_SUCCESS != r) + return r; + + r = MsiGetPropertyW(hProduct, szAttribute, szBuffer, pcchValueBuf); + MsiCloseHandle(hProduct); + } - r = MsiGetPropertyW(hProduct, szAttribute, szBuffer, pcchValueBuf); - MsiCloseHandle(hProduct); return r; } @@ -970,6 +1064,9 @@ end: return rrc; } +/****************************************************************** + * MsiQueryFeatureStateA [MSI.@] + */ INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature) { INSTALLSTATE rc; @@ -1001,15 +1098,37 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature) return rc; } +/****************************************************************** + * MsiQueryFeatureStateW [MSI.@] + * + * This does not verify that the Feature is functional. So i am only going to + * check the existence of the key in the registry. This should tell me if it is + * installed. + */ INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature) { - FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature)); - /* - * Iterates all the features components and the features parents components - */ - return INSTALLSTATE_LOCAL; + UINT rc; + DWORD sz = 0; + HKEY hkey; + + TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature)); + + rc = MSIREG_OpenFeaturesKey(szProduct, &hkey, FALSE); + if (rc != ERROR_SUCCESS) + return INSTALLSTATE_UNKNOWN; + + rc = RegQueryValueExW( hkey, szFeature, NULL, NULL, NULL, &sz); + RegCloseKey(hkey); + + if (rc == ERROR_SUCCESS) + return INSTALLSTATE_LOCAL; + else + return INSTALLSTATE_ABSENT; } +/****************************************************************** + * MsiGetFileVersionA [MSI.@] + */ UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf, DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf) { @@ -1055,6 +1174,9 @@ end: return ret; } +/****************************************************************** + * MsiGetFileVersionW [MSI.@] + */ UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf) { @@ -1195,7 +1317,7 @@ static IClassFactoryVtbl MsiCF_Vtbl = static IClassFactoryImpl Msi_CF = { &MsiCF_Vtbl }; /****************************************************************** - * DllGetClassObject [MSI.@] + * DllGetClassObject [MSI.@] */ HRESULT WINAPI MSI_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { @@ -1214,7 +1336,7 @@ HRESULT WINAPI MSI_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) } /****************************************************************** - * DllGetVersion [MSI.@] + * DllGetVersion [MSI.@] */ HRESULT WINAPI MSI_DllGetVersion(DLLVERSIONINFO *pdvi) { @@ -1232,7 +1354,7 @@ HRESULT WINAPI MSI_DllGetVersion(DLLVERSIONINFO *pdvi) } /****************************************************************** - * DllCanUnloadNow [MSI.@] + * DllCanUnloadNow [MSI.@] */ BOOL WINAPI MSI_DllCanUnloadNow(void) { @@ -1272,6 +1394,9 @@ INSTALLSTATE WINAPI MsiUseFeatureExW(LPCWSTR szProduct, LPCWSTR szFeature, return INSTALLSTATE_LOCAL; } +/*********************************************************************** + * MsiUseFeatureExA [MSI.@] + */ INSTALLSTATE WINAPI MsiUseFeatureExA(LPCSTR szProduct, LPCSTR szFeature, DWORD dwInstallMode, DWORD dwReserved) { @@ -1300,22 +1425,191 @@ UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent, DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf, DWORD* pcchPathBuf) { - FIXME("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent), + HKEY hkey; + UINT rc; + LPWSTR info; + DWORD sz; + LPWSTR product = NULL; + LPWSTR component = NULL; + LPWSTR ptr; + GUID clsid; + + TRACE("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent), debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct), Unused1, Unused2, lpPathBuf, pcchPathBuf); + + rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE); + if (rc != ERROR_SUCCESS) + return ERROR_INDEX_ABSENT; - return ERROR_INDEX_ABSENT; + sz = 0; + rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, NULL, &sz); + if (sz <= 0) + { + RegCloseKey(hkey); + return ERROR_INDEX_ABSENT; + } + + info = HeapAlloc(GetProcessHeap(),0,sz); + rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, (LPBYTE)info, &sz); + if (rc != ERROR_SUCCESS) + { + RegCloseKey(hkey); + HeapFree(GetProcessHeap(),0,info); + return ERROR_INDEX_ABSENT; + } + + /* find the component */ + ptr = strchrW(&info[20],'>'); + if (ptr) + ptr++; + else + { + RegCloseKey(hkey); + HeapFree(GetProcessHeap(),0,info); + return ERROR_INDEX_ABSENT; + } + + if (!szProduct) + { + decode_base85_guid(info,&clsid); + StringFromCLSID(&clsid, &product); + } + decode_base85_guid(ptr,&clsid); + StringFromCLSID(&clsid, &component); + + if (!szProduct) + rc = MsiGetComponentPathW(product, component, lpPathBuf, pcchPathBuf); + else + rc = MsiGetComponentPathW(szProduct, component, lpPathBuf, pcchPathBuf); + + RegCloseKey(hkey); + HeapFree(GetProcessHeap(),0,info); + HeapFree(GetProcessHeap(),0,product); + HeapFree(GetProcessHeap(),0,component); + + if (rc == INSTALLSTATE_LOCAL) + return ERROR_SUCCESS; + else + return ERROR_FILE_NOT_FOUND; +} + +/*********************************************************************** + * MsiProvideQualifiedComponentW [MSI.@] + */ +UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent, + LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf, + DWORD* pcchPathBuf) +{ + return MsiProvideQualifiedComponentExW(szComponent, szQualifier, + dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf); +} + +/*********************************************************************** + * MsiProvideQualifiedComponentA [MSI.@] + */ +UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent, + LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf, + DWORD* pcchPathBuf) +{ + LPWSTR szwComponent, szwQualifier, lpwPathBuf; + DWORD pcchwPathBuf; + UINT rc; + + TRACE("%s %s %li %p %p\n",szComponent, szQualifier, + dwInstallMode, lpPathBuf, pcchPathBuf); + + szwComponent= strdupAtoW( szComponent); + szwQualifier= strdupAtoW( szQualifier); + + lpwPathBuf = HeapAlloc(GetProcessHeap(),0,*pcchPathBuf * sizeof(WCHAR)); + + pcchwPathBuf = *pcchPathBuf; + + rc = MsiProvideQualifiedComponentW(szwComponent, szwQualifier, + dwInstallMode, lpwPathBuf, &pcchwPathBuf); + + HeapFree(GetProcessHeap(),0,szwComponent); + HeapFree(GetProcessHeap(),0,szwQualifier); + *pcchPathBuf = WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, pcchwPathBuf, + lpPathBuf, *pcchPathBuf, NULL, NULL); + + HeapFree(GetProcessHeap(),0,lpwPathBuf); + return rc; } USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf, DWORD* pcchUserNameBuf, LPWSTR lpOrgNameBuf, DWORD* pcchOrgNameBuf, LPWSTR lpSerialBuf, DWORD* pcchSerialBuf) { - FIXME("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf, + HKEY hkey; + DWORD sz; + UINT rc = ERROR_SUCCESS,rc2 = ERROR_SUCCESS; + static const WCHAR szOwner[] = {'R','e','g','O','w','n','e','r',0}; + static const WCHAR szCompany[] = {'R','e','g','C','o','m','p','a','n','y',0}; + static const WCHAR szSerial[] = {'P','r','o','d','u','c','t','I','D',0}; + + TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf, pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf, pcchSerialBuf); - return USERINFOSTATE_UNKNOWN; + rc = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE); + if (rc != ERROR_SUCCESS) + return USERINFOSTATE_UNKNOWN; + + if (lpUserNameBuf) + { + sz = *lpUserNameBuf * sizeof(WCHAR); + rc = RegQueryValueExW( hkey, szOwner, NULL, NULL, (LPBYTE)lpUserNameBuf, + &sz); + } + if (!lpUserNameBuf && pcchUserNameBuf) + { + sz = 0; + rc = RegQueryValueExW( hkey, szOwner, NULL, NULL, NULL, &sz); + } + + if (pcchUserNameBuf) + *pcchUserNameBuf = sz / sizeof(WCHAR); + + if (lpOrgNameBuf) + { + sz = *pcchOrgNameBuf * sizeof(WCHAR); + rc2 = RegQueryValueExW( hkey, szCompany, NULL, NULL, + (LPBYTE)lpOrgNameBuf, &sz); + } + if (!lpOrgNameBuf && pcchOrgNameBuf) + { + sz = 0; + rc2 = RegQueryValueExW( hkey, szCompany, NULL, NULL, NULL, &sz); + } + + if (pcchOrgNameBuf) + *pcchOrgNameBuf = sz / sizeof(WCHAR); + + if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA && + rc2 != ERROR_SUCCESS && rc2 != ERROR_MORE_DATA) + { + RegCloseKey(hkey); + return USERINFOSTATE_ABSENT; + } + + if (lpSerialBuf) + { + sz = *pcchSerialBuf * sizeof(WCHAR); + RegQueryValueExW( hkey, szSerial, NULL, NULL, (LPBYTE)lpSerialBuf, + &sz); + } + if (!lpSerialBuf && pcchSerialBuf) + { + sz = 0; + rc = RegQueryValueExW( hkey, szSerial, NULL, NULL, NULL, &sz); + } + if (pcchSerialBuf) + *pcchSerialBuf = sz / sizeof(WCHAR); + + RegCloseKey(hkey); + return USERINFOSTATE_PRESENT; } USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct, LPSTR lpUserNameBuf, @@ -1331,20 +1625,68 @@ USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct, LPSTR lpUserNameBuf, UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct) { - FIXME("%s\n",debugstr_w(szProduct)); - return ERROR_CALL_NOT_IMPLEMENTED; + MSIHANDLE handle; + UINT rc; + MSIPACKAGE *package; + static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0}; + + TRACE("(%s)\n",debugstr_w(szProduct)); + + rc = MsiOpenProductW(szProduct,&handle); + if (rc != ERROR_SUCCESS) + return ERROR_INVALID_PARAMETER; + + package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE); + rc = ACTION_PerformUIAction(package, szFirstRun); + msiobj_release( &package->hdr ); + + MsiCloseHandle(handle); + + return rc; } UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct) { - FIXME("%s\n",debugstr_a(szProduct)); - return ERROR_CALL_NOT_IMPLEMENTED; + MSIHANDLE handle; + UINT rc; + MSIPACKAGE *package; + static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0}; + + TRACE("(%s)\n",debugstr_a(szProduct)); + + rc = MsiOpenProductA(szProduct,&handle); + if (rc != ERROR_SUCCESS) + return ERROR_INVALID_PARAMETER; + + package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE); + rc = ACTION_PerformUIAction(package, szFirstRun); + msiobj_release( &package->hdr ); + + MsiCloseHandle(handle); + + return rc; } UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved) { - FIXME("%ld\n", dwReserved); - return ERROR_CALL_NOT_IMPLEMENTED; + WCHAR path[MAX_PATH]; + + if(dwReserved) { + FIXME("Don't know how to handle argument %ld\n", dwReserved); + return ERROR_CALL_NOT_IMPLEMENTED; + } + + if(!GetWindowsDirectoryW(path, MAX_PATH)) { + FIXME("GetWindowsDirectory failed unexpected! Error %ld\n", + GetLastError()); + return ERROR_CALL_NOT_IMPLEMENTED; + } + + strcatW(path, installerW); + + CreateDirectoryW(path, NULL); + + return 0; } UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget, diff --git a/reactos/lib/msi/msi.rc b/reactos/lib/msi/msi.rc index ce777aa13ef..4e48f957d33 100644 --- a/reactos/lib/msi/msi.rc +++ b/reactos/lib/msi/msi.rc @@ -33,3 +33,4 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL #include "msi_Fr.rc" #include "msi_Nl.rc" #include "msi_Pt.rc" +#include "msi_Ru.rc" diff --git a/reactos/lib/msi/msi.spec b/reactos/lib/msi/msi.spec index 4bf2712ecb1..91464064b0d 100644 --- a/reactos/lib/msi/msi.spec +++ b/reactos/lib/msi/msi.spec @@ -18,8 +18,8 @@ 18 stdcall MsiDatabaseApplyTransformA(long str long) 19 stdcall MsiDatabaseApplyTransformW(long wstr long) 20 stdcall MsiDatabaseCommit(long) -21 stub MsiDatabaseExportA -22 stub MsiDatabaseExportW +21 stdcall MsiDatabaseExportA(long str str str) +22 stdcall MsiDatabaseExportW(long wstr wstr wstr) 23 stdcall MsiDatabaseGenerateTransformA(long long str long long) 24 stdcall MsiDatabaseGenerateTransformW(long long wstr long long) 25 stdcall MsiDatabaseGetPrimaryKeysA(long str ptr) @@ -78,7 +78,7 @@ 78 stdcall MsiGetSummaryInformationW(long wstr long ptr) 79 stdcall MsiGetTargetPathA(long str ptr ptr) 80 stdcall MsiGetTargetPathW(long wstr ptr ptr) -81 stub MsiGetUserInfoA +81 stdcall MsiGetUserInfoA(str ptr ptr ptr ptr ptr ptr) 82 stdcall MsiGetUserInfoW(wstr ptr ptr ptr ptr ptr ptr) 83 stub MsiInstallMissingComponentA 84 stub MsiInstallMissingComponentW @@ -105,8 +105,8 @@ 105 stdcall MsiProvideComponentFromDescriptorA(str ptr ptr ptr) 106 stdcall MsiProvideComponentFromDescriptorW(wstr ptr ptr ptr) 107 stub MsiProvideComponentW -108 stub MsiProvideQualifiedComponentA -109 stub MsiProvideQualifiedComponentW +108 stdcall MsiProvideQualifiedComponentA(str str long ptr ptr) +109 stdcall MsiProvideQualifiedComponentW(str str long ptr ptr) 110 stdcall MsiQueryFeatureStateA(str str) 111 stdcall MsiQueryFeatureStateW(wstr wstr) 112 stdcall MsiQueryProductStateA(str) diff --git a/reactos/lib/msi/msi_Fr.rc b/reactos/lib/msi/msi_Fr.rc index d1551aba270..6ed10340aac 100644 --- a/reactos/lib/msi/msi_Fr.rc +++ b/reactos/lib/msi/msi_Fr.rc @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -LANGUAGE LANG_FRENCH, SUBLANG_DEFAULT +LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL STRINGTABLE DISCARDABLE { diff --git a/reactos/lib/msi/msi_Ru.rc b/reactos/lib/msi/msi_Ru.rc new file mode 100644 index 00000000000..355a0fb11ce --- /dev/null +++ b/reactos/lib/msi/msi_Ru.rc @@ -0,0 +1,34 @@ +/* + * Russian resources for MSI + * + * Copyright 2005 Mikhail Y. Zvyozdochkin + * Aleksey Bragin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + 5 "ïóòü %s íå íàéäåí" + 9 "âñòàâüòå äèñê %s" + 10 "íåâåðíûå ïàðàìåòðû" + 11 "ââåäèòå, êàêàÿ ïàïêà ñîäåðæèò %s" + 12 "íåäîñòóïåí èñòî÷íèê óñòàíîâêè (ñúåìíûé èëè êîìïàêò-äèñê íåâñòàâëåí â äèñêîâîä)" + 13 "íåäîñòóïåí ñåòåâîé äèñê, ñîäåðæàùèé íåîáõîäèìûé ôàéë" + 14 "ôóíêöèîíàëüíîñòü èç:" + 15 "âûáåðèòå, êàêàÿ ïàïêà ñîäåðæèò %s" +} diff --git a/reactos/lib/msi/msipriv.h b/reactos/lib/msi/msipriv.h index 290de68e075..2aad08a9d82 100644 --- a/reactos/lib/msi/msipriv.h +++ b/reactos/lib/msi/msipriv.h @@ -30,6 +30,7 @@ #include "objbase.h" #include "objidl.h" #include "wine/unicode.h" +#include "wine/list.h" #define MSI_DATASIZEMASK 0x00ff #define MSITYPE_VALID 0x0100 @@ -77,6 +78,7 @@ typedef struct tagMSIQUERY MSIVIEW *view; UINT row; MSIDATABASE *db; + struct list mem; } MSIQUERY; /* maybe we can use a Variant instead of doing it ourselves? */ @@ -288,7 +290,7 @@ extern const WCHAR *msi_string_lookup_id( string_table *st, UINT id ); extern UINT msi_string_get_codepage( string_table *st ); -extern UINT VIEW_find_column( MSIVIEW *view, LPWSTR name, UINT *n ); +extern UINT VIEW_find_column( MSIVIEW *view, LPCWSTR name, UINT *n ); extern BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name ); @@ -342,6 +344,7 @@ extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR ); extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * ); extern UINT MSI_GetFeatureStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * ); +extern UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE*, LPCWSTR, INSTALLSTATE ); /* for deformating */ extern UINT MSI_FormatRecordW(MSIPACKAGE* package, MSIRECORD* record, @@ -357,6 +360,7 @@ extern UINT MSIREG_OpenUserProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create extern UINT MSIREG_OpenFeatures(HKEY* key); extern UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create); extern UINT MSIREG_OpenComponents(HKEY* key); +extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create); extern UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create); extern UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create); extern UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create); @@ -367,10 +371,10 @@ typedef VOID (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dia extern msi_dialog *msi_dialog_create( MSIPACKAGE*, LPCWSTR, msi_dialog_event_handler ); extern UINT msi_dialog_run_message_loop( msi_dialog* ); extern void msi_dialog_end_dialog( msi_dialog* ); -extern void msi_dialog_check_messages( msi_dialog*, HANDLE ); +extern void msi_dialog_check_messages( HANDLE ); extern void msi_dialog_do_preview( msi_dialog* ); extern void msi_dialog_destroy( msi_dialog* ); -extern void msi_dialog_register_class( void ); +extern BOOL msi_dialog_register_class( void ); extern void msi_dialog_unregister_class( void ); /* UI globals */ diff --git a/reactos/lib/msi/msiquery.c b/reactos/lib/msi/msiquery.c index eb50d0991cc..cdd4457e612 100644 --- a/reactos/lib/msi/msiquery.c +++ b/reactos/lib/msi/msiquery.c @@ -41,13 +41,19 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); void MSI_CloseView( MSIOBJECTHDR *arg ) { MSIQUERY *query = (MSIQUERY*) arg; + struct list *ptr, *t; if( query->view && query->view->ops->delete ) query->view->ops->delete( query->view ); msiobj_release( &query->db->hdr ); + + LIST_FOR_EACH_SAFE( ptr, t, &query->mem ) + { + HeapFree( GetProcessHeap(), 0, ptr ); + } } -UINT VIEW_find_column( MSIVIEW *table, LPWSTR name, UINT *n ) +UINT VIEW_find_column( MSIVIEW *table, LPCWSTR name, UINT *n ) { LPWSTR col_name; UINT i, count, r; @@ -120,8 +126,9 @@ UINT MSI_DatabaseOpenViewW(MSIDATABASE *db, query->row = 0; query->db = db; query->view = NULL; + list_init( &query->mem ); - r = MSI_ParseSQL( db, szQuery, &query->view ); + r = MSI_ParseSQL( db, szQuery, &query->view, &query->mem ); if( r == ERROR_SUCCESS ) { msiobj_addref( &query->hdr ); @@ -141,7 +148,7 @@ UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) /* figure out how much space we need to allocate */ va_start(va, fmt); - sz = strlenW(fmt) + 1; + sz = lstrlenW(fmt) + 1; p = fmt; while (*p) { @@ -152,7 +159,7 @@ UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) switch (*p) { case 's': /* a string */ - sz += strlenW(va_arg(va,LPCWSTR)); + sz += lstrlenW(va_arg(va,LPCWSTR)); break; case 'd': case 'i': /* an integer -2147483648 seems to be longest */ diff --git a/reactos/lib/msi/order.c b/reactos/lib/msi/order.c index c23b1ef89ef..33947a0620f 100644 --- a/reactos/lib/msi/order.c +++ b/reactos/lib/msi/order.c @@ -264,40 +264,8 @@ MSIVIEWOPS order_ops = ORDER_delete }; -UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ) +static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name ) { - MSIORDERVIEW *ov = NULL; - UINT count = 0, r; - - TRACE("%p\n", ov ); - - r = table->ops->get_dimensions( table, NULL, &count ); - if( r != ERROR_SUCCESS ) - { - ERR("can't get table dimensions\n"); - return r; - } - - ov = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof *ov + sizeof (UINT) * count ); - if( !ov ) - return ERROR_FUNCTION_FAILED; - - /* fill the structure */ - ov->view.ops = &order_ops; - msiobj_addref( &db->hdr ); - ov->db = db; - ov->table = table; - ov->reorder = NULL; - ov->num_cols = 0; - *view = (MSIVIEW*) ov; - - return ERROR_SUCCESS; -} - -UINT ORDER_AddColumn( MSIVIEW *view, LPWSTR name ) -{ - MSIORDERVIEW *ov = (MSIORDERVIEW*)view; UINT n, count, r; MSIVIEW *table; @@ -332,3 +300,39 @@ UINT ORDER_AddColumn( MSIVIEW *view, LPWSTR name ) return ERROR_SUCCESS; } + +UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, + string_list *columns ) +{ + MSIORDERVIEW *ov = NULL; + UINT count = 0, r; + string_list *x; + + TRACE("%p\n", ov ); + + r = table->ops->get_dimensions( table, NULL, &count ); + if( r != ERROR_SUCCESS ) + { + ERR("can't get table dimensions\n"); + return r; + } + + ov = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof *ov + sizeof (UINT) * count ); + if( !ov ) + return ERROR_FUNCTION_FAILED; + + /* fill the structure */ + ov->view.ops = &order_ops; + msiobj_addref( &db->hdr ); + ov->db = db; + ov->table = table; + ov->reorder = NULL; + ov->num_cols = 0; + *view = (MSIVIEW*) ov; + + for( x = columns; x ; x = x->next ) + ORDER_AddColumn( ov, x->string ); + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/package.c b/reactos/lib/msi/package.c index 938de885d70..be257e1d9d0 100644 --- a/reactos/lib/msi/package.c +++ b/reactos/lib/msi/package.c @@ -73,7 +73,7 @@ static UINT clone_properties(MSIDATABASE *db) 'Y',' ','K','E','Y',' ','`','_','P','r','o','p','e','r','t','y','`',')',0}; static const WCHAR Query[] = { 'S','E','L','E','C','T',' ','*',' ', - 'f','r','o','m',' ','P','r','o','p','e','r','t','y',0}; + 'F','R','O','M',' ','`','P','r','o','p','e','r','t','y','`',0}; static const WCHAR Insert[] = { 'I','N','S','E','R','T',' ','i','n','t','o',' ', '`','_','P','r','o','p','e','r','t','y','`',' ', @@ -139,6 +139,7 @@ static VOID set_installer_properties(MSIPACKAGE *package) WCHAR pth[MAX_PATH]; WCHAR *ptr; OSVERSIONINFOA OSVersion; + MEMORYSTATUSEX msex; DWORD verval; WCHAR verstr[10], bufstr[20]; HDC dc; @@ -202,6 +203,7 @@ static VOID set_installer_properties(MSIPACKAGE *package) static const WCHAR szSix[] = {'6',0 }; static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 }; + static const WCHAR szPhysicalMemory[] = { 'P','h','y','s','i','c','a','l','M','e','m','o','r','y',0 }; static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0}; /* Screen properties */ static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0}; @@ -217,7 +219,6 @@ ComputerName UserLanguageID LogonUser VirtualMemory -PhysicalMemory Intel ShellAdvSupport DefaultUIFont @@ -306,6 +307,12 @@ Privileged SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth); strcatW(pth,cszbs); MSI_SetPropertyW(package, WF, pth); + + /* Physical Memory is specified in MB. Using total amount. */ + msex.dwLength = sizeof(msex); + GlobalMemoryStatusEx( &msex ); + sprintfW( bufstr, szScreenFormat, (int)(msex.ullTotalPhys/1024/1024)); + MSI_SetPropertyW(package, szPhysicalMemory, bufstr); SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth); ptr = strchrW(pth,'\\'); @@ -740,9 +747,10 @@ static UINT MSI_GetPropertyRow(MSIPACKAGE *package, LPCWSTR szName, MSIRECORD ** MSIQUERY *view; UINT rc, sz; static const WCHAR select[]= - {'s','e','l','e','c','t',' ','V','a','l','u','e',' ','f','r','o','m',' ' - ,'_','P','r','o','p','e','r','t','y',' ','w','h','e','r','e',' ' - ,'_','P','r','o','p','e','r','t','y','=','`','%','s','`',0}; + {'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ', + 'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`', + ' ','W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`', + '=','\'','%','s','\'',0}; LPWSTR query; if (!szName) @@ -793,7 +801,7 @@ UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, else { *pchValueBuf = 0; - TRACE("property not found\n"); + TRACE("property %s not found\n", debugstr_w(szName)); } return rc; diff --git a/reactos/lib/msi/query.h b/reactos/lib/msi/query.h index b66cc589df4..7227129405d 100644 --- a/reactos/lib/msi/query.h +++ b/reactos/lib/msi/query.h @@ -30,6 +30,7 @@ #include "msi.h" #include "msiquery.h" #include "msipriv.h" +#include "wine/list.h" #define OP_EQ 1 @@ -50,7 +51,6 @@ #define EXPR_SVAL 5 #define EXPR_UVAL 6 #define EXPR_STRCMP 7 -#define EXPR_UTF8 8 #define EXPR_WILDCARD 9 #define EXPR_COL_NUMBER_STRING 10 @@ -83,7 +83,6 @@ struct expr LPWSTR sval; LPWSTR column; UINT col_number; - char *utf8; } u; }; @@ -107,7 +106,8 @@ typedef struct _column_assignment } column_assignment; -UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phView); +UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview, + struct list *mem ); UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view ); @@ -116,8 +116,8 @@ UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ); -UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ); -UINT ORDER_AddColumn( MSIVIEW *group, LPWSTR name ); +UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, + string_list *columns ); UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, struct expr *cond ); @@ -133,10 +133,6 @@ UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **, LPWSTR table, UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ); -void delete_expr( struct expr *e ); -void delete_string_list( string_list *sl ); -void delete_value_list( value_list *vl ); - int sqliteGetToken(const WCHAR *z, int *tokenType); #endif /* __WINE_MSI_QUERY_H */ diff --git a/reactos/lib/msi/record.c b/reactos/lib/msi/record.c index a06b0a58658..2b0469040c2 100644 --- a/reactos/lib/msi/record.c +++ b/reactos/lib/msi/record.c @@ -98,6 +98,7 @@ MSIHANDLE WINAPI MsiCreateRecord( unsigned int cParams ) rec = MSI_CreateRecord( cParams ); if( rec ) ret = alloc_msihandle( &rec->hdr ); + msiobj_release( &rec->hdr ); return ret; } diff --git a/reactos/lib/msi/registry.c b/reactos/lib/msi/registry.c index c6de5692a96..15e91090dc5 100644 --- a/reactos/lib/msi/registry.c +++ b/reactos/lib/msi/registry.c @@ -85,6 +85,13 @@ static const WCHAR szInstaller_Components_fmt[] = { 'C','o','m','p','o','n','e','n','t','s','\\', '%','s',0}; +static const WCHAR szUser_Components_fmt[] = { +'S','o','f','t','w','a','r','e','\\', +'M','i','c','r','o','s','o','f','t','\\', +'I','n','s','t','a','l','l','e','r','\\', +'C','o','m','p','o','n','e','n','t','s','\\', +'%','s',0}; + static const WCHAR szUninstall_fmt[] = { 'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', @@ -388,6 +395,26 @@ UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create) return rc; } +UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create) +{ + UINT rc; + WCHAR squished_cc[GUID_SIZE]; + WCHAR keypath[0x200]; + + TRACE("%s\n",debugstr_w(szComponent)); + squash_guid(szComponent,squished_cc); + TRACE("squished (%s)\n", debugstr_w(squished_cc)); + + sprintfW(keypath,szUser_Components_fmt,squished_cc); + + if (create) + rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key); + else + rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key); + + return rc; +} + UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create) { UINT rc; @@ -695,26 +722,154 @@ UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct) return r; } +/************************************************************************* + * MsiEnumComponentQualifiersA [MSI.@] + * + */ UINT WINAPI MsiEnumComponentQualifiersA( LPSTR szComponent, DWORD iIndex, LPSTR lpQualifierBuf, DWORD* pcchQualifierBuf, LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf) { - FIXME("%s %08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex, + LPWSTR szwComponent; + LPWSTR lpwQualifierBuf; + DWORD pcchwQualifierBuf; + LPWSTR lpwApplicationDataBuf; + DWORD pcchwApplicationDataBuf; + DWORD rc; + DWORD length; + + TRACE("%s %08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf); - return ERROR_CALL_NOT_IMPLEMENTED; + + szwComponent = strdupAtoW(szComponent); + + if (lpQualifierBuf) + lpwQualifierBuf = HeapAlloc(GetProcessHeap(),0, (*pcchQualifierBuf) * + sizeof(WCHAR)); + else + lpwQualifierBuf = NULL; + + if (pcchQualifierBuf) + pcchwQualifierBuf = *pcchQualifierBuf; + else + pcchwQualifierBuf = 0; + + if (lpApplicationDataBuf) + lpwApplicationDataBuf = HeapAlloc(GetProcessHeap(),0 , + (*pcchApplicationDataBuf) * sizeof(WCHAR)); + else + lpwApplicationDataBuf = NULL; + + if (pcchApplicationDataBuf) + pcchwApplicationDataBuf = *pcchApplicationDataBuf; + else + pcchwApplicationDataBuf = 0; + + rc = MsiEnumComponentQualifiersW( szwComponent, iIndex, lpwQualifierBuf, + &pcchwQualifierBuf, lpwApplicationDataBuf, + &pcchwApplicationDataBuf); + + /* + * A bit of wizardry to report back the length without the null. + * just in case the buffer is too small and is filled. + */ + if (lpQualifierBuf) + { + length = WideCharToMultiByte(CP_ACP, 0, lpwQualifierBuf, -1, + lpQualifierBuf, *pcchQualifierBuf, NULL, NULL); + + if (*pcchQualifierBuf == length && lpQualifierBuf[length-1]) + *pcchQualifierBuf = length; + else + *pcchQualifierBuf = length - 1; + } + if (lpApplicationDataBuf) + { + length = WideCharToMultiByte(CP_ACP, 0, + lpwApplicationDataBuf, -1, lpApplicationDataBuf, + *pcchApplicationDataBuf, NULL, NULL); + + if (*pcchApplicationDataBuf == length && lpApplicationDataBuf[length-1]) + *pcchApplicationDataBuf = length; + else + *pcchApplicationDataBuf = length - 1; + } + + HeapFree(GetProcessHeap(),0,lpwApplicationDataBuf); + HeapFree(GetProcessHeap(),0,lpwQualifierBuf); + HeapFree(GetProcessHeap(),0,szwComponent); + + return rc; } +/************************************************************************* + * MsiEnumComponentQualifiersW [MSI.@] + * + */ UINT WINAPI MsiEnumComponentQualifiersW( LPWSTR szComponent, DWORD iIndex, LPWSTR lpQualifierBuf, DWORD* pcchQualifierBuf, LPWSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf ) { - FIXME("%s %08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex, + UINT rc; + HKEY key; + DWORD actual_pcchQualifierBuf = 0; + DWORD actual_pcchApplicationDataBuf = 0; + LPWSTR full_buffer = NULL; + DWORD full_buffer_size = 0; + LPWSTR ptr; + + TRACE("%s %08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf); - return ERROR_CALL_NOT_IMPLEMENTED; + + if (pcchQualifierBuf) + actual_pcchQualifierBuf = *pcchQualifierBuf * sizeof(WCHAR); + if (pcchApplicationDataBuf) + actual_pcchApplicationDataBuf = *pcchApplicationDataBuf * sizeof(WCHAR); + + rc = MSIREG_OpenUserComponentsKey(szComponent, &key, FALSE); + if (rc != ERROR_SUCCESS) + return ERROR_UNKNOWN_COMPONENT; + + full_buffer_size = (52 * sizeof(WCHAR)) + actual_pcchApplicationDataBuf; + full_buffer = HeapAlloc(GetProcessHeap(),0,full_buffer_size); + + rc = RegEnumValueW(key, iIndex, lpQualifierBuf, pcchQualifierBuf, NULL, + NULL, (LPBYTE)full_buffer, &full_buffer_size); + + RegCloseKey(key); + + if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA) + { + if (lpApplicationDataBuf && pcchApplicationDataBuf) + { + ptr = full_buffer; + /* Skip the first guid */ + ptr += 21; + + /* Skip the name and the component guid if it exists */ + if (strchrW(ptr,'<')) + ptr = strchrW(ptr,'<'); + else + ptr = strchrW(ptr,'>') + 21; + + lstrcpynW(lpApplicationDataBuf,ptr,*pcchApplicationDataBuf); + *pcchApplicationDataBuf = strlenW(ptr); + } + if (lpQualifierBuf && pcchQualifierBuf) + *pcchQualifierBuf /= sizeof(WCHAR); + TRACE("Providing %s and %s\n", debugstr_w(lpQualifierBuf), + debugstr_w(lpApplicationDataBuf)); + } + + return rc; } +/************************************************************************* + * MsiEnumRelatedProductsW [MSI.@] + * + */ UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved, DWORD iProductIndex, LPWSTR lpProductBuf) { @@ -742,6 +897,10 @@ UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved, return r; } +/************************************************************************* + * MsiEnumRelatedProductsA [MSI.@] + * + */ UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved, DWORD iProductIndex, LPSTR lpProductBuf) { diff --git a/reactos/lib/msi/sql.tab.c b/reactos/lib/msi/sql.tab.c index 874691c4c28..524ddda0788 100644 --- a/reactos/lib/msi/sql.tab.c +++ b/reactos/lib/msi/sql.tab.c @@ -1,2514 +1,2148 @@ -/* A Bison parser, made by GNU Bison 1.875b. */ - -/* Skeleton parser for Yacc-like parsing with Bison, - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* Written by Richard Stallman by simplifying the original so called - ``semantic'' parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 1 - -/* Using locations. */ -#define YYLSP_NEEDED 0 - -/* If NAME_PREFIX is specified substitute the variables and functions - names. */ -#define yyparse SQL_parse -#define yylex SQL_lex -#define yyerror SQL_error -#define yylval SQL_lval -#define yychar SQL_char -#define yydebug SQL_debug -#define yynerrs SQL_nerrs - - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - TK_ABORT = 258, - TK_AFTER = 259, - TK_AGG_FUNCTION = 260, - TK_ALL = 261, - TK_AND = 262, - TK_AS = 263, - TK_ASC = 264, - TK_BEFORE = 265, - TK_BEGIN = 266, - TK_BETWEEN = 267, - TK_BITAND = 268, - TK_BITNOT = 269, - TK_BITOR = 270, - TK_BY = 271, - TK_CASCADE = 272, - TK_CASE = 273, - TK_CHAR = 274, - TK_CHECK = 275, - TK_CLUSTER = 276, - TK_COLLATE = 277, - TK_COLUMN = 278, - TK_COMMA = 279, - TK_COMMENT = 280, - TK_COMMIT = 281, - TK_CONCAT = 282, - TK_CONFLICT = 283, - TK_CONSTRAINT = 284, - TK_COPY = 285, - TK_CREATE = 286, - TK_DEFAULT = 287, - TK_DEFERRABLE = 288, - TK_DEFERRED = 289, - TK_DELETE = 290, - TK_DELIMITERS = 291, - TK_DESC = 292, - TK_DISTINCT = 293, - TK_DOT = 294, - TK_DROP = 295, - TK_EACH = 296, - TK_ELSE = 297, - TK_END = 298, - TK_END_OF_FILE = 299, - TK_EQ = 300, - TK_EXCEPT = 301, - TK_EXPLAIN = 302, - TK_FAIL = 303, - TK_FLOAT = 304, - TK_FOR = 305, - TK_FOREIGN = 306, - TK_FROM = 307, - TK_FUNCTION = 308, - TK_GE = 309, - TK_GLOB = 310, - TK_GROUP = 311, - TK_GT = 312, - TK_HAVING = 313, - TK_HOLD = 314, - TK_IGNORE = 315, - TK_ILLEGAL = 316, - TK_IMMEDIATE = 317, - TK_IN = 318, - TK_INDEX = 319, - TK_INITIALLY = 320, - TK_ID = 321, - TK_INSERT = 322, - TK_INSTEAD = 323, - TK_INT = 324, - TK_INTEGER = 325, - TK_INTERSECT = 326, - TK_INTO = 327, - TK_IS = 328, - TK_ISNULL = 329, - TK_JOIN = 330, - TK_JOIN_KW = 331, - TK_KEY = 332, - TK_LE = 333, - TK_LIKE = 334, - TK_LIMIT = 335, - TK_LONG = 336, - TK_LONGCHAR = 337, - TK_LP = 338, - TK_LSHIFT = 339, - TK_LT = 340, - TK_LOCALIZABLE = 341, - TK_MATCH = 342, - TK_MINUS = 343, - TK_NE = 344, - TK_NOT = 345, - TK_NOTNULL = 346, - TK_NULL = 347, - TK_OBJECT = 348, - TK_OF = 349, - TK_OFFSET = 350, - TK_ON = 351, - TK_OR = 352, - TK_ORACLE_OUTER_JOIN = 353, - TK_ORDER = 354, - TK_PLUS = 355, - TK_PRAGMA = 356, - TK_PRIMARY = 357, - TK_RAISE = 358, - TK_REFERENCES = 359, - TK_REM = 360, - TK_REPLACE = 361, - TK_RESTRICT = 362, - TK_ROLLBACK = 363, - TK_ROW = 364, - TK_RP = 365, - TK_RSHIFT = 366, - TK_SELECT = 367, - TK_SEMI = 368, - TK_SET = 369, - TK_SHORT = 370, - TK_SLASH = 371, - TK_SPACE = 372, - TK_STAR = 373, - TK_STATEMENT = 374, - TK_STRING = 375, - TK_TABLE = 376, - TK_TEMP = 377, - TK_THEN = 378, - TK_TRANSACTION = 379, - TK_TRIGGER = 380, - TK_UMINUS = 381, - TK_UNCLOSED_STRING = 382, - TK_UNION = 383, - TK_UNIQUE = 384, - TK_UPDATE = 385, - TK_UPLUS = 386, - TK_USING = 387, - TK_VACUUM = 388, - TK_VALUES = 389, - TK_VIEW = 390, - TK_WHEN = 391, - TK_WHERE = 392, - TK_WILDCARD = 393, - COLUMN = 395, - FUNCTION = 396, - COMMENT = 397, - UNCLOSED_STRING = 398, - SPACE = 399, - ILLEGAL = 400, - END_OF_FILE = 401 - }; -#endif -#define TK_ABORT 258 -#define TK_AFTER 259 -#define TK_AGG_FUNCTION 260 -#define TK_ALL 261 -#define TK_AND 262 -#define TK_AS 263 -#define TK_ASC 264 -#define TK_BEFORE 265 -#define TK_BEGIN 266 -#define TK_BETWEEN 267 -#define TK_BITAND 268 -#define TK_BITNOT 269 -#define TK_BITOR 270 -#define TK_BY 271 -#define TK_CASCADE 272 -#define TK_CASE 273 -#define TK_CHAR 274 -#define TK_CHECK 275 -#define TK_CLUSTER 276 -#define TK_COLLATE 277 -#define TK_COLUMN 278 -#define TK_COMMA 279 -#define TK_COMMENT 280 -#define TK_COMMIT 281 -#define TK_CONCAT 282 -#define TK_CONFLICT 283 -#define TK_CONSTRAINT 284 -#define TK_COPY 285 -#define TK_CREATE 286 -#define TK_DEFAULT 287 -#define TK_DEFERRABLE 288 -#define TK_DEFERRED 289 -#define TK_DELETE 290 -#define TK_DELIMITERS 291 -#define TK_DESC 292 -#define TK_DISTINCT 293 -#define TK_DOT 294 -#define TK_DROP 295 -#define TK_EACH 296 -#define TK_ELSE 297 -#define TK_END 298 -#define TK_END_OF_FILE 299 -#define TK_EQ 300 -#define TK_EXCEPT 301 -#define TK_EXPLAIN 302 -#define TK_FAIL 303 -#define TK_FLOAT 304 -#define TK_FOR 305 -#define TK_FOREIGN 306 -#define TK_FROM 307 -#define TK_FUNCTION 308 -#define TK_GE 309 -#define TK_GLOB 310 -#define TK_GROUP 311 -#define TK_GT 312 -#define TK_HAVING 313 -#define TK_HOLD 314 -#define TK_IGNORE 315 -#define TK_ILLEGAL 316 -#define TK_IMMEDIATE 317 -#define TK_IN 318 -#define TK_INDEX 319 -#define TK_INITIALLY 320 -#define TK_ID 321 -#define TK_INSERT 322 -#define TK_INSTEAD 323 -#define TK_INT 324 -#define TK_INTEGER 325 -#define TK_INTERSECT 326 -#define TK_INTO 327 -#define TK_IS 328 -#define TK_ISNULL 329 -#define TK_JOIN 330 -#define TK_JOIN_KW 331 -#define TK_KEY 332 -#define TK_LE 333 -#define TK_LIKE 334 -#define TK_LIMIT 335 -#define TK_LONG 336 -#define TK_LONGCHAR 337 -#define TK_LP 338 -#define TK_LSHIFT 339 -#define TK_LT 340 -#define TK_LOCALIZABLE 341 -#define TK_MATCH 342 -#define TK_MINUS 343 -#define TK_NE 344 -#define TK_NOT 345 -#define TK_NOTNULL 346 -#define TK_NULL 347 -#define TK_OBJECT 348 -#define TK_OF 349 -#define TK_OFFSET 350 -#define TK_ON 351 -#define TK_OR 352 -#define TK_ORACLE_OUTER_JOIN 353 -#define TK_ORDER 354 -#define TK_PLUS 355 -#define TK_PRAGMA 356 -#define TK_PRIMARY 357 -#define TK_RAISE 358 -#define TK_REFERENCES 359 -#define TK_REM 360 -#define TK_REPLACE 361 -#define TK_RESTRICT 362 -#define TK_ROLLBACK 363 -#define TK_ROW 364 -#define TK_RP 365 -#define TK_RSHIFT 366 -#define TK_SELECT 367 -#define TK_SEMI 368 -#define TK_SET 369 -#define TK_SHORT 370 -#define TK_SLASH 371 -#define TK_SPACE 372 -#define TK_STAR 373 -#define TK_STATEMENT 374 -#define TK_STRING 375 -#define TK_TABLE 376 -#define TK_TEMP 377 -#define TK_THEN 378 -#define TK_TRANSACTION 379 -#define TK_TRIGGER 380 -#define TK_UMINUS 381 -#define TK_UNCLOSED_STRING 382 -#define TK_UNION 383 -#define TK_UNIQUE 384 -#define TK_UPDATE 385 -#define TK_UPLUS 386 -#define TK_USING 387 -#define TK_VACUUM 388 -#define TK_VALUES 389 -#define TK_VIEW 390 -#define TK_WHEN 391 -#define TK_WHERE 392 -#define TK_WILDCARD 393 -#define COLUMN 395 -#define FUNCTION 396 -#define COMMENT 397 -#define UNCLOSED_STRING 398 -#define SPACE 399 -#define ILLEGAL 400 -#define END_OF_FILE 401 - - - - -/* Copy the first part of user declarations. */ -#line 1 "./sql.y" - - -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002-2004 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "config.h" - -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "query.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -#define YYLEX_PARAM info -#define YYPARSE_PARAM info - -extern int SQL_error(const char *str); - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -typedef struct tag_SQL_input -{ - MSIDATABASE *db; - LPCWSTR command; - DWORD n, len; - MSIVIEW **view; /* view structure for the resulting query */ -} SQL_input; - -static LPWSTR SQL_getstring( struct sql_str *str ); -static INT SQL_getint( SQL_input *sql ); -static int SQL_lex( void *SQL_lval, SQL_input *info); - -static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, - string_list *columns ); -static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, - string_list *columns ); - -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, - string_list *keys); - -static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r ); -static struct expr * EXPR_column( LPWSTR ); -static struct expr * EXPR_ival( struct sql_str *, int sign); -static struct expr * EXPR_sval( struct sql_str *); -static struct expr * EXPR_wildcard(); - - - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) -#line 74 "./sql.y" -typedef union YYSTYPE { - struct sql_str str; - LPWSTR string; - string_list *column_list; - value_list *val_list; - MSIVIEW *query; - struct expr *expr; - USHORT column_type; - create_col_info *column_info; - column_assignment update_col_info; -} YYSTYPE; -/* Line 191 of yacc.c. */ -#line 457 "sql.tab.c" -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - - - -/* Copy the second part of user declarations. */ - - -/* Line 214 of yacc.c. */ -#line 469 "sql.tab.c" - -#if ! defined (yyoverflow) || YYERROR_VERBOSE - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# if YYSTACK_USE_ALLOCA -# define YYSTACK_ALLOC alloca -# else -# ifndef YYSTACK_USE_ALLOCA -# if defined (alloca) || defined (_ALLOCA_H) -# define YYSTACK_ALLOC alloca -# else -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# else -# if defined (__STDC__) || defined (__cplusplus) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -# define YYSTACK_ALLOC malloc -# define YYSTACK_FREE free -# endif -#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ - - -#if (! defined (yyoverflow) \ - && (! defined (__cplusplus) \ - || (YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - short yyss; - YYSTYPE yyvs; - }; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - register YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (0) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) - -#endif - -#if defined (__STDC__) || defined (__cplusplus) - typedef signed char yysigned_char; -#else - typedef short yysigned_char; -#endif - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 27 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 128 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 147 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 26 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 65 -/* YYNRULES -- Number of states. */ -#define YYNSTATES 126 - -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 401 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ -static const unsigned char yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, - 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, - 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, - 145, 146 -}; - -#if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const unsigned char yyprhs[] = -{ - 0, 0, 3, 5, 7, 9, 11, 13, 24, 36, - 43, 51, 58, 61, 66, 71, 74, 76, 79, 81, - 85, 87, 92, 94, 96, 98, 100, 102, 104, 109, - 111, 115, 120, 122, 126, 128, 131, 136, 140, 144, - 148, 152, 156, 160, 164, 168, 172, 176, 180, 185, - 187, 189, 191, 195, 197, 201, 205, 207, 210, 212, - 214, 216, 220, 222, 224, 226 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const short yyrhs[] = -{ - 148, 0, -1, 159, -1, 150, -1, 149, -1, 151, - -1, 152, -1, 67, 72, 171, 83, 161, 110, 134, - 83, 165, 110, -1, 67, 72, 171, 83, 161, 110, - 134, 83, 165, 110, 122, -1, 31, 121, 171, 83, - 153, 110, -1, 31, 121, 171, 83, 153, 110, 59, - -1, 130, 171, 114, 166, 137, 163, -1, 35, 162, - -1, 154, 102, 77, 161, -1, 154, 24, 170, 155, - -1, 170, 155, -1, 156, -1, 156, 86, -1, 157, - -1, 157, 90, 92, -1, 19, -1, 19, 83, 158, - 110, -1, 82, -1, 115, -1, 69, -1, 81, -1, - 93, -1, 70, -1, 160, 99, 16, 161, -1, 160, - -1, 112, 161, 162, -1, 112, 38, 161, 162, -1, - 170, -1, 170, 24, 161, -1, 118, -1, 52, 171, - -1, 52, 171, 137, 163, -1, 83, 163, 110, -1, - 169, 45, 169, -1, 163, 7, 163, -1, 163, 97, - 163, -1, 169, 45, 164, -1, 169, 57, 164, -1, - 169, 85, 164, -1, 169, 78, 164, -1, 169, 54, - 164, -1, 169, 89, 164, -1, 169, 73, 92, -1, - 169, 73, 90, 92, -1, 169, -1, 168, -1, 168, - -1, 168, 24, 165, -1, 167, -1, 167, 24, 166, - -1, 170, 45, 168, -1, 70, -1, 88, 70, -1, - 120, -1, 138, -1, 170, -1, 171, 39, 172, -1, - 172, -1, 172, -1, 66, -1, 120, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const unsigned short yyrline[] = -{ - 0, 143, 143, 148, 153, 158, 163, 171, 179, 190, - 200, 213, 224, 235, 245, 264, 276, 280, 288, 292, - 299, 303, 307, 311, 315, 319, 323, 330, 341, 352, - 356, 370, 388, 401, 414, 421, 432, 451, 455, 459, - 463, 467, 471, 475, 479, 483, 487, 491, 495, 502, - 503, 507, 519, 534, 535, 544, 560, 564, 568, 572, - 579, 586, 590, 597, 604, 608 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE -/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "$end", "error", "$undefined", "TK_ABORT", "TK_AFTER", "TK_AGG_FUNCTION", - "TK_ALL", "TK_AND", "TK_AS", "TK_ASC", "TK_BEFORE", "TK_BEGIN", - "TK_BETWEEN", "TK_BITAND", "TK_BITNOT", "TK_BITOR", "TK_BY", - "TK_CASCADE", "TK_CASE", "TK_CHAR", "TK_CHECK", "TK_CLUSTER", - "TK_COLLATE", "TK_COLUMN", "TK_COMMA", "TK_COMMENT", "TK_COMMIT", - "TK_CONCAT", "TK_CONFLICT", "TK_CONSTRAINT", "TK_COPY", "TK_CREATE", - "TK_DEFAULT", "TK_DEFERRABLE", "TK_DEFERRED", "TK_DELETE", - "TK_DELIMITERS", "TK_DESC", "TK_DISTINCT", "TK_DOT", "TK_DROP", - "TK_EACH", "TK_ELSE", "TK_END", "TK_END_OF_FILE", "TK_EQ", "TK_EXCEPT", - "TK_EXPLAIN", "TK_FAIL", "TK_FLOAT", "TK_FOR", "TK_FOREIGN", "TK_FROM", - "TK_FUNCTION", "TK_GE", "TK_GLOB", "TK_GROUP", "TK_GT", "TK_HAVING", - "TK_HOLD", "TK_IGNORE", "TK_ILLEGAL", "TK_IMMEDIATE", "TK_IN", - "TK_INDEX", "TK_INITIALLY", "TK_ID", "TK_INSERT", "TK_INSTEAD", - "TK_INT", "TK_INTEGER", "TK_INTERSECT", "TK_INTO", "TK_IS", "TK_ISNULL", - "TK_JOIN", "TK_JOIN_KW", "TK_KEY", "TK_LE", "TK_LIKE", "TK_LIMIT", - "TK_LONG", "TK_LONGCHAR", "TK_LP", "TK_LSHIFT", "TK_LT", - "TK_LOCALIZABLE", "TK_MATCH", "TK_MINUS", "TK_NE", "TK_NOT", - "TK_NOTNULL", "TK_NULL", "TK_OBJECT", "TK_OF", "TK_OFFSET", "TK_ON", - "TK_OR", "TK_ORACLE_OUTER_JOIN", "TK_ORDER", "TK_PLUS", "TK_PRAGMA", - "TK_PRIMARY", "TK_RAISE", "TK_REFERENCES", "TK_REM", "TK_REPLACE", - "TK_RESTRICT", "TK_ROLLBACK", "TK_ROW", "TK_RP", "TK_RSHIFT", - "TK_SELECT", "TK_SEMI", "TK_SET", "TK_SHORT", "TK_SLASH", "TK_SPACE", - "TK_STAR", "TK_STATEMENT", "TK_STRING", "TK_TABLE", "TK_TEMP", - "TK_THEN", "TK_TRANSACTION", "TK_TRIGGER", "TK_UMINUS", - "TK_UNCLOSED_STRING", "TK_UNION", "TK_UNIQUE", "TK_UPDATE", "TK_UPLUS", - "TK_USING", "TK_VACUUM", "TK_VALUES", "TK_VIEW", "TK_WHEN", "TK_WHERE", - "TK_WILDCARD", "AGG_FUNCTION.", "COLUMN", "FUNCTION", "COMMENT", - "UNCLOSED_STRING", "SPACE", "ILLEGAL", "END_OF_FILE", "$accept", - "onequery", "oneinsert", "onecreate", "oneupdate", "onedelete", - "table_def", "column_def", "column_type", "data_type_l", "data_type", - "data_count", "oneselect", "unorderedsel", "selcollist", "from", "expr", - "val", "constlist", "update_assign_list", "column_assignment", - "const_val", "column_val", "column", "table", "string_or_id", 0 -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ -static const unsigned short yytoknum[] = -{ - 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, - 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, - 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 401 -}; -# endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const unsigned char yyr1[] = -{ - 0, 147, 148, 148, 148, 148, 148, 149, 149, 150, - 150, 151, 152, 153, 154, 154, 155, 155, 156, 156, - 157, 157, 157, 157, 157, 157, 157, 158, 159, 159, - 160, 160, 161, 161, 161, 162, 162, 163, 163, 163, - 163, 163, 163, 163, 163, 163, 163, 163, 163, 164, - 164, 165, 165, 166, 166, 167, 168, 168, 168, 168, - 169, 170, 170, 171, 172, 172 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const unsigned char yyr2[] = -{ - 0, 2, 1, 1, 1, 1, 1, 10, 11, 6, - 7, 6, 2, 4, 4, 2, 1, 2, 1, 3, - 1, 4, 1, 1, 1, 1, 1, 1, 4, 1, - 3, 4, 1, 3, 1, 2, 4, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 4, 1, - 1, 1, 3, 1, 3, 3, 1, 2, 1, 1, - 1, 3, 1, 1, 1, 1 -}; - -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ -static const unsigned char yydefact[] = -{ - 0, 0, 0, 0, 0, 0, 0, 4, 3, 5, - 6, 2, 29, 0, 0, 12, 0, 0, 64, 34, - 65, 0, 32, 0, 62, 0, 63, 1, 0, 0, - 35, 0, 0, 30, 0, 0, 0, 0, 0, 0, - 0, 31, 33, 61, 0, 53, 0, 28, 0, 0, - 0, 0, 36, 0, 60, 0, 0, 0, 0, 9, - 0, 0, 20, 24, 25, 22, 26, 23, 15, 16, - 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 11, 54, 56, 0, 58, 59, 55, 10, - 0, 0, 0, 17, 0, 37, 39, 40, 58, 41, - 50, 38, 45, 49, 42, 0, 47, 44, 43, 46, - 0, 57, 14, 13, 27, 0, 19, 48, 0, 21, - 0, 51, 7, 0, 8, 52 -}; - -/* YYDEFGOTO[NTERM-NUM]. */ -static const yysigned_char yydefgoto[] = -{ - -1, 6, 7, 8, 9, 10, 48, 49, 68, 69, - 70, 115, 11, 12, 21, 15, 52, 99, 120, 44, - 45, 100, 53, 54, 23, 24 -}; - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -106 -static const yysigned_char yypact[] = -{ - -30, -105, -33, -54, -34, -51, 22, -106, -106, -106, - -106, -106, -79, -51, -51, -106, -51, -60, -106, -106, - -106, -33, 17, 10, 11, -63, -106, -106, 41, -24, - -75, -13, -33, -106, -60, -51, -51, -60, -51, -45, - -60, -106, -106, -106, -65, 50, 32, -106, -32, -15, - -17, -45, -4, 26, -106, -22, -45, -51, -59, 30, - -51, 24, 19, -106, -106, -106, -106, -106, -106, 21, - 15, -7, -45, -45, -53, -53, -53, -78, -53, -53, - -53, -28, -4, -106, -106, 46, -106, -106, -106, -106, - -17, -60, 47, -106, 27, -106, -4, -4, 79, -106, - -106, -106, -106, -106, -106, 28, -106, -106, -106, -106, - 38, -106, -106, -106, -106, 12, -106, -106, -59, -106, - 13, 100, 3, -59, -106, -106 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const yysigned_char yypgoto[] = -{ - -106, -106, -106, -106, -106, -106, -106, -106, 36, -106, - -106, -106, -106, -106, -10, 7, -25, 16, 4, 71, - -106, -50, 34, 6, 40, 20 -}; - -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -66 -static const yysigned_char yytable[] = -{ - 72, 1, 62, 72, 17, 2, 18, 32, 88, 60, - 22, 84, 105, 18, 106, 18, 13, 84, 16, 14, - 28, 18, 27, 22, 42, 26, 71, 47, 33, 85, - 55, 82, 18, 26, 26, 85, 26, 3, 51, 41, - 22, 34, 46, 22, 50, 25, 22, 96, 97, 35, - -63, 36, 63, 29, 30, 43, 31, 37, 19, 38, - 20, 86, 39, 46, 64, 65, 90, 98, 121, 20, - 40, 74, 56, 121, 57, 20, 66, 58, 59, 87, - 75, 113, 4, 76, 19, 87, 20, 61, 81, 89, - 73, 102, 104, 73, 107, 108, 109, 22, 67, 77, - 5, 91, 92, 95, 78, 94, 110, 93, 101, 103, - 103, 79, 103, 103, 103, 80, 111, 114, -65, 116, - 117, 118, 119, 122, 123, 124, 112, 125, 83 -}; - -static const unsigned char yycheck[] = -{ - 7, 31, 19, 7, 38, 35, 66, 17, 58, 24, - 4, 70, 90, 66, 92, 66, 121, 70, 72, 52, - 99, 66, 0, 17, 34, 5, 51, 37, 21, 88, - 40, 56, 66, 13, 14, 88, 16, 67, 83, 32, - 34, 24, 36, 37, 38, 5, 40, 72, 73, 39, - 39, 114, 69, 13, 14, 35, 16, 16, 118, 83, - 120, 120, 137, 57, 81, 82, 60, 120, 118, 120, - 83, 45, 137, 123, 24, 120, 93, 45, 110, 138, - 54, 91, 112, 57, 118, 138, 120, 102, 110, 59, - 97, 75, 76, 97, 78, 79, 80, 91, 115, 73, - 130, 77, 83, 110, 78, 90, 134, 86, 74, 75, - 76, 85, 78, 79, 80, 89, 70, 70, 39, 92, - 92, 83, 110, 110, 24, 122, 90, 123, 57 -}; - -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const unsigned char yystos[] = -{ - 0, 31, 35, 67, 112, 130, 148, 149, 150, 151, - 152, 159, 160, 121, 52, 162, 72, 38, 66, 118, - 120, 161, 170, 171, 172, 171, 172, 0, 99, 171, - 171, 171, 161, 162, 24, 39, 114, 16, 83, 137, - 83, 162, 161, 172, 166, 167, 170, 161, 153, 154, - 170, 83, 163, 169, 170, 161, 137, 24, 45, 110, - 24, 102, 19, 69, 81, 82, 93, 115, 155, 156, - 157, 163, 7, 97, 45, 54, 57, 73, 78, 85, - 89, 110, 163, 166, 70, 88, 120, 138, 168, 59, - 170, 77, 83, 86, 90, 110, 163, 163, 120, 164, - 168, 169, 164, 169, 164, 90, 92, 164, 164, 164, - 134, 70, 155, 161, 70, 158, 92, 92, 83, 110, - 165, 168, 110, 24, 122, 165 -}; - -#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) -# define YYSIZE_T __SIZE_TYPE__ -#endif -#if ! defined (YYSIZE_T) && defined (size_t) -# define YYSIZE_T size_t -#endif -#if ! defined (YYSIZE_T) -# if defined (__STDC__) || defined (__cplusplus) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -#endif -#if ! defined (YYSIZE_T) -# define YYSIZE_T unsigned int -#endif - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrlab1 - - -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ - -#define YYFAIL goto yyerrlab - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ - YYPOPSTACK; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror ("syntax error: cannot back up");\ - YYERROR; \ - } \ -while (0) - -#define YYTERROR 1 -#define YYERRCODE 256 - -/* YYLLOC_DEFAULT -- Compute the default location (before the actions - are run). */ - -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - Current.first_line = Rhs[1].first_line; \ - Current.first_column = Rhs[1].first_column; \ - Current.last_line = Rhs[N].last_line; \ - Current.last_column = Rhs[N].last_column; -#endif - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#ifdef YYLEX_PARAM -# define YYLEX yylex (&yylval, YYLEX_PARAM) -#else -# define YYLEX yylex (&yylval) -#endif - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) - -# define YYDSYMPRINT(Args) \ -do { \ - if (yydebug) \ - yysymprint Args; \ -} while (0) - -# define YYDSYMPRINTF(Title, Token, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yysymprint (stderr, \ - Token, Value); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (0) - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (cinluded). | -`------------------------------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yy_stack_print (short *bottom, short *top) -#else -static void -yy_stack_print (bottom, top) - short *bottom; - short *top; -#endif -{ - YYFPRINTF (stderr, "Stack now"); - for (/* Nothing. */; bottom <= top; ++bottom) - YYFPRINTF (stderr, " %d", *bottom); - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (0) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yy_reduce_print (int yyrule) -#else -static void -yy_reduce_print (yyrule) - int yyrule; -#endif -{ - int yyi; - unsigned int yylno = yyrline[yyrule]; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", - yyrule - 1, yylno); - /* Print the symbols being reduced, and their result. */ - for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) - YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); - YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]); -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (Rule); \ -} while (0) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YYDSYMPRINT(Args) -# define YYDSYMPRINTF(Title, Token, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#if YYMAXDEPTH == 0 -# undef YYMAXDEPTH -#endif - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined (__GLIBC__) && defined (_STRING_H) -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -static YYSIZE_T -# if defined (__STDC__) || defined (__cplusplus) -yystrlen (const char *yystr) -# else -yystrlen (yystr) - const char *yystr; -# endif -{ - register const char *yys = yystr; - - while (*yys++ != '\0') - continue; - - return yys - yystr - 1; -} -# endif -# endif - -# ifndef yystpcpy -# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -static char * -# if defined (__STDC__) || defined (__cplusplus) -yystpcpy (char *yydest, const char *yysrc) -# else -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -# endif -{ - register char *yyd = yydest; - register const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -#endif /* !YYERROR_VERBOSE */ - - - -#if YYDEBUG -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) -#else -static void -yysymprint (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - /* Pacify ``unused variable'' warnings. */ - (void) yyvaluep; - - if (yytype < YYNTOKENS) - { - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); -# ifdef YYPRINT - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# endif - } - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - - switch (yytype) - { - default: - break; - } - YYFPRINTF (yyoutput, ")"); -} - -#endif /* ! YYDEBUG */ -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yydestruct (int yytype, YYSTYPE *yyvaluep) -#else -static void -yydestruct (yytype, yyvaluep) - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - /* Pacify ``unused variable'' warnings. */ - (void) yyvaluep; - - switch (yytype) - { - - default: - break; - } -} - - -/* Prevent warnings from -Wmissing-prototypes. */ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -int yyparse (void *YYPARSE_PARAM); -# else -int yyparse (); -# endif -#else /* ! YYPARSE_PARAM */ -#if defined (__STDC__) || defined (__cplusplus) -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - - - - - - -/*----------. -| yyparse. | -`----------*/ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -int yyparse (void *YYPARSE_PARAM) -# else -int yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -# endif -#else /* ! YYPARSE_PARAM */ -#if defined (__STDC__) || defined (__cplusplus) -int -yyparse (void) -#else -int -yyparse () - -#endif -#endif -{ - /* The lookahead symbol. */ -int yychar; - -/* The semantic value of the lookahead symbol. */ -YYSTYPE yylval; - -/* Number of syntax errors so far. */ -int yynerrs; - - register int yystate; - register int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Lookahead token as an internal (translated) token number. */ - int yytoken = 0; - - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - short yyssa[YYINITDEPTH]; - short *yyss = yyssa; - register short *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - register YYSTYPE *yyvsp; - - - -#define YYPOPSTACK (yyvsp--, yyssp--) - - YYSIZE_T yystacksize = YYINITDEPTH; - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - - - /* When reducing, the number of symbols on the RHS of the reduced - rule. */ - int yylen; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss; - yyvsp = yyvs; - - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. so pushing a state here evens the stacks. - */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - short *yyss1 = yyss; - - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyoverflowlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyoverflowlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - short *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyoverflowlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); - -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - -/* Do appropriate processing given the current state. */ -/* Read a lookahead token if we need one and don't already have one. */ -/* yyresume: */ - - /* First try to decide what to do without reference to lookahead token. */ - - yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - if (yyn == YYFINAL) - YYACCEPT; - - /* Shift the lookahead token. */ - YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken])); - - /* Discard the token being shifted unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - *++yyvsp = yylval; - - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - yystate = yyn; - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 2: -#line 144 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - *sql->view = yyvsp[0].query; - ;} - break; - - case 3: -#line 149 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - *sql->view = yyvsp[0].query; - ;} - break; - - case 4: -#line 154 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - *sql->view = yyvsp[0].query; - ;} - break; - - case 5: -#line 159 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - *sql->view = yyvsp[0].query; - ;} - break; - - case 6: -#line 164 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - *sql->view = yyvsp[0].query; - ;} - break; - - case 7: -#line 172 "./sql.y" - { - SQL_input *sql = (SQL_input*) info; - MSIVIEW *insert = NULL; - - INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].val_list, FALSE ); - yyval.query = insert; - ;} - break; - - case 8: -#line 180 "./sql.y" - { - SQL_input *sql = (SQL_input*) info; - MSIVIEW *insert = NULL; - - INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].val_list, TRUE ); - yyval.query = insert; - ;} - break; - - case 9: -#line 191 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - MSIVIEW *create = NULL; - - if( !yyvsp[-1].column_info ) - YYABORT; - CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_info, FALSE ); - yyval.query = create; - ;} - break; - - case 10: -#line 201 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - MSIVIEW *create = NULL; - - if( !yyvsp[-2].column_info ) - YYABORT; - CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_info, TRUE ); - yyval.query = create; - ;} - break; - - case 11: -#line 214 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - MSIVIEW *update = NULL; - - UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, &yyvsp[-2].update_col_info, yyvsp[0].expr ); - yyval.query = update; - ;} - break; - - case 12: -#line 225 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - MSIVIEW *delete = NULL; - - DELETE_CreateView( sql->db, &delete, yyvsp[0].query ); - yyval.query = delete; - ;} - break; - - case 13: -#line 236 "./sql.y" - { - if( SQL_MarkPrimaryKeys( yyvsp[-3].column_info, yyvsp[0].column_list ) ) - yyval.column_info = yyvsp[-3].column_info; - else - yyval.column_info = NULL; - ;} - break; - - case 14: -#line 246 "./sql.y" - { - create_col_info *ci; - - for( ci = yyvsp[-3].column_info; ci->next; ci = ci->next ) - ; - - ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); - if( !ci->next ) - { - /* FIXME: free $1 */ - YYABORT; - } - ci->next->colname = yyvsp[-1].string; - ci->next->type = yyvsp[0].column_type; - ci->next->next = NULL; - - yyval.column_info = yyvsp[-3].column_info; - ;} - break; - - case 15: -#line 265 "./sql.y" - { - yyval.column_info = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); - if( ! yyval.column_info ) - YYABORT; - yyval.column_info->colname = yyvsp[-1].string; - yyval.column_info->type = yyvsp[0].column_type; - yyval.column_info->next = NULL; - ;} - break; - - case 16: -#line 277 "./sql.y" - { - yyval.column_type = yyvsp[0].column_type | MSITYPE_VALID; - ;} - break; - - case 17: -#line 281 "./sql.y" - { - FIXME("LOCALIZABLE ignored\n"); - yyval.column_type = yyvsp[-1].column_type | MSITYPE_VALID; - ;} - break; - - case 18: -#line 289 "./sql.y" - { - yyval.column_type |= MSITYPE_NULLABLE; - ;} - break; - - case 19: -#line 293 "./sql.y" - { - yyval.column_type = yyvsp[-2].column_type; - ;} - break; - - case 20: -#line 300 "./sql.y" - { - yyval.column_type = MSITYPE_STRING | 1; - ;} - break; - - case 21: -#line 304 "./sql.y" - { - yyval.column_type = MSITYPE_STRING | 0x400 | yyvsp[-1].column_type; - ;} - break; - - case 22: -#line 308 "./sql.y" - { - yyval.column_type = 2; - ;} - break; - - case 23: -#line 312 "./sql.y" - { - yyval.column_type = 2; - ;} - break; - - case 24: -#line 316 "./sql.y" - { - yyval.column_type = 2; - ;} - break; - - case 25: -#line 320 "./sql.y" - { - yyval.column_type = 4; - ;} - break; - - case 26: -#line 324 "./sql.y" - { - yyval.column_type = 0; - ;} - break; - - case 27: -#line 331 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - int val = SQL_getint(sql); - if( ( val > 255 ) || ( val < 0 ) ) - YYABORT; - yyval.column_type = val; - ;} - break; - - case 28: -#line 342 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - - if( !yyvsp[-3].query ) - YYABORT; - if( yyvsp[0].column_list ) - yyval.query = do_order_by( sql->db, yyvsp[-3].query, yyvsp[0].column_list ); - else - yyval.query = yyvsp[-3].query; - ;} - break; - - case 30: -#line 357 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - if( !yyvsp[0].query ) - YYABORT; - if( yyvsp[-1].column_list ) - { - yyval.query = do_one_select( sql->db, yyvsp[0].query, yyvsp[-1].column_list ); - if( !yyval.query ) - YYABORT; - } - else - yyval.query = yyvsp[0].query; - ;} - break; - - case 31: -#line 371 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - MSIVIEW *view = yyvsp[0].query; - - if( !view ) - YYABORT; - if( yyvsp[-1].column_list ) - { - view = do_one_select( sql->db, view, yyvsp[-1].column_list ); - if( !view ) - YYABORT; - } - DISTINCT_CreateView( sql->db, & yyval.query, view ); - ;} - break; - - case 32: -#line 389 "./sql.y" - { - string_list *list; - - list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); - if( !list ) - YYABORT; - list->string = yyvsp[0].string; - list->next = NULL; - - yyval.column_list = list; - TRACE("Collist %s\n",debugstr_w(yyval.column_list->string)); - ;} - break; - - case 33: -#line 402 "./sql.y" - { - string_list *list; - - list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); - if( !list ) - YYABORT; - list->string = yyvsp[-2].string; - list->next = yyvsp[0].column_list; - - yyval.column_list = list; - TRACE("From table: %s\n",debugstr_w(yyval.column_list->string)); - ;} - break; - - case 34: -#line 415 "./sql.y" - { - yyval.column_list = NULL; - ;} - break; - - case 35: -#line 422 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - UINT r; - - yyval.query = NULL; - TRACE("From table: %s\n",debugstr_w(yyvsp[0].string)); - r = TABLE_CreateView( sql->db, yyvsp[0].string, & yyval.query ); - if( r != ERROR_SUCCESS ) - YYABORT; - ;} - break; - - case 36: -#line 433 "./sql.y" - { - SQL_input* sql = (SQL_input*) info; - MSIVIEW *view = NULL; - UINT r; - - yyval.query = NULL; - TRACE("From table: %s\n",debugstr_w(yyvsp[-2].string)); - r = TABLE_CreateView( sql->db, yyvsp[-2].string, &view ); - if( r != ERROR_SUCCESS ) - YYABORT; - r = WHERE_CreateView( sql->db, &view, view, yyvsp[0].expr ); - if( r != ERROR_SUCCESS ) - YYABORT; - yyval.query = view; - ;} - break; - - case 37: -#line 452 "./sql.y" - { - yyval.expr = yyvsp[-1].expr; - ;} - break; - - case 38: -#line 456 "./sql.y" - { - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); - ;} - break; - - case 39: -#line 460 "./sql.y" - { - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_AND, yyvsp[0].expr ); - ;} - break; - - case 40: -#line 464 "./sql.y" - { - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_OR, yyvsp[0].expr ); - ;} - break; - - case 41: -#line 468 "./sql.y" - { - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); - ;} - break; - - case 42: -#line 472 "./sql.y" - { - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_GT, yyvsp[0].expr ); - ;} - break; - - case 43: -#line 476 "./sql.y" - { - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_LT, yyvsp[0].expr ); - ;} - break; - - case 44: -#line 480 "./sql.y" - { - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_LE, yyvsp[0].expr ); - ;} - break; - - case 45: -#line 484 "./sql.y" - { - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_GE, yyvsp[0].expr ); - ;} - break; - - case 46: -#line 488 "./sql.y" - { - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_NE, yyvsp[0].expr ); - ;} - break; - - case 47: -#line 492 "./sql.y" - { - yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_ISNULL, NULL ); - ;} - break; - - case 48: -#line 496 "./sql.y" - { - yyval.expr = EXPR_complex( yyvsp[-3].expr, OP_NOTNULL, NULL ); - ;} - break; - - case 51: -#line 508 "./sql.y" - { - value_list *vals; - - vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals ); - if( vals ) - { - vals->val = yyvsp[0].expr; - vals->next = NULL; - } - yyval.val_list = vals; - ;} - break; - - case 52: -#line 520 "./sql.y" - { - value_list *vals; - - vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals ); - if( vals ) - { - vals->val = yyvsp[-2].expr; - vals->next = yyvsp[0].val_list; - } - yyval.val_list = vals; - ;} - break; - - case 54: -#line 536 "./sql.y" - { - yyvsp[-2].update_col_info.col_list->next = yyvsp[0].update_col_info.col_list; - yyvsp[-2].update_col_info.val_list->next = yyvsp[0].update_col_info.val_list; - yyval.update_col_info = yyvsp[-2].update_col_info; - ;} - break; - - case 55: -#line 545 "./sql.y" - { - yyval.update_col_info.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.col_list ); - if( !yyval.update_col_info.col_list ) - YYABORT; - yyval.update_col_info.col_list->string = yyvsp[-2].string; - yyval.update_col_info.col_list->next = NULL; - yyval.update_col_info.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.val_list ); - if( !yyval.update_col_info.val_list ) - YYABORT; - yyval.update_col_info.val_list->val = yyvsp[0].expr; - yyval.update_col_info.val_list->next = 0; - ;} - break; - - case 56: -#line 561 "./sql.y" - { - yyval.expr = EXPR_ival( &yyvsp[0].str, 1 ); - ;} - break; - - case 57: -#line 565 "./sql.y" - { - yyval.expr = EXPR_ival( &yyvsp[0].str, -1 ); - ;} - break; - - case 58: -#line 569 "./sql.y" - { - yyval.expr = EXPR_sval( &yyvsp[0].str ); - ;} - break; - - case 59: -#line 573 "./sql.y" - { - yyval.expr = EXPR_wildcard(); - ;} - break; - - case 60: -#line 580 "./sql.y" - { - yyval.expr = EXPR_column( yyvsp[0].string ); - ;} - break; - - case 61: -#line 587 "./sql.y" - { - yyval.string = yyvsp[0].string; /* FIXME */ - ;} - break; - - case 62: -#line 591 "./sql.y" - { - yyval.string = yyvsp[0].string; - ;} - break; - - case 63: -#line 598 "./sql.y" - { - yyval.string = yyvsp[0].string; - ;} - break; - - case 64: -#line 605 "./sql.y" - { - yyval.string = SQL_getstring( &yyvsp[0].str ); - ;} - break; - - case 65: -#line 609 "./sql.y" - { - yyval.string = SQL_getstring( &yyvsp[0].str ); - ;} - break; - - - } - -/* Line 999 of yacc.c. */ -#line 2073 "sql.tab.c" - - yyvsp -= yylen; - yyssp -= yylen; - - - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if YYERROR_VERBOSE - yyn = yypact[yystate]; - - if (YYPACT_NINF < yyn && yyn < YYLAST) - { - YYSIZE_T yysize = 0; - int yytype = YYTRANSLATE (yychar); - const char* yyprefix; - char *yymsg; - int yyx; - - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yycount = 0; - - yyprefix = ", expecting "; - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]); - yycount += 1; - if (yycount == 5) - { - yysize = 0; - break; - } - } - yysize += (sizeof ("syntax error, unexpected ") - + yystrlen (yytname[yytype])); - yymsg = (char *) YYSTACK_ALLOC (yysize); - if (yymsg != 0) - { - char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); - yyp = yystpcpy (yyp, yytname[yytype]); - - if (yycount < 5) - { - yyprefix = ", expecting "; - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - yyp = yystpcpy (yyp, yyprefix); - yyp = yystpcpy (yyp, yytname[yyx]); - yyprefix = " or "; - } - } - yyerror (yymsg); - YYSTACK_FREE (yymsg); - } - else - yyerror ("syntax error; also virtual memory exhausted"); - } - else -#endif /* YYERROR_VERBOSE */ - yyerror ("syntax error"); - } - - - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - /* Return failure if at end of input. */ - if (yychar == YYEOF) - { - /* Pop the error token. */ - YYPOPSTACK; - /* Pop the rest of the stack. */ - while (yyss < yyssp) - { - YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); - yydestruct (yystos[*yyssp], yyvsp); - YYPOPSTACK; - } - YYABORT; - } - - YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc); - yydestruct (yytoken, &yylval); - yychar = YYEMPTY; - - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*----------------------------------------------------. -| yyerrlab1 -- error raised explicitly by an action. | -`----------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); - yydestruct (yystos[yystate], yyvsp); - yyvsp--; - yystate = *--yyssp; - - YY_STACK_PRINT (yyss, yyssp); - } - - if (yyn == YYFINAL) - YYACCEPT; - - YYDPRINTF ((stderr, "Shifting error token, ")); - - *++yyvsp = yylval; - - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#ifndef yyoverflow -/*----------------------------------------------. -| yyoverflowlab -- parser overflow comes here. | -`----------------------------------------------*/ -yyoverflowlab: - yyerror ("parser stack overflow"); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif - return yyresult; -} - - -#line 614 "./sql.y" - - -int SQL_lex( void *SQL_lval, SQL_input *sql) -{ - int token; - struct sql_str * str = SQL_lval; - - do - { - sql->n += sql->len; - if( ! sql->command[sql->n] ) - return 0; /* end of input */ - - TRACE("string : %s\n", debugstr_w(&sql->command[sql->n])); - sql->len = sqliteGetToken( &sql->command[sql->n], &token ); - if( sql->len==0 ) - break; - str->data = &sql->command[sql->n]; - str->len = sql->len; - } - while( token == TK_SPACE ); - - TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len)); - - return token; -} - -LPWSTR SQL_getstring( struct sql_str *strdata) -{ - LPCWSTR p = strdata->data; - UINT len = strdata->len; - LPWSTR str; - - /* if there's quotes, remove them */ - if( ( (p[0]=='`') && (p[len-1]=='`') ) || - ( (p[0]=='\'') && (p[len-1]=='\'') ) ) - { - p++; - len -= 2; - } - str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR)); - if(!str ) - return str; - memcpy(str, p, len*sizeof(WCHAR) ); - str[len]=0; - - return str; -} - -INT SQL_getint( SQL_input *sql ) -{ - LPCWSTR p = &sql->command[sql->n]; - - return atoiW( p ); -} - -int SQL_error(const char *str) -{ - return 0; -} - -static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, - string_list *columns ) -{ - MSIVIEW *view = NULL; - - SELECT_CreateView( db, &view, in, columns ); - delete_string_list( columns ); - if( !view ) - ERR("Error creating select query\n"); - return view; -} - -static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, - string_list *columns ) -{ - MSIVIEW *view = NULL; - - ORDER_CreateView( db, &view, in ); - if( view ) - { - string_list *x = columns; - - for( x = columns; x ; x = x->next ) - ORDER_AddColumn( view, x->string ); - } - else - ERR("Error creating select query\n"); - delete_string_list( columns ); - return view; -} - -static struct expr * EXPR_wildcard() -{ - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); - if( e ) - { - e->type = EXPR_WILDCARD; - } - return e; -} - -static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r ) -{ - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); - if( e ) - { - e->type = EXPR_COMPLEX; - e->u.expr.left = l; - e->u.expr.op = op; - e->u.expr.right = r; - } - return e; -} - -static struct expr * EXPR_column( LPWSTR str ) -{ - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); - if( e ) - { - e->type = EXPR_COLUMN; - e->u.sval = str; - } - return e; -} - -static struct expr * EXPR_ival( struct sql_str *str , int sign) -{ - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); - if( e ) - { - e->type = EXPR_IVAL; - e->u.ival = atoiW( str->data ) * sign; - } - return e; -} - -static struct expr * EXPR_sval( struct sql_str *str ) -{ - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); - if( e ) - { - e->type = EXPR_SVAL; - e->u.sval = SQL_getstring( str ); - } - return e; -} - -void delete_expr( struct expr *e ) -{ - if( !e ) - return; - if( e->type == EXPR_COMPLEX ) - { - delete_expr( e->u.expr.left ); - delete_expr( e->u.expr.right ); - } - else if( e->type == EXPR_UTF8 ) - HeapFree( GetProcessHeap(), 0, e->u.utf8 ); - else if( e->type == EXPR_SVAL ) - HeapFree( GetProcessHeap(), 0, e->u.sval ); - HeapFree( GetProcessHeap(), 0, e ); -} - -void delete_string_list( string_list *sl ) -{ - while( sl ) - { - string_list *t = sl->next; - HeapFree( GetProcessHeap(), 0, sl->string ); - HeapFree( GetProcessHeap(), 0, sl ); - sl = t; - } -} - -void delete_value_list( value_list *vl ) -{ - while( vl ) - { - value_list *t = vl->next; - delete_expr( vl->val ); - HeapFree( GetProcessHeap(), 0, vl ); - vl = t; - } -} - -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, - string_list *keys ) -{ - string_list *k; - BOOL found = TRUE; - - for( k = keys; k && found; k = k->next ) - { - create_col_info *c; - - found = FALSE; - for( c = cols; c && !found; c = c->next ) - { - if( lstrcmpW( k->string, c->colname ) ) - continue; - c->type |= MSITYPE_KEY; - found = TRUE; - } - } - - return found; -} - -UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview ) -{ - SQL_input sql; - int r; - - *phview = NULL; - - sql.db = db; - sql.command = command; - sql.n = 0; - sql.len = 0; - sql.view = phview; - - r = SQL_parse(&sql); - - TRACE("Parse returned %d\n", r); - if( r ) - { - if( *sql.view ) - (*sql.view)->ops->delete( *sql.view ); - *sql.view = NULL; - return ERROR_BAD_QUERY_SYNTAX; - } - - return ERROR_SUCCESS; -} - +/* A Bison parser, made from ./sql.y + by GNU bison 1.35. */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define yyparse SQL_parse +#define yylex SQL_lex +#define yyerror SQL_error +#define yylval SQL_lval +#define yychar SQL_char +#define yydebug SQL_debug +#define yynerrs SQL_nerrs +# define TK_ABORT 257 +# define TK_AFTER 258 +# define TK_AGG_FUNCTION 259 +# define TK_ALL 260 +# define TK_AND 261 +# define TK_AS 262 +# define TK_ASC 263 +# define TK_BEFORE 264 +# define TK_BEGIN 265 +# define TK_BETWEEN 266 +# define TK_BITAND 267 +# define TK_BITNOT 268 +# define TK_BITOR 269 +# define TK_BY 270 +# define TK_CASCADE 271 +# define TK_CASE 272 +# define TK_CHAR 273 +# define TK_CHECK 274 +# define TK_CLUSTER 275 +# define TK_COLLATE 276 +# define TK_COLUMN 277 +# define TK_COMMA 278 +# define TK_COMMENT 279 +# define TK_COMMIT 280 +# define TK_CONCAT 281 +# define TK_CONFLICT 282 +# define TK_CONSTRAINT 283 +# define TK_COPY 284 +# define TK_CREATE 285 +# define TK_DEFAULT 286 +# define TK_DEFERRABLE 287 +# define TK_DEFERRED 288 +# define TK_DELETE 289 +# define TK_DELIMITERS 290 +# define TK_DESC 291 +# define TK_DISTINCT 292 +# define TK_DOT 293 +# define TK_DROP 294 +# define TK_EACH 295 +# define TK_ELSE 296 +# define TK_END 297 +# define TK_END_OF_FILE 298 +# define TK_EQ 299 +# define TK_EXCEPT 300 +# define TK_EXPLAIN 301 +# define TK_FAIL 302 +# define TK_FLOAT 303 +# define TK_FOR 304 +# define TK_FOREIGN 305 +# define TK_FROM 306 +# define TK_FUNCTION 307 +# define TK_GE 308 +# define TK_GLOB 309 +# define TK_GROUP 310 +# define TK_GT 311 +# define TK_HAVING 312 +# define TK_HOLD 313 +# define TK_IGNORE 314 +# define TK_ILLEGAL 315 +# define TK_IMMEDIATE 316 +# define TK_IN 317 +# define TK_INDEX 318 +# define TK_INITIALLY 319 +# define TK_ID 320 +# define TK_INSERT 321 +# define TK_INSTEAD 322 +# define TK_INT 323 +# define TK_INTEGER 324 +# define TK_INTERSECT 325 +# define TK_INTO 326 +# define TK_IS 327 +# define TK_ISNULL 328 +# define TK_JOIN 329 +# define TK_JOIN_KW 330 +# define TK_KEY 331 +# define TK_LE 332 +# define TK_LIKE 333 +# define TK_LIMIT 334 +# define TK_LONG 335 +# define TK_LONGCHAR 336 +# define TK_LP 337 +# define TK_LSHIFT 338 +# define TK_LT 339 +# define TK_LOCALIZABLE 340 +# define TK_MATCH 341 +# define TK_MINUS 342 +# define TK_NE 343 +# define TK_NOT 344 +# define TK_NOTNULL 345 +# define TK_NULL 346 +# define TK_OBJECT 347 +# define TK_OF 348 +# define TK_OFFSET 349 +# define TK_ON 350 +# define TK_OR 351 +# define TK_ORACLE_OUTER_JOIN 352 +# define TK_ORDER 353 +# define TK_PLUS 354 +# define TK_PRAGMA 355 +# define TK_PRIMARY 356 +# define TK_RAISE 357 +# define TK_REFERENCES 358 +# define TK_REM 359 +# define TK_REPLACE 360 +# define TK_RESTRICT 361 +# define TK_ROLLBACK 362 +# define TK_ROW 363 +# define TK_RP 364 +# define TK_RSHIFT 365 +# define TK_SELECT 366 +# define TK_SEMI 367 +# define TK_SET 368 +# define TK_SHORT 369 +# define TK_SLASH 370 +# define TK_SPACE 371 +# define TK_STAR 372 +# define TK_STATEMENT 373 +# define TK_STRING 374 +# define TK_TABLE 375 +# define TK_TEMP 376 +# define TK_THEN 377 +# define TK_TRANSACTION 378 +# define TK_TRIGGER 379 +# define TK_UMINUS 380 +# define TK_UNCLOSED_STRING 381 +# define TK_UNION 382 +# define TK_UNIQUE 383 +# define TK_UPDATE 384 +# define TK_UPLUS 385 +# define TK_USING 386 +# define TK_VACUUM 387 +# define TK_VALUES 388 +# define TK_VIEW 389 +# define TK_WHEN 390 +# define TK_WHERE 391 +# define TK_WILDCARD 392 +# define END_OF_FILE 393 +# define ILLEGAL 394 +# define SPACE 395 +# define UNCLOSED_STRING 396 +# define COMMENT 397 +# define FUNCTION 398 +# define COLUMN 399 + +#line 1 "./sql.y" + + +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002-2004 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "config.h" + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "query.h" +#include "wine/list.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#define YYLEX_PARAM info +#define YYPARSE_PARAM info + +extern int SQL_error(const char *str); + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +typedef struct tag_SQL_input +{ + MSIDATABASE *db; + LPCWSTR command; + DWORD n, len; + MSIVIEW **view; /* view structure for the resulting query */ + struct list *mem; +} SQL_input; + +static LPWSTR SQL_getstring( void *info, struct sql_str *str ); +static INT SQL_getint( void *info ); +static int SQL_lex( void *SQL_lval, SQL_input *info ); + +static void *parser_alloc( void *info, unsigned int sz ); + +static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys); + +static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r ); +static struct expr * EXPR_column( void *info, LPWSTR column ); +static struct expr * EXPR_ival( void *info, struct sql_str *, int sign ); +static struct expr * EXPR_sval( void *info, struct sql_str * ); +static struct expr * EXPR_wildcard( void *info ); + + +#line 71 "./sql.y" +#ifndef YYSTYPE +typedef union +{ + struct sql_str str; + LPWSTR string; + string_list *column_list; + value_list *val_list; + MSIVIEW *query; + struct expr *expr; + USHORT column_type; + create_col_info *column_info; + column_assignment update_col_info; +} yystype; +# define YYSTYPE yystype +# define YYSTYPE_IS_TRIVIAL 1 +#endif +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + + + +#define YYFINAL 126 +#define YYFLAG -32768 +#define YYNTBASE 147 + +/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ +#define YYTRANSLATE(x) ((unsigned)(x) <= 400 ? yytranslate[x] : 175) + +/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ +static const short yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 146 +}; + +#if YYDEBUG +static const short yyprhs[] = +{ + 0, 0, 2, 4, 6, 8, 10, 12, 23, 35, + 42, 50, 57, 60, 65, 70, 73, 75, 78, 80, + 84, 86, 91, 93, 95, 97, 99, 101, 103, 108, + 110, 113, 117, 120, 122, 126, 128, 130, 134, 137, + 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, + 181, 186, 188, 190, 192, 196, 198, 202, 206, 208, + 211, 213, 215, 217, 221, 223, 225 +}; +static const short yyrhs[] = +{ + 148, 0, 159, 0, 150, 0, 149, 0, 151, 0, + 152, 0, 67, 72, 173, 83, 162, 110, 134, 83, + 167, 110, 0, 67, 72, 173, 83, 162, 110, 134, + 83, 167, 110, 122, 0, 31, 121, 173, 83, 153, + 110, 0, 31, 121, 173, 83, 153, 110, 59, 0, + 130, 173, 114, 168, 137, 165, 0, 35, 163, 0, + 154, 102, 77, 162, 0, 154, 24, 172, 155, 0, + 172, 155, 0, 156, 0, 156, 86, 0, 157, 0, + 157, 90, 92, 0, 19, 0, 19, 83, 158, 110, + 0, 82, 0, 115, 0, 69, 0, 81, 0, 93, + 0, 70, 0, 160, 99, 16, 162, 0, 160, 0, + 112, 161, 0, 112, 38, 161, 0, 162, 163, 0, + 172, 0, 172, 24, 162, 0, 118, 0, 164, 0, + 164, 137, 165, 0, 52, 173, 0, 83, 165, 110, + 0, 171, 45, 171, 0, 165, 7, 165, 0, 165, + 97, 165, 0, 171, 45, 166, 0, 171, 57, 166, + 0, 171, 85, 166, 0, 171, 78, 166, 0, 171, + 54, 166, 0, 171, 89, 166, 0, 171, 73, 92, + 0, 171, 73, 90, 92, 0, 171, 0, 170, 0, + 170, 0, 170, 24, 167, 0, 169, 0, 169, 24, + 168, 0, 172, 45, 170, 0, 70, 0, 88, 70, + 0, 120, 0, 138, 0, 172, 0, 173, 39, 174, + 0, 174, 0, 174, 0, 66, 0 +}; + +#endif + +#if YYDEBUG +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const short yyrline[] = +{ + 0, 140, 148, 150, 151, 152, 153, 156, 168, 180, + 193, 207, 220, 233, 243, 263, 274, 279, 286, 291, + 297, 302, 306, 310, 314, 318, 322, 328, 339, 352, + 355, 360, 371, 387, 401, 414, 420, 422, 434, 447, + 454, 460, 466, 472, 478, 484, 490, 496, 502, 508, + 514, 522, 524, 527, 539, 552, 554, 562, 578, 585, + 591, 597, 605, 614, 619, 625, 632 +}; +#endif + + +#if (YYDEBUG) || defined YYERROR_VERBOSE + +/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ +static const char *const yytname[] = +{ + "$", "error", "$undefined.", "TK_ABORT", "TK_AFTER", "TK_AGG_FUNCTION", + "TK_ALL", "TK_AND", "TK_AS", "TK_ASC", "TK_BEFORE", "TK_BEGIN", + "TK_BETWEEN", "TK_BITAND", "TK_BITNOT", "TK_BITOR", "TK_BY", + "TK_CASCADE", "TK_CASE", "TK_CHAR", "TK_CHECK", "TK_CLUSTER", + "TK_COLLATE", "TK_COLUMN", "TK_COMMA", "TK_COMMENT", "TK_COMMIT", + "TK_CONCAT", "TK_CONFLICT", "TK_CONSTRAINT", "TK_COPY", "TK_CREATE", + "TK_DEFAULT", "TK_DEFERRABLE", "TK_DEFERRED", "TK_DELETE", + "TK_DELIMITERS", "TK_DESC", "TK_DISTINCT", "TK_DOT", "TK_DROP", + "TK_EACH", "TK_ELSE", "TK_END", "TK_END_OF_FILE", "TK_EQ", "TK_EXCEPT", + "TK_EXPLAIN", "TK_FAIL", "TK_FLOAT", "TK_FOR", "TK_FOREIGN", "TK_FROM", + "TK_FUNCTION", "TK_GE", "TK_GLOB", "TK_GROUP", "TK_GT", "TK_HAVING", + "TK_HOLD", "TK_IGNORE", "TK_ILLEGAL", "TK_IMMEDIATE", "TK_IN", + "TK_INDEX", "TK_INITIALLY", "TK_ID", "TK_INSERT", "TK_INSTEAD", + "TK_INT", "TK_INTEGER", "TK_INTERSECT", "TK_INTO", "TK_IS", "TK_ISNULL", + "TK_JOIN", "TK_JOIN_KW", "TK_KEY", "TK_LE", "TK_LIKE", "TK_LIMIT", + "TK_LONG", "TK_LONGCHAR", "TK_LP", "TK_LSHIFT", "TK_LT", + "TK_LOCALIZABLE", "TK_MATCH", "TK_MINUS", "TK_NE", "TK_NOT", + "TK_NOTNULL", "TK_NULL", "TK_OBJECT", "TK_OF", "TK_OFFSET", "TK_ON", + "TK_OR", "TK_ORACLE_OUTER_JOIN", "TK_ORDER", "TK_PLUS", "TK_PRAGMA", + "TK_PRIMARY", "TK_RAISE", "TK_REFERENCES", "TK_REM", "TK_REPLACE", + "TK_RESTRICT", "TK_ROLLBACK", "TK_ROW", "TK_RP", "TK_RSHIFT", + "TK_SELECT", "TK_SEMI", "TK_SET", "TK_SHORT", "TK_SLASH", "TK_SPACE", + "TK_STAR", "TK_STATEMENT", "TK_STRING", "TK_TABLE", "TK_TEMP", + "TK_THEN", "TK_TRANSACTION", "TK_TRIGGER", "TK_UMINUS", + "TK_UNCLOSED_STRING", "TK_UNION", "TK_UNIQUE", "TK_UPDATE", "TK_UPLUS", + "TK_USING", "TK_VACUUM", "TK_VALUES", "TK_VIEW", "TK_WHEN", "TK_WHERE", + "TK_WILDCARD", "END_OF_FILE", "ILLEGAL", "SPACE", "UNCLOSED_STRING", + "COMMENT", "FUNCTION", "COLUMN", "AGG_FUNCTION.", "query", "onequery", + "oneinsert", "onecreate", "oneupdate", "onedelete", "table_def", + "column_def", "column_type", "data_type_l", "data_type", "data_count", + "oneselect", "unorderedsel", "selectfrom", "selcollist", "from", + "fromtable", "expr", "val", "constlist", "update_assign_list", + "column_assignment", "const_val", "column_val", "column", "table", "id", 0 +}; +#endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const short yyr1[] = +{ + 0, 147, 148, 148, 148, 148, 148, 149, 149, 150, + 150, 151, 152, 153, 154, 154, 155, 155, 156, 156, + 157, 157, 157, 157, 157, 157, 157, 158, 159, 159, + 160, 160, 161, 162, 162, 162, 163, 163, 164, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 166, 166, 167, 167, 168, 168, 169, 170, 170, + 170, 170, 171, 172, 172, 173, 174 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const short yyr2[] = +{ + 0, 1, 1, 1, 1, 1, 1, 10, 11, 6, + 7, 6, 2, 4, 4, 2, 1, 2, 1, 3, + 1, 4, 1, 1, 1, 1, 1, 1, 4, 1, + 2, 3, 2, 1, 3, 1, 1, 3, 2, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 1, 1, 1, 3, 1, 3, 3, 1, 2, + 1, 1, 1, 3, 1, 1, 1 +}; + +/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE + doesn't specify something else to do. Zero means the default is an + error. */ +static const short yydefact[] = +{ + 0, 0, 0, 0, 0, 0, 1, 4, 3, 5, + 6, 2, 29, 0, 0, 12, 36, 0, 0, 66, + 35, 30, 0, 33, 0, 64, 0, 65, 0, 0, + 38, 0, 0, 31, 32, 0, 0, 0, 0, 0, + 0, 37, 0, 62, 0, 34, 63, 0, 55, 0, + 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, + 0, 20, 24, 25, 22, 26, 23, 15, 16, 18, + 39, 41, 42, 58, 0, 60, 61, 43, 52, 40, + 47, 51, 44, 0, 49, 46, 45, 48, 0, 11, + 56, 57, 10, 0, 0, 0, 17, 0, 59, 50, + 0, 14, 13, 27, 0, 19, 0, 21, 0, 53, + 7, 0, 8, 54, 0, 0, 0 +}; + +static const short yydefgoto[] = +{ + 124, 6, 7, 8, 9, 10, 51, 52, 77, 78, + 79, 114, 11, 12, 21, 22, 15, 16, 41, 87, + 118, 47, 48, 88, 42, 43, 24, 25 +}; + +static const short yypact[] = +{ + -28, -102, -32, -48, -29, -39,-32768,-32768,-32768,-32768, + -32768,-32768, -61, -39, -39,-32768, -97, -39, -50,-32768, + -32768,-32768, -32, 19, 6, 9, -65,-32768, 34, -30, + -32768, -37, -26,-32768,-32768, -50, -39, -39, -50, -39, + -37, -2, -31,-32768, -50,-32768,-32768, -86, 32, 10, + -32768, -51, -20, -17, -7, -37, -37, -60, -60, -60, + -59, -60, -60, -60, -36, -37, -39, -58, 16, -39, + 2, 0,-32768,-32768,-32768,-32768,-32768,-32768, -5, 1, + -32768, -2, -2,-32768, 15,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768, -4,-32768,-32768,-32768,-32768, -42, -2, + -32768,-32768,-32768, -17, -50, 23,-32768, 5,-32768,-32768, + 11,-32768,-32768,-32768, -11,-32768, -58,-32768, -10, 83, + -9, -58,-32768,-32768, 117, 118,-32768 +}; + +static const short yypgoto[] = +{ + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 17,-32768, + -32768,-32768,-32768,-32768, 101, -27, 99,-32768, 31, 53, + 3, 57,-32768, -49, 47, -3, 56, 8 +}; + + +#define YYLAST 124 + + +static const short yytable[] = +{ + 55, 23, 71, 1, 69, 55, 19, 2, 45, 18, + 83, 50, 83, 27, 57, 23, 19, 64, 101, 13, + 14, 27, 27, 58, 17, 27, 59, 19, 84, 19, + 84, 93, 23, 94, 49, 23, 53, 19, 28, 3, + 31, 23, 60, 35, 46, 36, 40, 61, -65, 37, + 38, 65, 72, 39, 62, 67, 66, 44, 63, 68, + 85, 26, 85, 49, 73, 74, 103, 119, 20, 29, + 30, 54, 119, 32, 98, 102, 75, 112, 86, 104, + 86, 106, 70, 105, 4, 108, 81, 82, 109, 20, + 56, 107, 110, 113, 116, 56, 99, 115, 76, 117, + 120, 23, 5, 80, 89, 91, 91, 121, 91, 91, + 91, 90, 92, 122, 95, 96, 97, 125, 126, 33, + 111, 34, 0, 100, 123 +}; + +static const short yycheck[] = +{ + 7, 4, 19, 31, 24, 7, 66, 35, 35, 38, + 70, 38, 70, 5, 45, 18, 66, 44, 67, 121, + 52, 13, 14, 54, 72, 17, 57, 66, 88, 66, + 88, 90, 35, 92, 37, 38, 39, 66, 99, 67, + 137, 44, 73, 24, 36, 39, 83, 78, 39, 114, + 16, 137, 69, 83, 85, 45, 24, 83, 89, 110, + 120, 5, 120, 66, 81, 82, 69, 116, 118, 13, + 14, 40, 121, 17, 110, 59, 93, 104, 138, 77, + 138, 86, 102, 83, 112, 70, 55, 56, 92, 118, + 97, 90, 134, 70, 83, 97, 65, 92, 115, 110, + 110, 104, 130, 110, 57, 58, 59, 24, 61, 62, + 63, 58, 59, 122, 61, 62, 63, 0, 0, 18, + 103, 22, -1, 66, 121 +}; +#define YYPURE 1 + +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/share/bison/bison.simple" + +/* Skeleton output parser for bison, + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser when + the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC malloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short yyss; + YYSTYPE yyvs; +# if YYLSP_NEEDED + YYLTYPE yyls; +# endif +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# if YYLSP_NEEDED +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAX) +# else +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAX) +# endif + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up"); \ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). + + When YYLLOC_DEFAULT is run, CURRENT is set the location of the + first token. By default, to implement support for ranges, extend + its range to the last symbol. */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#if YYPURE +# if YYLSP_NEEDED +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval, &yylloc) +# endif +# else /* !YYLSP_NEEDED */ +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval) +# endif +# endif /* !YYLSP_NEEDED */ +#else /* !YYPURE */ +# define YYLEX yylex () +#endif /* !YYPURE */ + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +#endif /* !YYDEBUG */ + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + +#ifdef YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif +#endif + +#line 315 "/usr/share/bison/bison.simple" + + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +# define YYPARSE_PARAM_DECL +# else +# define YYPARSE_PARAM_ARG YYPARSE_PARAM +# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +# endif +#else /* !YYPARSE_PARAM */ +# define YYPARSE_PARAM_ARG +# define YYPARSE_PARAM_DECL +#endif /* !YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +# ifdef YYPARSE_PARAM +int yyparse (void *); +# else +int yyparse (void); +# endif +#endif + +/* YY_DECL_VARIABLES -- depending whether we use a pure parser, + variables are global, or local to YYPARSE. */ + +#define YY_DECL_NON_LSP_VARIABLES \ +/* The lookahead symbol. */ \ +int yychar; \ + \ +/* The semantic value of the lookahead symbol. */ \ +YYSTYPE yylval; \ + \ +/* Number of parse errors so far. */ \ +int yynerrs; + +#if YYLSP_NEEDED +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES \ + \ +/* Location data for the lookahead symbol. */ \ +YYLTYPE yylloc; +#else +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES +#endif + + +/* If nonreentrant, generate the variables here. */ + +#if !YYPURE +YY_DECL_VARIABLES +#endif /* !YYPURE */ + +int +yyparse (YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + /* If reentrant, generate the variables here. */ +#if YYPURE + YY_DECL_VARIABLES +#endif /* !YYPURE */ + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int yychar1 = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short yyssa[YYINITDEPTH]; + short *yyss = yyssa; + register short *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + +#if YYLSP_NEEDED + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; +#endif + +#if YYLSP_NEEDED +# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +# define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + YYSIZE_T yystacksize = YYINITDEPTH; + + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; +#if YYLSP_NEEDED + YYLTYPE yyloc; +#endif + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; +#if YYLSP_NEEDED + yylsp = yyls; +#endif + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. */ +# if YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + yyls = yyls1; +# else + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); +# endif + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + goto yyoverflowlab; + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + + { + short *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); +# if YYLSP_NEEDED + YYSTACK_RELOCATE (yyls); +# endif +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; +#if YYLSP_NEEDED + yylsp = yyls + yysize - 1; +#endif + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yychar1 = YYTRANSLATE (yychar); + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables + which are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + YYFPRINTF (stderr, "Next token is %d (%s", + yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise + meaning of a token, for further debugging info. */ +# ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +# endif + YYFPRINTF (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %d (%s), ", + yychar, yytname[yychar1])); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to the semantic value of + the lookahead token. This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + +#if YYLSP_NEEDED + /* Similarly for the default location. Let the user run additional + commands if for instance locations are ranges. */ + yyloc = yylsp[1-yylen]; + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); +#endif + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables which + are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + int yyi; + + YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) + YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); + YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + switch (yyn) { + +case 1: +#line 142 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + *sql->view = yyvsp[0].query; + ; + break;} +case 7: +#line 158 "./sql.y" +{ + SQL_input *sql = (SQL_input*) info; + MSIVIEW *insert = NULL; + UINT r; + + r = INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].val_list, FALSE ); + if( !insert ) + YYABORT; + yyval.query = insert; + ; + break;} +case 8: +#line 169 "./sql.y" +{ + SQL_input *sql = (SQL_input*) info; + MSIVIEW *insert = NULL; + + INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].val_list, TRUE ); + if( !insert ) + YYABORT; + yyval.query = insert; + ; + break;} +case 9: +#line 182 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + MSIVIEW *create = NULL; + + if( !yyvsp[-1].column_info ) + YYABORT; + CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_info, FALSE ); + if( !create ) + YYABORT; + yyval.query = create; + ; + break;} +case 10: +#line 194 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + MSIVIEW *create = NULL; + + if( !yyvsp[-2].column_info ) + YYABORT; + CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_info, TRUE ); + if( !create ) + YYABORT; + yyval.query = create; + ; + break;} +case 11: +#line 209 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + MSIVIEW *update = NULL; + + UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, &yyvsp[-2].update_col_info, yyvsp[0].expr ); + if( !update ) + YYABORT; + yyval.query = update; + ; + break;} +case 12: +#line 222 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + MSIVIEW *delete = NULL; + + DELETE_CreateView( sql->db, &delete, yyvsp[0].query ); + if( !delete ) + YYABORT; + yyval.query = delete; + ; + break;} +case 13: +#line 235 "./sql.y" +{ + if( SQL_MarkPrimaryKeys( yyvsp[-3].column_info, yyvsp[0].column_list ) ) + yyval.column_info = yyvsp[-3].column_info; + else + yyval.column_info = NULL; + ; + break;} +case 14: +#line 245 "./sql.y" +{ + create_col_info *ci; + + for( ci = yyvsp[-3].column_info; ci->next; ci = ci->next ) + ; + + ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); + if( !ci->next ) + { + /* FIXME: free $1 */ + YYABORT; + } + ci->next->colname = yyvsp[-1].string; + ci->next->type = yyvsp[0].column_type; + ci->next->next = NULL; + + yyval.column_info = yyvsp[-3].column_info; + ; + break;} +case 15: +#line 264 "./sql.y" +{ + yyval.column_info = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); + if( ! yyval.column_info ) + YYABORT; + yyval.column_info->colname = yyvsp[-1].string; + yyval.column_info->type = yyvsp[0].column_type; + yyval.column_info->next = NULL; + ; + break;} +case 16: +#line 276 "./sql.y" +{ + yyval.column_type = yyvsp[0].column_type | MSITYPE_VALID; + ; + break;} +case 17: +#line 280 "./sql.y" +{ + FIXME("LOCALIZABLE ignored\n"); + yyval.column_type = yyvsp[-1].column_type | MSITYPE_VALID; + ; + break;} +case 18: +#line 288 "./sql.y" +{ + yyval.column_type |= MSITYPE_NULLABLE; + ; + break;} +case 19: +#line 292 "./sql.y" +{ + yyval.column_type = yyvsp[-2].column_type; + ; + break;} +case 20: +#line 299 "./sql.y" +{ + yyval.column_type = MSITYPE_STRING | 1; + ; + break;} +case 21: +#line 303 "./sql.y" +{ + yyval.column_type = MSITYPE_STRING | 0x400 | yyvsp[-1].column_type; + ; + break;} +case 22: +#line 307 "./sql.y" +{ + yyval.column_type = 2; + ; + break;} +case 23: +#line 311 "./sql.y" +{ + yyval.column_type = 2; + ; + break;} +case 24: +#line 315 "./sql.y" +{ + yyval.column_type = 2; + ; + break;} +case 25: +#line 319 "./sql.y" +{ + yyval.column_type = 4; + ; + break;} +case 26: +#line 323 "./sql.y" +{ + yyval.column_type = 0; + ; + break;} +case 27: +#line 330 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + int val = SQL_getint(sql); + if( ( val > 255 ) || ( val < 0 ) ) + YYABORT; + yyval.column_type = val; + ; + break;} +case 28: +#line 341 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + + yyval.query = NULL; + if( yyvsp[0].column_list ) + ORDER_CreateView( sql->db, &yyval.query, yyvsp[-3].query, yyvsp[0].column_list ); + else + yyval.query = yyvsp[-3].query; + if( !yyval.query ) + YYABORT; + ; + break;} +case 30: +#line 357 "./sql.y" +{ + yyval.query = yyvsp[0].query; + ; + break;} +case 31: +#line 361 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + + yyval.query = NULL; + DISTINCT_CreateView( sql->db, &yyval.query, yyvsp[0].query ); + if( !yyval.query ) + YYABORT; + ; + break;} +case 32: +#line 373 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + + yyval.query = NULL; + if( yyvsp[-1].column_list ) + SELECT_CreateView( sql->db, &yyval.query, yyvsp[0].query, yyvsp[-1].column_list ); + else + yyval.query = yyvsp[0].query; + + if( !yyval.query ) + YYABORT; + ; + break;} +case 33: +#line 389 "./sql.y" +{ + string_list *list; + + list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); + if( !list ) + YYABORT; + list->string = yyvsp[0].string; + list->next = NULL; + + yyval.column_list = list; + TRACE("Collist %s\n",debugstr_w(yyval.column_list->string)); + ; + break;} +case 34: +#line 402 "./sql.y" +{ + string_list *list; + + list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); + if( !list ) + YYABORT; + list->string = yyvsp[-2].string; + list->next = yyvsp[0].column_list; + + yyval.column_list = list; + TRACE("From table: %s\n",debugstr_w(yyval.column_list->string)); + ; + break;} +case 35: +#line 415 "./sql.y" +{ + yyval.column_list = NULL; + ; + break;} +case 37: +#line 423 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + UINT r; + + yyval.query = NULL; + r = WHERE_CreateView( sql->db, &yyval.query, yyvsp[-2].query, yyvsp[0].expr ); + if( r != ERROR_SUCCESS || !yyval.query ) + YYABORT; + ; + break;} +case 38: +#line 436 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + UINT r; + + yyval.query = NULL; + r = TABLE_CreateView( sql->db, yyvsp[0].string, &yyval.query ); + if( r != ERROR_SUCCESS || !yyval.query ) + YYABORT; + ; + break;} +case 39: +#line 449 "./sql.y" +{ + yyval.expr = yyvsp[-1].expr; + if( !yyval.expr ) + YYABORT; + ; + break;} +case 40: +#line 455 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 41: +#line 461 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_AND, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 42: +#line 467 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_OR, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 43: +#line 473 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 44: +#line 479 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_GT, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 45: +#line 485 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_LT, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 46: +#line 491 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_LE, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 47: +#line 497 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_GE, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 48: +#line 503 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_NE, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 49: +#line 509 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_ISNULL, NULL ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 50: +#line 515 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-3].expr, OP_NOTNULL, NULL ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 53: +#line 529 "./sql.y" +{ + value_list *vals; + + vals = parser_alloc( info, sizeof *vals ); + if( !vals ) + YYABORT; + vals->val = yyvsp[0].expr; + vals->next = NULL; + yyval.val_list = vals; + ; + break;} +case 54: +#line 540 "./sql.y" +{ + value_list *vals; + + vals = parser_alloc( info, sizeof *vals ); + if( !vals ) + YYABORT; + vals->val = yyvsp[-2].expr; + vals->next = yyvsp[0].val_list; + yyval.val_list = vals; + ; + break;} +case 56: +#line 555 "./sql.y" +{ + yyvsp[-2].update_col_info.col_list->next = yyvsp[0].update_col_info.col_list; + yyvsp[-2].update_col_info.val_list->next = yyvsp[0].update_col_info.val_list; + yyval.update_col_info = yyvsp[-2].update_col_info; + ; + break;} +case 57: +#line 564 "./sql.y" +{ + yyval.update_col_info.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.col_list ); + if( !yyval.update_col_info.col_list ) + YYABORT; + yyval.update_col_info.col_list->string = yyvsp[-2].string; + yyval.update_col_info.col_list->next = NULL; + yyval.update_col_info.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.val_list ); + if( !yyval.update_col_info.val_list ) + YYABORT; + yyval.update_col_info.val_list->val = yyvsp[0].expr; + yyval.update_col_info.val_list->next = 0; + ; + break;} +case 58: +#line 580 "./sql.y" +{ + yyval.expr = EXPR_ival( info, &yyvsp[0].str, 1 ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 59: +#line 586 "./sql.y" +{ + yyval.expr = EXPR_ival( info, &yyvsp[0].str, -1 ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 60: +#line 592 "./sql.y" +{ + yyval.expr = EXPR_sval( info, &yyvsp[0].str ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 61: +#line 598 "./sql.y" +{ + yyval.expr = EXPR_wildcard( info ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 62: +#line 607 "./sql.y" +{ + yyval.expr = EXPR_column( info, yyvsp[0].string ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 63: +#line 616 "./sql.y" +{ + yyval.string = yyvsp[0].string; /* FIXME */ + ; + break;} +case 64: +#line 620 "./sql.y" +{ + yyval.string = yyvsp[0].string; + ; + break;} +case 65: +#line 627 "./sql.y" +{ + yyval.string = yyvsp[0].string; + ; + break;} +case 66: +#line 634 "./sql.y" +{ + yyval.string = SQL_getstring( info, &yyvsp[0].str ); + if( !yyval.string ) + YYABORT; + ; + break;} +} + +#line 705 "/usr/share/bison/bison.simple" + + + yyvsp -= yylen; + yyssp -= yylen; +#if YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; +#if YYLSP_NEEDED + *++yylsp = yyloc; +#endif + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + char *yymsg; + int yyx, yycount; + + yycount = 0; + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) + if (yycheck[yyx + yyn] == yyx) + yysize += yystrlen (yytname[yyx]) + 15, yycount++; + yysize += yystrlen ("parse error, unexpected ") + 1; + yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "parse error, unexpected "); + yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); + + if (yycount < 5) + { + yycount = 0; + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); + yyx++) + if (yycheck[yyx + yyn] == yyx) + { + const char *yyq = ! yycount ? ", expecting " : " or "; + yyp = yystpcpy (yyp, yyq); + yyp = yystpcpy (yyp, yytname[yyx]); + yycount++; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("parse error; also virtual memory exhausted"); + } + else +#endif /* defined (YYERROR_VERBOSE) */ + yyerror ("parse error"); + } + goto yyerrlab1; + + +/*--------------------------------------------------. +| yyerrlab1 -- error raised explicitly by an action | +`--------------------------------------------------*/ +yyerrlab1: + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + YYDPRINTF ((stderr, "Discarding token %d (%s).\n", + yychar, yytname[yychar1])); + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + + +/*-------------------------------------------------------------------. +| yyerrdefault -- current state does not do anything special for the | +| error token. | +`-------------------------------------------------------------------*/ +yyerrdefault: +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + + /* If its default is to accept any token, ok. Otherwise pop it. */ + yyn = yydefact[yystate]; + if (yyn) + goto yydefault; +#endif + + +/*---------------------------------------------------------------. +| yyerrpop -- pop the current state because it cannot handle the | +| error token | +`---------------------------------------------------------------*/ +yyerrpop: + if (yyssp == yyss) + YYABORT; + yyvsp--; + yystate = *--yyssp; +#if YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "Error: state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + +/*--------------. +| yyerrhandle. | +`--------------*/ +yyerrhandle: + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +/*---------------------------------------------. +| yyoverflowab -- parser overflow comes here. | +`---------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} +#line 641 "./sql.y" + + +static void *parser_alloc( void *info, unsigned int sz ) +{ + SQL_input* sql = (SQL_input*) info; + struct list *mem; + + mem = HeapAlloc( GetProcessHeap(), 0, sizeof (struct list) + sz ); + list_add_tail( sql->mem, mem ); + return &mem[1]; +} + +int SQL_lex( void *SQL_lval, SQL_input *sql ) +{ + int token; + struct sql_str * str = SQL_lval; + + do + { + sql->n += sql->len; + if( ! sql->command[sql->n] ) + return 0; /* end of input */ + + TRACE("string : %s\n", debugstr_w(&sql->command[sql->n])); + sql->len = sqliteGetToken( &sql->command[sql->n], &token ); + if( sql->len==0 ) + break; + str->data = &sql->command[sql->n]; + str->len = sql->len; + } + while( token == TK_SPACE ); + + TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len)); + + return token; +} + +LPWSTR SQL_getstring( void *info, struct sql_str *strdata ) +{ + LPCWSTR p = strdata->data; + UINT len = strdata->len; + LPWSTR str; + + /* if there's quotes, remove them */ + if( ( (p[0]=='`') && (p[len-1]=='`') ) || + ( (p[0]=='\'') && (p[len-1]=='\'') ) ) + { + p++; + len -= 2; + } + str = parser_alloc( info, (len + 1)*sizeof(WCHAR) ); + if( !str ) + return str; + memcpy( str, p, len*sizeof(WCHAR) ); + str[len]=0; + + return str; +} + +INT SQL_getint( void *info ) +{ + SQL_input* sql = (SQL_input*) info; + LPCWSTR p = &sql->command[sql->n]; + + return atoiW( p ); +} + +int SQL_error( const char *str ) +{ + return 0; +} + +static struct expr * EXPR_wildcard( void *info ) +{ + struct expr *e = parser_alloc( info, sizeof *e ); + if( e ) + { + e->type = EXPR_WILDCARD; + } + return e; +} + +static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r ) +{ + struct expr *e = parser_alloc( info, sizeof *e ); + if( e ) + { + e->type = EXPR_COMPLEX; + e->u.expr.left = l; + e->u.expr.op = op; + e->u.expr.right = r; + } + return e; +} + +static struct expr * EXPR_column( void *info, LPWSTR column ) +{ + struct expr *e = parser_alloc( info, sizeof *e ); + if( e ) + { + e->type = EXPR_COLUMN; + e->u.sval = column; + } + return e; +} + +static struct expr * EXPR_ival( void *info, struct sql_str *str, int sign ) +{ + struct expr *e = parser_alloc( info, sizeof *e ); + if( e ) + { + e->type = EXPR_IVAL; + e->u.ival = atoiW( str->data ) * sign; + } + return e; +} + +static struct expr * EXPR_sval( void *info, struct sql_str *str ) +{ + struct expr *e = parser_alloc( info, sizeof *e ); + if( e ) + { + e->type = EXPR_SVAL; + e->u.sval = SQL_getstring( info, str ); + } + return e; +} + +static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys) +{ + string_list *k; + BOOL found = TRUE; + + for( k = keys; k && found; k = k->next ) + { + create_col_info *c; + + found = FALSE; + for( c = cols; c && !found; c = c->next ) + { + if( lstrcmpW( k->string, c->colname ) ) + continue; + c->type |= MSITYPE_KEY; + found = TRUE; + } + } + + return found; +} + +UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview, + struct list *mem ) +{ + SQL_input sql; + int r; + + *phview = NULL; + + sql.db = db; + sql.command = command; + sql.n = 0; + sql.len = 0; + sql.view = phview; + sql.mem = mem; + + r = SQL_parse(&sql); + + TRACE("Parse returned %d\n", r); + if( r ) + { + if( *sql.view ) + (*sql.view)->ops->delete( *sql.view ); + *sql.view = NULL; + return ERROR_BAD_QUERY_SYNTAX; + } + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/sql.y b/reactos/lib/msi/sql.y index 5bd2c7dffd7..7a0edd9f6ab 100644 --- a/reactos/lib/msi/sql.y +++ b/reactos/lib/msi/sql.y @@ -30,6 +30,7 @@ #include "windef.h" #include "winbase.h" #include "query.h" +#include "wine/list.h" #include "wine/debug.h" #include "wine/unicode.h" @@ -46,25 +47,22 @@ typedef struct tag_SQL_input LPCWSTR command; DWORD n, len; MSIVIEW **view; /* view structure for the resulting query */ + struct list *mem; } SQL_input; -static LPWSTR SQL_getstring( struct sql_str *str ); -static INT SQL_getint( SQL_input *sql ); -static int SQL_lex( void *SQL_lval, SQL_input *info); +static LPWSTR SQL_getstring( void *info, struct sql_str *str ); +static INT SQL_getint( void *info ); +static int SQL_lex( void *SQL_lval, SQL_input *info ); -static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, - string_list *columns ); -static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, - string_list *columns ); +static void *parser_alloc( void *info, unsigned int sz ); -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, - string_list *keys); +static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys); -static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r ); -static struct expr * EXPR_column( LPWSTR ); -static struct expr * EXPR_ival( struct sql_str *, int sign); -static struct expr * EXPR_sval( struct sql_str *); -static struct expr * EXPR_wildcard(); +static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r ); +static struct expr * EXPR_column( void *info, LPWSTR column ); +static struct expr * EXPR_ival( void *info, struct sql_str *, int sign ); +static struct expr * EXPR_sval( void *info, struct sql_str * ); +static struct expr * EXPR_wildcard( void *info ); %} @@ -127,10 +125,10 @@ static struct expr * EXPR_wildcard(); %nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION COLUMN AGG_FUNCTION. -%type column table string_or_id +%type column table id %type selcollist -%type from unorderedsel oneselect onequery onecreate oneinsert -%type oneupdate onedelete +%type query from fromtable unorderedsel selectfrom +%type oneupdate onedelete oneselect onequery onecreate oneinsert %type expr val column_val const_val %type column_type data_type data_type_l data_count %type column_def table_def @@ -139,51 +137,44 @@ static struct expr * EXPR_wildcard(); %% -onequery: - oneselect - { - SQL_input* sql = (SQL_input*) info; - *sql->view = $1; - } - | onecreate - { - SQL_input* sql = (SQL_input*) info; - *sql->view = $1; - } - | oneinsert - { - SQL_input* sql = (SQL_input*) info; - *sql->view = $1; - } - | oneupdate - { - SQL_input* sql = (SQL_input*) info; - *sql->view = $1; - } - | onedelete +query: + onequery { SQL_input* sql = (SQL_input*) info; *sql->view = $1; } ; +onequery: + oneselect + | onecreate + | oneinsert + | oneupdate + | onedelete + ; + oneinsert: TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP - { - SQL_input *sql = (SQL_input*) info; - MSIVIEW *insert = NULL; + { + SQL_input *sql = (SQL_input*) info; + MSIVIEW *insert = NULL; + UINT r; - INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE ); - $$ = insert; - } + r = INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE ); + if( !insert ) + YYABORT; + $$ = insert; + } | TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMP - { - SQL_input *sql = (SQL_input*) info; - MSIVIEW *insert = NULL; + { + SQL_input *sql = (SQL_input*) info; + MSIVIEW *insert = NULL; - INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE ); - $$ = insert; - } + INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE ); + if( !insert ) + YYABORT; + $$ = insert; + } ; onecreate: @@ -195,6 +186,8 @@ onecreate: if( !$5 ) YYABORT; CREATE_CreateView( sql->db, &create, $3, $5, FALSE ); + if( !create ) + YYABORT; $$ = create; } | TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD @@ -205,6 +198,8 @@ onecreate: if( !$5 ) YYABORT; CREATE_CreateView( sql->db, &create, $3, $5, TRUE ); + if( !create ) + YYABORT; $$ = create; } ; @@ -216,6 +211,8 @@ oneupdate: MSIVIEW *update = NULL; UPDATE_CreateView( sql->db, &update, $2, &$4, $6 ); + if( !update ) + YYABORT; $$ = update; } ; @@ -227,6 +224,8 @@ onedelete: MSIVIEW *delete = NULL; DELETE_CreateView( sql->db, &delete, $2 ); + if( !delete ) + YYABORT; $$ = delete; } ; @@ -342,45 +341,46 @@ oneselect: { SQL_input* sql = (SQL_input*) info; - if( !$1 ) - YYABORT; + $$ = NULL; if( $4 ) - $$ = do_order_by( sql->db, $1, $4 ); + ORDER_CreateView( sql->db, &$$, $1, $4 ); else $$ = $1; + if( !$$ ) + YYABORT; } | unorderedsel ; unorderedsel: - TK_SELECT selcollist from + TK_SELECT selectfrom { - SQL_input* sql = (SQL_input*) info; - if( !$3 ) - YYABORT; - if( $2 ) - { - $$ = do_one_select( sql->db, $3, $2 ); - if( !$$ ) - YYABORT; - } - else - $$ = $3; + $$ = $2; } - | TK_SELECT TK_DISTINCT selcollist from + | TK_SELECT TK_DISTINCT selectfrom { SQL_input* sql = (SQL_input*) info; - MSIVIEW *view = $4; - if( !view ) + $$ = NULL; + DISTINCT_CreateView( sql->db, &$$, $3 ); + if( !$$ ) + YYABORT; + } + ; + +selectfrom: + selcollist from + { + SQL_input* sql = (SQL_input*) info; + + $$ = NULL; + if( $1 ) + SELECT_CreateView( sql->db, &$$, $2, $1 ); + else + $$ = $2; + + if( !$$ ) YYABORT; - if( $3 ) - { - view = do_one_select( sql->db, view, $3 ); - if( !view ) - YYABORT; - } - DISTINCT_CreateView( sql->db, & $$, view ); } ; @@ -418,32 +418,29 @@ selcollist: ; from: - TK_FROM table + fromtable + | fromtable TK_WHERE expr { SQL_input* sql = (SQL_input*) info; UINT r; $$ = NULL; - TRACE("From table: %s\n",debugstr_w($2)); - r = TABLE_CreateView( sql->db, $2, & $$ ); - if( r != ERROR_SUCCESS ) + r = WHERE_CreateView( sql->db, &$$, $1, $3 ); + if( r != ERROR_SUCCESS || !$$ ) YYABORT; } - | TK_FROM table TK_WHERE expr - { + ; + +fromtable: + TK_FROM table + { SQL_input* sql = (SQL_input*) info; - MSIVIEW *view = NULL; UINT r; $$ = NULL; - TRACE("From table: %s\n",debugstr_w($2)); - r = TABLE_CreateView( sql->db, $2, &view ); - if( r != ERROR_SUCCESS ) + r = TABLE_CreateView( sql->db, $2, &$$ ); + if( r != ERROR_SUCCESS || !$$ ) YYABORT; - r = WHERE_CreateView( sql->db, &view, view, $4 ); - if( r != ERROR_SUCCESS ) - YYABORT; - $$ = view; } ; @@ -451,50 +448,74 @@ expr: TK_LP expr TK_RP { $$ = $2; + if( !$$ ) + YYABORT; } | column_val TK_EQ column_val { - $$ = EXPR_complex( $1, OP_EQ, $3 ); + $$ = EXPR_complex( info, $1, OP_EQ, $3 ); + if( !$$ ) + YYABORT; } | expr TK_AND expr { - $$ = EXPR_complex( $1, OP_AND, $3 ); + $$ = EXPR_complex( info, $1, OP_AND, $3 ); + if( !$$ ) + YYABORT; } | expr TK_OR expr { - $$ = EXPR_complex( $1, OP_OR, $3 ); + $$ = EXPR_complex( info, $1, OP_OR, $3 ); + if( !$$ ) + YYABORT; } | column_val TK_EQ val { - $$ = EXPR_complex( $1, OP_EQ, $3 ); + $$ = EXPR_complex( info, $1, OP_EQ, $3 ); + if( !$$ ) + YYABORT; } | column_val TK_GT val { - $$ = EXPR_complex( $1, OP_GT, $3 ); + $$ = EXPR_complex( info, $1, OP_GT, $3 ); + if( !$$ ) + YYABORT; } | column_val TK_LT val { - $$ = EXPR_complex( $1, OP_LT, $3 ); + $$ = EXPR_complex( info, $1, OP_LT, $3 ); + if( !$$ ) + YYABORT; } | column_val TK_LE val { - $$ = EXPR_complex( $1, OP_LE, $3 ); + $$ = EXPR_complex( info, $1, OP_LE, $3 ); + if( !$$ ) + YYABORT; } | column_val TK_GE val { - $$ = EXPR_complex( $1, OP_GE, $3 ); + $$ = EXPR_complex( info, $1, OP_GE, $3 ); + if( !$$ ) + YYABORT; } | column_val TK_NE val { - $$ = EXPR_complex( $1, OP_NE, $3 ); + $$ = EXPR_complex( info, $1, OP_NE, $3 ); + if( !$$ ) + YYABORT; } | column_val TK_IS TK_NULL { - $$ = EXPR_complex( $1, OP_ISNULL, NULL ); + $$ = EXPR_complex( info, $1, OP_ISNULL, NULL ); + if( !$$ ) + YYABORT; } | column_val TK_IS TK_NOT TK_NULL { - $$ = EXPR_complex( $1, OP_NOTNULL, NULL ); + $$ = EXPR_complex( info, $1, OP_NOTNULL, NULL ); + if( !$$ ) + YYABORT; } ; @@ -508,24 +529,22 @@ constlist: { value_list *vals; - vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals ); - if( vals ) - { - vals->val = $1; - vals->next = NULL; - } + vals = parser_alloc( info, sizeof *vals ); + if( !vals ) + YYABORT; + vals->val = $1; + vals->next = NULL; $$ = vals; } | const_val TK_COMMA constlist { value_list *vals; - vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals ); - if( vals ) - { - vals->val = $1; - vals->next = $3; - } + vals = parser_alloc( info, sizeof *vals ); + if( !vals ) + YYABORT; + vals->val = $1; + vals->next = $3; $$ = vals; } ; @@ -559,61 +578,79 @@ column_assignment: const_val: TK_INTEGER { - $$ = EXPR_ival( &$1, 1 ); + $$ = EXPR_ival( info, &$1, 1 ); + if( !$$ ) + YYABORT; } | TK_MINUS TK_INTEGER { - $$ = EXPR_ival( &$2, -1 ); + $$ = EXPR_ival( info, &$2, -1 ); + if( !$$ ) + YYABORT; } | TK_STRING { - $$ = EXPR_sval( &$1 ); + $$ = EXPR_sval( info, &$1 ); + if( !$$ ) + YYABORT; } | TK_WILDCARD { - $$ = EXPR_wildcard(); + $$ = EXPR_wildcard( info ); + if( !$$ ) + YYABORT; } ; column_val: column { - $$ = EXPR_column( $1 ); + $$ = EXPR_column( info, $1 ); + if( !$$ ) + YYABORT; } ; column: - table TK_DOT string_or_id + table TK_DOT id { $$ = $3; /* FIXME */ } - | string_or_id + | id { $$ = $1; } ; table: - string_or_id + id { $$ = $1; } ; -string_or_id: +id: TK_ID { - $$ = SQL_getstring( &$1 ); - } - | TK_STRING - { - $$ = SQL_getstring( &$1 ); + $$ = SQL_getstring( info, &$1 ); + if( !$$ ) + YYABORT; } ; %% -int SQL_lex( void *SQL_lval, SQL_input *sql) +static void *parser_alloc( void *info, unsigned int sz ) +{ + SQL_input* sql = (SQL_input*) info; + struct list *mem; + + mem = HeapAlloc( GetProcessHeap(), 0, sizeof (struct list) + sz ); + list_add_tail( sql->mem, mem ); + return &mem[1]; +} + +int SQL_lex( void *SQL_lval, SQL_input *sql ) { int token; struct sql_str * str = SQL_lval; @@ -638,7 +675,7 @@ int SQL_lex( void *SQL_lval, SQL_input *sql) return token; } -LPWSTR SQL_getstring( struct sql_str *strdata) +LPWSTR SQL_getstring( void *info, struct sql_str *strdata ) { LPCWSTR p = strdata->data; UINT len = strdata->len; @@ -651,61 +688,31 @@ LPWSTR SQL_getstring( struct sql_str *strdata) p++; len -= 2; } - str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR)); - if(!str ) + str = parser_alloc( info, (len + 1)*sizeof(WCHAR) ); + if( !str ) return str; - memcpy(str, p, len*sizeof(WCHAR) ); + memcpy( str, p, len*sizeof(WCHAR) ); str[len]=0; return str; } -INT SQL_getint( SQL_input *sql ) +INT SQL_getint( void *info ) { + SQL_input* sql = (SQL_input*) info; LPCWSTR p = &sql->command[sql->n]; return atoiW( p ); } -int SQL_error(const char *str) +int SQL_error( const char *str ) { return 0; } -static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, - string_list *columns ) +static struct expr * EXPR_wildcard( void *info ) { - MSIVIEW *view = NULL; - - SELECT_CreateView( db, &view, in, columns ); - delete_string_list( columns ); - if( !view ) - ERR("Error creating select query\n"); - return view; -} - -static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, - string_list *columns ) -{ - MSIVIEW *view = NULL; - - ORDER_CreateView( db, &view, in ); - if( view ) - { - string_list *x = columns; - - for( x = columns; x ; x = x->next ) - ORDER_AddColumn( view, x->string ); - } - else - ERR("Error creating select query\n"); - delete_string_list( columns ); - return view; -} - -static struct expr * EXPR_wildcard() -{ - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); + struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_WILDCARD; @@ -713,9 +720,9 @@ static struct expr * EXPR_wildcard() return e; } -static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r ) +static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r ) { - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); + struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_COMPLEX; @@ -726,20 +733,20 @@ static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r ) return e; } -static struct expr * EXPR_column( LPWSTR str ) +static struct expr * EXPR_column( void *info, LPWSTR column ) { - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); + struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_COLUMN; - e->u.sval = str; + e->u.sval = column; } return e; } -static struct expr * EXPR_ival( struct sql_str *str , int sign) +static struct expr * EXPR_ival( void *info, struct sql_str *str, int sign ) { - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); + struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_IVAL; @@ -748,57 +755,18 @@ static struct expr * EXPR_ival( struct sql_str *str , int sign) return e; } -static struct expr * EXPR_sval( struct sql_str *str ) +static struct expr * EXPR_sval( void *info, struct sql_str *str ) { - struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e ); + struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_SVAL; - e->u.sval = SQL_getstring( str ); + e->u.sval = SQL_getstring( info, str ); } return e; } -void delete_expr( struct expr *e ) -{ - if( !e ) - return; - if( e->type == EXPR_COMPLEX ) - { - delete_expr( e->u.expr.left ); - delete_expr( e->u.expr.right ); - } - else if( e->type == EXPR_UTF8 ) - HeapFree( GetProcessHeap(), 0, e->u.utf8 ); - else if( e->type == EXPR_SVAL ) - HeapFree( GetProcessHeap(), 0, e->u.sval ); - HeapFree( GetProcessHeap(), 0, e ); -} - -void delete_string_list( string_list *sl ) -{ - while( sl ) - { - string_list *t = sl->next; - HeapFree( GetProcessHeap(), 0, sl->string ); - HeapFree( GetProcessHeap(), 0, sl ); - sl = t; - } -} - -void delete_value_list( value_list *vl ) -{ - while( vl ) - { - value_list *t = vl->next; - delete_expr( vl->val ); - HeapFree( GetProcessHeap(), 0, vl ); - vl = t; - } -} - -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, - string_list *keys ) +static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys) { string_list *k; BOOL found = TRUE; @@ -820,7 +788,8 @@ static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, return found; } -UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview ) +UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview, + struct list *mem ) { SQL_input sql; int r; @@ -832,6 +801,7 @@ UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview ) sql.n = 0; sql.len = 0; sql.view = phview; + sql.mem = mem; r = SQL_parse(&sql); diff --git a/reactos/lib/msi/suminfo.c b/reactos/lib/msi/suminfo.c index 74f00dc64ad..997dacc3698 100644 --- a/reactos/lib/msi/suminfo.c +++ b/reactos/lib/msi/suminfo.c @@ -39,7 +39,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); -#define MSI_MAX_PROPS 19 +#define MSI_MAX_PROPS 20 #include "pshpack1.h" @@ -81,6 +81,8 @@ typedef struct { #include "poppack.h" +#define SECT_HDR_SIZE (sizeof(PROPERTYSECTIONHEADER)) + typedef struct { BOOL unicode; union { @@ -162,17 +164,21 @@ static UINT get_property_count( PROPVARIANT *property ) } /* FIXME: doesn't deal with endian conversion */ -static void read_properties_from_data( PROPVARIANT *prop, - PROPERTYIDOFFSET *idofs, DWORD count, LPBYTE data, DWORD sz ) +static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz ) { UINT type; DWORD i; int size; PROPERTY_DATA *propdata; PROPVARIANT *property; + PROPERTYIDOFFSET *idofs; + PROPERTYSECTIONHEADER *section_hdr; + + section_hdr = (PROPERTYSECTIONHEADER*) &data[0]; + idofs = (PROPERTYIDOFFSET*) &data[SECT_HDR_SIZE]; /* now set all the properties */ - for( i = 0; i < count; i++ ) + for( i = 0; i < section_hdr->cProperties; i++ ) { type = get_type( idofs[i].propid ); if( type == VT_EMPTY ) @@ -181,12 +187,12 @@ static void read_properties_from_data( PROPVARIANT *prop, break; } - propdata = (PROPERTY_DATA*) &data[idofs[i].dwOffset]; + propdata = (PROPERTY_DATA*) &data[ idofs[i].dwOffset ]; /* check the type is the same as we expect */ if( type != propdata->type ) { - ERR("wrong type\n"); + ERR("wrong type %d != %ld\n", type, propdata->type); break; } @@ -200,6 +206,12 @@ static void read_properties_from_data( PROPVARIANT *prop, break; } + if( idofs[i].propid >= MSI_MAX_PROPS ) + { + ERR("Unknown property ID %ld\n", idofs[i].propid ); + break; + } + property = &prop[ idofs[i].propid ]; property->vt = type; @@ -225,7 +237,6 @@ static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm ) PROPERTYSETHEADER set_hdr; FORMATIDOFFSET format_hdr; PROPERTYSECTIONHEADER section_hdr; - PROPERTYIDOFFSET idofs[MSI_MAX_PROPS]; LPBYTE data = NULL; LARGE_INTEGER ofs; ULONG count, sz; @@ -261,7 +272,7 @@ static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm ) return ret; /* read the section itself */ - sz = sizeof section_hdr; + sz = SECT_HDR_SIZE; r = IStream_Read( stm, §ion_hdr, sz, &count ); if( FAILED(r) || count != sz ) return ret; @@ -272,23 +283,19 @@ static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm ) return ret; } - /* read the offsets */ - sz = sizeof idofs[0] * section_hdr.cProperties; - r = IStream_Read( stm, idofs, sz, &count ); - if( FAILED(r) || count != sz ) - return ret; - - /* read all the data in one go */ - sz = section_hdr.cbSection; - data = HeapAlloc( GetProcessHeap(), 0, sz ); + data = HeapAlloc( GetProcessHeap(), 0, section_hdr.cbSection); if( !data ) return ret; - r = IStream_Read( stm, data, sz, &count ); + + memcpy( data, §ion_hdr, SECT_HDR_SIZE ); + + /* read all the data in one go */ + sz = section_hdr.cbSection - SECT_HDR_SIZE; + r = IStream_Read( stm, &data[ SECT_HDR_SIZE ], sz, &count ); if( SUCCEEDED(r) && count == sz ) - { - read_properties_from_data( si->property, idofs, - section_hdr.cProperties, data, sz ); - } + read_properties_from_data( si->property, data, sz + SECT_HDR_SIZE ); + else + ERR("failed to read properties %ld %ld\n", count, sz); HeapFree( GetProcessHeap(), 0, data ); return ret; @@ -481,7 +488,7 @@ UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, end: if( db ) - msiobj_release(&db->hdr); + msiobj_release( &db->hdr ); return ret; } @@ -531,24 +538,20 @@ static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, { MSISUMMARYINFO *si; PROPVARIANT *prop; - UINT type; TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType, piValue, pftValue, str, pcchValueBuf); - type = get_type( uiProperty ); - if( puiDataType ) - *puiDataType = type; - si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ); if( !si ) return ERROR_INVALID_HANDLE; prop = &si->property[uiProperty]; - if( prop->vt != type ) - goto end; - switch( type ) + if( puiDataType ) + *puiDataType = prop->vt; + + switch( prop->vt ) { case VT_I2: if( piValue ) @@ -587,7 +590,6 @@ static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, FIXME("Unknown property variant type\n"); break; } -end: msiobj_release( &si->hdr ); return ERROR_SUCCESS; } diff --git a/reactos/lib/msi/table.c b/reactos/lib/msi/table.c index cf0718b19c7..b0fe75b69c3 100644 --- a/reactos/lib/msi/table.c +++ b/reactos/lib/msi/table.c @@ -35,8 +35,6 @@ #include "msipriv.h" #include "winnls.h" -#include "wine/unicode.h" - #include "query.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -98,7 +96,7 @@ static LPWSTR encode_streamname(BOOL bTable, LPCWSTR in) LPWSTR out, p; if( !bTable ) - count = strlenW( in )+2; + count = lstrlenW( in )+2; out = HeapAlloc( GetProcessHeap(), 0, count*sizeof(WCHAR) ); p = out; @@ -231,13 +229,13 @@ static UINT read_stream_data( IStorage *stg, LPCWSTR stname, r = IStream_Stat(stm, &stat, STATFLAG_NONAME ); if( FAILED( r ) ) { - ERR("open stream failed r = %08lx!\n",r); + WARN("open stream failed r = %08lx!\n",r); goto end; } if( stat.cbSize.QuadPart >> 32 ) { - ERR("Too big!\n"); + WARN("Too big!\n"); goto end; } @@ -245,7 +243,7 @@ static UINT read_stream_data( IStorage *stg, LPCWSTR stname, data = HeapAlloc( GetProcessHeap(), 0, sz ); if( !data ) { - ERR("couldn't allocate memory r=%08lx!\n",r); + WARN("couldn't allocate memory r=%08lx!\n",r); ret = ERROR_NOT_ENOUGH_MEMORY; goto end; } @@ -254,7 +252,7 @@ static UINT read_stream_data( IStorage *stg, LPCWSTR stname, if( FAILED( r ) || ( count != sz ) ) { HeapFree( GetProcessHeap(), 0, data ); - ERR("read stream failed r = %08lx!\n",r); + WARN("read stream failed r = %08lx!\n",r); goto end; } @@ -305,13 +303,13 @@ UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname, r = IStream_Stat(stm, &stat, STATFLAG_NONAME ); if( FAILED( r ) ) { - ERR("open stream failed r = %08lx!\n",r); + WARN("open stream failed r = %08lx!\n",r); goto end; } if( stat.cbSize.QuadPart >> 32 ) { - ERR("Too big!\n"); + WARN("Too big!\n"); goto end; } @@ -319,7 +317,7 @@ UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname, data = HeapAlloc( GetProcessHeap(), 0, sz ); if( !data ) { - ERR("couldn't allocate memory r=%08lx!\n",r); + WARN("couldn't allocate memory r=%08lx!\n",r); ret = ERROR_NOT_ENOUGH_MEMORY; goto end; } @@ -328,7 +326,7 @@ UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname, if( FAILED( r ) || ( count != sz ) ) { HeapFree( GetProcessHeap(), 0, data ); - ERR("read stream failed r = %08lx!\n",r); + WARN("read stream failed r = %08lx!\n",r); goto end; } @@ -364,7 +362,7 @@ static UINT write_stream_data( IStorage *stg, LPCWSTR stname, HeapFree( GetProcessHeap(), 0, encname ); if( FAILED( r ) ) { - ERR("open stream failed r = %08lx\n",r); + WARN("open stream failed r = %08lx\n",r); return ret; } @@ -372,7 +370,7 @@ static UINT write_stream_data( IStorage *stg, LPCWSTR stname, r = IStream_SetSize( stm, size ); if( FAILED( r ) ) { - ERR("Failed to SetSize\n"); + WARN("Failed to SetSize\n"); goto end; } @@ -380,14 +378,14 @@ static UINT write_stream_data( IStorage *stg, LPCWSTR stname, r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL ); if( FAILED( r ) ) { - ERR("Failed to Seek\n"); + WARN("Failed to Seek\n"); goto end; } r = IStream_Write(stm, data, sz, &count ); if( FAILED( r ) || ( count != sz ) ) { - ERR("Failed to Write\n"); + WARN("Failed to Write\n"); goto end; } @@ -438,7 +436,7 @@ UINT read_table_from_storage( MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) if( rawsize % row_size ) { - ERR("Table size is invalid %d/%d\n", rawsize, row_size ); + WARN("Table size is invalid %d/%d\n", rawsize, row_size ); return ERROR_FUNCTION_FAILED; } @@ -773,13 +771,13 @@ UINT save_string_table( MSIDATABASE *db ) pool = HeapAlloc( GetProcessHeap(), 0, poolsize ); if( ! pool ) { - ERR("Failed to alloc pool %d bytes\n", poolsize ); + WARN("Failed to alloc pool %d bytes\n", poolsize ); goto err; } data = HeapAlloc( GetProcessHeap(), 0, datasize ); if( ! data ) { - ERR("Failed to alloc data %d bytes\n", poolsize ); + WARN("Failed to alloc data %d bytes\n", poolsize ); goto err; } @@ -923,7 +921,7 @@ static UINT get_tablecolumns( MSIDATABASE *db, r = get_table( db, szColumns, &table); if( r != ERROR_SUCCESS ) { - ERR("table %s not available\n", debugstr_w(szColumns)); + WARN("table %s not available\n", debugstr_w(szColumns)); return r; } @@ -932,7 +930,7 @@ static UINT get_tablecolumns( MSIDATABASE *db, if( r != ERROR_SUCCESS ) { release_table( db, table ); - ERR("Couldn't find id for %s\n", debugstr_w(szTableName)); + WARN("Couldn't find id for %s\n", debugstr_w(szTableName)); return r; } @@ -1001,7 +999,7 @@ BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name ) r = get_table( db, szTables, &table); if( r != ERROR_SUCCESS ) { - ERR("table %s not available\n", debugstr_w(szTables)); + TRACE("table %s not available\n", debugstr_w(szTables)); return FALSE; } @@ -1016,7 +1014,7 @@ BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name ) if (i!=count) return TRUE; - ERR("Searched %d tables, but %d was not found\n", count, table_id ); + TRACE("Searched %d tables, but %d was not found\n", count, table_id ); return FALSE; } @@ -1117,11 +1115,11 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt if( !sval ) return ERROR_INVALID_PARAMETER; - len = strlenW( tv->name ) + 2 + strlenW( sval ); + len = lstrlenW( tv->name ) + 2 + lstrlenW( sval ); full_name = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); - strcpyW( full_name, tv->name ); - strcatW( full_name, szDot ); - strcatW( full_name, sval ); + lstrcpyW( full_name, tv->name ); + lstrcatW( full_name, szDot ); + lstrcatW( full_name, sval ); r = db_get_raw_stream( tv->db, full_name, stm ); if( r ) @@ -1397,7 +1395,7 @@ UINT MSI_CommitTables( MSIDATABASE *db ) r = save_string_table( db ); if( r != ERROR_SUCCESS ) { - ERR("failed to save string table r=%08x\n",r); + WARN("failed to save string table r=%08x\n",r); return r; } @@ -1406,7 +1404,7 @@ UINT MSI_CommitTables( MSIDATABASE *db ) r = save_table( db, table ); if( r != ERROR_SUCCESS ) { - ERR("failed to save table %s (r=%08x)\n", + WARN("failed to save table %s (r=%08x)\n", debugstr_w(table->name), r); return r; } diff --git a/reactos/lib/msi/tokenize.c b/reactos/lib/msi/tokenize.c index d3ad0cfaf8f..223414eb47b 100644 --- a/reactos/lib/msi/tokenize.c +++ b/reactos/lib/msi/tokenize.c @@ -346,7 +346,10 @@ int sqliteGetToken(const WCHAR *z, int *tokenType){ } } if( z[i] ) i++; - *tokenType = TK_STRING; + if( delim == '`' ) + *tokenType = TK_ID; + else + *tokenType = TK_STRING; return i; } case '.': { diff --git a/reactos/lib/msi/update.c b/reactos/lib/msi/update.c index 39c19d8d154..88644bd3005 100644 --- a/reactos/lib/msi/update.c +++ b/reactos/lib/msi/update.c @@ -171,7 +171,6 @@ static UINT UPDATE_delete( struct tagMSIVIEW *view ) wv = uv->wv; if( wv ) wv->ops->delete( wv ); - delete_value_list( uv->vals ); msiobj_release( &uv->db->hdr ); HeapFree( GetProcessHeap(), 0, uv ); diff --git a/reactos/lib/msi/version.rc b/reactos/lib/msi/version.rc index 625c7a7e85a..85179ce15e2 100644 --- a/reactos/lib/msi/version.rc +++ b/reactos/lib/msi/version.rc @@ -18,9 +18,9 @@ #define WINE_FILEDESCRIPTION_STR "Wine MSI dll" #define WINE_FILENAME_STR "msi.dll" -#define WINE_FILEVERSION 2,0,2600,0 -#define WINE_FILEVERSION_STR "2.0.2600.0" -#define WINE_PRODUCTVERSION 2,0,2600,0 -#define WINE_PRODUCTVERSION_STR "2.0.2600.0" +#define WINE_FILEVERSION 3,1,4000,2435 +#define WINE_FILEVERSION_STR "3.1.4000.2435" +#define WINE_PRODUCTVERSION 3,1,4000,2435 +#define WINE_PRODUCTVERSION_STR "3.1.4000.2435" #include "wine/wine_common_ver.rc" diff --git a/reactos/lib/msi/where.c b/reactos/lib/msi/where.c index 8b84d3aafab..9a78074ea1b 100644 --- a/reactos/lib/msi/where.c +++ b/reactos/lib/msi/where.c @@ -334,9 +334,6 @@ static UINT WHERE_delete( struct tagMSIVIEW *view ) wv->reorder = NULL; wv->row_count = 0; - if( wv->cond ) - delete_expr( wv->cond ); - msiobj_release( &wv->db->hdr ); HeapFree( GetProcessHeap(), 0, wv ); diff --git a/reactos/lib/msimg32/Makefile.in b/reactos/lib/msimg32/Makefile.in index 9314038c22a..3d097d3e85a 100644 --- a/reactos/lib/msimg32/Makefile.in +++ b/reactos/lib/msimg32/Makefile.in @@ -3,6 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = msimg32.dll +IMPORTLIB = libmsimg32.$(IMPLIBEXT) IMPORTS = gdi32 kernel32 C_SRCS = msimg32_main.c diff --git a/reactos/lib/msimg32/msimg32.xml b/reactos/lib/msimg32/msimg32.xml index 3345a59a6d8..620a937b044 100644 --- a/reactos/lib/msimg32/msimg32.xml +++ b/reactos/lib/msimg32/msimg32.xml @@ -1,4 +1,4 @@ - + . include diff --git a/reactos/lib/ntdll/ldr/utils.c b/reactos/lib/ntdll/ldr/utils.c index 13013316a97..093b75bce0b 100644 --- a/reactos/lib/ntdll/ldr/utils.c +++ b/reactos/lib/ntdll/ldr/utils.c @@ -289,7 +289,6 @@ LdrpInitializeTlsForProccess(VOID) * Is this region allways writable ? */ *(PULONG)TlsDirectory->AddressOfIndex = Module->TlsIndex; - CHECKPOINT1; } Entry = Entry->Flink; } @@ -1969,7 +1968,6 @@ PEPFUNC LdrPEStartup (PVOID ImageBase, RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock); if (!NT_SUCCESS(Status)) { - CHECKPOINT1; return NULL; } @@ -2158,7 +2156,6 @@ LdrpUnloadModule(PLDR_MODULE Module, if (LoadCount == 0) { /* ?????????????????? */ - CHECKPOINT1; } else if (LoadCount == 1) { diff --git a/reactos/lib/oledlg/oledlg_Ru.rc b/reactos/lib/oledlg/oledlg_Ru.rc new file mode 100644 index 00000000000..11972e4aee2 --- /dev/null +++ b/reactos/lib/oledlg/oledlg_Ru.rc @@ -0,0 +1,56 @@ +/* + * Copyright 2005 Mikhail Y. Zvyozdochkin + * Aleksey Bragin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT + +UIINSERTOBJECT DIALOG DISCARDABLE 0, 0, 294, 151 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Âñòàâêà îáúåêòà" +FONT 8, "MS Shell Dlg" +BEGIN + LISTBOX IDC_OBJTYPELIST,82,19,131,66,LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VISIBLE | WS_VSCROLL | + WS_TABSTOP + LTEXT "Òèï îáúåêòà:",IDC_OBJTYPELBL,82,7,53,8,WS_VISIBLE + DEFPUSHBUTTON "OK",IDOK,221,7,66,14 + PUSHBUTTON "Îòìåíà",IDCANCEL,221,24,66,14 + GROUPBOX "Ðåçóëüòàò",IDC_RESULT,7,103,208,41 + CONTROL "Ñîçäàòü íîâûé",IDC_CREATENEW,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,7,20,62,10 + CONTROL "Ñîçäàòü ýëåìåíò óïðàâëåíèÿ",IDC_CREATECONTROL,"Button", + BS_AUTORADIOBUTTON | NOT WS_VISIBLE,7,54,62,10 + CONTROL "Ñîçäàòü èç ôàéëà",IDC_CREATEFROMFILE,"Button", + BS_AUTORADIOBUTTON,7,37,67,10 + LTEXT "",IDC_RESULTDESC,49,112,159,23 + PUSHBUTTON "&Äîáàâèòü ýëåìåíò óïðàâëåíèÿ...",IDC_ADDCONTROL,81,88,63,14,NOT WS_VISIBLE + CONTROL "Îòîáðàæàòü â âèäå çíà÷êà",IDC_ASICON,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP | NOT WS_VISIBLE,223,58,64,10 + PUSHBUTTON "Îáçîð...",IDC_BROWSE,83,53,50,14,NOT WS_VISIBLE + LTEXT "Ôàéë:",IDC_FILELBL,83,27,20,8, NOT WS_VISIBLE + EDITTEXT IDC_FILE,83,37,132,13,ES_AUTOHSCROLL | NOT WS_VISIBLE +END + +STRINGTABLE DISCARDABLE +{ + IDS_RESULTOBJDESC "Âñòàâèòü íîâûé îáúåêò %s â Âàø äîêóìåíò" + IDS_RESULTFILEOBJDESC "Âñòàâèòü ñîäåðæèìîå ôàéëà êàê îáúåêò â Âàø äîêóìåíò òàê, ÷òî Âû ìîæåòå ðàáîòàòü ñ íèì, èñïîëüçóÿ òó ïðîãðàììó, êîòîðîé îí ñîçäàí." + IDS_BROWSE "Îáçîð" + IDS_NOTOLEMOD "Ôàéë íå ÿâëÿåòñÿ êîððåêòíûì ìîäóëåì OLE. Íå âîçìîæíî çàðåãèñòðèðîâàòü ýëåìåíò óïðàâëåíèÿ OLE." + IDS_NOTOLEMODCAPTION "Äîáàâëÿåò ýëåìåíò óïðàâëåíèÿ" +} diff --git a/reactos/lib/oledlg/rsrc.rc b/reactos/lib/oledlg/rsrc.rc index 09a88aa1f2b..4bf0648e25f 100644 --- a/reactos/lib/oledlg/rsrc.rc +++ b/reactos/lib/oledlg/rsrc.rc @@ -40,3 +40,4 @@ #include "oledlg_Ja.rc" #include "oledlg_Nl.rc" #include "oledlg_Pt.rc" +#include "oledlg_Ru.rc" diff --git a/reactos/lib/rpcrt4/rpcrt4_main.c b/reactos/lib/rpcrt4/rpcrt4_main.c index bdab2e87036..4f8d66a6ba6 100644 --- a/reactos/lib/rpcrt4/rpcrt4_main.c +++ b/reactos/lib/rpcrt4/rpcrt4_main.c @@ -319,6 +319,8 @@ static void RPC_UuidGetSystemTime(ULONGLONG *time) *time += TICKS_15_OCT_1582_TO_1601; } +typedef DWORD WINAPI (*LPGETADAPTERSINFO)(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen); + /* Assume that a hardware address is at least 6 bytes long */ #define ADDRESS_BYTES_NEEDED 6 @@ -329,28 +331,46 @@ static RPC_STATUS RPC_UuidGetNodeAddress(BYTE *address) ULONG buflen = sizeof(IP_ADAPTER_INFO); PIP_ADAPTER_INFO adapter = HeapAlloc(GetProcessHeap(), 0, buflen); + HANDLE hIpHlpApi; + LPGETADAPTERSINFO pGetAdaptersInfo; + + hIpHlpApi = LoadLibrary("iphlpapi.dll"); + if (hIpHlpApi) + { + pGetAdaptersInfo = (LPGETADAPTERSINFO)GetProcAddress(hIpHlpApi, "GetAdaptersInfo"); + if (pGetAdaptersInfo) + { + if (pGetAdaptersInfo(adapter, &buflen) == ERROR_BUFFER_OVERFLOW) { + HeapFree(GetProcessHeap(), 0, adapter); + adapter = HeapAlloc(GetProcessHeap(), 0, buflen); + } - if (GetAdaptersInfo(adapter, &buflen) == ERROR_BUFFER_OVERFLOW) { - HeapFree(GetProcessHeap(), 0, adapter); - adapter = HeapAlloc(GetProcessHeap(), 0, buflen); - } - - if (GetAdaptersInfo(adapter, &buflen) == NO_ERROR) { - for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { - address[i] = adapter->Address[i]; + if (pGetAdaptersInfo(adapter, &buflen) == NO_ERROR) { + for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { + address[i] = adapter->Address[i]; + } + } + else + { + goto local; + } } + + /* Free the Library */ + FreeLibrary(hIpHlpApi); + goto exit; } + +local: /* We can't get a hardware address, just use random numbers. - Set the multicast bit to prevent conflicts with real cards. */ - else { - for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { - address[i] = rand() & 0xff; - } - - address[0] |= 0x01; - status = RPC_S_UUID_LOCAL_ONLY; + Set the multicast bit to prevent conflicts with real cards. */ + for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { + address[i] = rand() & 0xff; } - + address[0] |= 0x01; + status = RPC_S_UUID_LOCAL_ONLY; + +exit: HeapFree(GetProcessHeap(), 0, adapter); return status; } diff --git a/reactos/lib/rtl/unicode.c b/reactos/lib/rtl/unicode.c index 8a772040616..79aa1d8af9c 100644 --- a/reactos/lib/rtl/unicode.c +++ b/reactos/lib/rtl/unicode.c @@ -990,7 +990,7 @@ RtlUnicodeStringToAnsiString( AnsiDest, UniSource, AllocateDestinationString, - NonPagedPool); + PagedPool); } @@ -1073,7 +1073,7 @@ RtlOemStringToUnicodeString( UniDest, OemSource, AllocateDestinationString, - NonPagedPool); + PagedPool); } @@ -1157,7 +1157,7 @@ RtlUnicodeStringToOemString( OemDest, UniSource, AllocateDestinationString, - NonPagedPool); + PagedPool); } @@ -1304,7 +1304,7 @@ RtlOemStringToCountedUnicodeString( UniDest, OemSource, AllocateDestinationString, - NonPagedPool); + PagedPool); } @@ -1634,7 +1634,7 @@ RtlUnicodeStringToCountedOemString( OemDest, UniSource, AllocateDestinationString, - NonPagedPool); + PagedPool); } /* @@ -1766,7 +1766,7 @@ RtlUpcaseUnicodeString( UniDest, UniSource, AllocateDestinationString, - NonPagedPool); + PagedPool); } @@ -1833,7 +1833,7 @@ RtlUpcaseUnicodeStringToAnsiString( AnsiDest, UniSource, AllocateDestinationString, - NonPagedPool); + PagedPool); } /* @@ -1921,7 +1921,7 @@ RtlUpcaseUnicodeStringToCountedOemString( OemDest, UniSource, AllocateDestinationString, - NonPagedPool); + PagedPool); } @@ -2007,7 +2007,7 @@ RtlUpcaseUnicodeStringToOemString ( OemDest, UniSource, AllocateDestinationString, - NonPagedPool); + PagedPool); } @@ -2287,7 +2287,7 @@ RtlCreateUnicodeString( { DPRINT("RtlCreateUnicodeString\n"); - return RtlpCreateUnicodeString(UniDest, Source, NonPagedPool); + return RtlpCreateUnicodeString(UniDest, Source, PagedPool); } @@ -2306,7 +2306,7 @@ RtlpCreateUnicodeString( ULONG Length; Length = (wcslen (Source) + 1) * sizeof(WCHAR); - + PoolType = PagedPool; UniDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG_USTR); if (UniDest->Buffer == NULL) return FALSE; @@ -2363,7 +2363,7 @@ RtlDowncaseUnicodeString( UniDest, UniSource, AllocateDestinationString, - NonPagedPool); + PagedPool); } @@ -2473,7 +2473,7 @@ RtlAnsiStringToUnicodeString( UniDest, AnsiSource, AllocateDestinationString, - NonPagedPool); + PagedPool); } @@ -2664,7 +2664,7 @@ RtlDuplicateUnicodeString( AddNull, SourceString, DestinationString, - NonPagedPool); + PagedPool); } diff --git a/reactos/lib/setupapi/Sv.rc b/reactos/lib/setupapi/Sv.rc new file mode 100644 index 00000000000..ad5a681b975 --- /dev/null +++ b/reactos/lib/setupapi/Sv.rc @@ -0,0 +1,34 @@ +/* + * Swedish resources for SETUPAPI + * + * Copyright 2005 Anders Bergh + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_SWEDISH, SUBLANG_DEFAULT + +COPYFILEDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE 20, 20, 208, 105 +STYLE DS_MODALFRAME | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "Kopierar filer..." +FONT 8, "MS Shell Dlg" +BEGIN + PUSHBUTTON "Avbryt", IDCANCEL, 79, 84, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP + LTEXT "Källa:", -1, 7, 7, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", SOURCESTRORD, 7, 18, 194, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "Destination:", -1, 7, 30, 77, 11, WS_CHILD | WS_VISIBLE | WS_GROUP + LTEXT "", DESTSTRORD, 7, 41, 194, 22, WS_CHILD | WS_VISIBLE | WS_GROUP + CONTROL "", PROGRESSORD, "setupx_progress", 7, 63, 194, 13, WS_CHILD | WS_VISIBLE | WS_TABSTOP +END diff --git a/reactos/lib/setupapi/misc.c b/reactos/lib/setupapi/misc.c index a74ef6f1a47..e5b9b542b10 100644 --- a/reactos/lib/setupapi/misc.c +++ b/reactos/lib/setupapi/misc.c @@ -934,3 +934,113 @@ DWORD WINAPI GetSetFileTimestamp(LPCWSTR lpFileName, return dwError; } + + +/************************************************************************** + * MyGetFileTitle [SETUPAPI.@] + * + * Returns a pointer to the last part of a fully qualified file name. + * + * PARAMS + * lpFileName [I] File name + * + * RETURNS + * Pointer to a files name. + */ +LPWSTR WINAPI +MyGetFileTitle(LPCWSTR lpFileName) +{ + LPWSTR ptr; + LPWSTR ret; + WCHAR c; + + TRACE("%s\n", debugstr_w(lpFileName)); + + ptr = (LPWSTR)lpFileName; + ret = ptr; + while (TRUE) + { + c = *ptr; + + if (c == 0) + break; + + ptr++; + if (c == (WCHAR)'\\' || c == (WCHAR)'/' || c == (WCHAR)':') + ret = ptr; + } + + return ret; +} + + +/************************************************************************** + * ConcatenatePaths [SETUPAPI.@] + * + * Concatenates two paths. + * + * PARAMS + * lpPath [I/O] Path to append path to + * lpAppend [I] Path to append + * dwBufferSize [I] Size of the path buffer + * lpRequiredSize [O] Required size for the concatenated path. Optional + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI +ConcatenatePaths(LPWSTR lpPath, + LPCWSTR lpAppend, + DWORD dwBufferSize, + LPDWORD lpRequiredSize) +{ + DWORD dwPathSize; + DWORD dwAppendSize; + DWORD dwTotalSize; + BOOL bBackslash = FALSE; + + TRACE("%s %s %lu %p\n", debugstr_w(lpPath), debugstr_w(lpAppend), + dwBufferSize, lpRequiredSize); + + dwPathSize = lstrlenW(lpPath); + + /* Ignore trailing backslash */ + if (lpPath[dwPathSize - 1] == (WCHAR)'\\') + dwPathSize--; + + dwAppendSize = lstrlenW(lpAppend); + + /* Does the source string have a leading backslash? */ + if (lpAppend[0] == (WCHAR)'\\') + { + bBackslash = TRUE; + dwAppendSize--; + } + + dwTotalSize = dwPathSize + dwAppendSize + 2; + if (lpRequiredSize != NULL) + *lpRequiredSize = dwTotalSize; + + /* Append a backslash to the destination string */ + if (bBackslash == FALSE) + { + if (dwPathSize < dwBufferSize) + { + lpPath[dwPathSize - 1] = (WCHAR)'\\'; + dwPathSize++; + } + } + + if (dwPathSize + dwAppendSize < dwBufferSize) + { + lstrcpynW(&lpPath[dwPathSize], + lpAppend, + dwAppendSize); + } + + if (dwBufferSize >= dwTotalSize) + lpPath[dwTotalSize - 1] = 0; + + return (dwBufferSize >= dwTotalSize); +} diff --git a/reactos/lib/setupapi/setupapi.rc b/reactos/lib/setupapi/setupapi.rc index 9cc3d89ddff..c33178e19e5 100644 --- a/reactos/lib/setupapi/setupapi.rc +++ b/reactos/lib/setupapi/setupapi.rc @@ -35,3 +35,4 @@ #include "Nl.rc" #include "Pt.rc" #include "Ru.rc" +#include "Sv.rc" diff --git a/reactos/lib/setupapi/setupapi.spec b/reactos/lib/setupapi/setupapi.spec index b5a6c867f00..7b172479d72 100644 --- a/reactos/lib/setupapi/setupapi.spec +++ b/reactos/lib/setupapi/setupapi.spec @@ -193,7 +193,7 @@ @ stdcall CaptureAndConvertAnsiArg(str ptr) @ stdcall CaptureStringArg(wstr ptr) @ stub CenterWindowRelativeToParent -@ stub ConcatenatePaths +@ stdcall ConcatenatePaths(wstr wstr long ptr) @ stdcall DelayedMove(wstr wstr) @ stub DelimStringToMultiSz @ stub DestroyTextFileReadBuffer @@ -220,7 +220,7 @@ @ stdcall MultiByteToUnicode(str long) @ stub MultiSzFromSearchControl @ stdcall MyFree(ptr) -@ stub MyGetFileTitle +@ stdcall MyGetFileTitle(wstr) @ stdcall MyMalloc(long) @ stdcall MyRealloc(ptr long) @ stdcall OpenAndMapFileForRead(wstr ptr ptr ptr ptr) @@ -424,8 +424,8 @@ @ stub SetupGetTargetPathW @ stdcall SetupInitDefaultQueueCallback(long) @ stdcall SetupInitDefaultQueueCallbackEx(long long long long ptr) -@ stdcall SetupInitializeFileLogA (str long) -@ stdcall SetupInitializeFileLogW (wstr long) +@ stdcall SetupInitializeFileLogA(str long) +@ stdcall SetupInitializeFileLogW(wstr long) @ stub SetupInstallFileA @ stub SetupInstallFileExA @ stub SetupInstallFileExW diff --git a/reactos/lib/shdocvw/Ru.rc b/reactos/lib/shdocvw/Ru.rc new file mode 100644 index 00000000000..2129f86916e --- /dev/null +++ b/reactos/lib/shdocvw/Ru.rc @@ -0,0 +1,37 @@ +/* + * Copyright 2005 Mikhail Y. Zvyozdochkin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT + +100 DIALOG LOADONCALL MOVEABLE DISCARDABLE 0, 0, 220, 62 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Çàãðóçêà ýëåìåíòà óïðàâëåíèÿ Mozilla Active X" +FONT 8, "MS Shell Dlg" +{ + CONTROL "Progress1",1000,"msctls_progress32",WS_BORDER|PBS_SMOOTH,10,10,200,12 + LTEXT "", 104, 10, 30, 200, 10, SS_CENTER + PUSHBUTTON "Îòìåíà", IDCANCEL, 85, 44, 50, 15, WS_GROUP | WS_TABSTOP +} + +STRINGTABLE +BEGIN + 1001 "Ïðèëîæåíèå çàïðàøèâàåò ActiveX-îáúåêò îáîçðåâàòåëÿ,\n" \ + "îäíàêî ýëåìåíò óïðàâëåíèÿ Mozilla ActiveX íåóñòàíîâëåí." \ + "Õîòèòå çàãðóçèòü è óñòàíîâèòü åãî?" +END + diff --git a/reactos/lib/shdocvw/Sv.rc b/reactos/lib/shdocvw/Sv.rc new file mode 100644 index 00000000000..45c5124cbaa --- /dev/null +++ b/reactos/lib/shdocvw/Sv.rc @@ -0,0 +1,34 @@ +/* + * Copyright 2005 Anders Bergh + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_SWEDISH, SUBLANG_DEFAULT + +100 DIALOG LOADONCALL MOVEABLE DISCARDABLE 0, 0, 220, 62 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Laddar ner Mozilla ActiveX-komponent" +FONT 8, "MS Shell Dlg" +{ + CONTROL "Progress1",1000,"msctls_progress32",WS_BORDER|PBS_SMOOTH,10,10,200,12 + PUSHBUTTON "Avbryt", IDCANCEL, 85, 44, 50, 15, WS_GROUP | WS_TABSTOP +} + +STRINGTABLE +BEGIN + 1001 "Programmet kräver en ActiveX-komponent som inte är tillgänglig.\n" + "Vill du ladda ner och installera Mozillas ActiveX-komponent?" +END diff --git a/reactos/lib/shdocvw/shdocvw.rc b/reactos/lib/shdocvw/shdocvw.rc index 362cebcbddd..160adee30b3 100644 --- a/reactos/lib/shdocvw/shdocvw.rc +++ b/reactos/lib/shdocvw/shdocvw.rc @@ -29,3 +29,5 @@ #include "Fr.rc" #include "Nl.rc" #include "Pt.rc" +#include "Ru.rc" +#include "Sv.rc" diff --git a/reactos/lib/shdocvw/shdocvw.xml b/reactos/lib/shdocvw/shdocvw.xml index fa7ac28294f..f803d48a060 100644 --- a/reactos/lib/shdocvw/shdocvw.xml +++ b/reactos/lib/shdocvw/shdocvw.xml @@ -1,4 +1,4 @@ - + . include/wine diff --git a/reactos/lib/user32/misc/display.c b/reactos/lib/user32/misc/display.c index 6fcd069f023..bca76e76544 100644 --- a/reactos/lib/user32/misc/display.c +++ b/reactos/lib/user32/misc/display.c @@ -110,7 +110,7 @@ EnumDisplayDevicesW( lpDisplayDevice, dwFlags ); - RtlFreeUnicodeString ( &Device ); + //RtlFreeUnicodeString ( &Device ); return rc; } @@ -200,15 +200,7 @@ EnumDisplaySettingsExA( { BOOL rc; UNICODE_STRING DeviceName; - LPDEVMODEW lpDevModeW; - - lpDevModeW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(DEVMODEW) + lpDevMode->dmDriverExtra); - if ( lpDevModeW == NULL ) - { - SetLastError ( ERROR_OUTOFMEMORY ); - return FALSE; - } + DEVMODEW lpDevModeW; if ( !RtlCreateUnicodeStringFromAsciiz ( &DeviceName, (PCSZ)lpszDeviceName ) ) { @@ -216,16 +208,16 @@ EnumDisplaySettingsExA( return FALSE; } - lpDevModeW->dmSize = sizeof(DEVMODEW); - lpDevModeW->dmDriverExtra = 0; - - rc = NtUserEnumDisplaySettings ( &DeviceName, iModeNum, lpDevModeW, + memset(&lpDevModeW,0,sizeof(DEVMODEW)); + lpDevModeW.dmSize = sizeof(DEVMODEW); + + rc = NtUserEnumDisplaySettings ( &DeviceName, iModeNum, &lpDevModeW, dwFlags ); - RosRtlDevModeW2A ( lpDevMode, lpDevModeW ); + RosRtlDevModeW2A ( lpDevMode, &lpDevModeW ); RtlFreeUnicodeString ( &DeviceName ); - HeapFree ( GetProcessHeap(), 0, lpDevModeW ); + return rc; } diff --git a/reactos/lib/user32/resources/ocr_normal.cur b/reactos/lib/user32/resources/ocr_normal.cur index 78365b0879c..19a0b084eef 100644 Binary files a/reactos/lib/user32/resources/ocr_normal.cur and b/reactos/lib/user32/resources/ocr_normal.cur differ diff --git a/reactos/lib/ws2_32/misc/dllmain.c b/reactos/lib/ws2_32/misc/dllmain.c index e51d0cbc187..db0756db674 100644 --- a/reactos/lib/ws2_32/misc/dllmain.c +++ b/reactos/lib/ws2_32/misc/dllmain.c @@ -17,10 +17,10 @@ #ifdef DBG /* See debug.h for debug/trace constants */ -DWORD DebugTraceLevel = MIN_TRACE; +//DWORD DebugTraceLevel = MIN_TRACE; //DWORD DebugTraceLevel = MAX_TRACE; //DWORD DebugTraceLevel = DEBUG_ULTRA; - +DWORD DebugTraceLevel = 0; #endif /* DBG */ /* To make the linker happy */ @@ -386,8 +386,8 @@ select( Sleep( timeout->tv_sec * 1000 + (timeout->tv_usec / 1000) ); } return 0; - } else { - WS_DbgPrint(MID_TRACE,("Calling WSPSelect\n")); + } else if (Provider->ProcTable.lpWSPSelect) { + WS_DbgPrint(MID_TRACE,("Calling WSPSelect:%x\n", Provider->ProcTable.lpWSPSelect)); Count = Provider->ProcTable.lpWSPSelect( nfds, readfds, writefds, exceptfds, (LPTIMEVAL)timeout, &Errno); @@ -400,6 +400,9 @@ select( WSASetLastError(Errno); return SOCKET_ERROR; } + } else { + WSASetLastError(WSAEINVAL); + return SOCKET_ERROR; } return Count; diff --git a/reactos/ntoskrnl/cc/view.c b/reactos/ntoskrnl/cc/view.c index 172f5f4269c..35266a1f1e5 100644 --- a/reactos/ntoskrnl/cc/view.c +++ b/reactos/ntoskrnl/cc/view.c @@ -49,10 +49,6 @@ #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S)) #define ROUND_DOWN(N, S) (((N) % (S)) ? ROUND_UP(N, S) - S : N) -#define TAG_CSEG TAG('C', 'S', 'E', 'G') -#define TAG_BCB TAG('B', 'C', 'B', ' ') -#define TAG_IBCB TAG('i', 'B', 'C', 'B') - static LIST_ENTRY DirtySegmentListHead; static LIST_ENTRY CacheSegmentListHead; static LIST_ENTRY CacheSegmentLRUListHead; diff --git a/reactos/ntoskrnl/cm/cm.h b/reactos/ntoskrnl/cm/cm.h index 15630cdbfce..4fe8c9ff3bd 100644 --- a/reactos/ntoskrnl/cm/cm.h +++ b/reactos/ntoskrnl/cm/cm.h @@ -744,4 +744,11 @@ NTSTATUS CmiSaveTempHive (PREGISTRY_HIVE Hive, HANDLE FileHandle); +/* TEMPORARY HACK UNTIL PROPER PARSE ROUTINES SOON. DO NOT REMOVE -- Alex */ +NTSTATUS +CmpFindObject(POBJECT_ATTRIBUTES ObjectAttributes, + PVOID* ReturnedObject, + PUNICODE_STRING RemainingPath, + POBJECT_TYPE ObjectType); + #endif /*__INCLUDE_CM_H*/ diff --git a/reactos/ntoskrnl/cm/ntfunc.c b/reactos/ntoskrnl/cm/ntfunc.c index 22f84ed0718..e3933aecf02 100644 --- a/reactos/ntoskrnl/cm/ntfunc.c +++ b/reactos/ntoskrnl/cm/ntfunc.c @@ -30,6 +30,138 @@ FAST_MUTEX CmiCallbackLock; /* FUNCTIONS ****************************************************************/ +/* TEMPORARY HACK UNTIL PROPER PARSE ROUTINES SOON. DO NOT REMOVE -- Alex */ +NTSTATUS +CmpFindObject(POBJECT_ATTRIBUTES ObjectAttributes, + PVOID* ReturnedObject, + PUNICODE_STRING RemainingPath, + POBJECT_TYPE ObjectType) +{ + PVOID NextObject; + PVOID CurrentObject; + PVOID RootObject; + POBJECT_HEADER CurrentHeader; + NTSTATUS Status; + PWSTR current; + UNICODE_STRING PathString; + ULONG Attributes; + PUNICODE_STRING ObjectName; + + PAGED_CODE(); + + DPRINT("CmpFindObject(ObjectAttributes %x, ReturnedObject %x, " + "RemainingPath %x)\n",ObjectAttributes,ReturnedObject,RemainingPath); + DPRINT("ObjectAttributes->ObjectName %wZ\n", + ObjectAttributes->ObjectName); + + RtlInitUnicodeString (RemainingPath, NULL); + + if (ObjectAttributes->RootDirectory == NULL) + { + ObReferenceObjectByPointer(NameSpaceRoot, + DIRECTORY_TRAVERSE, + NULL, + UserMode); + CurrentObject = NameSpaceRoot; + } + else + { + Status = ObReferenceObjectByHandle(ObjectAttributes->RootDirectory, + 0, + NULL, + UserMode, + &CurrentObject, + NULL); + if (!NT_SUCCESS(Status)) + { + return Status; + } + } + + ObjectName = ObjectAttributes->ObjectName; + if (ObjectName->Length == 0 || + ObjectName->Buffer[0] == UNICODE_NULL) + { + *ReturnedObject = CurrentObject; + return STATUS_SUCCESS; + } + + if (ObjectAttributes->RootDirectory == NULL && + ObjectName->Buffer[0] != L'\\') + { + ObDereferenceObject (CurrentObject); + return STATUS_UNSUCCESSFUL; + } + + /* Create a zero-terminated copy of the object name */ + PathString.Length = ObjectName->Length; + PathString.MaximumLength = ObjectName->Length + sizeof(WCHAR); + PathString.Buffer = ExAllocatePool (NonPagedPool, + PathString.MaximumLength); + if (PathString.Buffer == NULL) + { + ObDereferenceObject (CurrentObject); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory (PathString.Buffer, + ObjectName->Buffer, + ObjectName->Length); + PathString.Buffer[PathString.Length / sizeof(WCHAR)] = UNICODE_NULL; + + current = PathString.Buffer; + + RootObject = CurrentObject; + Attributes = ObjectAttributes->Attributes; + if (ObjectType == ObSymbolicLinkType) + Attributes |= OBJ_OPENLINK; + + while (TRUE) + { + DPRINT("current %S\n",current); + CurrentHeader = BODY_TO_HEADER(CurrentObject); + + DPRINT("Current ObjectType %wZ\n", + &CurrentHeader->Type->TypeName); + + if (CurrentHeader->Type->TypeInfo.ParseProcedure == NULL) + { + DPRINT("Current object can't parse\n"); + break; + } + Status = CurrentHeader->Type->TypeInfo.ParseProcedure(CurrentObject, + &NextObject, + &PathString, + ¤t, + Attributes); + if (Status == STATUS_REPARSE) + { + /* reparse the object path */ + NextObject = NameSpaceRoot; + current = PathString.Buffer; + + ObReferenceObjectByPointer(NextObject, + DIRECTORY_TRAVERSE, + NULL, + UserMode); + } + + if (NextObject == NULL) + { + break; + } + ObDereferenceObject(CurrentObject); + CurrentObject = NextObject; + } + + if (current) + RtlpCreateUnicodeString (RemainingPath, current, NonPagedPool); + RtlFreeUnicodeString (&PathString); + *ReturnedObject = CurrentObject; + + return STATUS_SUCCESS; +} + /* * @implemented */ @@ -199,13 +331,13 @@ NtCreateKey(OUT PHANDLE KeyHandle, KeyHandle, ObjectAttributes->RootDirectory); - Status = ObFindObject(ObjectAttributes, + Status = CmpFindObject(ObjectAttributes, &Object, &RemainingPath, CmiKeyType); if (!NT_SUCCESS(Status)) { - DPRINT("ObFindObject failed, Status: 0x%x\n", Status); + DPRINT("CmpFindObject failed, Status: 0x%x\n", Status); return(Status); } @@ -379,7 +511,7 @@ NtDeleteKey(IN HANDLE KeyHandle) PAGED_CODE(); - DPRINT1("NtDeleteKey(KeyHandle %x) called\n", KeyHandle); + DPRINT("NtDeleteKey(KeyHandle %x) called\n", KeyHandle); PreviousMode = ExGetPreviousMode(); @@ -418,7 +550,7 @@ NtDeleteKey(IN HANDLE KeyHandle) ExReleaseResourceLite(&CmiRegistryLock); KeLeaveCriticalRegion(); - DPRINT1("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject)); + DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject)); /* Dereference the object */ ObDereferenceObject(KeyObject); @@ -1146,14 +1278,14 @@ NtOpenKey(OUT PHANDLE KeyHandle, return(STATUS_BUFFER_OVERFLOW);*/ RemainingPath.Buffer = NULL; - Status = ObFindObject(ObjectAttributes, + Status = CmpFindObject(ObjectAttributes, &Object, &RemainingPath, CmiKeyType); if (!NT_SUCCESS(Status)) { - DPRINT("ObFindObject() returned 0x%08lx\n", Status); - Status = STATUS_INVALID_HANDLE; /* Because ObFindObject returns STATUS_UNSUCCESSFUL */ + DPRINT("CmpFindObject() returned 0x%08lx\n", Status); + Status = STATUS_INVALID_HANDLE; /* Because CmpFindObject returns STATUS_UNSUCCESSFUL */ hKey = *KeyHandle; /* Preserve hkResult value */ goto openkey_cleanup; } diff --git a/reactos/ntoskrnl/cm/registry.c b/reactos/ntoskrnl/cm/registry.c index 91140f38e4f..621963a756a 100644 --- a/reactos/ntoskrnl/cm/registry.c +++ b/reactos/ntoskrnl/cm/registry.c @@ -350,15 +350,15 @@ CmInitializeRegistry(VOID) OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING Name; - DPRINT1("Creating Registry Object Type\n"); + DPRINT("Creating Registry Object Type\n"); /* Initialize the Key object type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); RtlInitUnicodeString(&Name, L"Key"); ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); - ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KEY_OBJECT); + ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(KEY_OBJECT); ObjectTypeInitializer.GenericMapping = CmiKeyMapping; - ObjectTypeInitializer.PoolType = NonPagedPool; + ObjectTypeInitializer.PoolType = PagedPool; ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS; ObjectTypeInitializer.UseDefaultObject = TRUE; ObjectTypeInitializer.DeleteProcedure = CmiObjectDelete; @@ -702,7 +702,7 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes, DPRINT("CmiConnectHive(%p, %p) called.\n", KeyObjectAttributes, RegistryHive); - Status = ObFindObject(KeyObjectAttributes, + Status = CmpFindObject(KeyObjectAttributes, (PVOID*)&ParentKey, &RemainingPath, CmiKeyType); @@ -746,6 +746,7 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes, 0, 0, (PVOID*)&NewKey); + if (!NT_SUCCESS(Status)) { DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status); @@ -753,7 +754,14 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes, RtlFreeUnicodeString(&RemainingPath); return Status; } - + DPRINT("Inserting Key into Object Tree\n"); + Status = ObInsertObject((PVOID)NewKey, + NULL, + KEY_ALL_ACCESS, + 0, + NULL, + NULL); +DPRINT("Status %x\n", Status); NewKey->RegistryHive = RegistryHive; NewKey->KeyCellOffset = RegistryHive->HiveHeader->RootKeyOffset; NewKey->KeyCell = CmiGetCell (RegistryHive, NewKey->KeyCellOffset, NULL); diff --git a/reactos/ntoskrnl/cm/regobj.c b/reactos/ntoskrnl/cm/regobj.c index 15191076476..51c4ceb3ae0 100644 --- a/reactos/ntoskrnl/cm/regobj.c +++ b/reactos/ntoskrnl/cm/regobj.c @@ -176,6 +176,15 @@ CmiObjectParse(PVOID ParsedObject, RtlFreeUnicodeString(&KeyName); return(Status); } + DPRINT("Inserting Key into Object Tree\n"); + Status = ObInsertObject((PVOID)FoundObject, + NULL, + KEY_ALL_ACCESS, + 0, + NULL, + NULL); + DPRINT("Status %x\n", Status); + /* Add the keep-alive reference */ ObReferenceObject(FoundObject); @@ -503,7 +512,7 @@ CmiObjectQueryName (PVOID ObjectBody, else { /* KeyObject is the root key */ - Status = ObQueryNameString (BODY_TO_HEADER(KeyObject)->Parent, + Status = ObQueryNameString (HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(KeyObject))->Directory, LocalInfo, MAX_PATH * sizeof(WCHAR), &LocalReturnLength); diff --git a/reactos/ntoskrnl/ex/event.c b/reactos/ntoskrnl/ex/event.c index 05461e3a522..13223ba3177 100644 --- a/reactos/ntoskrnl/ex/event.c +++ b/reactos/ntoskrnl/ex/event.c @@ -39,7 +39,7 @@ ExpInitializeEventImplementation(VOID) OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING Name; - DPRINT1("Creating Event Object Type\n"); + DPRINT("Creating Event Object Type\n"); /* Create the Event Object Type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); diff --git a/reactos/ntoskrnl/ex/evtpair.c b/reactos/ntoskrnl/ex/evtpair.c index 177782c1d12..b3fd84f3300 100644 --- a/reactos/ntoskrnl/ex/evtpair.c +++ b/reactos/ntoskrnl/ex/evtpair.c @@ -36,7 +36,7 @@ ExpInitializeEventPairImplementation(VOID) OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING Name; - DPRINT1("Creating Event Pair Object Type\n"); + DPRINT("Creating Event Pair Object Type\n"); /* Create the Event Pair Object Type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); diff --git a/reactos/ntoskrnl/ex/fmutex.c b/reactos/ntoskrnl/ex/fmutex.c index 9f905d793c8..8fd4e057481 100644 --- a/reactos/ntoskrnl/ex/fmutex.c +++ b/reactos/ntoskrnl/ex/fmutex.c @@ -21,7 +21,7 @@ VOID FASTCALL ExAcquireFastMutexUnsafe(PFAST_MUTEX FastMutex) { - ASSERT(FastMutex->Owner != KeGetCurrentThread()); + //ASSERT(FastMutex->Owner != KeGetCurrentThread()); InterlockedIncrementUL(&FastMutex->Contention); while (InterlockedExchange(&FastMutex->Count, 0) == 0) { @@ -41,7 +41,7 @@ ExAcquireFastMutexUnsafe(PFAST_MUTEX FastMutex) VOID FASTCALL ExReleaseFastMutexUnsafe(PFAST_MUTEX FastMutex) { - ASSERT(FastMutex->Owner == KeGetCurrentThread()); + //ASSERT(FastMutex->Owner == KeGetCurrentThread()); FastMutex->Owner = NULL; InterlockedExchange(&FastMutex->Count, 1); if (FastMutex->Contention > 0) diff --git a/reactos/ntoskrnl/ex/init.c b/reactos/ntoskrnl/ex/init.c index 11124e10acd..f58d0187124 100644 --- a/reactos/ntoskrnl/ex/init.c +++ b/reactos/ntoskrnl/ex/init.c @@ -29,6 +29,7 @@ extern PRTL_MESSAGE_RESOURCE_DATA KiBugCodeMessages; extern LIST_ENTRY KiProfileListHead; extern LIST_ENTRY KiProfileSourceListHead; extern KSPIN_LOCK KiProfileLock; +BOOLEAN SetupMode = TRUE; VOID PspPostInitSystemProcess(VOID); @@ -258,7 +259,7 @@ ExecuteRuntimeAsserts(VOID) inline VOID STDCALL -ParseAndCacheLoadedModules(PBOOLEAN SetupBoot) +ParseAndCacheLoadedModules(VOID) { ULONG i; PCHAR Name; @@ -294,7 +295,7 @@ ParseAndCacheLoadedModules(PBOOLEAN SetupBoot) } else if (!_stricmp(Name, "system") || !_stricmp(Name, "system.hiv")) { CachedModules[SystemRegistry] = &KeLoaderModules[i]; - *SetupBoot = FALSE; + SetupMode = FALSE; } else if (!_stricmp(Name, "hardware") || !_stricmp(Name, "hardware.hiv")) { @@ -369,20 +370,54 @@ ParseCommandLine(PULONG MaxMem, p1 = p2; } } + +VOID +INIT_FUNCTION +ExpDisplayNotice(VOID) +{ + CHAR str[50]; + + if (SetupMode) + { + HalDisplayString( + "\n\n\n ReactOS " KERNEL_VERSION_STR " Setup \n"); + HalDisplayString( + " \xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"); + HalDisplayString( + "\xCD\xCD\n"); + return; + } + + HalDisplayString("Starting ReactOS "KERNEL_VERSION_STR" (Build " + KERNEL_VERSION_BUILD_STR")\n"); + HalDisplayString(RES_STR_LEGAL_COPYRIGHT); + HalDisplayString("\n\nReactOS is free software, covered by the GNU General " + "Public License, and you\n"); + HalDisplayString("are welcome to change it and/or distribute copies of it " + "under certain\n"); + HalDisplayString("conditions. There is absolutely no warranty for " + "ReactOS.\n\n"); + /* Display number of Processors */ + sprintf(str, + "Found %x system processor(s). [%lu MB Memory]\n", + (int)KeNumberProcessors, + (KeLoaderBlock.MemHigher + 1088)/ 1024); + HalDisplayString(str); + +} + VOID INIT_FUNCTION STDCALL ExpInitializeExecutive(VOID) { - CHAR str[50]; UNICODE_STRING EventName; HANDLE InitDoneEventHandle; OBJECT_ATTRIBUTES ObjectAttributes; BOOLEAN NoGuiBoot = FALSE; BOOLEAN BootLog = FALSE; ULONG MaxMem = 0; - BOOLEAN SetupBoot = TRUE; BOOLEAN ForceAcpiDisable = FALSE; LARGE_INTEGER Timeout; HANDLE ProcessHandle; @@ -413,7 +448,7 @@ ExpInitializeExecutive(VOID) MaxMem > 8 ? MaxMem : 4096); /* Parse the Loaded Modules (by FreeLoader) and cache the ones we'll need */ - ParseAndCacheLoadedModules(&SetupBoot); + ParseAndCacheLoadedModules(); /* Initialize the kernel debugger parameters */ KdInitSystem(0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); @@ -446,10 +481,10 @@ ExpInitializeExecutive(VOID) /* Set 1 CPU for now, we'll increment this later */ KeNumberProcessors = 1; - + /* Initalize the Process Manager */ PiInitProcessManager(); - + /* Break into the Debugger if requested */ if (KdPollBreakIn()) DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C); @@ -511,27 +546,12 @@ ExpInitializeExecutive(VOID) /* Report all resources used by hal */ HalReportResourceUsage(); - + /* Clear the screen to blue */ HalInitSystem(2, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); /* Display version number and copyright/warranty message */ - HalDisplayString("Starting ReactOS "KERNEL_VERSION_STR" (Build " - KERNEL_VERSION_BUILD_STR")\n"); - HalDisplayString(RES_STR_LEGAL_COPYRIGHT); - HalDisplayString("\n\nReactOS is free software, covered by the GNU General " - "Public License, and you\n"); - HalDisplayString("are welcome to change it and/or distribute copies of it " - "under certain\n"); - HalDisplayString("conditions. There is absolutely no warranty for " - "ReactOS.\n\n"); - - /* Display number of Processors */ - sprintf(str, - "Found %d system processor(s). [%lu MB Memory]\n", - KeNumberProcessors, - (KeLoaderBlock.MemHigher + 1088)/ 1024); - HalDisplayString(str); + ExpDisplayNotice(); /* Call KD Providers at Phase 2 */ KdInitSystem(2, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); @@ -540,13 +560,13 @@ ExpInitializeExecutive(VOID) RtlpInitNls(); /* Import and Load Registry Hives */ - CmInitHives(SetupBoot); + CmInitHives(SetupMode); /* Initialize the time zone information from the registry */ ExpInitTimeZoneInfo(); - /* Enter the kernel debugger before starting up the boot drivers */ - KdbEnter(); + /* Enter the kernel debugger before starting up the boot drivers */ + if (KdDebuggerEnabled) KdbEnter(); /* Setup Drivers and Root Device Node */ IoInit2(BootLog); diff --git a/reactos/ntoskrnl/ex/mutant.c b/reactos/ntoskrnl/ex/mutant.c index 91e3a098939..5e9ca894075 100644 --- a/reactos/ntoskrnl/ex/mutant.c +++ b/reactos/ntoskrnl/ex/mutant.c @@ -52,7 +52,7 @@ ExpInitializeMutantImplementation(VOID) OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING Name; - DPRINT1("Creating Mutant Object Type\n"); + DPRINT("Creating Mutant Object Type\n"); /* Create the Event Pair Object Type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); diff --git a/reactos/ntoskrnl/ex/profile.c b/reactos/ntoskrnl/ex/profile.c index 2fde67e5e65..6dd52492a43 100644 --- a/reactos/ntoskrnl/ex/profile.c +++ b/reactos/ntoskrnl/ex/profile.c @@ -9,6 +9,7 @@ /* INCLUDES *****************************************************************/ +#define NDEBUG #include #include @@ -81,7 +82,7 @@ ExpInitializeProfileImplementation(VOID) /* Initialize the Mutex to lock the States */ KeInitializeMutex(&ExpProfileMutex, 0x40); - DPRINT1("Creating Profile Object Type\n"); + DPRINT("Creating Profile Object Type\n"); /* Create the Event Pair Object Type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); diff --git a/reactos/ntoskrnl/ex/resource.c b/reactos/ntoskrnl/ex/resource.c index ac33636e4e1..d7e0434c527 100644 --- a/reactos/ntoskrnl/ex/resource.c +++ b/reactos/ntoskrnl/ex/resource.c @@ -41,12 +41,6 @@ #define NDEBUG #include -/* GLOBALS *******************************************************************/ - -#define TAG_OWNER_TABLE TAG('R', 'O', 'W', 'N') -#define TAG_EXCLUSIVE_LOCK TAG('E', 'R', 'E', 'L') -#define TAG_SHARED_SEM TAG('E', 'R', 'S', 'S') - /* FUNCTIONS *****************************************************************/ diff --git a/reactos/ntoskrnl/ex/sem.c b/reactos/ntoskrnl/ex/sem.c index 026ee942336..b4d85c01f56 100644 --- a/reactos/ntoskrnl/ex/sem.c +++ b/reactos/ntoskrnl/ex/sem.c @@ -37,7 +37,7 @@ ExpInitializeSemaphoreImplementation(VOID) OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING Name; - DPRINT1("Creating Semaphore Object Type\n"); + DPRINT("Creating Semaphore Object Type\n"); /* Create the Event Pair Object Type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); diff --git a/reactos/ntoskrnl/ex/timer.c b/reactos/ntoskrnl/ex/timer.c index 386fab368e6..7ca8509ee09 100644 --- a/reactos/ntoskrnl/ex/timer.c +++ b/reactos/ntoskrnl/ex/timer.c @@ -226,7 +226,7 @@ ExpInitializeTimerImplementation(VOID) OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING Name; - DPRINT1("Creating Timer Object Type\n"); + DPRINT("Creating Timer Object Type\n"); /* Create the Event Pair Object Type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); diff --git a/reactos/ntoskrnl/ex/win32k.c b/reactos/ntoskrnl/ex/win32k.c index 7b505f3e86e..04b56f6820c 100644 --- a/reactos/ntoskrnl/ex/win32k.c +++ b/reactos/ntoskrnl/ex/win32k.c @@ -129,7 +129,7 @@ ExpWin32kInit(VOID) OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING Name; - DPRINT1("Creating window station Object Type\n"); + DPRINT("Creating window station Object Type\n"); /* Create the window station Object Type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); diff --git a/reactos/ntoskrnl/fs/notify.c b/reactos/ntoskrnl/fs/notify.c index 2b02721a5ca..527fd8c5290 100644 --- a/reactos/ntoskrnl/fs/notify.c +++ b/reactos/ntoskrnl/fs/notify.c @@ -16,8 +16,6 @@ PAGED_LOOKASIDE_LIST NotifyEntryLookaside; -#define FSRTL_NOTIFY_TAG TAG('N','O','T','I') - typedef struct _NOTIFY_ENTRY { LIST_ENTRY ListEntry; diff --git a/reactos/ntoskrnl/include/config.h b/reactos/ntoskrnl/include/config.h index 73d0d716714..724352f5069 100644 --- a/reactos/ntoskrnl/include/config.h +++ b/reactos/ntoskrnl/include/config.h @@ -15,18 +15,30 @@ /********** mm/ppool.c **********/ -/* Enable strict checking of the nonpaged pool on every allocation */ -#undef ENABLE_VALIDATE_POOL +/* Disable Debugging Features */ +#ifndef DBG + /* Enable strict checking of the nonpaged pool on every allocation */ + #undef ENABLE_VALIDATE_POOL -/* Enable tracking of statistics about the tagged blocks in the pool */ -#undef TAG_STATISTICS_TRACKING + /* Enable tracking of statistics about the tagged blocks in the pool */ + #undef TAG_STATISTICS_TRACKING + + /* Enable Memory Debugging Features/Helpers */ + #undef POOL_DEBUG_APIS + + /* Enable Redzone */ + #define R_RZ 0 + + /* Enable Allocator Stack */ + #define R_STACK 0 -/* - * Put each block in its own range of pages and position the block at the - * end of the range so any accesses beyond the end of block are to invalid - * memory locations. - */ -#undef WHOLE_PAGE_ALLOCATIONS + /* + * Put each block in its own range of pages and position the block at the + * end of the range so any accesses beyond the end of block are to invalid + * memory locations. + */ + #undef WHOLE_PAGE_ALLOCATIONS +#endif #endif /* __INCLUDE_NTOSKRNL_CONFIG_H */ diff --git a/reactos/ntoskrnl/include/internal/debug.h b/reactos/ntoskrnl/include/internal/debug.h index 6a62383be8f..cfc177c3eec 100644 --- a/reactos/ntoskrnl/include/internal/debug.h +++ b/reactos/ntoskrnl/include/internal/debug.h @@ -73,9 +73,16 @@ #define CPRINT DbgPrint("(%s:%d) ",__FILE__,__LINE__); DbgPrint #endif +#ifdef __GNUC__ /* using GNU C/C99 macro ellipsis */ +#define DPRINT1(args...) do { DbgPrint("(%s:%d) ",__FILE__,__LINE__); DbgPrint(args); } while(0) +#else +#define DPRINT1 DbgPrint("(%s:%d) ",__FILE__,__LINE__); DbgPrint +#endif + #else /* DBG */ #define CPRINT(args...) +#define DPRINT1(args...) #define assert(x) #define ASSERT(x) #define assertmsg(_c_, _m_) @@ -83,12 +90,6 @@ #endif /* DBG */ -#ifdef __GNUC__ /* using GNU C/C99 macro ellipsis */ -#define DPRINT1(args...) do { DbgPrint("(%s:%d) ",__FILE__,__LINE__); DbgPrint(args); } while(0) -#else -#define DPRINT1 DbgPrint("(%s:%d) ",__FILE__,__LINE__); DbgPrint -#endif - #define CHECKPOINT1 do { DbgPrint("%s:%d\n",__FILE__,__LINE__); } while(0) #ifndef NDEBUG diff --git a/reactos/ntoskrnl/include/internal/io.h b/reactos/ntoskrnl/include/internal/io.h index b24d1ab29bf..0b40de614dc 100644 --- a/reactos/ntoskrnl/include/internal/io.h +++ b/reactos/ntoskrnl/include/internal/io.h @@ -385,11 +385,6 @@ IoSecondStageCompletion( PVOID* SystemArgument2); NTSTATUS STDCALL -IopCreateFile(PVOID ObjectBody, - PVOID Parent, - PWSTR RemainingPath, - POBJECT_ATTRIBUTES ObjectAttributes); -NTSTATUS STDCALL IopCreateDevice(PVOID ObjectBody, PVOID Parent, PWSTR RemainingPath, @@ -501,6 +496,10 @@ IopInitializeDevice( PDEVICE_NODE DeviceNode, PDRIVER_OBJECT DriverObject); +NTSTATUS +IopStartDevice( + PDEVICE_NODE DeviceNode); + /* driver.c */ VOID FASTCALL @@ -518,6 +517,12 @@ IopCreateDriverObject( PVOID DriverImageStart, ULONG DriverImageSize); +NTSTATUS FASTCALL +IopGetDriverObject( + PDRIVER_OBJECT *DriverObject, + PUNICODE_STRING ServiceName, + BOOLEAN FileSystem); + NTSTATUS FASTCALL IopLoadServiceModule( IN PUNICODE_STRING ServiceName, @@ -549,7 +554,7 @@ STDCALL IopCreateFile(PVOID ObjectBody, PVOID Parent, PWSTR RemainingPath, - POBJECT_ATTRIBUTES ObjectAttributes); + POBJECT_CREATE_INFORMATION ObjectAttributes); VOID STDCALL diff --git a/reactos/ntoskrnl/include/internal/ob.h b/reactos/ntoskrnl/include/internal/ob.h index 25a2355db26..55b70182aa1 100644 --- a/reactos/ntoskrnl/include/internal/ob.h +++ b/reactos/ntoskrnl/include/internal/ob.h @@ -16,45 +16,46 @@ struct _EPROCESS; -typedef struct -{ - CSHORT Type; - CSHORT Size; -} COMMON_BODY_HEADER, *PCOMMON_BODY_HEADER; - typedef PVOID POBJECT; -typedef struct _OBJECT_HEADER -/* - * PURPOSE: Header for every object managed by the object manager - */ +typedef struct _QUAD { - UNICODE_STRING Name; - LIST_ENTRY Entry; - LONG RefCount; - LONG HandleCount; - BOOLEAN Permanent; - BOOLEAN Inherit; - struct _DIRECTORY_OBJECT* Parent; - POBJECT_TYPE ObjectType; - PSECURITY_DESCRIPTOR SecurityDescriptor; - - /* - * PURPOSE: Object type - * NOTE: This overlaps the first member of the object body - */ - CSHORT Type; - - /* - * PURPOSE: Object size - * NOTE: This overlaps the second member of the object body - */ - CSHORT Size; + union { + LONGLONG UseThisFieldToCopy; + float DoNotUseThisField; + }; +} QUAD, *PQUAD; +#define OB_FLAG_CREATE_INFO 0x01 // has OBJECT_CREATE_INFO +#define OB_FLAG_KERNEL_MODE 0x02 // created by kernel +#define OB_FLAG_CREATOR_INFO 0x04 // has OBJECT_CREATOR_INFO +#define OB_FLAG_EXCLUSIVE 0x08 // OBJ_EXCLUSIVE +#define OB_FLAG_PERMANENT 0x10 // OBJ_PERMANENT +#define OB_FLAG_SECURITY 0x20 // has security descriptor +#define OB_FLAG_SINGLE_PROCESS 0x40 // no HandleDBList +/* Will be moved to public headers once "Entry" is gone */ +typedef struct _OBJECT_HEADER +{ + LIST_ENTRY Entry; + LONG PointerCount; + union { + LONG HandleCount; + PVOID NextToFree; + }; + POBJECT_TYPE Type; + UCHAR NameInfoOffset; + UCHAR HandleInfoOffset; + UCHAR QuotaInfoOffset; + UCHAR Flags; + union { + POBJECT_CREATE_INFORMATION ObjectCreateInfo; + PVOID QuotaBlockCharged; + }; + PSECURITY_DESCRIPTOR SecurityDescriptor; + QUAD Body; } OBJECT_HEADER, *POBJECT_HEADER; - typedef struct _DIRECTORY_OBJECT { CSHORT Type; @@ -92,13 +93,19 @@ enum OBJTYP_MAX, }; -#define HEADER_TO_BODY(objhdr) \ - (PVOID)((ULONG_PTR)objhdr + sizeof(OBJECT_HEADER) - sizeof(COMMON_BODY_HEADER)) - #define BODY_TO_HEADER(objbdy) \ - CONTAINING_RECORD(&(((PCOMMON_BODY_HEADER)objbdy)->Type), OBJECT_HEADER, Type) + CONTAINING_RECORD((objbdy), OBJECT_HEADER, Body) + +#define HEADER_TO_OBJECT_NAME(objhdr) ((POBJECT_HEADER_NAME_INFO) \ + (!(objhdr)->NameInfoOffset ? NULL: ((PCHAR)(objhdr) - (objhdr)->NameInfoOffset))) + +#define HEADER_TO_HANDLE_INFO(objhdr) ((POBJECT_HEADER_HANDLE_INFO) \ + (!(objhdr)->HandleInfoOffset ? NULL: ((PCHAR)(objhdr) - (objhdr)->HandleInfoOffset))) + +#define HEADER_TO_CREATOR_INFO(objhdr) ((POBJECT_HEADER_CREATOR_INFO) \ + (!((objhdr)->Flags & OB_FLAG_CREATOR_INFO) ? NULL: ((PCHAR)(objhdr) - sizeof(OBJECT_HEADER_CREATOR_INFO)))) -#define OBJECT_ALLOC_SIZE(ObjectSize) ((ObjectSize)+sizeof(OBJECT_HEADER)-sizeof(COMMON_BODY_HEADER)) +#define OBJECT_ALLOC_SIZE(ObjectSize) ((ObjectSize)+sizeof(OBJECT_HEADER)) #define HANDLE_TO_EX_HANDLE(handle) \ (LONG)(((LONG)(handle) >> 2) - 1) @@ -133,7 +140,8 @@ NTSTATUS ObpCreateHandle(struct _EPROCESS* Process, VOID ObCreateHandleTable(struct _EPROCESS* Parent, BOOLEAN Inherit, struct _EPROCESS* Process); -NTSTATUS ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes, +NTSTATUS ObFindObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo, + PUNICODE_STRING ObjectName, PVOID* ReturnedObject, PUNICODE_STRING RemainingPath, POBJECT_TYPE ObjectType); @@ -148,7 +156,7 @@ ObpSetHandleAttributes(HANDLE Handle, NTSTATUS STDCALL -ObpCreateTypeObject(POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, +ObpCreateTypeObject(struct _OBJECT_TYPE_INITIALIZER *ObjectTypeInitializer, PUNICODE_STRING TypeName, POBJECT_TYPE *ObjectType); @@ -224,18 +232,22 @@ typedef struct _CAPTURED_OBJECT_ATTRIBUTES } CAPTURED_OBJECT_ATTRIBUTES, *PCAPTURED_OBJECT_ATTRIBUTES; NTSTATUS -ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, +STDCALL +ObpCaptureObjectName(IN PUNICODE_STRING CapturedName, + IN PUNICODE_STRING ObjectName, + IN KPROCESSOR_MODE AccessMode); + +NTSTATUS +STDCALL +ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes, IN KPROCESSOR_MODE AccessMode, - IN POOL_TYPE PoolType, - IN BOOLEAN CaptureIfKernel, - OUT PCAPTURED_OBJECT_ATTRIBUTES CapturedObjectAttributes OPTIONAL, - OUT PUNICODE_STRING ObjectName OPTIONAL); + IN POBJECT_TYPE ObjectType, + IN POBJECT_CREATE_INFORMATION ObjectCreateInfo, + OUT PUNICODE_STRING ObjectName); VOID -ObpReleaseObjectAttributes(IN PCAPTURED_OBJECT_ATTRIBUTES CapturedObjectAttributes OPTIONAL, - IN PUNICODE_STRING ObjectName OPTIONAL, - IN KPROCESSOR_MODE AccessMode, - IN BOOLEAN CaptureIfKernel); +STDCALL +ObpReleaseCapturedAttributes(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo); /* object information classes */ diff --git a/reactos/ntoskrnl/include/internal/tag.h b/reactos/ntoskrnl/include/internal/tag.h new file mode 100644 index 00000000000..4ea0cd0c9f5 --- /dev/null +++ b/reactos/ntoskrnl/include/internal/tag.h @@ -0,0 +1,145 @@ +/* + * NTOSKRNL Tag names. + * License GPL + * + * FIXME: Replace with standard GPL Header. + * FIXME: Add notes as needed + */ + +#ifndef _NTOSKRNL_TAG_H +#define _NTOSKRNL_TAG_H + +/* formerly located in cc/view.c */ +#define TAG_CSEG TAG('C', 'S', 'E', 'G') +#define TAG_BCB TAG('B', 'C', 'B', ' ') +#define TAG_IBCB TAG('i', 'B', 'C', 'B') + +/* formerly located in ex/resource.c */ +#define TAG_OWNER_TABLE TAG('R', 'O', 'W', 'N') +#define TAG_EXCLUSIVE_LOCK TAG('E', 'R', 'E', 'L') +#define TAG_SHARED_SEM TAG('E', 'R', 'S', 'S') + +/* formerly located in fs/notify.c */ +#define FSRTL_NOTIFY_TAG TAG('N','O','T','I') + +/* formerly located in io/device.c */ +#define TAG_DEVICE_EXTENSION TAG('D', 'E', 'X', 'T') +#define TAG_SHUTDOWN_ENTRY TAG('S', 'H', 'U', 'T') +#define TAG_IO_TIMER TAG('I', 'O', 'T', 'M') + +/* formerly located in io/driver.c */ +#define TAG_DRIVER TAG('D', 'R', 'V', 'R') +#define TAG_DRIVER_EXTENSION TAG('D', 'R', 'V', 'E') + +/* formerly located in io/file.c */ +#define TAG_SYSB TAG('S', 'Y', 'S', 'B') +#define TAG_LOCK TAG('F','l','c','k') +#define TAG_FILE_NAME TAG('F', 'N', 'A', 'M') + +/* formerly located in io/fs.c */ +#define TAG_FILE_SYSTEM TAG('F', 'S', 'Y', 'S') +#define TAG_FS_CHANGE_NOTIFY TAG('F', 'S', 'C', 'N') + +/* formerly located in io/iocomp.c */ +#define IOC_TAG TAG('I', 'O', 'C', 'T') + +/* formerly located in io/iomgr.c */ +#define TAG_DEVICE_TYPE TAG('D', 'E', 'V', 'T') +#define TAG_FILE_TYPE TAG('F', 'I', 'L', 'E') +#define TAG_ADAPTER_TYPE TAG('A', 'D', 'P', 'T') +#define IO_LARGEIRP TAG('I', 'r', 'p', 'l') +#define IO_SMALLIRP TAG('I', 'r', 'p', 's') +#define IO_LARGEIRP_CPU TAG('I', 'r', 'p', 'L') +#define IO_SMALLIRP_CPU TAG('I', 'r', 'p', 'S') +#define IOC_TAG1 TAG('I', 'p', 'c', ' ') +#define IOC_CPU TAG('I', 'p', 'c', 'P') + +/* formerly located in io/work.c */ +#define TAG_IOWI TAG('I', 'O', 'W', 'I') + +/* formerly located in io/irp.c */ +#define TAG_IRP TAG('I', 'R', 'P', ' ') +#define TAG_SYS_BUF TAG('S', 'Y', 'S' , 'B') + +/* formerly located in io/irq.c */ +#define TAG_KINTERRUPT TAG('K', 'I', 'S', 'R') + +/* formerly located in io/mdl.c */ +#define TAG_MDL TAG('M', 'D', 'L', ' ') + +/* formerly located in io/pnpnotify.c */ +#define TAG_PNP_NOTIFY TAG('P', 'n', 'P', 'N') + +/* formerly located in io/resource.c */ +#define TAG_IO_RESOURCE TAG('R', 'S', 'R', 'C') + +/* formerly located in io/timer.c */ +#define TAG_IO_TIMER TAG('I', 'O', 'T', 'M') + +/* formerly located in io/vpb.c */ +#define TAG_VPB TAG('V', 'P', 'B', ' ') +#define TAG_SYSB TAG('S', 'Y', 'S', 'B') + +/* formerly located in kdbg/kdb_symbols.c */ +#define TAG_KDBS TAG('K', 'D', 'B', 'S') + +/* formerly located in ldr/loader.c */ +#define TAG_DRIVER_MEM TAG('D', 'R', 'V', 'M') /* drvm */ +#define TAG_MODULE_OBJECT TAG('k', 'l', 'm', 'o') /* klmo - kernel ldr module object */ +#define TAG_LDR_WSTR TAG('k', 'l', 'w', 's') /* klws - kernel ldr wide string */ +#define TAG_MODULE_TEXT_SECTION TAG('k', 'l', 'm', 't') /* klmt - kernel ldr module text */ + +/* formerly located in lpc/connect */ +#define TAG_LPC_CONNECT_MESSAGE TAG('L', 'P', 'C', 'C') + +/* formerly located in mm/aspace.c */ +#define TAG_PTRC TAG('P', 'T', 'R', 'C') + +/* formerly located in mm/marea.c */ +#define TAG_MAREA TAG('M', 'A', 'R', 'E') + +/* formerly located in mm/pageop.c */ +#define TAG_MM_PAGEOP TAG('M', 'P', 'O', 'P') + +/* formerly located in mm/pool.c */ +#define TAG_NONE TAG('N', 'o', 'n', 'e') + +/* formerly located in mm/region.c */ +#define TAG_MM_REGION TAG('M', 'R', 'G', 'N') + +/* formerly located in mm/rmap.c */ +#define TAG_RMAP TAG('R', 'M', 'A', 'P') + +/* formerly located in mm/section.c */ +#define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S') +#define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T') + +/* formerly located in ob/symlink.c */ +#define TAG_SYMLINK_TTARGET TAG('S', 'Y', 'T', 'T') +#define TAG_SYMLINK_TARGET TAG('S', 'Y', 'M', 'T') + +/* formerly located in ps/cid.c */ +#define TAG_CIDOBJECT TAG('C', 'I', 'D', 'O') + +/* formerly located in ps/job.c */ +#define TAG_EJOB TAG('E', 'J', 'O', 'B') /* EJOB */ + +/* formerly located in ps/kill.c */ +#define TAG_TERMINATE_APC TAG('T', 'A', 'P', 'C') + +/* formerly located in ps/notify.c */ +#define TAG_KAPC TAG('k','p','a','p') /* kpap - kernel ps apc */ + +/* formerly located in rtl/handle.c */ +#define TAG_HDTB TAG('H', 'D', 'T', 'B') + +/* formerly located in se/acl.c */ +#define TAG_ACL TAG('S', 'e', 'A', 'c') + +/* formerly located in se/sid.c */ +#define TAG_SID TAG('S', 'e', 'S', 'i') + +/* formerly located in se/sd.c */ +#define TAG_SD TAG('S', 'e', 'S', 'd') + +#endif /* _NTOSKRNL_TAG_H */ diff --git a/reactos/ntoskrnl/include/ntoskrnl.h b/reactos/ntoskrnl/include/ntoskrnl.h index e1ad277ead2..3f2c8ef06f1 100755 --- a/reactos/ntoskrnl/include/ntoskrnl.h +++ b/reactos/ntoskrnl/include/ntoskrnl.h @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include diff --git a/reactos/ntoskrnl/io/device.c b/reactos/ntoskrnl/io/device.c index 8625b3a4143..b07bb39535d 100644 --- a/reactos/ntoskrnl/io/device.c +++ b/reactos/ntoskrnl/io/device.c @@ -16,10 +16,6 @@ /* GLOBALS ********************************************************************/ -#define TAG_DEVICE_EXTENSION TAG('D', 'E', 'X', 'T') -#define TAG_SHUTDOWN_ENTRY TAG('S', 'H', 'U', 'T') -#define TAG_IO_TIMER TAG('I', 'O', 'T', 'M') - static ULONG IopDeviceObjectNumber = 0; typedef struct _SHUTDOWN_ENTRY @@ -80,8 +76,6 @@ FASTCALL IopInitializeDevice(PDEVICE_NODE DeviceNode, PDRIVER_OBJECT DriverObject) { - IO_STATUS_BLOCK IoStatusBlock; - IO_STACK_LOCATION Stack; PDEVICE_OBJECT Fdo; NTSTATUS Status; @@ -115,26 +109,6 @@ IopInitializeDevice(PDEVICE_NODE DeviceNode, IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED); - DPRINT("Sending IRP_MN_START_DEVICE to driver\n"); - - /* FIXME: Should be DeviceNode->ResourceList */ - Stack.Parameters.StartDevice.AllocatedResources = DeviceNode->BootResources; - /* FIXME: Should be DeviceNode->ResourceListTranslated */ - Stack.Parameters.StartDevice.AllocatedResourcesTranslated = DeviceNode->BootResources; - - Status = IopInitiatePnpIrp( - Fdo, - &IoStatusBlock, - IRP_MN_START_DEVICE, - &Stack); - - if (!NT_SUCCESS(Status)) - { - DPRINT("IopInitiatePnpIrp() failed\n"); - ObDereferenceObject(Fdo); - return Status; - } - if (Fdo->DeviceType == FILE_DEVICE_ACPI) { static BOOLEAN SystemPowerDeviceNodeCreated = FALSE; @@ -147,23 +121,51 @@ IopInitializeDevice(PDEVICE_NODE DeviceNode, } } + ObDereferenceObject(Fdo); + } + + return STATUS_SUCCESS; +} + +NTSTATUS +IopStartDevice( + PDEVICE_NODE DeviceNode) +{ + IO_STATUS_BLOCK IoStatusBlock; + IO_STACK_LOCATION Stack; + PDEVICE_OBJECT Fdo; + NTSTATUS Status; + + DPRINT("Sending IRP_MN_START_DEVICE to driver\n"); + + Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject); + Stack.Parameters.StartDevice.AllocatedResources = DeviceNode->ResourceList; + Stack.Parameters.StartDevice.AllocatedResourcesTranslated = DeviceNode->ResourceListTranslated; + + Status = IopInitiatePnpIrp( + Fdo, + &IoStatusBlock, + IRP_MN_START_DEVICE, + &Stack); + + if (!NT_SUCCESS(Status)) + { + DPRINT("IopInitiatePnpIrp() failed\n"); + } + else + { if (Fdo->DeviceType == FILE_DEVICE_BUS_EXTENDER || Fdo->DeviceType == FILE_DEVICE_ACPI) { DPRINT("Bus extender found\n"); Status = IopInvalidateDeviceRelations(DeviceNode, BusRelations); - if (!NT_SUCCESS(Status)) - { - ObDereferenceObject(Fdo); - return Status; - } } - - ObDereferenceObject(Fdo); } - return STATUS_SUCCESS; + ObDereferenceObject(Fdo); + + return Status; } NTSTATUS @@ -1101,129 +1103,4 @@ IoValidateDeviceIoControlAccess(IN PIRP Irp, return STATUS_NOT_IMPLEMENTED; } -/* - * @implemented - */ -NTSTATUS -STDCALL -NtDeviceIoControlFile(IN HANDLE DeviceHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, - IN PVOID UserApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG IoControlCode, - IN PVOID InputBuffer, - IN ULONG InputBufferLength OPTIONAL, - OUT PVOID OutputBuffer, - IN ULONG OutputBufferLength OPTIONAL) -{ - NTSTATUS Status = STATUS_SUCCESS; - PFILE_OBJECT FileObject; - PDEVICE_OBJECT DeviceObject; - PIRP Irp; - PIO_STACK_LOCATION StackPtr; - PKEVENT EventObject = NULL; - BOOLEAN LocalEvent = FALSE; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - - DPRINT("NtDeviceIoControlFile(DeviceHandle %x Event %x UserApcRoutine %x " - "UserApcContext %x IoStatusBlock %x IoControlCode %x " - "InputBuffer %x InputBufferLength %x OutputBuffer %x " - "OutputBufferLength %x)\n", - DeviceHandle,Event,UserApcRoutine,UserApcContext,IoStatusBlock, - IoControlCode,InputBuffer,InputBufferLength,OutputBuffer, - OutputBufferLength); - - if (IoStatusBlock == NULL) return STATUS_ACCESS_VIOLATION; - - /* Check granted access against the access rights from IoContolCode */ - Status = ObReferenceObjectByHandle(DeviceHandle, - (IoControlCode >> 14) & 0x3, - IoFileObjectType, - PreviousMode, - (PVOID *) &FileObject, - NULL); - if (!NT_SUCCESS(Status)) return Status; - - /* Check for an event */ - if (Event) - { - /* Reference it */ - Status = ObReferenceObjectByHandle(Event, - EVENT_MODIFY_STATE, - ExEventObjectType, - PreviousMode, - (PVOID*)&EventObject, - NULL); - if (!NT_SUCCESS(Status)) - { - ObDereferenceObject (FileObject); - return Status; - } - - /* Clear it */ - KeClearEvent(EventObject); - } - - /* Check if this is a direct open or not */ - if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) - { - DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); - } - else - { - DeviceObject = IoGetRelatedDeviceObject(FileObject); - } - - /* Check if we should use Sync IO or not */ - if (FileObject->Flags & FO_SYNCHRONOUS_IO) - { - /* Use File Object event */ - KeClearEvent(&FileObject->Event); - } - else - { - /* Use local event */ - LocalEvent = TRUE; - } - - /* Build the IRP */ - Irp = IoBuildDeviceIoControlRequest(IoControlCode, - DeviceObject, - InputBuffer, - InputBufferLength, - OutputBuffer, - OutputBufferLength, - FALSE, - EventObject, - IoStatusBlock); - - /* Set some extra settings */ - Irp->Tail.Overlay.OriginalFileObject = FileObject; - Irp->RequestorMode = PreviousMode; - Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine; - Irp->Overlay.AsynchronousParameters.UserApcContext = UserApcContext; - StackPtr = IoGetNextIrpStackLocation(Irp); - StackPtr->FileObject = FileObject; - - - /* Call the Driver */ - Status = IoCallDriver(DeviceObject, Irp); - if (Status == STATUS_PENDING) - { - if (!LocalEvent) - { - KeWaitForSingleObject(&FileObject->Event, - Executive, - PreviousMode, - FileObject->Flags & FO_ALERTABLE_IO, - NULL); - Status = FileObject->FinalStatus; - } - } - - /* Return the Status */ - return Status; -} - /* EOF */ diff --git a/reactos/ntoskrnl/io/deviface.c b/reactos/ntoskrnl/io/deviface.c index 0d7b654d0d9..b9588928013 100644 --- a/reactos/ntoskrnl/io/deviface.c +++ b/reactos/ntoskrnl/io/deviface.c @@ -573,11 +573,13 @@ IoRegisterDeviceInterface( PUNICODE_STRING InstancePath; UNICODE_STRING GuidString; UNICODE_STRING SubKeyName; + UNICODE_STRING InterfaceKeyName; UNICODE_STRING BaseKeyName; UCHAR PdoNameInfoBuffer[sizeof(OBJECT_NAME_INFORMATION) + (256 * sizeof(WCHAR))]; POBJECT_NAME_INFORMATION PdoNameInfo = (POBJECT_NAME_INFORMATION)PdoNameInfoBuffer; UNICODE_STRING DeviceInstance = RTL_CONSTANT_STRING(L"DeviceInstance"); UNICODE_STRING SymbolicLink = RTL_CONSTANT_STRING(L"SymbolicLink"); + HANDLE ClassKey; HANDLE InterfaceKey; HANDLE SubKey; ULONG StartIndex; @@ -611,15 +613,11 @@ IoRegisterDeviceInterface( } ASSERT(PdoNameInfo->Name.Length); - /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\DeviceClasses\{GUID}\##?#ACPI#PNP0501#1#{GUID} */ + /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */ ASSERT(PhysicalDeviceObject->DeviceObjectExtension->DeviceNode); InstancePath = &PhysicalDeviceObject->DeviceObjectExtension->DeviceNode->InstancePath; BaseKeyName.Length = wcslen(BaseKeyString) * sizeof(WCHAR); BaseKeyName.MaximumLength = BaseKeyName.Length - + GuidString.Length - + 5 * sizeof(WCHAR) /* 5 = size of \##?# */ - + InstancePath->Length - + sizeof(WCHAR) /* 1 = size of # */ + GuidString.Length; BaseKeyName.Buffer = ExAllocatePool( NonPagedPool, @@ -631,16 +629,6 @@ IoRegisterDeviceInterface( } wcscpy(BaseKeyName.Buffer, BaseKeyString); RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString); - RtlAppendUnicodeToString(&BaseKeyName, L"\\##?#"); - StartIndex = BaseKeyName.Length / sizeof(WCHAR); - RtlAppendUnicodeStringToString(&BaseKeyName, InstancePath); - for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++) - { - if (BaseKeyName.Buffer[StartIndex + i] == '\\') - BaseKeyName.Buffer[StartIndex + i] = '#'; - } - RtlAppendUnicodeToString(&BaseKeyName, L"#"); - RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString); /* Create BaseKeyName key in registry */ InitializeObjectAttributes( @@ -650,6 +638,57 @@ IoRegisterDeviceInterface( NULL, /* RootDirectory */ NULL); /* SecurityDescriptor */ + Status = ZwCreateKey( + &ClassKey, + KEY_WRITE, + &ObjectAttributes, + 0, /* TileIndex */ + NULL, /* Class */ + REG_OPTION_VOLATILE, + NULL); /* Disposition */ + + if (!NT_SUCCESS(Status)) + { + DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); + ExFreePool(BaseKeyName.Buffer); + return Status; + } + + /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */ + InterfaceKeyName.Length = 0; + InterfaceKeyName.MaximumLength = + 4 * sizeof(WCHAR) + /* 4 = size of ##?# */ + InstancePath->Length + + sizeof(WCHAR) + /* 1 = size of # */ + GuidString.Length; + InterfaceKeyName.Buffer = ExAllocatePool( + NonPagedPool, + InterfaceKeyName.MaximumLength); + if (!InterfaceKeyName.Buffer) + { + DPRINT("ExAllocatePool() failed\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlAppendUnicodeToString(&InterfaceKeyName, L"##?#"); + StartIndex = InterfaceKeyName.Length / sizeof(WCHAR); + RtlAppendUnicodeStringToString(&InterfaceKeyName, InstancePath); + for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++) + { + if (InterfaceKeyName.Buffer[StartIndex + i] == '\\') + InterfaceKeyName.Buffer[StartIndex + i] = '#'; + } + RtlAppendUnicodeToString(&InterfaceKeyName, L"#"); + RtlAppendUnicodeStringToString(&InterfaceKeyName, &GuidString); + + /* Create the interface key in registry */ + InitializeObjectAttributes( + &ObjectAttributes, + &InterfaceKeyName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF, + ClassKey, + NULL); /* SecurityDescriptor */ + Status = ZwCreateKey( &InterfaceKey, KEY_WRITE, @@ -662,6 +701,7 @@ IoRegisterDeviceInterface( if (!NT_SUCCESS(Status)) { DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); + ZwClose(ClassKey); ExFreePool(BaseKeyName.Buffer); return Status; } @@ -678,6 +718,8 @@ IoRegisterDeviceInterface( { DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status); ZwClose(InterfaceKey); + ZwClose(ClassKey); + ExFreePool(InterfaceKeyName.Buffer); ExFreePool(BaseKeyName.Buffer); return Status; } @@ -694,6 +736,8 @@ IoRegisterDeviceInterface( { DPRINT("ExAllocatePool() failed\n"); ZwClose(InterfaceKey); + ZwClose(ClassKey); + ExFreePool(InterfaceKeyName.Buffer); ExFreePool(BaseKeyName.Buffer); return STATUS_INSUFFICIENT_RESOURCES; } @@ -722,6 +766,8 @@ IoRegisterDeviceInterface( { DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); ZwClose(InterfaceKey); + ZwClose(ClassKey); + ExFreePool(InterfaceKeyName.Buffer); ExFreePool(BaseKeyName.Buffer); return Status; } @@ -742,8 +788,10 @@ IoRegisterDeviceInterface( if (!SymbolicLinkName->Buffer) { DPRINT("ExAllocatePool() failed\n"); - ZwClose(InterfaceKey); ZwClose(SubKey); + ZwClose(InterfaceKey); + ZwClose(ClassKey); + ExFreePool(InterfaceKeyName.Buffer); ExFreePool(SubKeyName.Buffer); ExFreePool(BaseKeyName.Buffer); return STATUS_INSUFFICIENT_RESOURCES; @@ -771,9 +819,11 @@ IoRegisterDeviceInterface( if (!NT_SUCCESS(Status)) { DPRINT("IoCreateSymbolicLink() failed with status 0x%08lx\n", Status); - ZwClose(InterfaceKey); ZwClose(SubKey); + ZwClose(InterfaceKey); + ZwClose(ClassKey); ExFreePool(SubKeyName.Buffer); + ExFreePool(InterfaceKeyName.Buffer); ExFreePool(BaseKeyName.Buffer); ExFreePool(SymbolicLinkName->Buffer); return Status; @@ -793,9 +843,11 @@ IoRegisterDeviceInterface( ExFreePool(SymbolicLinkName->Buffer); } - ZwClose(InterfaceKey); ZwClose(SubKey); + ZwClose(InterfaceKey); + ZwClose(ClassKey); ExFreePool(SubKeyName.Buffer); + ExFreePool(InterfaceKeyName.Buffer); ExFreePool(BaseKeyName.Buffer); return Status; diff --git a/reactos/ntoskrnl/io/driver.c b/reactos/ntoskrnl/io/driver.c index f4f5941f4aa..5f2b543d40a 100644 --- a/reactos/ntoskrnl/io/driver.c +++ b/reactos/ntoskrnl/io/driver.c @@ -18,6 +18,7 @@ /* ke/main.c */ extern LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock; extern ULONG KeTickCount; +extern BOOLEAN SetupMode; NTSTATUS LdrProcessModule(PVOID ModuleLoadBase, @@ -75,9 +76,6 @@ static UNICODE_STRING IopHardwareDatabaseKey = POBJECT_TYPE EXPORTED IoDriverObjectType = NULL; -#define TAG_DRIVER TAG('D', 'R', 'V', 'R') -#define TAG_DRIVER_EXTENSION TAG('D', 'R', 'V', 'E') - /* DECLARATIONS ***************************************************************/ VOID STDCALL @@ -92,7 +90,7 @@ IopInitDriverImplementation(VOID) OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING Name; - DPRINT1("Creating Registry Object Type\n"); + DPRINT("Creating Registry Object Type\n"); /* Initialize the Driver object type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); @@ -150,6 +148,64 @@ IopDeleteDriver(PVOID ObjectBody) KfLowerIrql(OldIrql); } +NTSTATUS FASTCALL +IopGetDriverObject( + PDRIVER_OBJECT *DriverObject, + PUNICODE_STRING ServiceName, + BOOLEAN FileSystem) +{ + PDRIVER_OBJECT Object; + WCHAR NameBuffer[MAX_PATH]; + UNICODE_STRING DriverName; + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + + DPRINT("IopOpenDriverObject(%p '%wZ' %x)\n", + DriverObject, ServiceName, FileSystem); + + *DriverObject = NULL; + + /* Create ModuleName string */ + if (ServiceName == NULL || ServiceName->Buffer == NULL) + /* We don't know which DriverObject we have to open */ + return STATUS_INVALID_PARAMETER_2; + + if (FileSystem == TRUE) + wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME); + else + wcscpy(NameBuffer, DRIVER_ROOT_NAME); + wcscat(NameBuffer, ServiceName->Buffer); + + RtlInitUnicodeString(&DriverName, NameBuffer); + DPRINT("Driver name: '%wZ'\n", &DriverName); + + /* Initialize ObjectAttributes for driver object */ + InitializeObjectAttributes( + &ObjectAttributes, + &DriverName, + OBJ_OPENIF | OBJ_KERNEL_HANDLE, + NULL, + NULL); + + /* Open driver object */ + Status = ObReferenceObjectByName( + &DriverName, + 0, /* Attributes */ + NULL, /* PassedAccessState */ + 0, /* DesiredAccess */ + IoDriverObjectType, + KernelMode, + NULL, /* ParseContext */ + (PVOID*)&Object); + + if (!NT_SUCCESS(Status)) + return Status; + + *DriverObject = Object; + + return STATUS_SUCCESS; +} + NTSTATUS FASTCALL IopCreateDriverObject( PDRIVER_OBJECT *DriverObject, @@ -217,8 +273,19 @@ IopCreateDriverObject( { return Status; } - - /* Create driver extension */ + + Status = ObInsertObject(Object, + NULL, + FILE_ALL_ACCESS, + 0, + NULL, + NULL); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + /* Create driver extension */ Object->DriverExtension = (PDRIVER_EXTENSION) ExAllocatePoolWithTag( NonPagedPool, @@ -264,12 +331,23 @@ IopCreateDriverObject( * Display 'Loading XXX...' message. */ -VOID FASTCALL -IopDisplayLoadingMessage(PWCHAR ServiceName) +VOID +FASTCALL +INIT_FUNCTION +IopDisplayLoadingMessage(PVOID ServiceName, + BOOLEAN Unicode) { - CHAR TextBuffer[256]; - sprintf(TextBuffer, "Loading %S...\n", ServiceName); - HalDisplayString(TextBuffer); + if (SetupMode) return; + CHAR TextBuffer[256]; + if (Unicode) + { + sprintf(TextBuffer, "Loading %S...\n", (PWCHAR)ServiceName); + } + else + { + sprintf(TextBuffer, "Loading %s...\n", (PCHAR)ServiceName); + } + HalDisplayString(TextBuffer); } /* @@ -382,8 +460,8 @@ IopLoadServiceModule( DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status); return Status; } - - IopDisplayLoadingMessage(ServiceName->Buffer); + + IopDisplayLoadingMessage(ServiceName->Buffer, TRUE); /* * Normalize the image path for all later processing. @@ -619,13 +697,10 @@ IopAttachFilterDriversCallback( else { /* get existing DriverObject pointer */ - Status = IopCreateDriverObject( + Status = IopGetDriverObject( &DriverObject, &ServiceName, - OBJ_OPENIF, - FALSE, - ModuleObject->Base, - ModuleObject->Length); + FALSE); if (!NT_SUCCESS(Status)) continue; } @@ -1114,7 +1189,6 @@ IopInitializeBuiltinDriver( PDEVICE_NODE DeviceNode; PDRIVER_OBJECT DriverObject; NTSTATUS Status; - CHAR TextBuffer[256]; PCHAR FileNameWithoutPath; LPWSTR FileExtension; @@ -1122,11 +1196,9 @@ IopInitializeBuiltinDriver( FileName, ModuleLoadBase, ModuleLength); /* - * Display 'Initializing XXX...' message + * Display 'Loading XXX...' message */ - - sprintf(TextBuffer, "Initializing %s...\n", FileName); - HalDisplayString(TextBuffer); + IopDisplayLoadingMessage(FileName, FALSE); /* * Determine the right device object @@ -1202,6 +1274,10 @@ IopInitializeBuiltinDriver( } Status = IopInitializeDevice(DeviceNode, DriverObject); + if (NT_SUCCESS(Status)) + { + Status = IopStartDevice(DeviceNode); + } return Status; } @@ -1295,7 +1371,7 @@ IopLoadDriver(PSERVICE Service) { NTSTATUS Status = STATUS_UNSUCCESSFUL; - IopDisplayLoadingMessage(Service->ServiceName.Buffer); + IopDisplayLoadingMessage(Service->ServiceName.Buffer, TRUE); Status = ZwLoadDriver(&Service->RegistryPath); IopBootLog(&Service->ImagePath, NT_SUCCESS(Status) ? TRUE : FALSE); if (!NT_SUCCESS(Status)) @@ -1938,6 +2014,7 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName) } IopInitializeDevice(DeviceNode, DriverObject); + Status = IopStartDevice(DeviceNode); ReleaseCapturedString: RtlReleaseCapturedUnicodeString(&CapturedDriverServiceName, diff --git a/reactos/ntoskrnl/io/file.c b/reactos/ntoskrnl/io/file.c index 6f04adc0dcd..a635f706f93 100644 --- a/reactos/ntoskrnl/io/file.c +++ b/reactos/ntoskrnl/io/file.c @@ -16,10 +16,6 @@ /* GLOBALS *******************************************************************/ -#define TAG_SYSB TAG('S', 'Y', 'S', 'B') -#define TAG_LOCK TAG('F','l','c','k') -#define TAG_FILE_NAME TAG('F', 'N', 'A', 'M') - extern GENERIC_MAPPING IopFileMapping; NTSTATUS @@ -47,7 +43,7 @@ STDCALL IopCreateFile(PVOID ObjectBody, PVOID Parent, PWSTR RemainingPath, - POBJECT_ATTRIBUTES ObjectAttributes) + POBJECT_CREATE_INFORMATION ObjectCreateInfo) { PDEVICE_OBJECT DeviceObject; PFILE_OBJECT FileObject = (PFILE_OBJECT) ObjectBody; @@ -67,14 +63,14 @@ IopCreateFile(PVOID ObjectBody, return(STATUS_SUCCESS); } - ParentObjectType = BODY_TO_HEADER(Parent)->ObjectType; + ParentObjectType = BODY_TO_HEADER(Parent)->Type; if (ParentObjectType != IoDeviceObjectType && ParentObjectType != IoFileObjectType) { DPRINT("Parent [%wZ] is a %S which is neither a file type nor a device type ; remaining path = %S\n", - &BODY_TO_HEADER(Parent)->Name, - BODY_TO_HEADER(Parent)->ObjectType->TypeName.Buffer, + &BODY_TO_HEADER(Parent)->NameInfo->Name, + BODY_TO_HEADER(Parent)->Type->Name.Buffer, RemainingPath); return(STATUS_UNSUCCESSFUL); } @@ -278,7 +274,7 @@ IopSecurityFile(PVOID ObjectBody, if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) { /* Get the Device Object */ - DPRINT1("here\n"); + DPRINT("here\n"); DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); /* Assign the Security Descriptor */ @@ -344,6 +340,8 @@ IopSecurityFile(PVOID ObjectBody, StackPtr->Parameters.SetSecurity.SecurityDescriptor = SecurityDescriptor; } + ObReferenceObject(FileObject); + /* Call the Driver */ Status = IoCallDriver(FileObject->DeviceObject, Irp); @@ -511,6 +509,130 @@ IopCloseFile(PVOID ObjectBody, IoFreeIrp(Irp); } +NTSTATUS +STDCALL +IopDeviceFsIoControl(IN HANDLE DeviceHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferLength OPTIONAL, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferLength OPTIONAL, + BOOLEAN IsDevIoCtl) +{ + NTSTATUS Status = STATUS_SUCCESS; + PFILE_OBJECT FileObject; + PDEVICE_OBJECT DeviceObject; + PIRP Irp; + PIO_STACK_LOCATION StackPtr; + PKEVENT EventObject = NULL; + BOOLEAN LocalEvent = FALSE; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + + DPRINT("IopDeviceFsIoControl(DeviceHandle %x Event %x UserApcRoutine %x " + "UserApcContext %x IoStatusBlock %x IoControlCode %x " + "InputBuffer %x InputBufferLength %x OutputBuffer %x " + "OutputBufferLength %x)\n", + DeviceHandle,Event,UserApcRoutine,UserApcContext,IoStatusBlock, + IoControlCode,InputBuffer,InputBufferLength,OutputBuffer, + OutputBufferLength); + + if (IoStatusBlock == NULL) return STATUS_ACCESS_VIOLATION; + + /* Check granted access against the access rights from IoContolCode */ + Status = ObReferenceObjectByHandle(DeviceHandle, + (IoControlCode >> 14) & 0x3, + IoFileObjectType, + PreviousMode, + (PVOID *) &FileObject, + NULL); + if (!NT_SUCCESS(Status)) return Status; + + /* Check for an event */ + if (Event) + { + /* Reference it */ + Status = ObReferenceObjectByHandle(Event, + EVENT_MODIFY_STATE, + ExEventObjectType, + PreviousMode, + (PVOID*)&EventObject, + NULL); + if (!NT_SUCCESS(Status)) + { + ObDereferenceObject (FileObject); + return Status; + } + + /* Clear it */ + KeClearEvent(EventObject); + } + + /* Check if this is a direct open or not */ + if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) + { + DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); + } + else + { + DeviceObject = IoGetRelatedDeviceObject(FileObject); + } + + /* Check if we should use Sync IO or not */ + if (FileObject->Flags & FO_SYNCHRONOUS_IO) + { + /* Use File Object event */ + KeClearEvent(&FileObject->Event); + } + else + { + /* Use local event */ + LocalEvent = TRUE; + } + + /* Build the IRP */ + Irp = IoBuildDeviceIoControlRequest(IoControlCode, + DeviceObject, + InputBuffer, + InputBufferLength, + OutputBuffer, + OutputBufferLength, + FALSE, + EventObject, + IoStatusBlock); + + /* Set some extra settings */ + Irp->Tail.Overlay.OriginalFileObject = FileObject; + Irp->RequestorMode = PreviousMode; + Irp->Overlay.AsynchronousParameters.UserApcRoutine = UserApcRoutine; + Irp->Overlay.AsynchronousParameters.UserApcContext = UserApcContext; + StackPtr = IoGetNextIrpStackLocation(Irp); + StackPtr->FileObject = FileObject; + StackPtr->MajorFunction = IsDevIoCtl ? + IRP_MJ_DEVICE_CONTROL : IRP_MJ_FILE_SYSTEM_CONTROL; + + /* Call the Driver */ + Status = IoCallDriver(DeviceObject, Irp); + if (Status == STATUS_PENDING) + { + if (!LocalEvent) + { + KeWaitForSingleObject(&FileObject->Event, + Executive, + PreviousMode, + FileObject->Flags & FO_ALERTABLE_IO, + NULL); + Status = FileObject->FinalStatus; + } + } + + /* Return the Status */ + return Status; +} + /* FUNCTIONS *****************************************************************/ /* @@ -726,6 +848,7 @@ IoCreateFile(OUT PHANDLE FileHandle, if (CreateDisposition == FILE_OPEN || CreateDisposition == FILE_OPEN_IF) { + Status = ObOpenObjectByName(ObjectAttributes, NULL, NULL, @@ -733,6 +856,7 @@ IoCreateFile(OUT PHANDLE FileHandle, DesiredAccess, NULL, &LocalHandle); + if (NT_SUCCESS(Status)) { Status = ObReferenceObjectByHandle(LocalHandle, @@ -746,13 +870,17 @@ IoCreateFile(OUT PHANDLE FileHandle, { return Status; } - if (BODY_TO_HEADER(DeviceObject)->ObjectType != IoDeviceObjectType) + if (BODY_TO_HEADER(DeviceObject)->Type != IoDeviceObjectType) { ObDereferenceObject (DeviceObject); return STATUS_OBJECT_NAME_COLLISION; } /* FIXME: wt... */ FileObject = IoCreateStreamFileObject(NULL, DeviceObject); + /* HACK */ + FileObject->Flags |= FO_DIRECT_DEVICE_OPEN; + DPRINT("%wZ\n", ObjectAttributes->ObjectName); + ObDereferenceObject (DeviceObject); } } @@ -776,7 +904,7 @@ IoCreateFile(OUT PHANDLE FileHandle, } } RtlMapGenericMask(&DesiredAccess, - &BODY_TO_HEADER(FileObject)->ObjectType->TypeInfo.GenericMapping); + &BODY_TO_HEADER(FileObject)->Type->TypeInfo.GenericMapping); Status = ObInsertObject ((PVOID)FileObject, NULL, @@ -886,7 +1014,7 @@ IoCreateFile(OUT PHANDLE FileHandle, */ Status = IofCallDriver(FileObject->DeviceObject, Irp ); DPRINT("Status :%x\n", Status); - + if (Status == STATUS_PENDING) { KeWaitForSingleObject(&FileObject->Event, @@ -1021,9 +1149,7 @@ IoCreateStreamFileObject(PFILE_OBJECT FileObject, CreatedFileObject->DeviceObject = DeviceObject; CreatedFileObject->Vpb = DeviceObject->Vpb; CreatedFileObject->Type = IO_TYPE_FILE; - /* HACK */ - CreatedFileObject->Flags |= FO_DIRECT_DEVICE_OPEN; - //CreatedFileObject->Flags = FO_STREAM_FILE; + CreatedFileObject->Flags |= FO_STREAM_FILE; /* Initialize Lock and Event */ KeInitializeEvent(&CreatedFileObject->Event, NotificationEvent, FALSE); @@ -1509,6 +1635,65 @@ NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes) return(STATUS_NOT_IMPLEMENTED); } +/* + * @implemented + */ +NTSTATUS +STDCALL +NtDeviceIoControlFile(IN HANDLE DeviceHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferLength OPTIONAL, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferLength OPTIONAL) +{ + /* Call the Generic Function */ + return IopDeviceFsIoControl(DeviceHandle, + Event, + UserApcRoutine, + UserApcContext, + IoStatusBlock, + IoControlCode, + InputBuffer, + InputBufferLength, + OutputBuffer, + OutputBufferLength, + TRUE); +} + +/* + * @implemented + */ +NTSTATUS +STDCALL +NtFsControlFile(IN HANDLE DeviceHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferLength OPTIONAL, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferLength OPTIONAL) +{ + return IopDeviceFsIoControl(DeviceHandle, + Event, + UserApcRoutine, + UserApcContext, + IoStatusBlock, + IoControlCode, + InputBuffer, + InputBufferLength, + OutputBuffer, + OutputBufferLength, + FALSE); +} + NTSTATUS STDCALL NtFlushWriteBuffer(VOID) @@ -2536,7 +2721,12 @@ NtReadFile(IN HANDLE FileHandle, Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; Irp->Flags |= IRP_READ_OPERATION; +#if 0 + /* FIXME: + * Vfat doesn't handle non cached files correctly. + */ if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE; +#endif /* Setup Stack Data */ StackPtr = IoGetNextIrpStackLocation(Irp); @@ -3114,7 +3304,7 @@ NtWriteFile (IN HANDLE FileHandle, _SEH_TRY { Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, - FileObject->DeviceObject, + DeviceObject, Buffer, Length, ByteOffset, @@ -3148,7 +3338,12 @@ NtWriteFile (IN HANDLE FileHandle, Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; Irp->Flags |= IRP_WRITE_OPERATION; +#if 0 + /* FIXME: + * Vfat doesn't handle non cached files correctly. + */ if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE; +#endif /* Setup Stack Data */ StackPtr = IoGetNextIrpStackLocation(Irp); diff --git a/reactos/ntoskrnl/io/fs.c b/reactos/ntoskrnl/io/fs.c index ababaef3925..d92d32505f7 100644 --- a/reactos/ntoskrnl/io/fs.c +++ b/reactos/ntoskrnl/io/fs.c @@ -38,10 +38,6 @@ static LIST_ENTRY FileSystemListHead; static KGUARDED_MUTEX FsChangeNotifyListLock; static LIST_ENTRY FsChangeNotifyListHead; -#define TAG_FILE_SYSTEM TAG('F', 'S', 'Y', 'S') -#define TAG_FS_CHANGE_NOTIFY TAG('F', 'S', 'C', 'N') - - static VOID IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject, BOOLEAN DriverActive); @@ -62,115 +58,6 @@ IoCancelFileOpen( UNIMPLEMENTED; } -/* - * @implemented - */ -NTSTATUS STDCALL -NtFsControlFile ( - IN HANDLE DeviceHandle, - IN HANDLE EventHandle OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG IoControlCode, - IN PVOID InputBuffer, - IN ULONG InputBufferSize, - OUT PVOID OutputBuffer, - IN ULONG OutputBufferSize - ) -{ - NTSTATUS Status; - PFILE_OBJECT FileObject; - PDEVICE_OBJECT DeviceObject; - PIRP Irp; - PIO_STACK_LOCATION StackPtr; - PKEVENT ptrEvent; - KPROCESSOR_MODE PreviousMode; - - DPRINT("NtFsControlFile(DeviceHandle %x EventHandle %x ApcRoutine %x " - "ApcContext %x IoStatusBlock %x IoControlCode %x " - "InputBuffer %x InputBufferSize %x OutputBuffer %x " - "OutputBufferSize %x)\n", - DeviceHandle,EventHandle,ApcRoutine,ApcContext,IoStatusBlock, - IoControlCode,InputBuffer,InputBufferSize,OutputBuffer, - OutputBufferSize); - - PreviousMode = ExGetPreviousMode(); - - /* Check granted access against the access rights from IoContolCode */ - Status = ObReferenceObjectByHandle(DeviceHandle, - (IoControlCode >> 14) & 0x3, - NULL, - PreviousMode, - (PVOID *) &FileObject, - NULL); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - if (EventHandle != NULL) - { - Status = ObReferenceObjectByHandle(EventHandle, - SYNCHRONIZE, - ExEventObjectType, - PreviousMode, - (PVOID*)&ptrEvent, - NULL); - if (!NT_SUCCESS(Status)) - { - ObDereferenceObject(FileObject); - return Status; - } - } - else - { - KeResetEvent(&FileObject->Event); - ptrEvent = &FileObject->Event; - } - - DeviceObject = FileObject->DeviceObject; - - Irp = IoBuildDeviceIoControlRequest(IoControlCode, - DeviceObject, - InputBuffer, - InputBufferSize, - OutputBuffer, - OutputBufferSize, - FALSE, - ptrEvent, - IoStatusBlock); - - /* Trigger FileObject/Event dereferencing */ - Irp->Tail.Overlay.OriginalFileObject = FileObject; - - Irp->RequestorMode = PreviousMode; - Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; - Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; - - StackPtr = IoGetNextIrpStackLocation(Irp); - StackPtr->FileObject = FileObject; - StackPtr->DeviceObject = DeviceObject; - StackPtr->Parameters.FileSystemControl.InputBufferLength = InputBufferSize; - StackPtr->Parameters.FileSystemControl.OutputBufferLength = - OutputBufferSize; - StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; - - Status = IoCallDriver(DeviceObject,Irp); - if (Status == STATUS_PENDING && (FileObject->Flags & FO_SYNCHRONOUS_IO)) - { - KeWaitForSingleObject(ptrEvent, - Executive, - PreviousMode, - FileObject->Flags & FO_ALERTABLE_IO, - NULL); - Status = IoStatusBlock->Status; - } - - return Status; -} - - VOID INIT_FUNCTION IoInitFileSystemImplementation(VOID) { diff --git a/reactos/ntoskrnl/io/iocomp.c b/reactos/ntoskrnl/io/iocomp.c index 0f21d3aec3a..2b6aacc30c6 100644 --- a/reactos/ntoskrnl/io/iocomp.c +++ b/reactos/ntoskrnl/io/iocomp.c @@ -13,8 +13,6 @@ #define NDEBUG #include -#define IOC_TAG TAG('I', 'O', 'C', 'T') - POBJECT_TYPE IoCompletionType; NPAGED_LOOKASIDE_LIST IoCompletionPacketLookaside; @@ -206,7 +204,7 @@ IopInitIoCompletionImplementation(VOID) OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING Name; - DPRINT1("Creating IoCompletion Object Type\n"); + DPRINT("Creating IoCompletion Object Type\n"); /* Initialize the Driver object type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); @@ -514,9 +512,6 @@ NtRemoveIoCompletion(IN HANDLE IoCompletionHandle, Status = _SEH_GetExceptionCode(); } _SEH_END; - - /* Free packet */ - ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet); } /* Dereference the Object */ diff --git a/reactos/ntoskrnl/io/iomgr.c b/reactos/ntoskrnl/io/iomgr.c index 1198b11928e..cfb92f86011 100644 --- a/reactos/ntoskrnl/io/iomgr.c +++ b/reactos/ntoskrnl/io/iomgr.c @@ -13,18 +13,6 @@ #define NDEBUG #include -/* GLOBALS *******************************************************************/ - -#define TAG_DEVICE_TYPE TAG('D', 'E', 'V', 'T') -#define TAG_FILE_TYPE TAG('F', 'I', 'L', 'E') -#define TAG_ADAPTER_TYPE TAG('A', 'D', 'P', 'T') -#define IO_LARGEIRP TAG('I', 'r', 'p', 'l') -#define IO_SMALLIRP TAG('I', 'r', 'p', 's') -#define IO_LARGEIRP_CPU TAG('I', 'r', 'p', 'L') -#define IO_SMALLIRP_CPU TAG('I', 'r', 'p', 'S') -#define IOC_TAG TAG('I', 'p', 'c', ' ') -#define IOC_CPU TAG('I', 'p', 'c', 'P') - /* DATA ********************************************************************/ POBJECT_TYPE EXPORTED IoDeviceObjectType = NULL; @@ -105,7 +93,7 @@ IopInitLookasideLists(VOID) NULL, 0, sizeof(IO_COMPLETION_PACKET), - IOC_TAG, + IOC_TAG1, 0); /* Now allocate the per-processor lists */ @@ -113,7 +101,7 @@ IopInitLookasideLists(VOID) { /* Get the PRCB for this CPU */ Prcb = ((PKPCR)(KPCR_BASE + i * PAGE_SIZE))->Prcb; - DPRINT1("Setting up lookaside for CPU: %x, PRCB: %p\n", i, Prcb); + DPRINT("Setting up lookaside for CPU: %x, PRCB: %p\n", i, Prcb); /* Set the Large IRP List */ Prcb->PPLookasideList[LookasideLargeIrpList].L = &IoLargeIrpLookaside.L; @@ -182,7 +170,7 @@ IopInitLookasideLists(VOID) Prcb->PPLookasideList[LookasideCompletionList].P = &CurrentList->L; } - DPRINT1("Done allocation\n"); + DPRINT("Done allocation\n"); } VOID @@ -198,7 +186,7 @@ IoInit (VOID) IopInitDriverImplementation(); - DPRINT1("Creating Device Object Type\n"); + DPRINT("Creating Device Object Type\n"); /* Initialize the Driver object type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); @@ -378,6 +366,14 @@ IoInit2(BOOLEAN BootLog) return; } + Status = IopStartDevice(DeviceNode); + if (!NT_SUCCESS(Status)) + { + IopFreeDeviceNode(DeviceNode); + CPRINT("IopInitializeDevice() failed with status (%x)\n", Status); + return; + } + /* * Initialize PnP root releations */ @@ -403,10 +399,10 @@ IoInit3(VOID) IoCreateArcNames(); /* Create the SystemRoot symbolic link */ - CPRINT("CommandLine: %s\n", (PCHAR)KeLoaderBlock.CommandLine); + DPRINT("CommandLine: %s\n", (PCHAR)KeLoaderBlock.CommandLine); Status = IoCreateSystemRootLink((PCHAR)KeLoaderBlock.CommandLine); if (!NT_SUCCESS(Status)) { - DbgPrint("IoCreateSystemRootLink FAILED: (0x%x) - ", Status); + CPRINT("IoCreateSystemRootLink FAILED: (0x%x) - ", Status); KEBUGCHECK(INACCESSIBLE_BOOT_DEVICE); } diff --git a/reactos/ntoskrnl/io/iowork.c b/reactos/ntoskrnl/io/iowork.c index f27c1761749..838d2a90b27 100644 --- a/reactos/ntoskrnl/io/iowork.c +++ b/reactos/ntoskrnl/io/iowork.c @@ -25,10 +25,6 @@ typedef struct _IO_WORKITEM PVOID Context; } IO_WORKITEM; -/* GLOBALS ******************************************************************/ - -#define TAG_IOWI TAG('I', 'O', 'W', 'I') - /* FUNCTIONS ****************************************************************/ VOID STATIC STDCALL diff --git a/reactos/ntoskrnl/io/irp.c b/reactos/ntoskrnl/io/irp.c index 71b748efaf4..af9c36c674b 100644 --- a/reactos/ntoskrnl/io/irp.c +++ b/reactos/ntoskrnl/io/irp.c @@ -15,11 +15,6 @@ #define NDEBUG #include -/* GLOBALS *******************************************************************/ - -#define TAG_IRP TAG('I', 'R', 'P', ' ') -#define TAG_SYS_BUF TAG('S', 'Y', 'S' , 'B') - /* PRIVATE FUNCTIONS ********************************************************/ VOID diff --git a/reactos/ntoskrnl/io/irq.c b/reactos/ntoskrnl/io/irq.c index ecb75fc040c..d80f7c00986 100644 --- a/reactos/ntoskrnl/io/irq.c +++ b/reactos/ntoskrnl/io/irq.c @@ -14,10 +14,6 @@ #define NDEBUG #include -/* GLOBALS *****************************************************************/ - -#define TAG_KINTERRUPT TAG('K', 'I', 'S', 'R') - /* FUNCTIONS *****************************************************************/ /* diff --git a/reactos/ntoskrnl/io/mdl.c b/reactos/ntoskrnl/io/mdl.c index b5319ab7202..a26ab838cf2 100644 --- a/reactos/ntoskrnl/io/mdl.c +++ b/reactos/ntoskrnl/io/mdl.c @@ -14,10 +14,6 @@ #define NDEBUG #include -/* GLOBALS *******************************************************************/ - -#define TAG_MDL TAG('M', 'D', 'L', ' ') - /* FUNCTIONS *****************************************************************/ /* diff --git a/reactos/ntoskrnl/io/pnpmgr.c b/reactos/ntoskrnl/io/pnpmgr.c index a8fcc3e4111..83d0902e64b 100644 --- a/reactos/ntoskrnl/io/pnpmgr.c +++ b/reactos/ntoskrnl/io/pnpmgr.c @@ -60,7 +60,7 @@ IoGetDeviceProperty( { PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); ULONG Length; - PVOID Data; + PVOID Data = NULL; PWSTR Ptr; DPRINT("IoGetDeviceProperty(%x %d)\n", DeviceObject, DeviceProperty); @@ -236,15 +236,19 @@ IoGetDeviceProperty( if (Ptr != NULL) { Length = (ULONG)((ULONG_PTR)Ptr - (ULONG_PTR)DeviceNode->InstancePath.Buffer) + sizeof(WCHAR); + Data = DeviceNode->InstancePath.Buffer; } else { Length = 0; Data = NULL; } + break; case DevicePropertyPhysicalDeviceObjectName: - return STATUS_NOT_IMPLEMENTED; + Length = DeviceNode->InstancePath.Length + sizeof(WCHAR); + Data = DeviceNode->InstancePath.Buffer; + break; default: return STATUS_INVALID_PARAMETER_2; @@ -256,7 +260,8 @@ IoGetDeviceProperty( RtlCopyMemory(PropertyBuffer, Data, Length); /* Terminate the string */ - if (DeviceProperty == DevicePropertyEnumeratorName) + if (DeviceProperty == DevicePropertyEnumeratorName + || DeviceProperty == DevicePropertyPhysicalDeviceObjectName) { Ptr = (PWSTR)PropertyBuffer; Ptr[(Length / sizeof(WCHAR)) - 1] = 0; @@ -894,6 +899,200 @@ IopSetDeviceInstanceData(HANDLE InstanceKey, } +NTSTATUS +IopAssignDeviceResources( + PDEVICE_NODE DeviceNode) +{ + PIO_RESOURCE_LIST ResourceList; + PIO_RESOURCE_DESCRIPTOR ResourceDescriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated; + ULONG NumberOfResources = 0; + ULONG i; + NTSTATUS Status; + + /* Fill DeviceNode->ResourceList and DeviceNode->ResourceListTranslated; + * by using DeviceNode->ResourceRequirements */ + + if (!DeviceNode->ResourceRequirements + || DeviceNode->ResourceRequirements->AlternativeLists == 0) + { + DeviceNode->ResourceList = DeviceNode->ResourceListTranslated = NULL; + return STATUS_SUCCESS; + } + + /* FIXME: that's here that PnP arbiter should go */ + /* Actually, simply use resource list #0 as assigned resource list */ + ResourceList = &DeviceNode->ResourceRequirements->List[0]; + if (ResourceList->Version != 1 || ResourceList->Revision != 1) + { + Status = STATUS_REVISION_MISMATCH; + goto ByeBye; + } + + DeviceNode->ResourceList = ExAllocatePool(PagedPool, + sizeof(CM_RESOURCE_LIST) + ResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + if (!DeviceNode->ResourceList) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ByeBye; + } + + DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool, + sizeof(CM_RESOURCE_LIST) + ResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + if (!DeviceNode->ResourceListTranslated) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ByeBye; + } + + DeviceNode->ResourceList->Count = 1; + DeviceNode->ResourceList->List[0].InterfaceType = DeviceNode->ResourceRequirements->InterfaceType; + DeviceNode->ResourceList->List[0].BusNumber = DeviceNode->ResourceRequirements->BusNumber; + DeviceNode->ResourceList->List[0].PartialResourceList.Version = 1; + DeviceNode->ResourceList->List[0].PartialResourceList.Revision = 1; + + DeviceNode->ResourceListTranslated->Count = 1; + DeviceNode->ResourceListTranslated->List[0].InterfaceType = DeviceNode->ResourceRequirements->InterfaceType; + DeviceNode->ResourceListTranslated->List[0].BusNumber = DeviceNode->ResourceRequirements->BusNumber; + DeviceNode->ResourceListTranslated->List[0].PartialResourceList.Version = 1; + DeviceNode->ResourceListTranslated->List[0].PartialResourceList.Revision = 1; + + for (i = 0; i < ResourceList->Count; i++) + { + ResourceDescriptor = &ResourceList->Descriptors[i]; + + if (ResourceDescriptor->Option == 0 || ResourceDescriptor->Option == IO_RESOURCE_PREFERRED) + { + DescriptorRaw = &DeviceNode->ResourceList->List[0].PartialResourceList.PartialDescriptors[NumberOfResources]; + DescriptorTranslated = &DeviceNode->ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[NumberOfResources]; + NumberOfResources++; + + /* Copy ResourceDescriptor to DescriptorRaw and DescriptorTranslated */ + DescriptorRaw->Type = DescriptorTranslated->Type = ResourceDescriptor->Type; + DescriptorRaw->ShareDisposition = DescriptorTranslated->ShareDisposition = ResourceDescriptor->ShareDisposition; + DescriptorRaw->Flags = DescriptorTranslated->Flags = ResourceDescriptor->Flags; + switch (ResourceDescriptor->Type) + { + case CmResourceTypePort: + { + ULONG AddressSpace = 0; /* IO space */ + DescriptorRaw->u.Port.Start = ResourceDescriptor->u.Port.MinimumAddress; + DescriptorRaw->u.Port.Length = DescriptorTranslated->u.Port.Length + = ResourceDescriptor->u.Port.Length; + if (!HalTranslateBusAddress( + DeviceNode->ResourceRequirements->InterfaceType, + DeviceNode->ResourceRequirements->BusNumber, + DescriptorRaw->u.Port.Start, + &AddressSpace, + &DescriptorTranslated->u.Port.Start)) + { + Status = STATUS_UNSUCCESSFUL; + goto ByeBye; + } + break; + } + case CmResourceTypeInterrupt: + { + DescriptorRaw->u.Interrupt.Level = 0; + /* FIXME: if IRQ 9 is in the possible range, use it. + * This should be a PCI device */ + if (ResourceDescriptor->u.Interrupt.MinimumVector <= 9 + && ResourceDescriptor->u.Interrupt.MaximumVector >= 9) + DescriptorRaw->u.Interrupt.Vector = 9; + else + DescriptorRaw->u.Interrupt.Vector = ResourceDescriptor->u.Interrupt.MinimumVector; + + DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector( + DeviceNode->ResourceRequirements->InterfaceType, + DeviceNode->ResourceRequirements->BusNumber, + DescriptorRaw->u.Interrupt.Level, + DescriptorRaw->u.Interrupt.Vector, + (PKIRQL)&DescriptorTranslated->u.Interrupt.Level, + &DescriptorRaw->u.Interrupt.Affinity); + DescriptorTranslated->u.Interrupt.Affinity = DescriptorRaw->u.Interrupt.Affinity; + break; + } + case CmResourceTypeMemory: + { + ULONG AddressSpace = 1; /* Memory space */ + DescriptorRaw->u.Memory.Start = ResourceDescriptor->u.Memory.MinimumAddress; + DescriptorRaw->u.Memory.Length = DescriptorTranslated->u.Memory.Length + = ResourceDescriptor->u.Memory.Length; + if (!HalTranslateBusAddress( + DeviceNode->ResourceRequirements->InterfaceType, + DeviceNode->ResourceRequirements->BusNumber, + DescriptorRaw->u.Memory.Start, + &AddressSpace, + &DescriptorTranslated->u.Memory.Start)) + { + Status = STATUS_UNSUCCESSFUL; + goto ByeBye; + } + break; + } + case CmResourceTypeDma: + { + DescriptorRaw->u.Dma.Channel = DescriptorTranslated->u.Dma.Channel + = ResourceDescriptor->u.Dma.MinimumChannel; + DescriptorRaw->u.Dma.Port = DescriptorTranslated->u.Dma.Port + = 0; /* FIXME */ + DescriptorRaw->u.Dma.Reserved1 = DescriptorTranslated->u.Dma.Reserved1 + = 0; + break; + } + /*case CmResourceTypeBusNumber: + { + DescriptorRaw->u.BusNumber.Start = DescriptorTranslated->u.BusNumber.Start + = ResourceDescriptor->u.BusNumber.MinBusNumber; + DescriptorRaw->u.BusNumber.Length = DescriptorTranslated->u.BusNumber.Length + = ResourceDescriptor->u.BusNumber.Length; + DescriptorRaw->u.BusNumber.Reserved = DescriptorTranslated->u.BusNumber.Reserved + = ResourceDescriptor->u.BusNumber.Reserved; + break; + }*/ + /*CmResourceTypeDevicePrivate: + case CmResourceTypePcCardConfig: + case CmResourceTypeMfCardConfig: + { + RtlCopyMemory( + &DescriptorRaw->u.DevicePrivate, + &ResourceDescriptor->u.DevicePrivate, + sizeof(ResourceDescriptor->u.DevicePrivate)); + RtlCopyMemory( + &DescriptorTranslated->u.DevicePrivate, + &ResourceDescriptor->u.DevicePrivate, + sizeof(ResourceDescriptor->u.DevicePrivate)); + break; + }*/ + default: + DPRINT1("IopAssignDeviceResources(): unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type); + NumberOfResources--; + } + } + + } + + DeviceNode->ResourceList->List[0].PartialResourceList.Count = NumberOfResources; + DeviceNode->ResourceListTranslated->List[0].PartialResourceList.Count = NumberOfResources; + + return STATUS_SUCCESS; + +ByeBye: + if (DeviceNode->ResourceList) + { + ExFreePool(DeviceNode->ResourceList); + DeviceNode->ResourceList = NULL; + } + if (DeviceNode->ResourceListTranslated) + { + ExFreePool(DeviceNode->ResourceListTranslated); + DeviceNode->ResourceListTranslated = NULL; + } + + return Status; +} + + /* * IopActionInterrogateDeviceStack * @@ -1317,6 +1516,12 @@ IopActionInterrogateDeviceStack( ZwClose(InstanceKey); + Status = IopAssignDeviceResources(DeviceNode); + if (!NT_SUCCESS(Status)) + { + DPRINT("IopAssignDeviceResources() failed (Status %x)\n", Status); + } + DeviceNode->Flags |= DNF_PROCESSED; /* Report the device to the user-mode pnp manager */ @@ -1507,13 +1712,10 @@ IopActionInitChildServices( else { /* get existing DriverObject pointer */ - Status = IopCreateDriverObject( - &DriverObject, - &DeviceNode->ServiceName, - OBJ_OPENIF, - FALSE, - ModuleObject->Base, - ModuleObject->Length); + Status = IopGetDriverObject( + &DriverObject, + &DeviceNode->ServiceName, + FALSE); } if (NT_SUCCESS(Status)) { @@ -1523,9 +1725,11 @@ IopActionInitChildServices( Status = IopInitializeDevice(DeviceNode, DriverObject); if (NT_SUCCESS(Status)) { - IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED); /* Attach upper level filter drivers. */ IopAttachFilterDrivers(DeviceNode, FALSE); + IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED); + + Status = IopStartDevice(DeviceNode); } } } diff --git a/reactos/ntoskrnl/io/pnpnotify.c b/reactos/ntoskrnl/io/pnpnotify.c index d218e99265d..e92e5cc578b 100644 --- a/reactos/ntoskrnl/io/pnpnotify.c +++ b/reactos/ntoskrnl/io/pnpnotify.c @@ -30,8 +30,6 @@ typedef struct _PNP_NOTIFY_ENTRY static KGUARDED_MUTEX PnpNotifyListLock; static LIST_ENTRY PnpNotifyListHead; -#define TAG_PNP_NOTIFY TAG('P', 'n', 'P', 'N') - /* FUNCTIONS *****************************************************************/ /* diff --git a/reactos/ntoskrnl/io/pnpreport.c b/reactos/ntoskrnl/io/pnpreport.c index ea378a2b511..721e6b0ca43 100644 --- a/reactos/ntoskrnl/io/pnpreport.c +++ b/reactos/ntoskrnl/io/pnpreport.c @@ -80,8 +80,14 @@ IoReportResourceForDetection( IN ULONG DeviceListSize OPTIONAL, OUT PBOOLEAN ConflictDetected) { + static int warned = 0; + if (!warned) + { + DPRINT1("IoReportResourceForDetection partly implemented\n"); + warned = 1; + } + *ConflictDetected = FALSE; - DPRINT1("IoReportResourceForDetection partly implemented\n"); /* FIXME: Manually indicate conflicts with KD Ports */ if (DriverList) diff --git a/reactos/ntoskrnl/io/pnproot.c b/reactos/ntoskrnl/io/pnproot.c index 6a0b74d1f54..afe7a29cf49 100644 --- a/reactos/ntoskrnl/io/pnproot.c +++ b/reactos/ntoskrnl/io/pnproot.c @@ -671,7 +671,7 @@ PnpRootQueryBusRelations( /* FIXME: */ } - DPRINT1("DeviceID: %wZ PDO %p\n", + DPRINT("DeviceID: %wZ PDO %p\n", &PdoDeviceExtension->DeviceID, Device->Pdo); @@ -684,7 +684,7 @@ PnpRootQueryBusRelations( /* FIXME: */ } - DPRINT1("InstanceID: %wZ PDO %p\n", + DPRINT("InstanceID: %wZ PDO %p\n", &PdoDeviceExtension->InstanceID, Device->Pdo); } diff --git a/reactos/ntoskrnl/io/rawfs.c b/reactos/ntoskrnl/io/rawfs.c index b19e58e428a..6881de87437 100755 --- a/reactos/ntoskrnl/io/rawfs.c +++ b/reactos/ntoskrnl/io/rawfs.c @@ -90,8 +90,6 @@ typedef struct _RAWFS_CCB /* GLOBALS ******************************************************************/ -#define TAG_IRP TAG('R', 'I', 'R', 'P') - static PDRIVER_OBJECT RawFsDriverObject; static PDEVICE_OBJECT DiskDeviceObject; static PDEVICE_OBJECT CdromDeviceObject; diff --git a/reactos/ntoskrnl/io/resource.c b/reactos/ntoskrnl/io/resource.c index 49c78788fc6..aea22acc1e2 100644 --- a/reactos/ntoskrnl/io/resource.c +++ b/reactos/ntoskrnl/io/resource.c @@ -76,8 +76,6 @@ PWSTR ArcTypes[42] = { L"Undefined" }; -#define TAG_IO_RESOURCE TAG('R', 'S', 'R', 'C') - /* PRIVATE FUNCTIONS **********************************************************/ /* diff --git a/reactos/ntoskrnl/io/timer.c b/reactos/ntoskrnl/io/timer.c index 090daa1a671..33f9cf83ab8 100644 --- a/reactos/ntoskrnl/io/timer.c +++ b/reactos/ntoskrnl/io/timer.c @@ -17,8 +17,6 @@ /* GLOBALS *******************************************************************/ -#define TAG_IO_TIMER TAG('I', 'O', 'T', 'M') - /* Timer Database */ KSPIN_LOCK IopTimerLock; LIST_ENTRY IopTimerQueueHead; diff --git a/reactos/ntoskrnl/io/vpb.c b/reactos/ntoskrnl/io/vpb.c index 56f34acad90..b16186bffe6 100644 --- a/reactos/ntoskrnl/io/vpb.c +++ b/reactos/ntoskrnl/io/vpb.c @@ -18,9 +18,6 @@ static KSPIN_LOCK IoVpbLock; -#define TAG_VPB TAG('V', 'P', 'B', ' ') -#define TAG_SYSB TAG('S', 'Y', 'S', 'B') - /* FUNCTIONS *****************************************************************/ VOID INIT_FUNCTION diff --git a/reactos/ntoskrnl/kd/kdmain.c b/reactos/ntoskrnl/kd/kdmain.c index 3569c06690e..72d5b12cac1 100644 --- a/reactos/ntoskrnl/kd/kdmain.c +++ b/reactos/ntoskrnl/kd/kdmain.c @@ -37,6 +37,7 @@ KdpServiceDispatcher(ULONG Service, Result = KdpPrintString ((PANSI_STRING)Context1); break; +#ifdef DBG case TAG('R', 'o', 's', ' '): /* ROS-INTERNAL */ { switch ((ULONG)Context1) @@ -77,7 +78,7 @@ KdpServiceDispatcher(ULONG Service, break; } } - +#endif default: HalDisplayString ("Invalid debug service call!\n"); break; diff --git a/reactos/ntoskrnl/kdbg/kdb_cli.c b/reactos/ntoskrnl/kdbg/kdb_cli.c index bb96f7e2c87..19528192efe 100644 --- a/reactos/ntoskrnl/kdbg/kdb_cli.c +++ b/reactos/ntoskrnl/kdbg/kdb_cli.c @@ -2278,7 +2278,7 @@ KdbpCliInterpretInitFile() CHAR c; /* Execute the commands in the init file */ - DbgPrint("KDB: Executing KDBinit file...\n"); + DPRINT("KDB: Executing KDBinit file...\n"); p1 = KdbInitFileBuffer; while (p1[0] != '\0') { @@ -2309,7 +2309,7 @@ KdbpCliInterpretInitFile() while (p1[0] == '\r' || p1[0] == '\n') p1++; } - DbgPrint("KDB: KDBinit executed\n"); + DPRINT("KDB: KDBinit executed\n"); } /*!\brief Called when KDB is initialized diff --git a/reactos/ntoskrnl/kdbg/kdb_symbols.c b/reactos/ntoskrnl/kdbg/kdb_symbols.c index 0cfd513b47d..70d39905471 100644 --- a/reactos/ntoskrnl/kdbg/kdb_symbols.c +++ b/reactos/ntoskrnl/kdbg/kdb_symbols.c @@ -19,8 +19,6 @@ /* GLOBALS ******************************************************************/ -#define TAG_KDBS TAG('K', 'D', 'B', 'S') - typedef struct _IMAGE_SYMBOL_INFO_CACHE { LIST_ENTRY ListEntry; ULONG RefCount; diff --git a/reactos/ntoskrnl/ke/bug.c b/reactos/ntoskrnl/ke/bug.c index bfff3a6eb6e..086f87c8ddb 100644 --- a/reactos/ntoskrnl/ke/bug.c +++ b/reactos/ntoskrnl/ke/bug.c @@ -53,7 +53,7 @@ KiInitializeBugCheck(VOID) /* Make sure it worked */ if (NT_SUCCESS(Status)) { - DPRINT1("Found Bugcheck Resource Data!\n"); + DPRINT("Found Bugcheck Resource Data!\n"); /* Now actually get a pointer to it */ Status = LdrAccessResource((PVOID)KERNEL_BASE, @@ -64,7 +64,7 @@ KiInitializeBugCheck(VOID) /* Make sure it worked */ if (NT_SUCCESS(Status)) { - DPRINT1("Got Pointer to Bugcheck Resource Data!\n"); + DPRINT("Got Pointer to Bugcheck Resource Data!\n"); KiBugCodeMessages = BugCheckData; } } diff --git a/reactos/ntoskrnl/ke/clock.c b/reactos/ntoskrnl/ke/clock.c index e22d81bfb0f..4ff89f0c29a 100644 --- a/reactos/ntoskrnl/ke/clock.c +++ b/reactos/ntoskrnl/ke/clock.c @@ -77,7 +77,7 @@ KiInitializeSystemClock(VOID) { TIME_FIELDS TimeFields; - DPRINT1("KiInitializeSystemClock()\n"); + DPRINT("KiInitializeSystemClock()\n"); InitializeListHead(&KiTimerListHead); KeInitializeDpc(&KiExpireTimerDpc, (PKDEFERRED_ROUTINE)KiExpireTimers, 0); @@ -96,7 +96,7 @@ KiInitializeSystemClock(VOID) SharedUserData->SystemTime.High1Time = SystemBootTime.u.HighPart; KiClockSetupComplete = TRUE; - DPRINT1("Finished KiInitializeSystemClock()\n"); + DPRINT("Finished KiInitializeSystemClock()\n"); } VOID diff --git a/reactos/ntoskrnl/ke/gate.c b/reactos/ntoskrnl/ke/gate.c index 220e2f41c9a..27999148712 100644 --- a/reactos/ntoskrnl/ke/gate.c +++ b/reactos/ntoskrnl/ke/gate.c @@ -19,7 +19,7 @@ VOID FASTCALL KeInitializeGate(PKGATE Gate) { - DPRINT1("KeInitializeGate(Gate %x)\n", Gate); + DPRINT("KeInitializeGate(Gate %x)\n", Gate); /* Initialize the Dispatcher Header */ KeInitializeDispatcherHeader(&Gate->Header, @@ -39,7 +39,7 @@ KeWaitForGate(PKGATE Gate, PKWAIT_BLOCK GateWaitBlock; NTSTATUS Status; - DPRINT1("KeWaitForGate(Gate %x)\n", Gate); + DPRINT("KeWaitForGate(Gate %x)\n", Gate); do { @@ -74,7 +74,7 @@ KeWaitForGate(PKGATE Gate, /* Handle Kernel Queues */ if (CurrentThread->Queue) { - DPRINT1("Waking Queue\n"); + DPRINT("Waking Queue\n"); KiWakeQueue(CurrentThread->Queue); } @@ -82,7 +82,7 @@ KeWaitForGate(PKGATE Gate, KeReleaseSpinLock(&CurrentThread->ApcQueueLock, OldIrql); /* Block the Thread */ - DPRINT1("Blocking the Thread: %x\n", CurrentThread); + DPRINT("Blocking the Thread: %x\n", CurrentThread); KiBlockThread(&Status, CurrentThread->Alertable, WaitMode, @@ -91,7 +91,7 @@ KeWaitForGate(PKGATE Gate, /* Check if we were executing an APC */ if (Status != STATUS_KERNEL_APC) return; - DPRINT1("Looping Again\n"); + DPRINT("Looping Again\n"); } while (TRUE); } @@ -104,7 +104,7 @@ KeSignalGateBoostPriority(PKGATE Gate) KIRQL OldIrql; NTSTATUS WaitStatus = STATUS_SUCCESS; - DPRINT1("KeSignalGateBoostPriority(EveGate %x)\n", Gate); + DPRINT("KeSignalGateBoostPriority(EveGate %x)\n", Gate); /* Acquire Dispatcher Database Lock */ OldIrql = KeAcquireDispatcherDatabaseLock(); @@ -132,12 +132,12 @@ KeSignalGateBoostPriority(PKGATE Gate) /* Increment the Queue's active threads */ if (WaitThread->Queue) { - DPRINT1("Incrementing Queue's active threads\n"); + DPRINT("Incrementing Queue's active threads\n"); WaitThread->Queue->CurrentCount++; } /* Reschedule the Thread */ - DPRINT1("Unblocking the Thread\n"); + DPRINT("Unblocking the Thread\n"); KiUnblockThread(WaitThread, &WaitStatus, EVENT_INCREMENT); return; diff --git a/reactos/ntoskrnl/ke/i386/exp.c b/reactos/ntoskrnl/ke/i386/exp.c index 2db4926aa61..5027e2ef950 100644 --- a/reactos/ntoskrnl/ke/i386/exp.c +++ b/reactos/ntoskrnl/ke/i386/exp.c @@ -725,7 +725,7 @@ KeDumpStackFrames(PULONG Frame) &ResultLength ); if ( !NT_SUCCESS(Status) ) { - DPRINT1("Can't dump stack frames: NtQueryVirtualMemory() failed: %x\n", Status ); + DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status ); return; } @@ -782,7 +782,7 @@ KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount ) &ResultLength ); if ( !NT_SUCCESS(Status) ) { - DPRINT1("Can't dump stack frames: NtQueryVirtualMemory() failed: %x\n", Status ); + DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status ); return; } @@ -834,7 +834,7 @@ KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount ) &ResultLength ); if ( !NT_SUCCESS(Status) ) { - DPRINT1("Can't get stack frames: NtQueryVirtualMemory() failed: %x\n", Status ); + DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status ); return 0; } diff --git a/reactos/ntoskrnl/ke/i386/irq.c b/reactos/ntoskrnl/ke/i386/irq.c index 2678e2504ca..59bbf0feed9 100644 --- a/reactos/ntoskrnl/ke/i386/irq.c +++ b/reactos/ntoskrnl/ke/i386/irq.c @@ -53,9 +53,7 @@ __asm__( \ "pushl %esp\n\t" \ "pushl %ebx\n\t" \ "call _KiInterruptDispatch\n\t" \ - "popl %eax\n\t" \ - "popl %eax\n\t" \ - "popl %eax\n\t" \ + "addl $0xC, %esp\n\t" \ "popl %gs\n\t" \ "popl %fs\n\t" \ "popl %es\n\t" \ diff --git a/reactos/ntoskrnl/ke/i386/irqhand.s b/reactos/ntoskrnl/ke/i386/irqhand.s index f248ab1d0dd..12406ef8c6b 100644 --- a/reactos/ntoskrnl/ke/i386/irqhand.s +++ b/reactos/ntoskrnl/ke/i386/irqhand.s @@ -21,9 +21,7 @@ _irq_handler_0: pushl %esp pushl $(IRQ_BASE + 0) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -50,9 +48,7 @@ _irq_handler_1: pushl %esp pushl $(IRQ_BASE + 1) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -79,9 +75,7 @@ _irq_handler_2: pushl %esp pushl $(IRQ_BASE + 2) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -108,9 +102,7 @@ _irq_handler_3: pushl %esp pushl $(IRQ_BASE + 3) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -137,9 +129,7 @@ _irq_handler_4: pushl %esp pushl $(IRQ_BASE + 4) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -166,9 +156,7 @@ _irq_handler_5: pushl %esp pushl $(IRQ_BASE + 5) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -195,9 +183,7 @@ _irq_handler_6: pushl %esp pushl $(IRQ_BASE + 6) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -224,9 +210,7 @@ _irq_handler_7: pushl %esp pushl $(IRQ_BASE + 7) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -253,9 +237,7 @@ _irq_handler_8: pushl %esp pushl $(IRQ_BASE + 8) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -282,9 +264,7 @@ _irq_handler_9: pushl %esp pushl $(IRQ_BASE + 9) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -311,9 +291,7 @@ _irq_handler_10: pushl %esp pushl $(IRQ_BASE + 10) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -340,9 +318,7 @@ _irq_handler_11: pushl %esp pushl $(IRQ_BASE + 11) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -369,9 +345,7 @@ _irq_handler_12: pushl %esp pushl $(IRQ_BASE + 12) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -398,9 +372,7 @@ _irq_handler_13: pushl %esp pushl $(IRQ_BASE + 13) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -427,9 +399,7 @@ _irq_handler_14: pushl %esp pushl $(IRQ_BASE + 14) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es @@ -456,9 +426,7 @@ _irq_handler_15: pushl %esp pushl $(IRQ_BASE + 15) call _KiInterruptDispatch - popl %eax - popl %eax - popl %eax + addl $0xC, %esp popl %gs popl %fs popl %es diff --git a/reactos/ntoskrnl/ke/i386/main.S b/reactos/ntoskrnl/ke/i386/main.S index d2641e0f428..121f50448ed 100644 --- a/reactos/ntoskrnl/ke/i386/main.S +++ b/reactos/ntoskrnl/ke/i386/main.S @@ -6,7 +6,7 @@ #include #include -#define AP_MAGIC (0x12481020) +#define AP_MAGIC (0x12481020) .globl _NtProcessStartup @@ -23,20 +23,20 @@ _NtProcessStartup: cmpl $AP_MAGIC, %ecx jne .m1 - pushl $0 - popfl - - /* - * Reserve space for the floating point save area. - */ - subl $SIZEOF_FX_SAVE_AREA, %esp - - /* - * Call the application processor initialization code - */ - pushl $0 - call _KiSystemStartup - + pushl $0 + popfl + + /* + * Reserve space for the floating point save area. + */ + subl $SIZEOF_FX_SAVE_AREA, %esp + + /* + * Call the application processor initialization code + */ + pushl $0 + call _KiSystemStartup + .m1: /* Load the initial kernel stack */ lea _kernel_stack, %eax diff --git a/reactos/ntoskrnl/ke/main.c b/reactos/ntoskrnl/ke/main.c index c4299a1d27e..cb2dba1aba5 100644 --- a/reactos/ntoskrnl/ke/main.c +++ b/reactos/ntoskrnl/ke/main.c @@ -288,6 +288,10 @@ _main(ULONG MultiBootMagic, /* Initialize HAL */ HalInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock); + /* Display separator + ReactOS version at start of the debug log */ + DPRINT1("---------------------------------------------------------------\n"); + DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n"); + /* Do general System Startup */ KiSystemStartup(1); } diff --git a/reactos/ntoskrnl/ke/wait.c b/reactos/ntoskrnl/ke/wait.c index d34e8973dca..03057c82b9b 100644 --- a/reactos/ntoskrnl/ke/wait.c +++ b/reactos/ntoskrnl/ke/wait.c @@ -799,14 +799,14 @@ KiIsObjectWaitable(PVOID Object) POBJECT_HEADER Header; Header = BODY_TO_HEADER(Object); - if (Header->ObjectType == ExEventObjectType || - Header->ObjectType == IoCompletionType || - Header->ObjectType == ExMutantObjectType || - Header->ObjectType == ExSemaphoreObjectType || - Header->ObjectType == ExTimerType || - Header->ObjectType == PsProcessType || - Header->ObjectType == PsThreadType || - Header->ObjectType == IoFileObjectType) { + if (Header->Type == ExEventObjectType || + Header->Type == IoCompletionType || + Header->Type == ExMutantObjectType || + Header->Type == ExSemaphoreObjectType || + Header->Type == ExTimerType || + Header->Type == PsProcessType || + Header->Type == PsThreadType || + Header->Type == IoFileObjectType) { return TRUE; diff --git a/reactos/ntoskrnl/ldr/loader.c b/reactos/ntoskrnl/ldr/loader.c index d7153d8d82f..3979dc151b5 100644 --- a/reactos/ntoskrnl/ldr/loader.c +++ b/reactos/ntoskrnl/ldr/loader.c @@ -41,11 +41,6 @@ STATIC MODULE_TEXT_SECTION NtoskrnlTextSection; STATIC MODULE_TEXT_SECTION LdrHalTextSection; ULONG_PTR LdrHalBase; -#define TAG_DRIVER_MEM TAG('D', 'R', 'V', 'M') /* drvm */ -#define TAG_MODULE_OBJECT TAG('k', 'l', 'm', 'o') /* klmo - kernel ldr module object */ -#define TAG_LDR_WSTR TAG('k', 'l', 'w', 's') /* klws - kernel ldr wide string */ -#define TAG_MODULE_TEXT_SECTION TAG('k', 'l', 'm', 't') /* klmt - kernel ldr module text */ - #ifndef HIWORD #define HIWORD(X) ((WORD) (((DWORD) (X) >> 16) & 0xFFFF)) #endif @@ -314,7 +309,7 @@ LdrLoadModule( GENERIC_READ, &ObjectAttributes, &IoStatusBlock, - 0, + FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT); CHECKPOINT; if (!NT_SUCCESS(Status)) @@ -792,7 +787,7 @@ LdrPEProcessModule( CPRINT("Failed to allocate a virtual section for driver\n"); return STATUS_UNSUCCESSFUL; } - DbgPrint("DriverBase for %wZ: %x\n", FileName, DriverBase); + DPRINT("DriverBase for %wZ: %x\n", FileName, DriverBase); /* Copy headers over */ memcpy(DriverBase, ModuleLoadBase, PENtHeaders->OptionalHeader.SizeOfHeaders); diff --git a/reactos/ntoskrnl/ldr/sysdll.c b/reactos/ntoskrnl/ldr/sysdll.c index 8567ab57407..d75db35b0d6 100644 --- a/reactos/ntoskrnl/ldr/sysdll.c +++ b/reactos/ntoskrnl/ldr/sysdll.c @@ -56,6 +56,7 @@ PVOID LdrpGetSystemDllRaiseExceptionDispatcher(VOID) NTSTATUS STDCALL +INIT_FUNCTION LdrpGetSystemDllEntryPoints(VOID) { ANSI_STRING ProcedureName; @@ -169,6 +170,7 @@ LdrpMapSystemDll(PEPROCESS Process, NTSTATUS STDCALL +INIT_FUNCTION LdrpInitializeSystemDll(VOID) { UNICODE_STRING DllPathname = ROS_STRING_INITIALIZER(L"\\SystemRoot\\system32\\ntdll.dll"); diff --git a/reactos/ntoskrnl/lpc/connect.c b/reactos/ntoskrnl/lpc/connect.c index 9bb82a7ea0f..6020915f7eb 100644 --- a/reactos/ntoskrnl/lpc/connect.c +++ b/reactos/ntoskrnl/lpc/connect.c @@ -14,10 +14,6 @@ #define NDEBUG #include -/* GLOBALS *******************************************************************/ - -#define TAG_LPC_CONNECT_MESSAGE TAG('L', 'P', 'C', 'C') - /* FUNCTIONS *****************************************************************/ /********************************************************************** diff --git a/reactos/ntoskrnl/lpc/port.c b/reactos/ntoskrnl/lpc/port.c index a346ad7ba9f..a3917529898 100644 --- a/reactos/ntoskrnl/lpc/port.c +++ b/reactos/ntoskrnl/lpc/port.c @@ -38,7 +38,7 @@ LpcpInitSystem (VOID) OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING Name; - DPRINT1("Creating Port Object Type\n"); + DPRINT("Creating Port Object Type\n"); /* Create the Port Object Type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); diff --git a/reactos/ntoskrnl/mm/aspace.c b/reactos/ntoskrnl/mm/aspace.c index d66d5610e40..5a97b03bf5b 100644 --- a/reactos/ntoskrnl/mm/aspace.c +++ b/reactos/ntoskrnl/mm/aspace.c @@ -17,8 +17,6 @@ STATIC MADDRESS_SPACE KernelAddressSpace; -#define TAG_PTRC TAG('P', 'T', 'R', 'C') - /* FUNCTIONS *****************************************************************/ VOID diff --git a/reactos/ntoskrnl/mm/marea.c b/reactos/ntoskrnl/mm/marea.c index cf3f55f1ec3..9291de2816f 100644 --- a/reactos/ntoskrnl/mm/marea.c +++ b/reactos/ntoskrnl/mm/marea.c @@ -14,10 +14,6 @@ #define NDEBUG #include -/* GLOBALS *******************************************************************/ - -#define TAG_MAREA TAG('M', 'A', 'R', 'E') - /* #define VALIDATE_MEMORY_AREAS */ /* FUNCTIONS *****************************************************************/ diff --git a/reactos/ntoskrnl/mm/mdl.c b/reactos/ntoskrnl/mm/mdl.c index 488988eb0c7..d51fefd5c69 100644 --- a/reactos/ntoskrnl/mm/mdl.c +++ b/reactos/ntoskrnl/mm/mdl.c @@ -85,7 +85,9 @@ MmInitializeMdlImplementation(VOID) } MmUnlockAddressSpace(MmGetKernelAddressSpace()); - Buffer = ExAllocatePool(NonPagedPool, MI_MDL_MAPPING_REGION_SIZE / (PAGE_SIZE * 8)); + Buffer = ExAllocatePoolWithTag(NonPagedPool, + MI_MDL_MAPPING_REGION_SIZE / (PAGE_SIZE * 8), + TAG_MDL); RtlInitializeBitMap(&MiMdlMappingRegionAllocMap, Buffer, MI_MDL_MAPPING_REGION_SIZE / PAGE_SIZE); RtlClearAllBits(&MiMdlMappingRegionAllocMap); diff --git a/reactos/ntoskrnl/mm/mm.c b/reactos/ntoskrnl/mm/mm.c index eafada883d2..0bd5e39cdc5 100644 --- a/reactos/ntoskrnl/mm/mm.c +++ b/reactos/ntoskrnl/mm/mm.c @@ -321,8 +321,11 @@ NTSTATUS MmNotPresentFault(KPROCESSOR_MODE Mode, } if (PsGetCurrentProcess() == NULL) { + /* Allow this! It lets us page alloc much earlier! It won't be needed + * after my init patch anyways + */ DbgPrint("No current process\n"); - return(STATUS_UNSUCCESSFUL); + //return(STATUS_UNSUCCESSFUL); } /* diff --git a/reactos/ntoskrnl/mm/npool.c b/reactos/ntoskrnl/mm/npool.c index c019519728c..b507e3254fa 100644 --- a/reactos/ntoskrnl/mm/npool.c +++ b/reactos/ntoskrnl/mm/npool.c @@ -872,7 +872,7 @@ MiDebugDumpNonPagedPoolStats(BOOLEAN NewOnly) VOID MiDebugDumpNonPagedPool(BOOLEAN NewOnly) { -#ifndef WHOLE_PAGE_ALLOCATIONS +#if defined(POOL_DEBUG_APIS) && !defined(WHOLE_PAGE_ALLOCATIONS) BLOCK_HDR* current; PLIST_ENTRY current_entry; KIRQL oldIrql; diff --git a/reactos/ntoskrnl/mm/pageop.c b/reactos/ntoskrnl/mm/pageop.c index d290c960e88..47b3c92480b 100644 --- a/reactos/ntoskrnl/mm/pageop.c +++ b/reactos/ntoskrnl/mm/pageop.c @@ -22,8 +22,6 @@ static KSPIN_LOCK MmPageOpHashTableLock; static PMM_PAGEOP MmPageOpHashTable[PAGEOP_HASH_TABLE_SIZE]; static NPAGED_LOOKASIDE_LIST MmPageOpLookasideList; -#define TAG_MM_PAGEOP TAG('M', 'P', 'O', 'P') - /* FUNCTIONS *****************************************************************/ VOID diff --git a/reactos/ntoskrnl/mm/pe.c b/reactos/ntoskrnl/mm/pe.c index 0993043011d..27ff7429025 100644 --- a/reactos/ntoskrnl/mm/pe.c +++ b/reactos/ntoskrnl/mm/pe.c @@ -518,8 +518,8 @@ l_ReadHeaderFromFile: /* size of the executable's headers */ if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfHeaders)) { - if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment)) - DIE(("SizeOfHeaders is not aligned\n")); + //if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment)) + //DIE(("SizeOfHeaders is not aligned\n")); if(cbSectionHeadersSize > piohOptHeader->SizeOfHeaders) DIE(("The section headers overflow SizeOfHeaders\n")); @@ -611,7 +611,7 @@ l_ReadHeaderFromFile: /* initialize the headers segment */ pssSegments = ImageSectionObject->Segments; - ASSERT(IsAligned(cbHeadersSize, nFileAlignment)); + //ASSERT(IsAligned(cbHeadersSize, nFileAlignment)); if(!AlignUp(&nFileSizeOfHeaders, cbHeadersSize, nFileAlignment)) DIE(("Cannot align the size of the section headers\n")); @@ -655,8 +655,8 @@ l_ReadHeaderFromFile: DIE(("SizeOfRawData[%u] is not aligned\n", i)); #endif - if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment)) - DIE(("PointerToRawData[%u] is not aligned\n", i)); + //if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment)) + //DIE(("PointerToRawData[%u] is not aligned\n", i)); /* conversion */ pssSegments[i].FileOffset = pishSectionHeaders[i].PointerToRawData; diff --git a/reactos/ntoskrnl/mm/pool.c b/reactos/ntoskrnl/mm/pool.c index 5d7d8b7cb23..15be0c02b21 100644 --- a/reactos/ntoskrnl/mm/pool.c +++ b/reactos/ntoskrnl/mm/pool.c @@ -22,8 +22,6 @@ extern MM_STATS MmStats; /* GLOBALS *****************************************************************/ -#define TAG_NONE (ULONG)(('N'<<0) + ('o'<<8) + ('n'<<16) + ('e'<<24)) - ULONG STDCALL ExRosQueryPagedPoolTag ( PVOID Block ); diff --git a/reactos/ntoskrnl/mm/ppool.c b/reactos/ntoskrnl/mm/ppool.c index 0a141302056..767b739b3b8 100644 --- a/reactos/ntoskrnl/mm/ppool.c +++ b/reactos/ntoskrnl/mm/ppool.c @@ -33,7 +33,7 @@ #define R_EXTRA_STACK_UP 2 #define R_GET_STACK_FRAMES(ptr,cnt) KeRosGetStackFrames(ptr,cnt) -#include "RPoolMgr.h" +#include "rpoolmgr.h" /* GLOBALS *******************************************************************/ diff --git a/reactos/ntoskrnl/mm/region.c b/reactos/ntoskrnl/mm/region.c index 0a7738c46e1..4dc04aea08d 100644 --- a/reactos/ntoskrnl/mm/region.c +++ b/reactos/ntoskrnl/mm/region.c @@ -14,10 +14,6 @@ #define NDEBUG #include -/* GLOBALS *******************************************************************/ - -#define TAG_MM_REGION TAG('M', 'R', 'G', 'N') - /* FUNCTIONS *****************************************************************/ VOID STATIC diff --git a/reactos/ntoskrnl/mm/rmap.c b/reactos/ntoskrnl/mm/rmap.c index d12dfaa18d2..6808388b794 100644 --- a/reactos/ntoskrnl/mm/rmap.c +++ b/reactos/ntoskrnl/mm/rmap.c @@ -24,8 +24,6 @@ typedef struct _MM_RMAP_ENTRY } MM_RMAP_ENTRY, *PMM_RMAP_ENTRY; -#define TAG_RMAP TAG('R', 'M', 'A', 'P') - /* GLOBALS ******************************************************************/ static FAST_MUTEX RmapListLock; @@ -142,7 +140,7 @@ MmWritePagePhysicalAddress(PFN_TYPE Page) Status = MmWritePageSectionView(AddressSpace, MemoryArea, Address, PageOp); } - else if (Type == MEMORY_AREA_VIRTUAL_MEMORY) + else if ((Type == MEMORY_AREA_VIRTUAL_MEMORY) || (Type == MEMORY_AREA_PEB_OR_TEB)) { PageOp = MmGetPageOp(MemoryArea, Address < (PVOID)KERNEL_BASE ? Process->UniqueProcessId : NULL, Address, NULL, 0, MM_PAGEOP_PAGEOUT, TRUE); @@ -265,7 +263,7 @@ MmPageOutPhysicalAddress(PFN_TYPE Page) Status = MmPageOutSectionView(AddressSpace, MemoryArea, Address, PageOp); } - else if (Type == MEMORY_AREA_VIRTUAL_MEMORY) + else if ((Type == MEMORY_AREA_VIRTUAL_MEMORY) || (Type == MEMORY_AREA_PEB_OR_TEB)) { PageOp = MmGetPageOp(MemoryArea, Address < (PVOID)KERNEL_BASE ? Process->UniqueProcessId : NULL, Address, NULL, 0, MM_PAGEOP_PAGEOUT, TRUE); diff --git a/reactos/ntoskrnl/mm/section.c b/reactos/ntoskrnl/mm/section.c index 666d977ecd8..3f14d7d69ae 100644 --- a/reactos/ntoskrnl/mm/section.c +++ b/reactos/ntoskrnl/mm/section.c @@ -38,9 +38,6 @@ static GENERIC_MAPPING MmpSectionMapping = { STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE, SECTION_ALL_ACCESS}; -#define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S') -#define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T') - #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000) #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT) #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1) @@ -201,7 +198,7 @@ MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment, { Table = Segment->PageDirectory.PageTables[DirectoryOffset] = - ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_PAGE_TABLE), + ExAllocatePoolWithTag(PagedPool, sizeof(SECTION_PAGE_TABLE), TAG_SECTION_PAGE_TABLE); if (Table == NULL) { @@ -2099,6 +2096,16 @@ MmCreatePhysicalMemorySection(VOID) DbgPrint("Failed to create PhysicalMemory section\n"); KEBUGCHECK(0); } + Status = ObInsertObject(PhysSection, + NULL, + SECTION_ALL_ACCESS, + 0, + NULL, + NULL); + if (!NT_SUCCESS(Status)) + { + ObDereferenceObject(PhysSection); + } PhysSection->AllocationAttributes |= SEC_PHYSICALMEMORY; return(STATUS_SUCCESS); @@ -2110,14 +2117,14 @@ MmInitSectionImplementation(VOID) OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; UNICODE_STRING Name; - DPRINT1("Creating Section Object Type\n"); + DPRINT("Creating Section Object Type\n"); /* Initialize the Section object type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); RtlInitUnicodeString(&Name, L"Section"); ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); - ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(SECTION_OBJECT); - ObjectTypeInitializer.PoolType = NonPagedPool; + ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(SECTION_OBJECT); + ObjectTypeInitializer.PoolType = PagedPool; ObjectTypeInitializer.UseDefaultObject = TRUE; ObjectTypeInitializer.GenericMapping = MmpSectionMapping; ObjectTypeInitializer.DeleteProcedure = MmpDeleteSection; @@ -2176,7 +2183,7 @@ MmCreatePageFileSection(PSECTION_OBJECT *SectionObject, KeInitializeSpinLock(&Section->ViewListLock); Section->FileObject = NULL; Section->MaximumSize = MaximumSize; - Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT), + Segment = ExAllocatePoolWithTag(PagedPool, sizeof(MM_SECTION_SEGMENT), TAG_MM_SECTION_SEGMENT); if (Segment == NULL) { @@ -2239,7 +2246,6 @@ MmCreateDataFileSection(PSECTION_OBJECT *SectionObject, { return(Status); } - /* * Initialize it */ @@ -2381,7 +2387,7 @@ MmCreateDataFileSection(PSECTION_OBJECT *SectionObject, */ if (FileObject->SectionObjectPointer->DataSectionObject == NULL) { - Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SECTION_SEGMENT), + Segment = ExAllocatePoolWithTag(PagedPool, sizeof(MM_SECTION_SEGMENT), TAG_MM_SECTION_SEGMENT); if (Segment == NULL) { @@ -2493,7 +2499,7 @@ ExeFmtpAllocateSegments(IN ULONG NrSegments) /* TODO: check for integer overflow */ SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * NrSegments; - Segments = ExAllocatePoolWithTag(NonPagedPool, + Segments = ExAllocatePoolWithTag(PagedPool, SizeOfSegments, TAG_MM_SECTION_SEGMENT); @@ -3067,7 +3073,7 @@ ExeFmtpCreateImageSection(HANDLE FileHandle, SizeOfSegments = sizeof(MM_SECTION_SEGMENT) * ImageSectionObject->NrSegments; - Segments = ExAllocatePoolWithTag(NonPagedPool, + Segments = ExAllocatePoolWithTag(PagedPool, SizeOfSegments, TAG_MM_SECTION_SEGMENT); @@ -3140,6 +3146,7 @@ MmCreateImageSection(PSECTION_OBJECT *SectionObject, UserMode, (PVOID*)(PVOID)&FileObject, NULL); + if (!NT_SUCCESS(Status)) { return Status; @@ -3181,7 +3188,7 @@ MmCreateImageSection(PSECTION_OBJECT *SectionObject, { NTSTATUS StatusExeFmt; - ImageSectionObject = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT); + ImageSectionObject = ExAllocatePoolWithTag(PagedPool, sizeof(MM_IMAGE_SECTION_OBJECT), TAG_MM_SECTION_SEGMENT); if (ImageSectionObject == NULL) { ObDereferenceObject(FileObject); diff --git a/reactos/ntoskrnl/mm/virtual.c b/reactos/ntoskrnl/mm/virtual.c index 1b198b295a7..7e696da4ad3 100644 --- a/reactos/ntoskrnl/mm/virtual.c +++ b/reactos/ntoskrnl/mm/virtual.c @@ -207,15 +207,6 @@ MiQueryVirtualMemory (IN HANDLE ProcessHandle, *ResultLength = sizeof(MEMORY_BASIC_INFORMATION); break; case MEMORY_AREA_SYSTEM: - { - static int warned = 0; - if ( !warned ) - { - DPRINT1("FIXME: MEMORY_AREA_SYSTEM case incomplete (or possibly wrong) for NtQueryVirtualMemory()\n"); - warned = 1; - } - } - /* FIXME - don't have a clue if this is right, but it's better than nothing */ Info->Type = 0; Info->State = MEM_COMMIT; Info->Protect = MemoryArea->Attributes; @@ -228,15 +219,6 @@ MiQueryVirtualMemory (IN HANDLE ProcessHandle, *ResultLength = sizeof(MEMORY_BASIC_INFORMATION); break; case MEMORY_AREA_KERNEL_STACK: - { - static int warned = 0; - if ( !warned ) - { - DPRINT1("FIXME: MEMORY_AREA_KERNEL_STACK case incomplete (or possibly wrong) for NtQueryVirtualMemory()\n"); - warned = 1; - } - } - /* FIXME - don't have a clue if this is right, but it's better than nothing */ Info->Type = 0; Info->State = MEM_COMMIT; Info->Protect = MemoryArea->Attributes; @@ -304,7 +286,7 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle, PrevMode = ExGetPreviousMode(); - if (PrevMode == UserMode && Address >= (PVOID)KERNEL_BASE) + if (Address >= (PVOID)KERNEL_BASE) { DPRINT1("Invalid parameter\n"); return STATUS_INVALID_PARAMETER; diff --git a/reactos/ntoskrnl/ob/dirobj.c b/reactos/ntoskrnl/ob/dirobj.c index cc374dbed65..6a5c7ce3575 100644 --- a/reactos/ntoskrnl/ob/dirobj.c +++ b/reactos/ntoskrnl/ob/dirobj.c @@ -253,11 +253,11 @@ NtQueryDirectoryObject (IN HANDLE DirectoryHandle, EntryHeader = CONTAINING_RECORD(ListEntry, OBJECT_HEADER, Entry); /* calculate the size of the required buffer space for this entry */ - Name = (EntryHeader->Name.Length != 0 ? &EntryHeader->Name : NULL); - Type = &EntryHeader->ObjectType->Name; + Name = (HEADER_TO_OBJECT_NAME(EntryHeader)->Name.Length != 0 ? &HEADER_TO_OBJECT_NAME(EntryHeader)->Name : NULL); + Type = &EntryHeader->Type->Name; EntrySize = sizeof(OBJECT_DIRECTORY_INFORMATION) + ((Name != NULL) ? ((ULONG)Name->Length + sizeof(WCHAR)) : 0) + - (ULONG)EntryHeader->ObjectType->Name.Length + sizeof(WCHAR); + (ULONG)EntryHeader->Type->Name.Length + sizeof(WCHAR); if(RequiredSize + EntrySize <= BufferLength) { @@ -440,8 +440,8 @@ NtCreateDirectoryObject (OUT PHANDLE DirectoryHandle, PAGED_CODE(); DPRINT("NtCreateDirectoryObject(DirectoryHandle %x, " - "DesiredAccess %x, ObjectAttributes %x\n", - DirectoryHandle, DesiredAccess, ObjectAttributes); + "DesiredAccess %x, ObjectAttributes %x\n", + DirectoryHandle, DesiredAccess, ObjectAttributes); PreviousMode = ExGetPreviousMode(); diff --git a/reactos/ntoskrnl/ob/handle.c b/reactos/ntoskrnl/ob/handle.c index 9145aa62531..1d0dd7040bf 100644 --- a/reactos/ntoskrnl/ob/handle.c +++ b/reactos/ntoskrnl/ob/handle.c @@ -46,25 +46,38 @@ PHANDLE_TABLE ObpKernelHandleTable = NULL; +/* TEMPORARY HACK. DO NOT REMOVE -- Alex */ +NTSTATUS +STDCALL +ExpDesktopCreate(PVOID ObjectBody, + PVOID Parent, + PWSTR RemainingPath, + POBJECT_CREATE_INFORMATION ObjectCreateInformation); + /* FUNCTIONS ***************************************************************/ static VOID ObpDecrementHandleCount(PVOID ObjectBody) { POBJECT_HEADER ObjectHeader = BODY_TO_HEADER(ObjectBody); + DPRINT("Header: %x\n", ObjectHeader); LONG NewHandleCount = InterlockedDecrement(&ObjectHeader->HandleCount); + DPRINT("NewHandleCount: %x\n", NewHandleCount); + DPRINT("HEADER_TO_OBJECT_NAME: %x\n", HEADER_TO_OBJECT_NAME(ObjectHeader)); - if ((ObjectHeader->ObjectType != NULL) && - (ObjectHeader->ObjectType->TypeInfo.CloseProcedure != NULL)) + if ((ObjectHeader->Type != NULL) && + (ObjectHeader->Type->TypeInfo.CloseProcedure != NULL)) { /* the handle count should be decremented but we pass the previous value to the callback */ - ObjectHeader->ObjectType->TypeInfo.CloseProcedure(ObjectBody, NewHandleCount + 1); + ObjectHeader->Type->TypeInfo.CloseProcedure(ObjectBody, NewHandleCount + 1); } if(NewHandleCount == 0) { - if(ObjectHeader->Parent != NULL && !ObjectHeader->Permanent) + if(HEADER_TO_OBJECT_NAME(ObjectHeader) && + HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory != NULL && + !(ObjectHeader->Flags & OB_FLAG_PERMANENT)) { /* delete the object from the namespace when the last handle got closed. Only do this if it's actually been inserted into the namespace and @@ -207,7 +220,7 @@ ObpDeleteHandle(PHANDLE_TABLE HandleTable, } ObjectHeader = EX_HTE_TO_HDR(HandleEntry); - Body = HEADER_TO_BODY(ObjectHeader); + Body = &ObjectHeader->Body; ObpDecrementHandleCount(Body); @@ -268,7 +281,7 @@ ObDuplicateObject(PEPROCESS SourceProcess, } ObjectHeader = EX_HTE_TO_HDR(SourceHandleEntry); - ObjectBody = HEADER_TO_BODY(ObjectHeader); + ObjectBody = &ObjectHeader->Body; NewHandleEntry.u1.Object = SourceHandleEntry->u1.Object; if(InheritHandle) @@ -287,7 +300,7 @@ ObDuplicateObject(PEPROCESS SourceProcess, if (DesiredAccess & GENERIC_ANY) { RtlMapGenericMask(&DesiredAccess, - &ObjectHeader->ObjectType->TypeInfo.GenericMapping); + &ObjectHeader->Type->TypeInfo.GenericMapping); } NewHandleEntry.u2.GrantedAccess = DesiredAccess; } @@ -516,7 +529,7 @@ DeleteHandleCallback(PHANDLE_TABLE HandleTable, PAGED_CODE(); ObjectHeader = EX_OBJ_TO_HDR(Object); - ObjectBody = HEADER_TO_BODY(ObjectHeader); + ObjectBody = &ObjectHeader->Body; ObpDecrementHandleCount(ObjectBody); } @@ -537,7 +550,7 @@ DuplicateHandleCallback(PHANDLE_TABLE HandleTable, ObjectHeader = EX_HTE_TO_HDR(HandleTableEntry); if(InterlockedIncrement(&ObjectHeader->HandleCount) == 1) { - ObReferenceObject(HEADER_TO_BODY(ObjectHeader)); + ObReferenceObject(&ObjectHeader->Body); } } @@ -623,7 +636,7 @@ ObpCreateHandle(PEPROCESS Process, if (GrantedAccess & GENERIC_ANY) { RtlMapGenericMask(&GrantedAccess, - &ObjectHeader->ObjectType->TypeInfo.GenericMapping); + &ObjectHeader->Type->TypeInfo.GenericMapping); } NewEntry.u1.Object = ObjectHeader; @@ -731,6 +744,10 @@ ObReferenceObjectByHandle(HANDLE Handle, "ObjectType %x, AccessMode %d, Object %x)\n",Handle,DesiredAccess, ObjectType,AccessMode,Object); + if (Handle == NULL) + { + return STATUS_INVALID_HANDLE; + } /* * Handle special handle names */ @@ -810,13 +827,13 @@ ObReferenceObjectByHandle(HANDLE Handle, } ObjectHeader = EX_HTE_TO_HDR(HandleEntry); - ObjectBody = HEADER_TO_BODY(ObjectHeader); + ObjectBody = &ObjectHeader->Body; DPRINT("locked1: ObjectHeader: 0x%x [HT:0x%x]\n", ObjectHeader, HandleTable); - if (ObjectType != NULL && ObjectType != ObjectHeader->ObjectType) + if (ObjectType != NULL && ObjectType != ObjectHeader->Type) { - DPRINT("ObjectType mismatch: %wZ vs %wZ (handle 0x%x)\n", &ObjectType->TypeName, ObjectHeader->ObjectType ? &ObjectHeader->ObjectType->TypeName : NULL, Handle); + DPRINT("ObjectType mismatch: %wZ vs %wZ (handle 0x%x)\n", &ObjectType->TypeName, ObjectHeader->Type ? &ObjectHeader->Type->TypeName : NULL, Handle); ExUnlockHandleTableEntry(HandleTable, HandleEntry); @@ -830,7 +847,7 @@ ObReferenceObjectByHandle(HANDLE Handle, if (DesiredAccess & GENERIC_ANY) { RtlMapGenericMask(&DesiredAccess, - &BODY_TO_HEADER(ObjectBody)->ObjectType->TypeInfo.GenericMapping); + &BODY_TO_HEADER(ObjectBody)->Type->TypeInfo.GenericMapping); } GrantedAccess = HandleEntry->u2.GrantedAccess; @@ -925,27 +942,215 @@ NtClose(IN HANDLE Handle) /* * @implemented */ -NTSTATUS STDCALL +NTSTATUS +STDCALL ObInsertObject(IN PVOID Object, - IN PACCESS_STATE PassedAccessState OPTIONAL, - IN ACCESS_MASK DesiredAccess, - IN ULONG AdditionalReferences, - OUT PVOID* ReferencedObject OPTIONAL, - OUT PHANDLE Handle) + IN PACCESS_STATE PassedAccessState OPTIONAL, + IN ACCESS_MASK DesiredAccess, + IN ULONG AdditionalReferences, + OUT PVOID* ReferencedObject OPTIONAL, + OUT PHANDLE Handle) { - POBJECT_HEADER ObjectHeader; - ACCESS_MASK Access; + POBJECT_CREATE_INFORMATION ObjectCreateInfo; + POBJECT_HEADER Header; + POBJECT_HEADER_NAME_INFO ObjectNameInfo; + PVOID FoundObject = NULL; + POBJECT_HEADER FoundHeader = NULL; + NTSTATUS Status = STATUS_SUCCESS; + UNICODE_STRING RemainingPath; + BOOLEAN ObjectAttached = FALSE; + PSECURITY_DESCRIPTOR NewSecurityDescriptor = NULL; + SECURITY_SUBJECT_CONTEXT SubjectContext; - PAGED_CODE(); + PAGED_CODE(); + + /* Get the Header and Create Info */ + DPRINT("ObInsertObject: %x\n", Object); + Header = BODY_TO_HEADER(Object); + ObjectCreateInfo = Header->ObjectCreateInfo; + ObjectNameInfo = HEADER_TO_OBJECT_NAME(Header); + + /* First try to find the Object */ + if (ObjectNameInfo && ObjectNameInfo->Name.Buffer) + { + DPRINT("Object has a name. Trying to find it: %wZ.\n", &ObjectNameInfo->Name); + Status = ObFindObject(ObjectCreateInfo, + &ObjectNameInfo->Name, + &FoundObject, + &RemainingPath, + NULL); + DPRINT("FoundObject: %x, Path: %wZ\n", FoundObject, &RemainingPath); + if (!NT_SUCCESS(Status)) + { + DPRINT1("ObFindObject() failed! (Status 0x%x)\n", Status); + return Status; + } + + if (FoundObject) + { + DPRINT("Getting header: %x\n", FoundObject); + FoundHeader = BODY_TO_HEADER(FoundObject); + } + + if (FoundHeader && RemainingPath.Buffer == NULL) + { + DPRINT("Object exists\n"); + ObDereferenceObject(FoundObject); + return STATUS_OBJECT_NAME_COLLISION; + } + } + else + { + DPRINT("No name, empty remaining path\n"); + RtlInitUnicodeString(&RemainingPath, NULL); + } - Access = DesiredAccess; - ObjectHeader = BODY_TO_HEADER(Object); + if (FoundHeader && FoundHeader->Type == ObDirectoryType && + RemainingPath.Buffer) + { + ObpAddEntryDirectory(FoundObject, Header, NULL); + ObjectAttached = TRUE; + + /* The name was changed so let's update it */ + /* FIXME: TEMPORARY HACK This will go in ObFindObject in the next commit */ + PVOID NewName; + PWSTR BufferPos = RemainingPath.Buffer; + + NewName = ExAllocatePool(NonPagedPool, RemainingPath.MaximumLength); + ObjectNameInfo = HEADER_TO_OBJECT_NAME(Header); + + if (BufferPos[0] == L'\\') + { + BufferPos++; + } + + RtlMoveMemory(NewName, BufferPos, RemainingPath.MaximumLength); + if (ObjectNameInfo->Name.Buffer) ExFreePool(ObjectNameInfo->Name.Buffer); + ObjectNameInfo->Name.Buffer = NewName; + ObjectNameInfo->Name.Length = RemainingPath.Length; + ObjectNameInfo->Name.MaximumLength = RemainingPath.MaximumLength; + DPRINT("Name: %S\n", ObjectNameInfo->Name.Buffer); + } - return(ObpCreateHandle(PsGetCurrentProcess(), - Object, - Access, - ObjectHeader->Inherit, - Handle)); + if ((Header->Type == IoFileObjectType) || + (Header->Type == ExDesktopObjectType) || + (Header->Type->TypeInfo.OpenProcedure != NULL)) + { + DPRINT("About to call Open Routine\n"); + if (Header->Type == IoFileObjectType) + { + /* TEMPORARY HACK. DO NOT TOUCH -- Alex */ + DPRINT("Calling IopCreateFile: %x\n", FoundObject); + Status = IopCreateFile(&Header->Body, + FoundObject, + RemainingPath.Buffer, + ObjectCreateInfo); + DPRINT("Called IopCreateFile: %x\n", Status); + + } + else if (Header->Type == ExDesktopObjectType) + { + /* TEMPORARY HACK. DO NOT TOUCH -- Alex */ + DPRINT("Calling ExpDesktopCreate\n"); + Status = ExpDesktopCreate(&Header->Body, + FoundObject, + RemainingPath.Buffer, + ObjectCreateInfo); + } + else if (Header->Type->TypeInfo.OpenProcedure != NULL) + { + DPRINT("Calling %x\n", Header->Type->TypeInfo.OpenProcedure); + Status = Header->Type->TypeInfo.OpenProcedure(ObCreateHandle, + &Header->Body, + NULL, + 0, + 0); + } + + if (!NT_SUCCESS(Status)) + { + DPRINT("Create Failed\n"); + if (ObjectAttached == TRUE) + { + ObpRemoveEntryDirectory(Header); + } + if (FoundObject) + { + ObDereferenceObject(FoundObject); + } + RtlFreeUnicodeString(&RemainingPath); + return Status; + } + } + + RtlFreeUnicodeString(&RemainingPath); + + DPRINT("Security Assignment in progress\n"); + SeCaptureSubjectContext(&SubjectContext); + + /* Build the new security descriptor */ + Status = SeAssignSecurity((FoundHeader != NULL) ? FoundHeader->SecurityDescriptor : NULL, + (ObjectCreateInfo != NULL) ? ObjectCreateInfo->SecurityDescriptor : NULL, + &NewSecurityDescriptor, + (Header->Type == ObDirectoryType), + &SubjectContext, + &Header->Type->TypeInfo.GenericMapping, + PagedPool); + + if (NT_SUCCESS(Status)) + { + DPRINT("NewSecurityDescriptor %p\n", NewSecurityDescriptor); + + if (Header->Type->TypeInfo.SecurityProcedure != NULL) + { + /* Call the security method */ + Status = Header->Type->TypeInfo.SecurityProcedure(&Header->Body, + AssignSecurityDescriptor, + 0, + NewSecurityDescriptor, + NULL); + } + else + { + /* Assign the security descriptor to the object header */ + Status = ObpAddSecurityDescriptor(NewSecurityDescriptor, + &Header->SecurityDescriptor); + DPRINT("Object security descriptor %p\n", Header->SecurityDescriptor); + } + + /* Release the new security descriptor */ + SeDeassignSecurity(&NewSecurityDescriptor); + } + + DPRINT("Security Complete\n"); + SeReleaseSubjectContext(&SubjectContext); + + /* Create the Handle */ + /* HACKHACK: Because of ROS's incorrect startup, this can be called + * without a valid Process until I finalize the startup patch, + * so don't create a handle if this is the case. We also don't create + * a handle if Handle is NULL when the Registry Code calls it, because + * the registry code totally bastardizes the Ob and needs to be fixed + */ + DPRINT("Creating handle\n"); + if (Handle != NULL) + { + Status = ObpCreateHandle(PsGetCurrentProcess(), + &Header->Body, + DesiredAccess, + ObjectCreateInfo->Attributes & OBJ_INHERIT, + Handle); + DPRINT("handle Created: %d. refcount. handlecount %d %d\n", + *Handle, Header->RefCount, Header->HandleCount); + } + + /* We can delete the Create Info now */ + Header->ObjectCreateInfo = NULL; + ObpReleaseCapturedAttributes(ObjectCreateInfo); + ExFreePool(ObjectCreateInfo); + + DPRINT("Status %x\n", Status); + return Status; } @@ -1026,7 +1231,7 @@ ObpGetNextHandleByProcessCount(PSYSTEM_HANDLE_TABLE_ENTRY_INFO pshi, // pshi->GrantedAccess; // pshi->Object; -// pshi->ObjectTypeIndex; +// pshi->TypeIndex; // pshi->HandleAttributes; // KeReleaseSpinLock( &Process->HandleTable.ListLock, oldIrql ); diff --git a/reactos/ntoskrnl/ob/namespc.c b/reactos/ntoskrnl/ob/namespc.c index 30974240ba1..fb276a5aa25 100644 --- a/reactos/ntoskrnl/ob/namespc.c +++ b/reactos/ntoskrnl/ob/namespc.c @@ -40,7 +40,8 @@ static GENERIC_MAPPING ObpTypeMapping = { NTSTATUS STDCALL -ObpAllocateObject(POBJECT_ATTRIBUTES ObjectAttributes, +ObpAllocateObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo, + PUNICODE_STRING ObjectName, POBJECT_TYPE ObjectType, ULONG ObjectSize, POBJECT_HEADER *ObjectHeader); @@ -62,7 +63,9 @@ ObReferenceObjectByName(PUNICODE_STRING ObjectPath, { PVOID Object = NULL; UNICODE_STRING RemainingPath; + UNICODE_STRING ObjectName; OBJECT_ATTRIBUTES ObjectAttributes; + OBJECT_CREATE_INFORMATION ObjectCreateInfo; NTSTATUS Status; PAGED_CODE(); @@ -72,21 +75,38 @@ ObReferenceObjectByName(PUNICODE_STRING ObjectPath, Attributes | OBJ_OPENIF, NULL, NULL); - Status = ObFindObject(&ObjectAttributes, + + /* Capture all the info */ + DPRINT("Capturing Create Info\n"); + Status = ObpCaptureObjectAttributes(&ObjectAttributes, + AccessMode, + ObjectType, + &ObjectCreateInfo, + &ObjectName); + if (!NT_SUCCESS(Status)) + { + DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status); + return Status; + } + + Status = ObFindObject(&ObjectCreateInfo, + &ObjectName, &Object, &RemainingPath, ObjectType); + + ObpReleaseCapturedAttributes(&ObjectCreateInfo); + if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer); + if (!NT_SUCCESS(Status)) { return(Status); } -CHECKPOINT; -DPRINT("RemainingPath.Buffer '%S' Object %p\n", RemainingPath.Buffer, Object); + DPRINT("RemainingPath.Buffer '%S' Object %p\n", RemainingPath.Buffer, Object); if (RemainingPath.Buffer != NULL || Object == NULL) { -CHECKPOINT; -DPRINT("Object %p\n", Object); + DPRINT("Object %p\n", Object); *ObjectPtr = NULL; RtlFreeUnicodeString (&RemainingPath); return(STATUS_OBJECT_NAME_NOT_FOUND); @@ -136,22 +156,41 @@ ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes, { UNICODE_STRING RemainingPath; PVOID Object = NULL; + UNICODE_STRING ObjectName; + OBJECT_CREATE_INFORMATION ObjectCreateInfo; NTSTATUS Status; PAGED_CODE(); DPRINT("ObOpenObjectByName(...)\n"); - Status = ObFindObject(ObjectAttributes, + /* Capture all the info */ + DPRINT("Capturing Create Info\n"); + Status = ObpCaptureObjectAttributes(ObjectAttributes, + AccessMode, + ObjectType, + &ObjectCreateInfo, + &ObjectName); + if (!NT_SUCCESS(Status)) + { + DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status); + return Status; + } + + Status = ObFindObject(&ObjectCreateInfo, + &ObjectName, &Object, &RemainingPath, ObjectType); + ObpReleaseCapturedAttributes(&ObjectCreateInfo); + if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer); if (!NT_SUCCESS(Status)) { DPRINT("ObFindObject() failed (Status %lx)\n", Status); return Status; } + DPRINT("OBject: %x, Remaining Path: %wZ\n", Object, &RemainingPath); if (Object == NULL) { RtlFreeUnicodeString(&RemainingPath); @@ -167,7 +206,7 @@ ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes, ObDereferenceObject(Object); return Status; } - + Status = ObpCreateHandle(PsGetCurrentProcess(), Object, DesiredAccess, @@ -217,8 +256,8 @@ ObpAddEntryDirectory(PDIRECTORY_OBJECT Parent, { KIRQL oldlvl; - RtlpCreateUnicodeString(&Header->Name, Name, NonPagedPool); - Header->Parent = Parent; + ASSERT(HEADER_TO_OBJECT_NAME(Header)); + HEADER_TO_OBJECT_NAME(Header)->Directory = Parent; KeAcquireSpinLock(&Parent->Lock, &oldlvl); InsertTailList(&Parent->head, &Header->Entry); @@ -238,13 +277,13 @@ ObpRemoveEntryDirectory(POBJECT_HEADER Header) DPRINT("ObpRemoveEntryDirectory(Header %x)\n",Header); - KeAcquireSpinLock(&(Header->Parent->Lock),&oldlvl); + KeAcquireSpinLock(&(HEADER_TO_OBJECT_NAME(Header)->Directory->Lock),&oldlvl); if (Header->Entry.Flink && Header->Entry.Blink) { RemoveEntryList(&(Header->Entry)); Header->Entry.Flink = Header->Entry.Blink = NULL; } - KeReleaseSpinLock(&(Header->Parent->Lock),oldlvl); + KeReleaseSpinLock(&(HEADER_TO_OBJECT_NAME(Header)->Directory->Lock),oldlvl); } NTSTATUS @@ -286,26 +325,26 @@ ObpFindEntryDirectory(PDIRECTORY_OBJECT DirectoryObject, } if (Name[0]=='.' && Name[1]=='.' && Name[2]==0) { - return(BODY_TO_HEADER(DirectoryObject)->Parent); + return(HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(DirectoryObject))->Directory); } while (current!=(&(DirectoryObject->head))) { current_obj = CONTAINING_RECORD(current,OBJECT_HEADER,Entry); - DPRINT(" Scanning: %S for: %S\n",current_obj->Name.Buffer, Name); + DPRINT(" Scanning: %S for: %S\n",HEADER_TO_OBJECT_NAME(current_obj)->Name.Buffer, Name); if (Attributes & OBJ_CASE_INSENSITIVE) { - if (_wcsicmp(current_obj->Name.Buffer, Name)==0) + if (_wcsicmp(HEADER_TO_OBJECT_NAME(current_obj)->Name.Buffer, Name)==0) { - DPRINT("Found it %x\n",HEADER_TO_BODY(current_obj)); - return(HEADER_TO_BODY(current_obj)); + DPRINT("Found it %x\n",¤t_obj->Body); + return(¤t_obj->Body); } } else { - if ( wcscmp(current_obj->Name.Buffer, Name)==0) + if ( wcscmp(HEADER_TO_OBJECT_NAME(current_obj)->Name.Buffer, Name)==0) { - DPRINT("Found it %x\n",HEADER_TO_BODY(current_obj)); - return(HEADER_TO_BODY(current_obj)); + DPRINT("Found it %x\n",¤t_obj->Body); + return(¤t_obj->Body); } } current = current->Flink; @@ -389,7 +428,7 @@ ObInit(VOID) ObpInitSdCache(); /* Create the Type Type */ - DPRINT1("Creating Type Type\n"); + DPRINT("Creating Type Type\n"); RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); RtlInitUnicodeString(&Name, L"Type"); ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); @@ -402,7 +441,7 @@ ObInit(VOID) ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ObTypeObjectType); /* Create the Directory Type */ - DPRINT1("Creating Directory Type\n"); + DPRINT("Creating Directory Type\n"); RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); RtlInitUnicodeString(&Name, L"Directory"); ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); @@ -430,7 +469,7 @@ ObInit(VOID) FALSE); /* Create root directory */ - DPRINT1("Creating Root Directory\n"); + DPRINT("Creating Root Directory\n"); InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_PERMANENT, @@ -445,6 +484,12 @@ ObInit(VOID) 0, 0, (PVOID*)&NameSpaceRoot); + ObInsertObject((PVOID)NameSpaceRoot, + NULL, + DIRECTORY_ALL_ACCESS, + 0, + NULL, + NULL); /* Create '\ObjectTypes' directory */ RtlInitUnicodeString(&Name, L"\\ObjectTypes"); @@ -462,11 +507,17 @@ ObInit(VOID) 0, 0, (PVOID*)&ObpTypeDirectoryObject); + ObInsertObject((PVOID)ObpTypeDirectoryObject, + NULL, + DIRECTORY_ALL_ACCESS, + 0, + NULL, + NULL); /* Insert the two objects we already created but couldn't add */ /* NOTE: Uses TypeList & Creator Info in OB 2.0 */ - ObpAddEntryDirectory(ObpTypeDirectoryObject, BODY_TO_HEADER(ObTypeObjectType), L"Type"); - ObpAddEntryDirectory(ObpTypeDirectoryObject, BODY_TO_HEADER(ObDirectoryType), L"Directory"); + ObpAddEntryDirectory(ObpTypeDirectoryObject, BODY_TO_HEADER(ObTypeObjectType), NULL); + ObpAddEntryDirectory(ObpTypeDirectoryObject, BODY_TO_HEADER(ObDirectoryType), NULL); /* Create 'symbolic link' object type */ ObInitSymbolicLinkImplementation(); @@ -490,6 +541,7 @@ ObpCreateTypeObject(POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, /* Allocate the Object */ Status = ObpAllocateObject(NULL, + TypeName, ObTypeObjectType, OBJECT_ALLOC_SIZE(sizeof(OBJECT_TYPE)), &Header); @@ -499,17 +551,29 @@ ObpCreateTypeObject(POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, return Status; } - LocalObjectType = HEADER_TO_BODY(Header); + LocalObjectType = (POBJECT_TYPE)&Header->Body; + DPRINT("Local ObjectType: %p Header: %p \n", LocalObjectType, Header); /* Check if this is the first Object Type */ if (!ObTypeObjectType) { ObTypeObjectType = LocalObjectType; - Header->ObjectType = ObTypeObjectType; + Header->Type = ObTypeObjectType; + LocalObjectType->Key = TAG('O', 'b', 'j', 'T'); + } + else + { + CHAR Tag[4]; + Tag[0] = TypeName->Buffer[0]; + Tag[1] = TypeName->Buffer[1]; + Tag[2] = TypeName->Buffer[2]; + Tag[3] = TypeName->Buffer[3]; + + /* Set Tag */ + DPRINT("Convert: %s \n", Tag); + LocalObjectType->Key = *(PULONG)Tag; } - /* FIXME: Generate Tag */ - /* Set it up */ LocalObjectType->TypeInfo = *ObjectTypeInitializer; LocalObjectType->Name = *TypeName; diff --git a/reactos/ntoskrnl/ob/ntobj.c b/reactos/ntoskrnl/ob/ntobj.c index 77702b55eb7..a7ffab75e62 100644 --- a/reactos/ntoskrnl/ob/ntobj.c +++ b/reactos/ntoskrnl/ob/ntobj.c @@ -122,13 +122,13 @@ NtQueryObject (IN HANDLE ObjectHandle, BasicInfo->Attributes = HandleInfo.HandleAttributes; BasicInfo->GrantedAccess = HandleInfo.GrantedAccess; BasicInfo->HandleCount = ObjectHeader->HandleCount; - BasicInfo->PointerCount = ObjectHeader->RefCount; + BasicInfo->PointerCount = ObjectHeader->PointerCount; BasicInfo->PagedPoolUsage = 0; /* FIXME*/ BasicInfo->NonPagedPoolUsage = 0; /* FIXME*/ BasicInfo->NameInformationLength = 0; /* FIXME*/ BasicInfo->TypeInformationLength = 0; /* FIXME*/ BasicInfo->SecurityDescriptorLength = 0; /* FIXME*/ - if (ObjectHeader->ObjectType == ObSymbolicLinkType) + if (ObjectHeader->Type == ObSymbolicLinkType) { BasicInfo->CreateTime.QuadPart = ((PSYMLINK_OBJECT)Object)->CreateTime.QuadPart; @@ -169,10 +169,10 @@ NtQueryObject (IN HANDLE ObjectHandle, break; } - RtlCopyUnicodeString(&typeinfo->Type,&ObjectHeader->ObjectType->TypeName); + RtlCopyUnicodeString(&typeinfo->Type,&ObjectHeader->Type->TypeName); //This should be info from the object header, not the object type, right? typeinfo->TotalHandles = ObjectHeader-> HandleCount; - typeinfo->ReferenceCount = ObjectHeader -> RefCount; + typeinfo->ReferenceCount = ObjectHeader -> PointerCount; } #endif Status = STATUS_NOT_IMPLEMENTED; @@ -223,9 +223,9 @@ ObpSetPermanentObject (IN PVOID ObjectBody, IN BOOLEAN Permanent) POBJECT_HEADER ObjectHeader; ObjectHeader = BODY_TO_HEADER(ObjectBody); - ObjectHeader->Permanent = Permanent; + ObjectHeader->Flags |= OB_FLAG_PERMANENT; - if (ObjectHeader->HandleCount == 0 && !Permanent && ObjectHeader->Parent != NULL) + if (ObjectHeader->HandleCount == 0 && !Permanent && HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory) { /* Remove the object from the namespace */ ObpRemoveEntryDirectory(ObjectHeader); diff --git a/reactos/ntoskrnl/ob/object.c b/reactos/ntoskrnl/ob/object.c index d0f91a1c0e7..29c3c182742 100644 --- a/reactos/ntoskrnl/ob/object.c +++ b/reactos/ntoskrnl/ob/object.c @@ -22,346 +22,248 @@ typedef struct _RETENTION_CHECK_PARAMS POBJECT_HEADER ObjectHeader; } RETENTION_CHECK_PARAMS, *PRETENTION_CHECK_PARAMS; -/* TEMPORARY HACK. DO NOT REMOVE -- Alex */ -NTSTATUS -STDCALL -ExpDesktopCreate(PVOID ObjectBody, - PVOID Parent, - PWSTR RemainingPath, - struct _OBJECT_ATTRIBUTES* ObjectAttributes); /* FUNCTIONS ************************************************************/ NTSTATUS -ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN KPROCESSOR_MODE AccessMode, - IN POOL_TYPE PoolType, - IN BOOLEAN CaptureIfKernel, - OUT PCAPTURED_OBJECT_ATTRIBUTES CapturedObjectAttributes OPTIONAL, - OUT PUNICODE_STRING ObjectName OPTIONAL) +STDCALL +ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName, + IN PUNICODE_STRING ObjectName, + IN KPROCESSOR_MODE AccessMode) { - OBJECT_ATTRIBUTES AttributesCopy; - NTSTATUS Status = STATUS_SUCCESS; - - /* at least one output parameter must be != NULL! */ - ASSERT(CapturedObjectAttributes != NULL || ObjectName != NULL); - - if(ObjectAttributes == NULL) - { - /* we're going to return STATUS_SUCCESS! */ - goto failbasiccleanup; - } - - if(AccessMode != KernelMode) - { - RtlZeroMemory(&AttributesCopy, sizeof(AttributesCopy)); - - _SEH_TRY + NTSTATUS Status = STATUS_SUCCESS; + UNICODE_STRING LocalName = {}; /* <= GCC 4.0 + Optimizer */ + + /* First Probe the String */ + DPRINT("ObpCaptureObjectName: %wZ\n", ObjectName); + if (AccessMode != KernelMode) { - ProbeForRead(ObjectAttributes, - sizeof(ObjectAttributes), - sizeof(ULONG)); - /* make a copy on the stack */ - AttributesCopy = *ObjectAttributes; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - DPRINT1("ObpCaptureObjectAttributes failed to probe object attributes\n"); - goto failbasiccleanup; - } - } - else if(!CaptureIfKernel) - { - if(ObjectAttributes->Length == sizeof(OBJECT_ATTRIBUTES)) - { - if(ObjectName != NULL) - { - /* we don't have to capture any memory, the caller considers the passed data - as valid */ - if(ObjectAttributes->ObjectName != NULL) - { - *ObjectName = *ObjectAttributes->ObjectName; - } - else - { - ObjectName->Length = ObjectName->MaximumLength = 0; - ObjectName->Buffer = NULL; - } - } - if(CapturedObjectAttributes != NULL) - { - CapturedObjectAttributes->RootDirectory = ObjectAttributes->RootDirectory; - CapturedObjectAttributes->Attributes = ObjectAttributes->Attributes; - CapturedObjectAttributes->SecurityDescriptor = ObjectAttributes->SecurityDescriptor; - CapturedObjectAttributes->SecurityQualityOfService = ObjectAttributes->SecurityQualityOfService; - } - - return STATUS_SUCCESS; - } - else - { - Status = STATUS_INVALID_PARAMETER; - goto failbasiccleanup; - } - } - else - { - AttributesCopy = *ObjectAttributes; - } - - /* if Length isn't as expected, bail with an invalid parameter status code so - the caller knows he passed garbage... */ - if(AttributesCopy.Length != sizeof(OBJECT_ATTRIBUTES)) - { - Status = STATUS_INVALID_PARAMETER; - goto failbasiccleanup; - } - - if(CapturedObjectAttributes != NULL) - { - CapturedObjectAttributes->RootDirectory = AttributesCopy.RootDirectory; - CapturedObjectAttributes->Attributes = AttributesCopy.Attributes; - - if(AttributesCopy.SecurityDescriptor != NULL) - { - Status = SeCaptureSecurityDescriptor(AttributesCopy.SecurityDescriptor, - AccessMode, - PoolType, - TRUE, - &CapturedObjectAttributes->SecurityDescriptor); - if(!NT_SUCCESS(Status)) - { - DPRINT1("Unable to capture the security descriptor!!!\n"); - goto failbasiccleanup; - } - } - else - { - CapturedObjectAttributes->SecurityDescriptor = NULL; - } - - if(AttributesCopy.SecurityQualityOfService != NULL) - { - SECURITY_QUALITY_OF_SERVICE SafeQoS; - - RtlZeroMemory(&SafeQoS, sizeof(SafeQoS)); - - _SEH_TRY - { - ProbeForRead(AttributesCopy.SecurityQualityOfService, - sizeof(SECURITY_QUALITY_OF_SERVICE), - sizeof(ULONG)); - SafeQoS = *(PSECURITY_QUALITY_OF_SERVICE)AttributesCopy.SecurityQualityOfService; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - DPRINT1("Unable to capture QoS!!!\n"); - goto failcleanupsdescriptor; - } - - if(SafeQoS.Length != sizeof(SECURITY_QUALITY_OF_SERVICE)) - { - DPRINT1("Unable to capture QoS, wrong size!!!\n"); - Status = STATUS_INVALID_PARAMETER; - goto failcleanupsdescriptor; - } - - CapturedObjectAttributes->SecurityQualityOfService = ExAllocatePool(PoolType, - sizeof(SECURITY_QUALITY_OF_SERVICE)); - if(CapturedObjectAttributes->SecurityQualityOfService != NULL) - { - *CapturedObjectAttributes->SecurityQualityOfService = SafeQoS; - } - else - { - Status = STATUS_INSUFFICIENT_RESOURCES; - goto failcleanupsdescriptor; - } - } - else - { - CapturedObjectAttributes->SecurityQualityOfService = NULL; - } - } - - if(ObjectName != NULL) - { - if(AttributesCopy.ObjectName != NULL) - { - UNICODE_STRING OriginalCopy; - - if(AccessMode != KernelMode) - { - RtlZeroMemory(&OriginalCopy, sizeof(OriginalCopy)); - + DPRINT("Probing Struct\n"); _SEH_TRY { - /* probe the ObjectName structure and make a local stack copy of it */ - ProbeForRead(AttributesCopy.ObjectName, - sizeof(UNICODE_STRING), - sizeof(ULONG)); - OriginalCopy = *AttributesCopy.ObjectName; - if(OriginalCopy.Length > 0) - { - ProbeForRead(OriginalCopy.Buffer, - OriginalCopy.Length, - sizeof(WCHAR)); - } + /* FIXME: Explorer or win32 broken I think */ + #if 0 + ProbeForRead(ObjectName, + sizeof(UNICODE_STRING), + sizeof(USHORT)); + #endif + LocalName = *ObjectName; } _SEH_HANDLE { - Status = _SEH_GetExceptionCode(); + Status = _SEH_GetExceptionCode(); } _SEH_END; - - if(NT_SUCCESS(Status)) + + if (NT_SUCCESS(Status)) { - if(OriginalCopy.Length > 0) - { - ObjectName->MaximumLength = OriginalCopy.Length + sizeof(WCHAR); - ObjectName->Buffer = ExAllocatePool(PoolType, - ObjectName->MaximumLength); - if(ObjectName->Buffer != NULL) + DPRINT("Probing OK\n"); + _SEH_TRY + { + #if 0 + DPRINT("Probing buffer\n"); + ProbeForRead(LocalName.Buffer, + LocalName.Length, + sizeof(USHORT)); + #endif + } + _SEH_HANDLE { - _SEH_TRY - { - /* no need to probe OriginalCopy.Buffer again, we already did that - when capturing the UNICODE_STRING structure itself */ - RtlCopyMemory(ObjectName->Buffer, OriginalCopy.Buffer, OriginalCopy.Length); - ObjectName->Buffer[OriginalCopy.Length / sizeof(WCHAR)] = L'\0'; - } - _SEH_HANDLE - { Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - DPRINT1("ObpCaptureObjectAttributes failed to copy the unicode string!\n"); - } } - else - { - Status = STATUS_INSUFFICIENT_RESOURCES; - } - } - else if(AttributesCopy.RootDirectory != NULL /* && OriginalCopy.Length == 0 */) - { - /* if the caller specified a root directory, there must be an object name! */ - Status = STATUS_OBJECT_NAME_INVALID; - } + _SEH_END; } - else + + /* Fail if anything up to here died */ + if (!NT_SUCCESS(Status)) { - DPRINT1("ObpCaptureObjectAttributes failed to probe the object name UNICODE_STRING structure!\n"); + DPRINT1("Probing failed\n"); + return Status; } - } - else /* AccessMode == KernelMode */ - { - OriginalCopy = *AttributesCopy.ObjectName; - - if(OriginalCopy.Length > 0) - { - ObjectName->MaximumLength = OriginalCopy.Length + sizeof(WCHAR); - ObjectName->Buffer = ExAllocatePool(PoolType, - ObjectName->MaximumLength); - if(ObjectName->Buffer != NULL) - { - RtlCopyMemory(ObjectName->Buffer, OriginalCopy.Buffer, OriginalCopy.Length); - ObjectName->Buffer[OriginalCopy.Length / sizeof(WCHAR)] = L'\0'; - } - else - { - Status = STATUS_INSUFFICIENT_RESOURCES; - } - } - else if(AttributesCopy.RootDirectory != NULL /* && OriginalCopy.Length == 0 */) - { - /* if the caller specified a root directory, there must be an object name! */ - Status = STATUS_OBJECT_NAME_INVALID; - } - } } else { - ObjectName->Length = ObjectName->MaximumLength = 0; - ObjectName->Buffer = NULL; + LocalName = *ObjectName; } - } - - if(!NT_SUCCESS(Status)) - { - if(ObjectName->Buffer) + + /* Make sure there really is a string */ + DPRINT("Probing OK\n"); + if (LocalName.Length) { - ExFreePool(ObjectName->Buffer); + /* Allocate a non-paged buffer for this string */ + DPRINT("Capturing String\n"); + CapturedName->Length = LocalName.Length; + CapturedName->MaximumLength = LocalName.Length + sizeof(WCHAR); + CapturedName->Buffer = ExAllocatePoolWithTag(NonPagedPool, + CapturedName->MaximumLength, + TAG('O','b','N','m')); + + /* Copy the string and null-terminate it */ + RtlMoveMemory(CapturedName->Buffer, LocalName.Buffer, LocalName.Length); + CapturedName->Buffer[LocalName.Length / sizeof(WCHAR)] = UNICODE_NULL; + DPRINT("String Captured: %p, %wZ\n", CapturedName, CapturedName); } + + return Status; +} -failcleanupsdescriptor: - if(CapturedObjectAttributes != NULL) - { - /* cleanup allocated resources */ - SeReleaseSecurityDescriptor(CapturedObjectAttributes->SecurityDescriptor, - AccessMode, - TRUE); - } +NTSTATUS +STDCALL +ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes, + IN KPROCESSOR_MODE AccessMode, + IN POBJECT_TYPE ObjectType, + IN POBJECT_CREATE_INFORMATION ObjectCreateInfo, + OUT PUNICODE_STRING ObjectName) +{ + NTSTATUS Status = STATUS_SUCCESS; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PSECURITY_QUALITY_OF_SERVICE SecurityQos; + PUNICODE_STRING LocalObjectName = NULL; -failbasiccleanup: - if(ObjectName != NULL) + /* Zero out the Capture Data */ + DPRINT("ObpCaptureObjectAttributes\n"); + RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION)); + + /* Check if we got Oba */ + if (ObjectAttributes) { - ObjectName->Length = ObjectName->MaximumLength = 0; - ObjectName->Buffer = NULL; - } - if(CapturedObjectAttributes != NULL) - { - RtlZeroMemory(CapturedObjectAttributes, sizeof(CAPTURED_OBJECT_ATTRIBUTES)); - } - } + if (AccessMode != KernelMode) + { + DPRINT("Probing OBA\n"); + _SEH_TRY + { + /* FIXME: SMSS SENDS BULLSHIT. */ + #if 0 + ProbeForRead(ObjectAttributes, + sizeof(ObjectAttributes), + sizeof(ULONG)); + #endif + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + + /* Validate the Size */ + DPRINT("Validating OBA\n"); + if (ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) + { + Status = STATUS_INVALID_PARAMETER; + } - return Status; + /* Fail if SEH or Size Validation failed */ + if(!NT_SUCCESS(Status)) + { + DPRINT1("ObpCaptureObjectAttributes failed to probe object attributes\n"); + goto fail; + } + + /* Set some Create Info */ + DPRINT("Creating OBCI\n"); + ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory; + ObjectCreateInfo->Attributes = ObjectAttributes->Attributes; + LocalObjectName = ObjectAttributes->ObjectName; + SecurityDescriptor = ObjectAttributes->SecurityDescriptor; + SecurityQos = ObjectAttributes->SecurityQualityOfService; + + /* Validate the SD */ + if (SecurityDescriptor) + { + DPRINT("Probing SD: %x\n", SecurityDescriptor); + Status = SeCaptureSecurityDescriptor(SecurityDescriptor, + AccessMode, + NonPagedPool, + TRUE, + &ObjectCreateInfo->SecurityDescriptor); + if(!NT_SUCCESS(Status)) + { + DPRINT1("Unable to capture the security descriptor!!!\n"); + ObjectCreateInfo->SecurityDescriptor = NULL; + goto fail; + } + + DPRINT("Probe done\n"); + ObjectCreateInfo->SecurityDescriptorCharge = 0; /* FIXME */ + ObjectCreateInfo->ProbeMode = AccessMode; + } + + /* Validate the QoS */ + if (SecurityQos) + { + if (AccessMode != KernelMode) + { + DPRINT("Probing QoS\n"); + _SEH_TRY + { + ProbeForRead(SecurityQos, + sizeof(SECURITY_QUALITY_OF_SERVICE), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + + if(!NT_SUCCESS(Status)) + { + DPRINT1("Unable to capture QoS!!!\n"); + goto fail; + } + + ObjectCreateInfo->SecurityQualityOfService = *SecurityQos; + ObjectCreateInfo->SecurityQos = &ObjectCreateInfo->SecurityQualityOfService; + } + } + + /* Clear Local Object Name */ + DPRINT("Clearing name\n"); + RtlZeroMemory(ObjectName, sizeof(UNICODE_STRING)); + + /* Now check if the Object Attributes had an Object Name */ + if (LocalObjectName) + { + DPRINT("Name Buffer: %x\n", LocalObjectName->Buffer); + Status = ObpCaptureObjectName(ObjectName, + LocalObjectName, + AccessMode); + } + else + { + /* He can't have specified a Root Directory */ + if (ObjectCreateInfo->RootDirectory) + { + DPRINT1("Invalid name\n"); + Status = STATUS_OBJECT_NAME_INVALID; + } + } + +fail: + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to capture, cleaning up\n"); + ObpReleaseCapturedAttributes(ObjectCreateInfo); + } + + DPRINT("Return to caller\n"); + return Status; } VOID -ObpReleaseObjectAttributes(IN PCAPTURED_OBJECT_ATTRIBUTES CapturedObjectAttributes OPTIONAL, - IN PUNICODE_STRING ObjectName OPTIONAL, - IN KPROCESSOR_MODE AccessMode, - IN BOOLEAN CaptureIfKernel) +STDCALL +ObpReleaseCapturedAttributes(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo) { - /* WARNING - You need to pass the same parameters to this function as you passed - to ObpCaptureObjectAttributes() to avoid memory leaks */ - if(AccessMode != KernelMode || CaptureIfKernel) - { - if(CapturedObjectAttributes != NULL) + /* Release the SD, it's the only thing we allocated */ + if (ObjectCreateInfo->SecurityDescriptor) { - if(CapturedObjectAttributes->SecurityDescriptor != NULL) - { - ExFreePool(CapturedObjectAttributes->SecurityDescriptor); - CapturedObjectAttributes->SecurityDescriptor = NULL; - } - if(CapturedObjectAttributes->SecurityQualityOfService != NULL) - { - ExFreePool(CapturedObjectAttributes->SecurityQualityOfService); - CapturedObjectAttributes->SecurityQualityOfService = NULL; - } + SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor, + ObjectCreateInfo->ProbeMode, + TRUE); + ObjectCreateInfo->SecurityDescriptor = NULL; } - if(ObjectName != NULL && - ObjectName->Length > 0) - { - ExFreePool(ObjectName->Buffer); - } - } } @@ -389,7 +291,8 @@ ObpReleaseObjectAttributes(IN PCAPTURED_OBJECT_ATTRIBUTES CapturedObjectAttribut * RETURN VALUE */ NTSTATUS -ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes, +ObFindObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo, + PUNICODE_STRING ObjectName, PVOID* ReturnedObject, PUNICODE_STRING RemainingPath, POBJECT_TYPE ObjectType) @@ -402,18 +305,15 @@ ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes, PWSTR current; UNICODE_STRING PathString; ULONG Attributes; - PUNICODE_STRING ObjectName; PAGED_CODE(); - DPRINT("ObFindObject(ObjectAttributes %x, ReturnedObject %x, " - "RemainingPath %x)\n",ObjectAttributes,ReturnedObject,RemainingPath); - DPRINT("ObjectAttributes->ObjectName %wZ\n", - ObjectAttributes->ObjectName); + DPRINT("ObFindObject(ObjectCreateInfo %x, ReturnedObject %x, " + "RemainingPath %x)\n",ObjectCreateInfo,ReturnedObject,RemainingPath); RtlInitUnicodeString (RemainingPath, NULL); - if (ObjectAttributes->RootDirectory == NULL) + if (ObjectCreateInfo->RootDirectory == NULL) { ObReferenceObjectByPointer(NameSpaceRoot, DIRECTORY_TRAVERSE, @@ -423,7 +323,7 @@ ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes, } else { - Status = ObReferenceObjectByHandle(ObjectAttributes->RootDirectory, + Status = ObReferenceObjectByHandle(ObjectCreateInfo->RootDirectory, 0, NULL, UserMode, @@ -435,7 +335,6 @@ ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes, } } - ObjectName = ObjectAttributes->ObjectName; if (ObjectName->Length == 0 || ObjectName->Buffer[0] == UNICODE_NULL) { @@ -443,10 +342,11 @@ ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes, return STATUS_SUCCESS; } - if (ObjectAttributes->RootDirectory == NULL && + if (ObjectCreateInfo->RootDirectory == NULL && ObjectName->Buffer[0] != L'\\') { ObDereferenceObject (CurrentObject); + DPRINT1("failed\n"); return STATUS_UNSUCCESSFUL; } @@ -469,7 +369,7 @@ ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes, current = PathString.Buffer; RootObject = CurrentObject; - Attributes = ObjectAttributes->Attributes; + Attributes = ObjectCreateInfo->Attributes; if (ObjectType == ObSymbolicLinkType) Attributes |= OBJ_OPENLINK; @@ -479,14 +379,14 @@ ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes, CurrentHeader = BODY_TO_HEADER(CurrentObject); DPRINT("Current ObjectType %wZ\n", - &CurrentHeader->ObjectType->TypeName); + &CurrentHeader->Type->Name); - if (CurrentHeader->ObjectType->TypeInfo.ParseProcedure == NULL) + if (CurrentHeader->Type->TypeInfo.ParseProcedure == NULL) { DPRINT("Current object can't parse\n"); break; } - Status = CurrentHeader->ObjectType->TypeInfo.ParseProcedure(CurrentObject, + Status = CurrentHeader->Type->TypeInfo.ParseProcedure(CurrentObject, &NextObject, &PathString, ¤t, @@ -512,7 +412,10 @@ ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes, } if (current) + { RtlpCreateUnicodeString (RemainingPath, current, NonPagedPool); + } + RtlFreeUnicodeString (&PathString); *ReturnedObject = CurrentObject; @@ -558,27 +461,27 @@ ObQueryNameString (IN PVOID Object, ObjectHeader = BODY_TO_HEADER(Object); - if (ObjectHeader->ObjectType != NULL && - ObjectHeader->ObjectType->TypeInfo.QueryNameProcedure != NULL) + if (ObjectHeader->Type != NULL && + ObjectHeader->Type->TypeInfo.QueryNameProcedure != NULL) { - DPRINT ("Calling %x\n", ObjectHeader->ObjectType->TypeInfo.QueryNameProcedure); - Status = ObjectHeader->ObjectType->TypeInfo.QueryNameProcedure (Object, + DPRINT ("Calling %x\n", ObjectHeader->Type->TypeInfo.QueryNameProcedure); + Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure (Object, ObjectNameInfo, Length, ReturnLength); } - else if (ObjectHeader->Name.Length > 0 && ObjectHeader->Name.Buffer != NULL) + else if (HEADER_TO_OBJECT_NAME(ObjectHeader)->Name.Length > 0 && HEADER_TO_OBJECT_NAME(ObjectHeader)->Name.Buffer != NULL) { DPRINT ("Object does not have a 'QueryName' function\n"); - if (ObjectHeader->Parent == NameSpaceRoot) + if (HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory == NameSpaceRoot) { DPRINT ("Reached the root directory\n"); ObjectNameInfo->Name.Length = 0; ObjectNameInfo->Name.Buffer[0] = 0; Status = STATUS_SUCCESS; } - else if (ObjectHeader->Parent != NULL) + else if (HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory != NULL) { LocalInfo = ExAllocatePool (NonPagedPool, sizeof(OBJECT_NAME_INFORMATION) + @@ -586,7 +489,7 @@ ObQueryNameString (IN PVOID Object, if (LocalInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES; - Status = ObQueryNameString (ObjectHeader->Parent, + Status = ObQueryNameString (HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory, LocalInfo, MAX_PATH * sizeof(WCHAR), &LocalReturnLength); @@ -605,14 +508,14 @@ ObQueryNameString (IN PVOID Object, return Status; } - DPRINT ("Object path %wZ\n", &ObjectHeader->Name); + DPRINT ("Object path %wZ\n", &HEADER_TO_OBJECT_NAME(ObjectHeader)->Name); Status = RtlAppendUnicodeToString (&ObjectNameInfo->Name, L"\\"); if (!NT_SUCCESS (Status)) return Status; Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name, - &ObjectHeader->Name); + &HEADER_TO_OBJECT_NAME(ObjectHeader)->Name); } else { @@ -639,13 +542,21 @@ ObQueryNameString (IN PVOID Object, NTSTATUS STDCALL -ObpAllocateObject(POBJECT_ATTRIBUTES ObjectAttributes, +ObpAllocateObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo, + PUNICODE_STRING ObjectName, POBJECT_TYPE ObjectType, ULONG ObjectSize, POBJECT_HEADER *ObjectHeader) { POBJECT_HEADER Header; + BOOLEAN HasHandleInfo = FALSE; + BOOLEAN HasNameInfo = FALSE; + BOOLEAN HasCreatorInfo = FALSE; + POBJECT_HEADER_HANDLE_INFO HandleInfo; + POBJECT_HEADER_NAME_INFO NameInfo; + POBJECT_HEADER_CREATOR_INFO CreatorInfo; POOL_TYPE PoolType; + ULONG FinalSize = ObjectSize; ULONG Tag; /* If we don't have an Object Type yet, force NonPaged */ @@ -661,28 +572,105 @@ ObpAllocateObject(POBJECT_ATTRIBUTES ObjectAttributes, Tag = ObjectType->Key; } - /* Allocate memory for the Object */ - Header = (POBJECT_HEADER)ExAllocatePoolWithTag(PoolType, ObjectSize, Tag); + DPRINT("Checking ObjectName: %x\n", ObjectName); + /* Check if the Object has a name */ + if (ObjectName->Buffer) + { + FinalSize += sizeof(OBJECT_HEADER_NAME_INFO); + HasNameInfo = TRUE; + } + + if (ObjectType) + { + /* Check if the Object maintains handle counts */ + DPRINT("Checking ObjectType->TypeInfo: %x\n", &ObjectType->TypeInfo); + if (ObjectType->TypeInfo.MaintainHandleCount) + { + FinalSize += sizeof(OBJECT_HEADER_HANDLE_INFO); + HasHandleInfo = TRUE; + } + + /* Check if the Object maintains type lists */ + if (ObjectType->TypeInfo.MaintainTypeList) + { + FinalSize += sizeof(OBJECT_HEADER_CREATOR_INFO); + HasCreatorInfo = TRUE; + } + } + + /* Allocate memory for the Object and Header */ + DPRINT("Allocating: %x %x\n", FinalSize, Tag); + Header = ExAllocatePoolWithTag(PoolType, FinalSize, Tag); if (!Header) { DPRINT1("Not enough memory!\n"); return STATUS_INSUFFICIENT_RESOURCES; } + + /* Initialize Handle Info */ + if (HasHandleInfo) + { + HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header; + DPRINT("Info: %x\n", HandleInfo); + HandleInfo->SingleEntry.HandleCount = 0; + Header = (POBJECT_HEADER)(HandleInfo + 1); + } + + /* Initialize the Object Name Info */ + if (HasNameInfo) + { + NameInfo = (POBJECT_HEADER_NAME_INFO)Header; + DPRINT("Info: %x %wZ\n", NameInfo, ObjectName); + NameInfo->Name = *ObjectName; + NameInfo->Directory = NULL; + Header = (POBJECT_HEADER)(NameInfo + 1); + } + + /* Initialize Creator Info */ + if (HasCreatorInfo) + { + CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header; + DPRINT("Info: %x\n", CreatorInfo); + /* FIXME: Needs Alex's Init patch + * CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcessId(); + */ + InitializeListHead(&CreatorInfo->TypeList); + Header = (POBJECT_HEADER)(CreatorInfo + 1); + } /* Initialize the object header */ RtlZeroMemory(Header, ObjectSize); - DPRINT("Initalizing header %p\n", Header); + DPRINT("Initalized header %p\n", Header); Header->HandleCount = 0; - Header->RefCount = 1; - Header->ObjectType = ObjectType; - if (ObjectAttributes && ObjectAttributes->Attributes & OBJ_PERMANENT) + Header->PointerCount = 1; + Header->Type = ObjectType; + Header->Flags = OB_FLAG_CREATE_INFO; + + /* Set the Offsets for the Info */ + if (HasHandleInfo) { - Header->Permanent = TRUE; + Header->HandleInfoOffset = HasNameInfo * sizeof(OBJECT_HEADER_NAME_INFO) + + sizeof(OBJECT_HEADER_HANDLE_INFO) + + HasCreatorInfo * sizeof(OBJECT_HEADER_CREATOR_INFO); + Header->Flags |= OB_FLAG_SINGLE_PROCESS; } - if (ObjectAttributes && ObjectAttributes->Attributes & OBJ_INHERIT) + if (HasNameInfo) { - Header->Inherit = TRUE; + Header->NameInfoOffset = sizeof(OBJECT_HEADER_NAME_INFO) + + HasCreatorInfo * sizeof(OBJECT_HEADER_CREATOR_INFO); } - RtlInitUnicodeString(&Header->Name, NULL); + if (HasCreatorInfo) Header->Flags |= OB_FLAG_CREATOR_INFO; + + if (ObjectCreateInfo && ObjectCreateInfo->Attributes & OBJ_PERMANENT) + { + Header->Flags |= OB_FLAG_PERMANENT; + } + if (ObjectCreateInfo && ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE) + { + Header->Flags |= OB_FLAG_EXCLUSIVE; + } + + /* Link stuff to Object Header */ + Header->ObjectCreateInfo = ObjectCreateInfo; /* Return Header */ *ObjectHeader = Header; @@ -702,223 +690,72 @@ ObpAllocateObject(POBJECT_ATTRIBUTES ObjectAttributes, * * @implemented */ -NTSTATUS STDCALL -ObCreateObject (IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL, - IN POBJECT_TYPE Type, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN KPROCESSOR_MODE AccessMode, - IN OUT PVOID ParseContext OPTIONAL, - IN ULONG ObjectSize, - IN ULONG PagedPoolCharge OPTIONAL, - IN ULONG NonPagedPoolCharge OPTIONAL, - OUT PVOID *Object) +NTSTATUS +STDCALL +ObCreateObject(IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL, + IN POBJECT_TYPE Type, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN KPROCESSOR_MODE AccessMode, + IN OUT PVOID ParseContext OPTIONAL, + IN ULONG ObjectSize, + IN ULONG PagedPoolCharge OPTIONAL, + IN ULONG NonPagedPoolCharge OPTIONAL, + OUT PVOID *Object) { - PVOID Parent = NULL; - UNICODE_STRING RemainingPath; - POBJECT_HEADER Header; - POBJECT_HEADER ParentHeader = NULL; - NTSTATUS Status; - BOOLEAN ObjectAttached = FALSE; - PWCHAR NamePtr; - PSECURITY_DESCRIPTOR NewSecurityDescriptor = NULL; - SECURITY_SUBJECT_CONTEXT SubjectContext; - - PAGED_CODE(); - - if(ObjectAttributesAccessMode == UserMode && ObjectAttributes != NULL) - { - Status = STATUS_SUCCESS; - _SEH_TRY - { - ProbeForRead(ObjectAttributes, - sizeof(OBJECT_ATTRIBUTES), - sizeof(ULONG)); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - return Status; - } - } - - DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n", - Type, ObjectAttributes, Object); - - if (Type == NULL) - { - DPRINT1("Invalid object type!\n"); - return STATUS_INVALID_PARAMETER; - } - - if (ObjectAttributes != NULL && - ObjectAttributes->ObjectName != NULL && - ObjectAttributes->ObjectName->Buffer != NULL) - { - Status = ObFindObject(ObjectAttributes, - &Parent, - &RemainingPath, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ObFindObject() failed! (Status 0x%x)\n", Status); - return Status; - } - if (Parent != NULL) - { - ParentHeader = BODY_TO_HEADER(Parent); - } - if (ParentHeader && - RemainingPath.Buffer == NULL) - { - if (ParentHeader->ObjectType != Type - || !(ObjectAttributes->Attributes & OBJ_OPENIF)) - { - ObDereferenceObject(Parent); - return STATUS_OBJECT_NAME_COLLISION; - } - *Object = Parent; - return STATUS_OBJECT_EXISTS; - } - } - else - { - RtlInitUnicodeString(&RemainingPath, NULL); - } + NTSTATUS Status; + POBJECT_CREATE_INFORMATION ObjectCreateInfo; + UNICODE_STRING ObjectName; + POBJECT_HEADER Header; - /* Allocate the Object */ - Status = ObpAllocateObject(ObjectAttributes, - Type, - OBJECT_ALLOC_SIZE(ObjectSize), - &Header); - if (!NT_SUCCESS(Status)) + DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n", + Type, ObjectAttributes, Object); + + /* Allocate a Buffer for the Object Create Info */ + DPRINT("Allocating Create Buffer\n"); + ObjectCreateInfo = ExAllocatePoolWithTag(NonPagedPool, + sizeof(*ObjectCreateInfo), + TAG('O','b','C', 'I')); + + /* Capture all the info */ + DPRINT("Capturing Create Info\n"); + Status = ObpCaptureObjectAttributes(ObjectAttributes, + AccessMode, + Type, + ObjectCreateInfo, + &ObjectName); + + if (NT_SUCCESS(Status)) { - DPRINT1("ObpAllocateObject failed!\n"); - return Status; + /* Allocate the Object */ + DPRINT("Allocating: %wZ\n", &ObjectName); + Status = ObpAllocateObject(ObjectCreateInfo, + &ObjectName, + Type, + OBJECT_ALLOC_SIZE(ObjectSize), + &Header); + + if (NT_SUCCESS(Status)) + { + /* Return the Object */ + DPRINT("Returning Object\n"); + *Object = &Header->Body; + + /* Return to caller, leave the Capture Info Alive for ObInsert */ + return Status; + } + + /* Release the Capture Info, we don't need it */ + DPRINT1("Allocation failed\n"); + ObpReleaseCapturedAttributes(ObjectCreateInfo); + if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer); } - - DPRINT("Getting Parent and adding entry\n"); - if (ParentHeader != NULL && - ParentHeader->ObjectType == ObDirectoryType && - RemainingPath.Buffer != NULL) - { - NamePtr = RemainingPath.Buffer; - if (*NamePtr == L'\\') - NamePtr++; - - ObpAddEntryDirectory(Parent, - Header, - NamePtr); - - ObjectAttached = TRUE; - } - - if ((Header->ObjectType == IoFileObjectType) || - (Header->ObjectType == ExDesktopObjectType) || - (Header->ObjectType->TypeInfo.OpenProcedure != NULL)) - { - DPRINT("About to call Open Routine\n"); - if (Header->ObjectType == IoFileObjectType) - { - /* TEMPORARY HACK. DO NOT TOUCH -- Alex */ - DPRINT("Calling IopCreateFile\n"); - Status = IopCreateFile(HEADER_TO_BODY(Header), - Parent, - RemainingPath.Buffer, - ObjectAttributes); - } - else if (Header->ObjectType == ExDesktopObjectType) - { - /* TEMPORARY HACK. DO NOT TOUCH -- Alex */ - DPRINT("Calling ExpDesktopCreate\n"); - Status = ExpDesktopCreate(HEADER_TO_BODY(Header), - Parent, - RemainingPath.Buffer, - ObjectAttributes); - } - else if (Header->ObjectType->TypeInfo.OpenProcedure != NULL) - { - DPRINT("Calling %x\n", Header->ObjectType->TypeInfo.OpenProcedure); - Status = Header->ObjectType->TypeInfo.OpenProcedure(ObCreateHandle, - HEADER_TO_BODY(Header), - NULL, - 0, - 0); - } - - if (!NT_SUCCESS(Status)) - { - if (ObjectAttached == TRUE) - { - ObpRemoveEntryDirectory(Header); - } - if (Parent) - { - ObDereferenceObject(Parent); - } - RtlFreeUnicodeString(&Header->Name); - RtlFreeUnicodeString(&RemainingPath); - ExFreePool(Header); - DPRINT("Create Failed\n"); - return Status; - } - } - - RtlFreeUnicodeString(&RemainingPath); - - SeCaptureSubjectContext(&SubjectContext); - - DPRINT("Security Assignment in progress\n"); - /* Build the new security descriptor */ - Status = SeAssignSecurity((ParentHeader != NULL) ? ParentHeader->SecurityDescriptor : NULL, - (ObjectAttributes != NULL) ? ObjectAttributes->SecurityDescriptor : NULL, - &NewSecurityDescriptor, - (Header->ObjectType == ObDirectoryType), - &SubjectContext, - &Header->ObjectType->TypeInfo.GenericMapping, - PagedPool); - if (NT_SUCCESS(Status)) - { - DPRINT("NewSecurityDescriptor %p\n", NewSecurityDescriptor); - - if (Header->ObjectType->TypeInfo.SecurityProcedure != NULL) - { - /* Call the security method */ - Status = Header->ObjectType->TypeInfo.SecurityProcedure(HEADER_TO_BODY(Header), - AssignSecurityDescriptor, - 0, - NewSecurityDescriptor, - NULL); - } - else - { - /* Assign the security descriptor to the object header */ - Status = ObpAddSecurityDescriptor(NewSecurityDescriptor, - &Header->SecurityDescriptor); - DPRINT("Object security descriptor %p\n", Header->SecurityDescriptor); - } - - /* Release the new security descriptor */ - SeDeassignSecurity(&NewSecurityDescriptor); - } - - DPRINT("Security Complete\n"); - SeReleaseSubjectContext(&SubjectContext); - - if (Object != NULL) - { - *Object = HEADER_TO_BODY(Header); - } - - DPRINT("Sucess!\n"); - return STATUS_SUCCESS; + + /* We failed, so release the Buffer */ + DPRINT1("Capture failed\n"); + ExFreePool(ObjectCreateInfo); + return Status; } - /* * FUNCTION: Increments the pointer reference count for a given object * ARGUMENTS: @@ -945,43 +782,43 @@ ObReferenceObjectByPointer(IN PVOID Object, Header = BODY_TO_HEADER(Object); - if (ObjectType != NULL && Header->ObjectType != ObjectType) + if (ObjectType != NULL && Header->Type != ObjectType) { - DPRINT("Failed %x (type was %x %S) should be %x %S\n", + DPRINT("Failed %p (type was %x %wZ) should be %x %wZ\n", Header, - Header->ObjectType, - Header->ObjectType->TypeName.Buffer, + Header->Type, + &BODY_TO_HEADER(Header->Type)->NameInfo, ObjectType, - ObjectType->TypeName.Buffer); + &BODY_TO_HEADER(ObjectType)->NameInfo); return(STATUS_UNSUCCESSFUL); } - if (Header->ObjectType == PsProcessType) + if (Header->Type == PsProcessType) { - DPRINT("Ref p 0x%x refcount %d type %x ", - Object, Header->RefCount, PsProcessType); + DPRINT("Ref p 0x%x PointerCount %d type %x ", + Object, Header->PointerCount, PsProcessType); DPRINT("eip %x\n", ((PULONG)&Object)[-1]); } - if (Header->ObjectType == PsThreadType) + if (Header->Type == PsThreadType) { - DPRINT("Deref t 0x%x with refcount %d type %x ", - Object, Header->RefCount, PsThreadType); + DPRINT("Deref t 0x%x with PointerCount %d type %x ", + Object, Header->PointerCount, PsThreadType); DPRINT("eip %x\n", ((PULONG)&Object)[-1]); } - if (Header->RefCount == 0 && !Header->Permanent) + if (Header->PointerCount == 0 && !(Header->Flags & OB_FLAG_PERMANENT)) { - if (Header->ObjectType == PsProcessType) + if (Header->Type == PsProcessType) { return STATUS_PROCESS_IS_TERMINATING; } - if (Header->ObjectType == PsThreadType) + if (Header->Type == PsThreadType) { return STATUS_THREAD_IS_TERMINATING; } return(STATUS_UNSUCCESSFUL); } - if (1 == InterlockedIncrement(&Header->RefCount) && !Header->Permanent) + if (1 == InterlockedIncrement(&Header->PointerCount) && !(Header->Flags & OB_FLAG_PERMANENT)) { KEBUGCHECK(0); } @@ -1032,6 +869,11 @@ ObOpenObjectByPointer(IN POBJECT Object, static NTSTATUS ObpDeleteObject(POBJECT_HEADER Header) { + PVOID HeaderLocation = Header; + POBJECT_HEADER_HANDLE_INFO HandleInfo; + POBJECT_HEADER_NAME_INFO NameInfo; + POBJECT_HEADER_CREATOR_INFO CreatorInfo; + DPRINT("ObpDeleteObject(Header %p)\n", Header); if (KeGetCurrentIrql() != PASSIVE_LEVEL) { @@ -1039,25 +881,46 @@ ObpDeleteObject(POBJECT_HEADER Header) KEBUGCHECK(0); } + if (Header->Type != NULL && + Header->Type->TypeInfo.DeleteProcedure != NULL) + { + Header->Type->TypeInfo.DeleteProcedure(&Header->Body); + } + if (Header->SecurityDescriptor != NULL) { ObpRemoveSecurityDescriptor(Header->SecurityDescriptor); } - - if (Header->ObjectType != NULL && - Header->ObjectType->TypeInfo.DeleteProcedure != NULL) + + if (HEADER_TO_OBJECT_NAME(Header)) { - Header->ObjectType->TypeInfo.DeleteProcedure(HEADER_TO_BODY(Header)); + if(HEADER_TO_OBJECT_NAME(Header)->Name.Buffer) + { + ExFreePool(HEADER_TO_OBJECT_NAME(Header)->Name.Buffer); + } } - - if (Header->Name.Buffer != NULL) + if (Header->ObjectCreateInfo) { - ObpRemoveEntryDirectory(Header); - RtlFreeUnicodeString(&Header->Name); + ObpReleaseCapturedAttributes(Header->ObjectCreateInfo); + ExFreePool(Header->ObjectCreateInfo); } + + /* To find the header, walk backwards from how we allocated */ + if ((CreatorInfo = HEADER_TO_CREATOR_INFO(Header))) + { + HeaderLocation = CreatorInfo; + } + if ((NameInfo = HEADER_TO_OBJECT_NAME(Header))) + { + HeaderLocation = NameInfo; + } + if ((HandleInfo = HEADER_TO_HANDLE_INFO(Header))) + { + HeaderLocation = HandleInfo; + } DPRINT("ObPerformRetentionChecks() = Freeing object\n"); - ExFreePool(Header); + ExFreePool(HeaderLocation); return(STATUS_SUCCESS); } @@ -1073,7 +936,7 @@ ObpDeleteObjectWorkRoutine (IN PVOID Parameter) ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); /* We need PAGED_CODE somewhere... */ /* Turn this on when we have ExFreePoolWithTag - Tag = Params->ObjectHeader->ObjectType->Tag; */ + Tag = Params->ObjectHeader->Type->Tag; */ ObpDeleteObject(Params->ObjectHeader); ExFreePool(Params); /* ExFreePoolWithTag(Params, Tag); */ @@ -1082,14 +945,14 @@ ObpDeleteObjectWorkRoutine (IN PVOID Parameter) STATIC NTSTATUS ObpDeleteObjectDpcLevel(IN POBJECT_HEADER ObjectHeader, - IN LONG OldRefCount) + IN LONG OldPointerCount) { #if 0 - if (ObjectHeader->RefCount < 0) + if (ObjectHeader->PointerCount < 0) { CPRINT("Object %p/%p has invalid reference count (%d)\n", ObjectHeader, HEADER_TO_BODY(ObjectHeader), - ObjectHeader->RefCount); + ObjectHeader->PointerCount); KEBUGCHECK(0); } @@ -1120,7 +983,7 @@ ObpDeleteObjectDpcLevel(IN POBJECT_HEADER ObjectHeader, Params = (PRETENTION_CHECK_PARAMS) ExAllocatePoolWithTag(NonPagedPoolMustSucceed, sizeof(RETENTION_CHECK_PARAMS), - ObjectHeader->ObjectType->Key); + ObjectHeader->Type->Key); Params->ObjectHeader = ObjectHeader; ExInitializeWorkItem(&Params->WorkItem, ObpDeleteObjectWorkRoutine, @@ -1167,7 +1030,7 @@ ObfReferenceObject(IN PVOID Object) Header = BODY_TO_HEADER(Object); /* No one should be referencing an object once we are deleting it. */ - if (InterlockedIncrement(&Header->RefCount) == 1 && !Header->Permanent) + if (InterlockedIncrement(&Header->PointerCount) == 1 && !(Header->Flags & OB_FLAG_PERMANENT)) { KEBUGCHECK(0); } @@ -1194,28 +1057,28 @@ VOID FASTCALL ObfDereferenceObject(IN PVOID Object) { POBJECT_HEADER Header; - LONG NewRefCount; + LONG NewPointerCount; BOOL Permanent; ASSERT(Object); /* Extract the object header. */ Header = BODY_TO_HEADER(Object); - Permanent = Header->Permanent; + Permanent = Header->Flags & OB_FLAG_PERMANENT; /* Drop our reference and get the new count so we can tell if this was the last reference. */ - NewRefCount = InterlockedDecrement(&Header->RefCount); - DPRINT("ObfDereferenceObject(0x%x)==%d (%wZ)\n", Object, NewRefCount, &Header->ObjectType->TypeName); - ASSERT(NewRefCount >= 0); + NewPointerCount = InterlockedDecrement(&Header->PointerCount); + DPRINT("ObfDereferenceObject(0x%x)==%d\n", Object, NewPointerCount); + ASSERT(NewPointerCount >= 0); /* Check whether the object can now be deleted. */ - if (NewRefCount == 0 && + if (NewPointerCount == 0 && !Permanent) { - ObpDeleteObjectDpcLevel(Header, NewRefCount); + ObpDeleteObjectDpcLevel(Header, NewPointerCount); } } @@ -1295,7 +1158,7 @@ ObGetObjectPointerCount(PVOID Object) ASSERT(Object); Header = BODY_TO_HEADER(Object); - return Header->RefCount; + return Header->PointerCount; } diff --git a/reactos/ntoskrnl/ob/security.c b/reactos/ntoskrnl/ob/security.c index 87e70e41a07..1fd2a2e4cd1 100644 --- a/reactos/ntoskrnl/ob/security.c +++ b/reactos/ntoskrnl/ob/security.c @@ -79,10 +79,10 @@ ObGetObjectSecurity(IN PVOID Object, PAGED_CODE(); Header = BODY_TO_HEADER(Object); - if (Header->ObjectType == NULL) + if (Header->Type == NULL) return STATUS_UNSUCCESSFUL; - if (Header->ObjectType->TypeInfo.SecurityProcedure == NULL) + if (Header->Type->TypeInfo.SecurityProcedure == NULL) { ObpReferenceCachedSecurityDescriptor(Header->SecurityDescriptor); *SecurityDescriptor = Header->SecurityDescriptor; @@ -92,7 +92,7 @@ ObGetObjectSecurity(IN PVOID Object, /* Get the security descriptor size */ Length = 0; - Status = Header->ObjectType->TypeInfo.SecurityProcedure(Object, + Status = Header->Type->TypeInfo.SecurityProcedure(Object, QuerySecurityDescriptor, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, @@ -108,7 +108,7 @@ ObGetObjectSecurity(IN PVOID Object, return STATUS_INSUFFICIENT_RESOURCES; /* Query security descriptor */ - Status = Header->ObjectType->TypeInfo.SecurityProcedure(Object, + Status = Header->Type->TypeInfo.SecurityProcedure(Object, QuerySecurityDescriptor, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, @@ -180,17 +180,17 @@ NtQuerySecurityObject(IN HANDLE Handle, } Header = BODY_TO_HEADER(Object); - if (Header->ObjectType == NULL) + if (Header->Type == NULL) { DPRINT1("Invalid object type\n"); ObDereferenceObject(Object); return STATUS_UNSUCCESSFUL; } - if (Header->ObjectType->TypeInfo.SecurityProcedure != NULL) + if (Header->Type->TypeInfo.SecurityProcedure != NULL) { *ResultLength = Length; - Status = Header->ObjectType->TypeInfo.SecurityProcedure(Object, + Status = Header->Type->TypeInfo.SecurityProcedure(Object, QuerySecurityDescriptor, SecurityInformation, SecurityDescriptor, @@ -252,16 +252,16 @@ NtSetSecurityObject(IN HANDLE Handle, } Header = BODY_TO_HEADER(Object); - if (Header->ObjectType == NULL) + if (Header->Type == NULL) { DPRINT1("Invalid object type\n"); ObDereferenceObject(Object); return STATUS_UNSUCCESSFUL; } - if (Header->ObjectType->TypeInfo.SecurityProcedure != NULL) + if (Header->Type->TypeInfo.SecurityProcedure != NULL) { - Status = Header->ObjectType->TypeInfo.SecurityProcedure(Object, + Status = Header->Type->TypeInfo.SecurityProcedure(Object, SetSecurityDescriptor, SecurityInformation, SecurityDescriptor, diff --git a/reactos/ntoskrnl/ob/symlink.c b/reactos/ntoskrnl/ob/symlink.c index 48347025e5d..2161481fdb6 100644 --- a/reactos/ntoskrnl/ob/symlink.c +++ b/reactos/ntoskrnl/ob/symlink.c @@ -25,10 +25,6 @@ static GENERIC_MAPPING ObpSymbolicLinkMapping = { STANDARD_RIGHTS_EXECUTE|SYMBOLIC_LINK_QUERY, SYMBOLIC_LINK_ALL_ACCESS}; -#define TAG_SYMLINK_TTARGET TAG('S', 'Y', 'T', 'T') -#define TAG_SYMLINK_TARGET TAG('S', 'Y', 'M', 'T') - - /* FUNCTIONS ****************************************************************/ /********************************************************************** @@ -140,7 +136,7 @@ ObInitSymbolicLinkImplementation (VOID) UNICODE_STRING Name; OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; - DPRINT1("Creating SymLink Object Type\n"); + DPRINT("Creating SymLink Object Type\n"); /* Initialize the Directory type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); diff --git a/reactos/ntoskrnl/ob/wait.c b/reactos/ntoskrnl/ob/wait.c index 23c8511c02a..470f928b046 100644 --- a/reactos/ntoskrnl/ob/wait.c +++ b/reactos/ntoskrnl/ob/wait.c @@ -91,7 +91,7 @@ NtWaitForMultipleObjects(IN ULONG ObjectCount, if (NT_SUCCESS(Status)) { DPRINT1("Waiting for object type '%wZ' is not supported\n", - &BODY_TO_HEADER(ObjectPtrArray[i])->ObjectType->Name); + &BODY_TO_HEADER(ObjectPtrArray[i])->Type->Name); Status = STATUS_HANDLE_NOT_WAITABLE; i++; } @@ -178,7 +178,7 @@ NtWaitForSingleObject(IN HANDLE ObjectHandle, if (!KiIsObjectWaitable(ObjectPtr)) { DPRINT1("Waiting for object type '%wZ' is not supported\n", - &BODY_TO_HEADER(ObjectPtr)->ObjectType->Name); + &BODY_TO_HEADER(ObjectPtr)->Type->Name); Status = STATUS_HANDLE_NOT_WAITABLE; } else diff --git a/reactos/ntoskrnl/ps/cid.c b/reactos/ntoskrnl/ps/cid.c index c50839043cf..83eea3ba00b 100644 --- a/reactos/ntoskrnl/ps/cid.c +++ b/reactos/ntoskrnl/ps/cid.c @@ -18,8 +18,6 @@ PHANDLE_TABLE PspCidTable = NULL; -#define TAG_CIDOBJECT TAG('C', 'I', 'D', 'O') - #define CID_FLAG_PROCESS 0x1 #define CID_FLAG_THREAD 0x2 #define CID_FLAGS_MASK (CID_FLAG_PROCESS | CID_FLAG_THREAD) diff --git a/reactos/ntoskrnl/ps/debug.c b/reactos/ntoskrnl/ps/debug.c index bd72696f362..487e5d94866 100644 --- a/reactos/ntoskrnl/ps/debug.c +++ b/reactos/ntoskrnl/ps/debug.c @@ -267,6 +267,7 @@ NtSetContextThread(IN HANDLE ThreadHandle, return Status; } +#ifdef DBG VOID STDCALL PspDumpThreads(BOOLEAN IncludeSystem) @@ -339,5 +340,6 @@ PspDumpThreads(BOOLEAN IncludeSystem) CurrentProcess = CurrentProcess->Flink; } } +#endif /* EOF */ diff --git a/reactos/ntoskrnl/ps/job.c b/reactos/ntoskrnl/ps/job.c index 47588371455..90b2d632af3 100644 --- a/reactos/ntoskrnl/ps/job.c +++ b/reactos/ntoskrnl/ps/job.c @@ -12,13 +12,12 @@ /* Note: Jobs are only supported on Win2K+ */ /* INCLUDES *****************************************************************/ +#define NDEBUG #include #include /* GLOBALS *******************************************************************/ -#define TAG_EJOB TAG('E', 'J', 'O', 'B') /* EJOB */ - POBJECT_TYPE EXPORTED PsJobType = NULL; LIST_ENTRY PsJobListHead; @@ -63,7 +62,7 @@ PsInitJobManagment ( VOID ) UNICODE_STRING Name; OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; - DPRINT1("Creating Job Object Type\n"); + DPRINT("Creating Job Object Type\n"); /* Initialize the Job type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); diff --git a/reactos/ntoskrnl/ps/kill.c b/reactos/ntoskrnl/ps/kill.c index 9306a6b2de6..35bafc4a59e 100644 --- a/reactos/ntoskrnl/ps/kill.c +++ b/reactos/ntoskrnl/ps/kill.c @@ -16,8 +16,6 @@ /* GLOBALS *******************************************************************/ -#define TAG_TERMINATE_APC TAG('T', 'A', 'P', 'C') - PETHREAD PspReaperList = NULL; WORK_QUEUE_ITEM PspReaperWorkItem; BOOLEAN PspReaping = FALSE; diff --git a/reactos/ntoskrnl/ps/notify.c b/reactos/ntoskrnl/ps/notify.c index b3fe83dc967..703d82114d9 100644 --- a/reactos/ntoskrnl/ps/notify.c +++ b/reactos/ntoskrnl/ps/notify.c @@ -16,7 +16,6 @@ /* GLOBAL *******************************************************************/ #define MAX_THREAD_NOTIFY_ROUTINE_COUNT 8 -#define TAG_KAPC TAG('k','p','a','p') /* kpap - kernel ps apc */ static ULONG PspThreadNotifyRoutineCount = 0; static PCREATE_THREAD_NOTIFY_ROUTINE diff --git a/reactos/ntoskrnl/ps/psmgr.c b/reactos/ntoskrnl/ps/psmgr.c index 1a6f2627e7e..a19d8eaa7a1 100644 --- a/reactos/ntoskrnl/ps/psmgr.c +++ b/reactos/ntoskrnl/ps/psmgr.c @@ -81,7 +81,7 @@ PsInitThreadManagment(VOID) InitializeListHead(&PriorityListHead[i]); } - DPRINT1("Creating Thread Object Type\n"); + DPRINT("Creating Thread Object Type\n"); /* Initialize the Thread type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); @@ -124,7 +124,7 @@ PsInitProcessManagment(VOID) * Register the process object type */ - DPRINT1("Creating Process Object Type\n"); + DPRINT("Creating Process Object Type\n"); /* Initialize the Thread type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); diff --git a/reactos/ntoskrnl/rtl/handle.c b/reactos/ntoskrnl/rtl/handle.c index 8bd7df97b25..90a1befe941 100644 --- a/reactos/ntoskrnl/rtl/handle.c +++ b/reactos/ntoskrnl/rtl/handle.c @@ -14,10 +14,6 @@ #define NDEBUG #include - -#define TAG_HDTB TAG('H', 'D', 'T', 'B') - - static BOOLEAN RtlpIsValidHandle(PRTL_HANDLE_TABLE HandleTable, PRTL_HANDLE Handle); static BOOLEAN @@ -67,7 +63,7 @@ RtlpAllocateHandle(PRTL_HANDLE_TABLE HandleTable, { /* allocate handle array */ ArraySize = sizeof(RTL_HANDLE) * HandleTable->TableSize; - ArrayPointer = ExAllocatePoolWithTag(NonPagedPool, + ArrayPointer = ExAllocatePoolWithTag(PagedPool, ArraySize, TAG_HDTB); if (ArrayPointer == NULL) diff --git a/reactos/ntoskrnl/rtl/nls.c b/reactos/ntoskrnl/rtl/nls.c index 3b85ea6156e..d32d6316258 100644 --- a/reactos/ntoskrnl/rtl/nls.c +++ b/reactos/ntoskrnl/rtl/nls.c @@ -139,7 +139,16 @@ RtlpCreateNlsSection(VOID) DPRINT1("MmCreateSection() failed\n"); KEBUGCHECKEX(0x32, Status, 1, 1, 0); } - + Status = ObInsertObject(NlsSectionObject, + NULL, + SECTION_ALL_ACCESS, + 0, + NULL, + NULL); + if (!NT_SUCCESS(Status)) + { + ObDereferenceObject(NlsSectionObject); + } Status = MmMapViewInSystemSpace(NlsSectionObject, &NlsSectionBase, &NlsSectionViewSize); diff --git a/reactos/ntoskrnl/se/acl.c b/reactos/ntoskrnl/se/acl.c index 4e2c732b6a7..ad725253abf 100644 --- a/reactos/ntoskrnl/se/acl.c +++ b/reactos/ntoskrnl/se/acl.c @@ -13,9 +13,6 @@ #include #include -#define TAG_ACL TAG('A', 'C', 'L', 'T') - - /* GLOBALS ******************************************************************/ PACL EXPORTED SePublicDefaultDacl = NULL; @@ -39,7 +36,7 @@ SepInitDACLs(VOID) (sizeof(ACE) + RtlLengthSid(SeWorldSid)) + (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)); - SePublicDefaultDacl = ExAllocatePoolWithTag(NonPagedPool, + SePublicDefaultDacl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_ACL); if (SePublicDefaultDacl == NULL) @@ -67,7 +64,7 @@ SepInitDACLs(VOID) (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) + (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)); - SePublicDefaultUnrestrictedDacl = ExAllocatePoolWithTag(NonPagedPool, + SePublicDefaultUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_ACL); if (SePublicDefaultUnrestrictedDacl == NULL) @@ -103,7 +100,7 @@ SepInitDACLs(VOID) (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)); - SePublicOpenDacl = ExAllocatePoolWithTag(NonPagedPool, + SePublicOpenDacl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_ACL); if (SePublicOpenDacl == NULL) @@ -135,7 +132,7 @@ SepInitDACLs(VOID) (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) + (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)); - SePublicOpenUnrestrictedDacl = ExAllocatePoolWithTag(NonPagedPool, + SePublicOpenUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_ACL); if (SePublicOpenUnrestrictedDacl == NULL) @@ -170,7 +167,7 @@ SepInitDACLs(VOID) (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) + (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)); - SeSystemDefaultDacl = ExAllocatePoolWithTag(NonPagedPool, + SeSystemDefaultDacl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_ACL); if (SeSystemDefaultDacl == NULL) @@ -195,7 +192,7 @@ SepInitDACLs(VOID) (sizeof(ACE) + RtlLengthSid(SeWorldSid)) + (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)); - SeUnrestrictedDacl = ExAllocatePoolWithTag(NonPagedPool, + SeUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_ACL); if (SeUnrestrictedDacl == NULL) diff --git a/reactos/ntoskrnl/se/sd.c b/reactos/ntoskrnl/se/sd.c index 8e61acc18f2..404744ab21e 100644 --- a/reactos/ntoskrnl/se/sd.c +++ b/reactos/ntoskrnl/se/sd.c @@ -28,8 +28,8 @@ BOOLEAN INIT_FUNCTION SepInitSDs(VOID) { /* Create PublicDefaultSd */ - SePublicDefaultSd = ExAllocatePool(NonPagedPool, - sizeof(SECURITY_DESCRIPTOR)); + SePublicDefaultSd = ExAllocatePoolWithTag(PagedPool, + sizeof(SECURITY_DESCRIPTOR), TAG_SD); if (SePublicDefaultSd == NULL) return FALSE; @@ -41,8 +41,8 @@ SepInitSDs(VOID) FALSE); /* Create PublicDefaultUnrestrictedSd */ - SePublicDefaultUnrestrictedSd = ExAllocatePool(NonPagedPool, - sizeof(SECURITY_DESCRIPTOR)); + SePublicDefaultUnrestrictedSd = ExAllocatePoolWithTag(PagedPool, + sizeof(SECURITY_DESCRIPTOR), TAG_SD); if (SePublicDefaultUnrestrictedSd == NULL) return FALSE; @@ -54,8 +54,8 @@ SepInitSDs(VOID) FALSE); /* Create PublicOpenSd */ - SePublicOpenSd = ExAllocatePool(NonPagedPool, - sizeof(SECURITY_DESCRIPTOR)); + SePublicOpenSd = ExAllocatePoolWithTag(PagedPool, + sizeof(SECURITY_DESCRIPTOR), TAG_SD); if (SePublicOpenSd == NULL) return FALSE; @@ -67,8 +67,8 @@ SepInitSDs(VOID) FALSE); /* Create PublicOpenUnrestrictedSd */ - SePublicOpenUnrestrictedSd = ExAllocatePool(NonPagedPool, - sizeof(SECURITY_DESCRIPTOR)); + SePublicOpenUnrestrictedSd = ExAllocatePoolWithTag(PagedPool, + sizeof(SECURITY_DESCRIPTOR), TAG_SD); if (SePublicOpenUnrestrictedSd == NULL) return FALSE; @@ -80,8 +80,8 @@ SepInitSDs(VOID) FALSE); /* Create SystemDefaultSd */ - SeSystemDefaultSd = ExAllocatePool(NonPagedPool, - sizeof(SECURITY_DESCRIPTOR)); + SeSystemDefaultSd = ExAllocatePoolWithTag(PagedPool, + sizeof(SECURITY_DESCRIPTOR), TAG_SD); if (SeSystemDefaultSd == NULL) return FALSE; @@ -93,8 +93,8 @@ SepInitSDs(VOID) FALSE); /* Create UnrestrictedSd */ - SeUnrestrictedSd = ExAllocatePool(NonPagedPool, - sizeof(SECURITY_DESCRIPTOR)); + SeUnrestrictedSd = ExAllocatePoolWithTag(PagedPool, + sizeof(SECURITY_DESCRIPTOR), TAG_SD); if (SeUnrestrictedSd == NULL) return FALSE; @@ -604,6 +604,7 @@ SeCaptureSecurityDescriptor( { ULONG_PTR Offset = sizeof(SECURITY_DESCRIPTOR); + RtlZeroMemory(NewDescriptor, DescriptorSize); NewDescriptor->Revision = DescriptorCopy.Revision; NewDescriptor->Sbz1 = DescriptorCopy.Sbz1; NewDescriptor->Control = DescriptorCopy.Control | SE_SELF_RELATIVE; diff --git a/reactos/ntoskrnl/se/semgr.c b/reactos/ntoskrnl/se/semgr.c index de5962989a6..f58be6a8232 100644 --- a/reactos/ntoskrnl/se/semgr.c +++ b/reactos/ntoskrnl/se/semgr.c @@ -14,12 +14,10 @@ #define NDEBUG #include -#define TAG_SXPT TAG('S', 'X', 'P', 'T') - - /* GLOBALS ******************************************************************/ PSE_EXPORTS EXPORTED SeExports = NULL; +SE_EXPORTS SepExports; static ERESOURCE SepSubjectContextLock; @@ -124,56 +122,51 @@ SeInitSRM(VOID) static BOOLEAN INIT_FUNCTION SepInitExports(VOID) { - SeExports = ExAllocatePoolWithTag(NonPagedPool, - sizeof(SE_EXPORTS), - TAG_SXPT); - if (SeExports == NULL) - return FALSE; + SepExports.SeCreateTokenPrivilege = SeCreateTokenPrivilege; + SepExports.SeAssignPrimaryTokenPrivilege = SeAssignPrimaryTokenPrivilege; + SepExports.SeLockMemoryPrivilege = SeLockMemoryPrivilege; + SepExports.SeIncreaseQuotaPrivilege = SeIncreaseQuotaPrivilege; + SepExports.SeUnsolicitedInputPrivilege = SeUnsolicitedInputPrivilege; + SepExports.SeTcbPrivilege = SeTcbPrivilege; + SepExports.SeSecurityPrivilege = SeSecurityPrivilege; + SepExports.SeTakeOwnershipPrivilege = SeTakeOwnershipPrivilege; + SepExports.SeLoadDriverPrivilege = SeLoadDriverPrivilege; + SepExports.SeCreatePagefilePrivilege = SeCreatePagefilePrivilege; + SepExports.SeIncreaseBasePriorityPrivilege = SeIncreaseBasePriorityPrivilege; + SepExports.SeSystemProfilePrivilege = SeSystemProfilePrivilege; + SepExports.SeSystemtimePrivilege = SeSystemtimePrivilege; + SepExports.SeProfileSingleProcessPrivilege = SeProfileSingleProcessPrivilege; + SepExports.SeCreatePermanentPrivilege = SeCreatePermanentPrivilege; + SepExports.SeBackupPrivilege = SeBackupPrivilege; + SepExports.SeRestorePrivilege = SeRestorePrivilege; + SepExports.SeShutdownPrivilege = SeShutdownPrivilege; + SepExports.SeDebugPrivilege = SeDebugPrivilege; + SepExports.SeAuditPrivilege = SeAuditPrivilege; + SepExports.SeSystemEnvironmentPrivilege = SeSystemEnvironmentPrivilege; + SepExports.SeChangeNotifyPrivilege = SeChangeNotifyPrivilege; + SepExports.SeRemoteShutdownPrivilege = SeRemoteShutdownPrivilege; - SeExports->SeCreateTokenPrivilege = SeCreateTokenPrivilege; - SeExports->SeAssignPrimaryTokenPrivilege = SeAssignPrimaryTokenPrivilege; - SeExports->SeLockMemoryPrivilege = SeLockMemoryPrivilege; - SeExports->SeIncreaseQuotaPrivilege = SeIncreaseQuotaPrivilege; - SeExports->SeUnsolicitedInputPrivilege = SeUnsolicitedInputPrivilege; - SeExports->SeTcbPrivilege = SeTcbPrivilege; - SeExports->SeSecurityPrivilege = SeSecurityPrivilege; - SeExports->SeTakeOwnershipPrivilege = SeTakeOwnershipPrivilege; - SeExports->SeLoadDriverPrivilege = SeLoadDriverPrivilege; - SeExports->SeCreatePagefilePrivilege = SeCreatePagefilePrivilege; - SeExports->SeIncreaseBasePriorityPrivilege = SeIncreaseBasePriorityPrivilege; - SeExports->SeSystemProfilePrivilege = SeSystemProfilePrivilege; - SeExports->SeSystemtimePrivilege = SeSystemtimePrivilege; - SeExports->SeProfileSingleProcessPrivilege = SeProfileSingleProcessPrivilege; - SeExports->SeCreatePermanentPrivilege = SeCreatePermanentPrivilege; - SeExports->SeBackupPrivilege = SeBackupPrivilege; - SeExports->SeRestorePrivilege = SeRestorePrivilege; - SeExports->SeShutdownPrivilege = SeShutdownPrivilege; - SeExports->SeDebugPrivilege = SeDebugPrivilege; - SeExports->SeAuditPrivilege = SeAuditPrivilege; - SeExports->SeSystemEnvironmentPrivilege = SeSystemEnvironmentPrivilege; - SeExports->SeChangeNotifyPrivilege = SeChangeNotifyPrivilege; - SeExports->SeRemoteShutdownPrivilege = SeRemoteShutdownPrivilege; - - SeExports->SeNullSid = SeNullSid; - SeExports->SeWorldSid = SeWorldSid; - SeExports->SeLocalSid = SeLocalSid; - SeExports->SeCreatorOwnerSid = SeCreatorOwnerSid; - SeExports->SeCreatorGroupSid = SeCreatorGroupSid; - SeExports->SeNtAuthoritySid = SeNtAuthoritySid; - SeExports->SeDialupSid = SeDialupSid; - SeExports->SeNetworkSid = SeNetworkSid; - SeExports->SeBatchSid = SeBatchSid; - SeExports->SeInteractiveSid = SeInteractiveSid; - SeExports->SeLocalSystemSid = SeLocalSystemSid; - SeExports->SeAliasAdminsSid = SeAliasAdminsSid; - SeExports->SeAliasUsersSid = SeAliasUsersSid; - SeExports->SeAliasGuestsSid = SeAliasGuestsSid; - SeExports->SeAliasPowerUsersSid = SeAliasPowerUsersSid; - SeExports->SeAliasAccountOpsSid = SeAliasAccountOpsSid; - SeExports->SeAliasSystemOpsSid = SeAliasSystemOpsSid; - SeExports->SeAliasPrintOpsSid = SeAliasPrintOpsSid; - SeExports->SeAliasBackupOpsSid = SeAliasBackupOpsSid; + SepExports.SeNullSid = SeNullSid; + SepExports.SeWorldSid = SeWorldSid; + SepExports.SeLocalSid = SeLocalSid; + SepExports.SeCreatorOwnerSid = SeCreatorOwnerSid; + SepExports.SeCreatorGroupSid = SeCreatorGroupSid; + SepExports.SeNtAuthoritySid = SeNtAuthoritySid; + SepExports.SeDialupSid = SeDialupSid; + SepExports.SeNetworkSid = SeNetworkSid; + SepExports.SeBatchSid = SeBatchSid; + SepExports.SeInteractiveSid = SeInteractiveSid; + SepExports.SeLocalSystemSid = SeLocalSystemSid; + SepExports.SeAliasAdminsSid = SeAliasAdminsSid; + SepExports.SeAliasUsersSid = SeAliasUsersSid; + SepExports.SeAliasGuestsSid = SeAliasGuestsSid; + SepExports.SeAliasPowerUsersSid = SeAliasPowerUsersSid; + SepExports.SeAliasAccountOpsSid = SeAliasAccountOpsSid; + SepExports.SeAliasSystemOpsSid = SeAliasSystemOpsSid; + SepExports.SeAliasPrintOpsSid = SeAliasPrintOpsSid; + SepExports.SeAliasBackupOpsSid = SeAliasBackupOpsSid; + SeExports = &SepExports; return TRUE; } @@ -362,9 +355,11 @@ SeAssignSecurity(PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL, { DPRINT("Use explicit owner sid!\n"); Owner = ExplicitDescriptor->Owner; + if (ExplicitDescriptor->Control & SE_SELF_RELATIVE) { Owner = (PSID)(((ULONG_PTR)Owner) + (ULONG_PTR)ExplicitDescriptor); + } } else @@ -499,7 +494,7 @@ SeAssignSecurity(PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL, DaclLength, SaclLength); - Descriptor = ExAllocatePool(NonPagedPool, + Descriptor = ExAllocatePool(PagedPool, Length); RtlZeroMemory( Descriptor, Length ); diff --git a/reactos/ntoskrnl/se/sid.c b/reactos/ntoskrnl/se/sid.c index de59741a876..00b9656c4a1 100644 --- a/reactos/ntoskrnl/se/sid.c +++ b/reactos/ntoskrnl/se/sid.c @@ -15,9 +15,6 @@ #define NDEBUG #include -#define TAG_SID TAG('S', 'I', 'D', 'T') - - /* GLOBALS ******************************************************************/ SID_IDENTIFIER_AUTHORITY SeNullSidAuthority = {SECURITY_NULL_SID_AUTHORITY}; @@ -70,7 +67,7 @@ SepInitSecurityIDs(VOID) SidLength2 = RtlLengthRequiredSid(2); /* create NullSid */ - SeNullSid = ExAllocatePoolWithTag(NonPagedPool, + SeNullSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeNullSid == NULL) @@ -84,7 +81,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_NULL_RID; /* create WorldSid */ - SeWorldSid = ExAllocatePoolWithTag(NonPagedPool, + SeWorldSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeWorldSid == NULL) @@ -98,7 +95,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_WORLD_RID; /* create LocalSid */ - SeLocalSid = ExAllocatePoolWithTag(NonPagedPool, + SeLocalSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeLocalSid == NULL) @@ -112,7 +109,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_LOCAL_RID; /* create CreatorOwnerSid */ - SeCreatorOwnerSid = ExAllocatePoolWithTag(NonPagedPool, + SeCreatorOwnerSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeCreatorOwnerSid == NULL) @@ -126,7 +123,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_CREATOR_OWNER_RID; /* create CreatorGroupSid */ - SeCreatorGroupSid = ExAllocatePoolWithTag(NonPagedPool, + SeCreatorGroupSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeCreatorGroupSid == NULL) @@ -140,7 +137,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_CREATOR_GROUP_RID; /* create CreatorOwnerServerSid */ - SeCreatorOwnerServerSid = ExAllocatePoolWithTag(NonPagedPool, + SeCreatorOwnerServerSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeCreatorOwnerServerSid == NULL) @@ -154,7 +151,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_CREATOR_OWNER_SERVER_RID; /* create CreatorGroupServerSid */ - SeCreatorGroupServerSid = ExAllocatePoolWithTag(NonPagedPool, + SeCreatorGroupServerSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeCreatorGroupServerSid == NULL) @@ -169,7 +166,7 @@ SepInitSecurityIDs(VOID) /* create NtAuthoritySid */ - SeNtAuthoritySid = ExAllocatePoolWithTag(NonPagedPool, + SeNtAuthoritySid = ExAllocatePoolWithTag(PagedPool, SidLength0, TAG_SID); if (SeNtAuthoritySid == NULL) @@ -180,7 +177,7 @@ SepInitSecurityIDs(VOID) 0); /* create DialupSid */ - SeDialupSid = ExAllocatePoolWithTag(NonPagedPool, + SeDialupSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeDialupSid == NULL) @@ -194,7 +191,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_DIALUP_RID; /* create NetworkSid */ - SeNetworkSid = ExAllocatePoolWithTag(NonPagedPool, + SeNetworkSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeNetworkSid == NULL) @@ -208,7 +205,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_NETWORK_RID; /* create BatchSid */ - SeBatchSid = ExAllocatePoolWithTag(NonPagedPool, + SeBatchSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeBatchSid == NULL) @@ -222,7 +219,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_BATCH_RID; /* create InteractiveSid */ - SeInteractiveSid = ExAllocatePoolWithTag(NonPagedPool, + SeInteractiveSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeInteractiveSid == NULL) @@ -236,7 +233,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_INTERACTIVE_RID; /* create ServiceSid */ - SeServiceSid = ExAllocatePoolWithTag(NonPagedPool, + SeServiceSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeServiceSid == NULL) @@ -250,7 +247,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_SERVICE_RID; /* create AnonymousLogonSid */ - SeAnonymousLogonSid = ExAllocatePoolWithTag(NonPagedPool, + SeAnonymousLogonSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeAnonymousLogonSid == NULL) @@ -264,7 +261,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_ANONYMOUS_LOGON_RID; /* create PrincipalSelfSid */ - SePrincipalSelfSid = ExAllocatePoolWithTag(NonPagedPool, + SePrincipalSelfSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SePrincipalSelfSid == NULL) @@ -278,7 +275,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_PRINCIPAL_SELF_RID; /* create LocalSystemSid */ - SeLocalSystemSid = ExAllocatePoolWithTag(NonPagedPool, + SeLocalSystemSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeLocalSystemSid == NULL) @@ -292,7 +289,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_LOCAL_SYSTEM_RID; /* create AuthenticatedUserSid */ - SeAuthenticatedUserSid = ExAllocatePoolWithTag(NonPagedPool, + SeAuthenticatedUserSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeAuthenticatedUserSid == NULL) @@ -306,7 +303,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_AUTHENTICATED_USER_RID; /* create RestrictedCodeSid */ - SeRestrictedCodeSid = ExAllocatePoolWithTag(NonPagedPool, + SeRestrictedCodeSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID); if (SeRestrictedCodeSid == NULL) @@ -320,7 +317,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = SECURITY_RESTRICTED_CODE_RID; /* create AliasAdminsSid */ - SeAliasAdminsSid = ExAllocatePoolWithTag(NonPagedPool, + SeAliasAdminsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); if (SeAliasAdminsSid == NULL) @@ -338,7 +335,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = DOMAIN_ALIAS_RID_ADMINS; /* create AliasUsersSid */ - SeAliasUsersSid = ExAllocatePoolWithTag(NonPagedPool, + SeAliasUsersSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); if (SeAliasUsersSid == NULL) @@ -356,7 +353,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = DOMAIN_ALIAS_RID_USERS; /* create AliasGuestsSid */ - SeAliasGuestsSid = ExAllocatePoolWithTag(NonPagedPool, + SeAliasGuestsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); if (SeAliasGuestsSid == NULL) @@ -374,7 +371,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = DOMAIN_ALIAS_RID_GUESTS; /* create AliasPowerUsersSid */ - SeAliasPowerUsersSid = ExAllocatePoolWithTag(NonPagedPool, + SeAliasPowerUsersSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); if (SeAliasPowerUsersSid == NULL) @@ -392,7 +389,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = DOMAIN_ALIAS_RID_POWER_USERS; /* create AliasAccountOpsSid */ - SeAliasAccountOpsSid = ExAllocatePoolWithTag(NonPagedPool, + SeAliasAccountOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); if (SeAliasAccountOpsSid == NULL) @@ -410,7 +407,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = DOMAIN_ALIAS_RID_ACCOUNT_OPS; /* create AliasSystemOpsSid */ - SeAliasSystemOpsSid = ExAllocatePoolWithTag(NonPagedPool, + SeAliasSystemOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); if (SeAliasSystemOpsSid == NULL) @@ -428,7 +425,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = DOMAIN_ALIAS_RID_SYSTEM_OPS; /* create AliasPrintOpsSid */ - SeAliasPrintOpsSid = ExAllocatePoolWithTag(NonPagedPool, + SeAliasPrintOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); if (SeAliasPrintOpsSid == NULL) @@ -446,7 +443,7 @@ SepInitSecurityIDs(VOID) *SubAuthority = DOMAIN_ALIAS_RID_PRINT_OPS; /* create AliasBackupOpsSid */ - SeAliasBackupOpsSid = ExAllocatePoolWithTag(NonPagedPool, + SeAliasBackupOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID); if (SeAliasBackupOpsSid == NULL) diff --git a/reactos/ntoskrnl/se/token.c b/reactos/ntoskrnl/se/token.c index 843da887926..9dce60c2c41 100644 --- a/reactos/ntoskrnl/se/token.c +++ b/reactos/ntoskrnl/se/token.c @@ -565,15 +565,15 @@ SepInitializeTokenImplementation(VOID) ExInitializeResource(&SepTokenLock); - DPRINT1("Creating Token Object Type\n"); + DPRINT("Creating Token Object Type\n"); /* Initialize the Token type */ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); RtlInitUnicodeString(&Name, L"Token"); ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); - ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(TOKEN); + ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(TOKEN); ObjectTypeInitializer.GenericMapping = SepTokenMapping; - ObjectTypeInitializer.PoolType = NonPagedPool; + ObjectTypeInitializer.PoolType = PagedPool; ObjectTypeInitializer.ValidAccessMask = TOKEN_ALL_ACCESS; ObjectTypeInitializer.UseDefaultObject = TRUE; ObjectTypeInitializer.DeleteProcedure = SepDeleteToken; @@ -1808,6 +1808,12 @@ SepCreateSystemProcessToken(VOID) { return NULL; } + Status = ObInsertObject(AccessToken, + NULL, + TOKEN_ALL_ACCESS, + 0, + NULL, + NULL); Status = ExpAllocateLocallyUniqueId(&AccessToken->TokenId); if (!NT_SUCCESS(Status)) @@ -1847,7 +1853,7 @@ SepCreateSystemProcessToken(VOID) uSize += uAdminsLength; AccessToken->UserAndGroups = - (PSID_AND_ATTRIBUTES)ExAllocatePoolWithTag(NonPagedPool, + (PSID_AND_ATTRIBUTES)ExAllocatePoolWithTag(PagedPool, uSize, TAG('T', 'O', 'K', 'u')); SidArea = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount]; @@ -1879,7 +1885,7 @@ SepCreateSystemProcessToken(VOID) uSize = AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES); AccessToken->Privileges = - (PLUID_AND_ATTRIBUTES)ExAllocatePoolWithTag(NonPagedPool, + (PLUID_AND_ATTRIBUTES)ExAllocatePoolWithTag(PagedPool, uSize, TAG('T', 'O', 'K', 'p')); @@ -1958,7 +1964,7 @@ SepCreateSystemProcessToken(VOID) uSize += sizeof(ACE) + uAdminsLength; uSize = (uSize & (~3)) + 8; AccessToken->DefaultDacl = - (PACL) ExAllocatePoolWithTag(NonPagedPool, + (PACL) ExAllocatePoolWithTag(PagedPool, uSize, TAG('T', 'O', 'K', 'd')); Status = RtlCreateAcl(AccessToken->DefaultDacl, uSize, ACL_REVISION); diff --git a/reactos/subsys/csrss/api/handle.c b/reactos/subsys/csrss/api/handle.c index faa8c3ef663..5286f29db86 100644 --- a/reactos/subsys/csrss/api/handle.c +++ b/reactos/subsys/csrss/api/handle.c @@ -123,8 +123,10 @@ CsrReleaseObject(PCSRSS_PROCESS_DATA ProcessData, } Status = CsrReleaseObjectByPointer(ProcessData->HandleTable[h]); - ProcessData->HandleTable[h] = 0; + RtlEnterCriticalSection(&ProcessData->HandleTableLock); + ProcessData->HandleTable[h] = 0; + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return Status; } @@ -138,33 +140,36 @@ NTSTATUS STDCALL CsrInsertObject( PCSRSS_PROCESS_DATA ProcessData, PHANDLE Handl return STATUS_INVALID_PARAMETER; } + RtlEnterCriticalSection(&ProcessData->HandleTableLock); + for (i = 0; i < ProcessData->HandleTableSize; i++) { if (ProcessData->HandleTable[i] == NULL) { - ProcessData->HandleTable[i] = Object; - *Handle = (HANDLE)(((i + 1) << 2) | 0x3); - InterlockedIncrement( &Object->ReferenceCount ); - return(STATUS_SUCCESS); + break; } } - NewBlock = RtlAllocateHeap(CsrssApiHeap, - HEAP_ZERO_MEMORY, - (ProcessData->HandleTableSize + 64) * - sizeof(HANDLE)); - if (NewBlock == NULL) + if (i >= ProcessData->HandleTableSize) { - return(STATUS_UNSUCCESSFUL); + NewBlock = RtlAllocateHeap(CsrssApiHeap, + HEAP_ZERO_MEMORY, + (ProcessData->HandleTableSize + 64) * sizeof(HANDLE)); + if (NewBlock == NULL) + { + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + return(STATUS_UNSUCCESSFUL); + } + RtlCopyMemory(NewBlock, + ProcessData->HandleTable, + ProcessData->HandleTableSize * sizeof(HANDLE)); + RtlFreeHeap( CsrssApiHeap, 0, ProcessData->HandleTable ); + ProcessData->HandleTable = (Object_t **)NewBlock; + ProcessData->HandleTableSize += 64; } - RtlCopyMemory(NewBlock, - ProcessData->HandleTable, - ProcessData->HandleTableSize * sizeof(HANDLE)); - RtlFreeHeap( CsrssApiHeap, 0, ProcessData->HandleTable ); - ProcessData->HandleTable = (Object_t **)NewBlock; ProcessData->HandleTable[i] = Object; *Handle = (HANDLE)(((i + 1) << 2) | 0x3); InterlockedIncrement( &Object->ReferenceCount ); - ProcessData->HandleTableSize = ProcessData->HandleTableSize + 64; + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return(STATUS_SUCCESS); } diff --git a/reactos/subsys/csrss/api/process.c b/reactos/subsys/csrss/api/process.c index 01159854987..79849f39b67 100644 --- a/reactos/subsys/csrss/api/process.c +++ b/reactos/subsys/csrss/api/process.c @@ -103,7 +103,8 @@ PCSRSS_PROCESS_DATA STDCALL CsrCreateProcessData(HANDLE ProcessId) ProcessData[hash] = pProcessData->next; RtlFreeHeap(CsrssApiHeap, 0, pProcessData); pProcessData = NULL; - } + } + RtlInitializeCriticalSection(&pProcessData->HandleTableLock); } } else @@ -160,6 +161,7 @@ NTSTATUS STDCALL CsrFreeProcessData(HANDLE Pid) } RtlFreeHeap(CsrssApiHeap, 0, pProcessData->HandleTable); } + RtlDeleteCriticalSection(&pProcessData->HandleTableLock); if (pProcessData->Console) { CsrReleaseObjectByPointer((Object_t *) pProcessData->Console); @@ -254,7 +256,6 @@ CSR_API(CsrCreateProcess) if( !NT_SUCCESS( Status ) ) { DbgPrint( "CSR: NtDuplicateObject() failed: %x\n", Status ); - InterlockedDecrement( &(NewProcessData->Console->Header.ReferenceCount) ); CsrFreeProcessData( NewProcessData->ProcessId ); Reply->Status = Status; return Status; diff --git a/reactos/subsys/csrss/include/api.h b/reactos/subsys/csrss/include/api.h index 520bbc3733f..ae4bdc1fa90 100644 --- a/reactos/subsys/csrss/include/api.h +++ b/reactos/subsys/csrss/include/api.h @@ -34,6 +34,7 @@ typedef struct tagCSRSS_CONSOLE *PCSRSS_CONSOLE; typedef struct _CSRSS_PROCESS_DATA { PCSRSS_CONSOLE Console; + RTL_CRITICAL_SECTION HandleTableLock; ULONG HandleTableSize; Object_t ** HandleTable; HANDLE ProcessId; diff --git a/reactos/subsys/smss/client.c b/reactos/subsys/smss/client.c index 212e3332e86..5e2bb5f6e6a 100644 --- a/reactos/subsys/smss/client.c +++ b/reactos/subsys/smss/client.c @@ -1,324 +1,448 @@ -/* $Id: smss.c 12852 2005-01-06 13:58:04Z mf $ - * - * client.c - Session Manager client Management - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ -#define NTOS_MODE_USER -#include -#include "smss.h" -#include - -#define NDEBUG -#include - -/* Private ADT */ - - -struct _SM_CLIENT_DIRECTORY -{ - RTL_CRITICAL_SECTION Lock; - ULONG Count; - PSM_CLIENT_DATA Client; - -} SmpClientDirectory; - -/********************************************************************** - * SmInitializeClientManagement/0 - */ -NTSTATUS -SmInitializeClientManagement (VOID) -{ - DPRINT("SM: %s called\n", __FUNCTION__); - RtlInitializeCriticalSection(& SmpClientDirectory.Lock); - SmpClientDirectory.Count = 0; - SmpClientDirectory.Client = NULL; - return STATUS_SUCCESS; - -} - -/********************************************************************** - * SmCompleteClientInitialization/1 - * - * DESCRIPTION - * Lookup the subsystem server descriptor given the process handle - * of the subsystem server process. - */ -NTSTATUS STDCALL -SmCompleteClientInitialization (HANDLE hProcess) -{ - NTSTATUS Status = STATUS_SUCCESS; - PSM_CLIENT_DATA Client = NULL; - - DPRINT("SM: %s called\n", __FUNCTION__); - - RtlEnterCriticalSection (& SmpClientDirectory.Lock); - if (SmpClientDirectory.Count > 0) - { - Client = SmpClientDirectory.Client; - while (NULL != Client) - { - if (hProcess == Client->ServerProcess) - { - Client->Initialized = TRUE; - break; - } - Client = Client->Next; - } - Status = STATUS_NOT_FOUND; - } - RtlLeaveCriticalSection (& SmpClientDirectory.Lock); - return Status; -} - -/********************************************************************** - * SmpLookupClient/1 PRIVATE - * - * DESCRIPTION - * Lookup the subsystem server descriptor given its image ID. - * - * SIDE EFFECTS - * SmpClientDirectory.Lock is released only on success. - */ -static PSM_CLIENT_DATA FASTCALL -SmpLookupClientUnsafe (USHORT SubsystemId, - PSM_CLIENT_DATA * Parent) -{ - PSM_CLIENT_DATA Client = NULL; - - DPRINT("SM: %s(%d) called\n", __FUNCTION__, SubsystemId); - - if(NULL != Parent) - { - *Parent = NULL; - } - if (SmpClientDirectory.Count > 0) - { - Client = SmpClientDirectory.Client; - while (NULL != Client) - { - if (SubsystemId == Client->SubsystemId) - { - break; - } - if(NULL != Parent) - { - *Parent = Client; - } - Client = Client->Next; - } - } - return Client; -} - -static PSM_CLIENT_DATA STDCALL -SmpLookupClient (USHORT SubsystemId) -{ - PSM_CLIENT_DATA Client = NULL; - - DPRINT("SM: %s called\n", __FUNCTION__); - - RtlEnterCriticalSection (& SmpClientDirectory.Lock); - Client = SmpLookupClientUnsafe (SubsystemId, NULL); - if(NULL != Client) - { - RtlLeaveCriticalSection (& SmpClientDirectory.Lock); - } - /* - * Note that we do *not* release SmpClientDirectory.Lock here - * because SmpLookupClient is called to FAIL when SubsystemId - * is not registered yet. - */ - return Client; -} - -/********************************************************************** - * SmpCreateClient/2 - */ -NTSTATUS STDCALL -SmCreateClient(PSM_PORT_MESSAGE Request, PSM_CLIENT_DATA * ClientData) -{ - PSM_CLIENT_DATA pClient = NULL; - PSM_CONNECT_DATA ConnectData = SmpGetConnectData (Request); - ULONG SbApiPortNameSize = SM_CONNECT_DATA_SIZE(*Request); - - DPRINT("SM: %s called\n", __FUNCTION__); - - /* - * Check if a client for the ID already exist. - */ - if (SmpLookupClient(ConnectData->SubSystemId)) - { - DPRINT("SM: %s: attempt to register again subsystem %d.\n", - __FUNCTION__, - ConnectData->SubSystemId); - return STATUS_UNSUCCESSFUL; - } - DPRINT("SM: %s: registering subsystem ID=%d \n", __FUNCTION__, ConnectData->SubSystemId); - /* - * Allocate the storage for client data - */ - pClient = RtlAllocateHeap (SmpHeap, - HEAP_ZERO_MEMORY, - sizeof (SM_CLIENT_DATA)); - if (NULL == pClient) - { - DPRINT("SM: %s: out of memory!\n",__FUNCTION__); - return STATUS_NO_MEMORY; - } - /* - * Initialize the client data - */ - pClient->SubsystemId = ConnectData->SubSystemId; - /* SM auto-initializes; other subsystems are required to call - * SM_API_COMPLETE_SESSION via SMDLL. */ - pClient->Initialized = (IMAGE_SUBSYSTEM_NATIVE == pClient->SubsystemId); - if (SbApiPortNameSize > 0) - { - RtlCopyMemory (pClient->SbApiPortName, - ConnectData->SbName, - SbApiPortNameSize); - } - /* - * Insert the new descriptor in the - * client directory. - */ - if (NULL == SmpClientDirectory.Client) - { - SmpClientDirectory.Client = pClient; - } else { - PSM_CLIENT_DATA pCD = NULL; - - for (pCD=SmpClientDirectory.Client; - (NULL != pCD->Next); - pCD = pCD->Next); - pCD->Next = pClient; - } - pClient->Next = NULL; - ++ SmpClientDirectory.Count; - /* - * Note we unlock the client directory here, because - * it was locked by SmpLookupClient on failure. - */ - RtlLeaveCriticalSection (& SmpClientDirectory.Lock); - if (ClientData) - { - *ClientData = pClient; - } - return STATUS_SUCCESS; -} - -/********************************************************************** - * SmpDestroyClient/1 - * - * 1. close any handle - * 2. kill client process - * 3. release resources - */ -NTSTATUS STDCALL -SmDestroyClient (ULONG SubsystemId) -{ - NTSTATUS Status = STATUS_SUCCESS; - PSM_CLIENT_DATA Parent = NULL; - PSM_CLIENT_DATA Client = NULL; - - DPRINT("SM: %s called\n", __FUNCTION__); - - RtlEnterCriticalSection (& SmpClientDirectory.Lock); - Client = SmpLookupClientUnsafe (SubsystemId, & Parent); - if(NULL == Client) - { - DPRINT1("SM: %s: del req for non existent subsystem (id=%d)\n", - __FUNCTION__, SubsystemId); - Status = STATUS_NOT_FOUND; - } - else - { - /* 1st in the list? */ - if(NULL == Parent) - { - SmpClientDirectory.Client = Client->Next; - } - else - { - if(NULL != Parent) - { - Parent->Next = Client->Next; - } else { - DPRINT1("SM: %s: n-th has no parent!\n", __FUNCTION__); - Status = STATUS_UNSUCCESSFUL; /* FIXME */ - } - } - /* TODO: send shutdown or kill */ - RtlFreeHeap (SmpHeap, 0, Client); - -- SmpClientDirectory.Count; - } - RtlLeaveCriticalSection (& SmpClientDirectory.Lock); - return Status; -} - -/* === Utilities for SmQryInfo === */ - -/********************************************************************** - * SmGetClientBasicInformation/1 - */ -NTSTATUS FASTCALL -SmGetClientBasicInformation (PSM_BASIC_INFORMATION i) -{ - INT Index = 0; - PSM_CLIENT_DATA Client = NULL; - - DPRINT("SM: %s called\n", __FUNCTION__); - - RtlEnterCriticalSection (& SmpClientDirectory.Lock); - - i->SubSystemCount = SmpClientDirectory.Count; - i->Unused = 0; - - if (SmpClientDirectory.Count > 0) - { - Client = SmpClientDirectory.Client; - while ((NULL != Client) && (Index < SM_QRYINFO_MAX_SS_COUNT)) - { - i->SubSystem[Index].Id = Client->SubsystemId; - i->SubSystem[Index].Flags = 0; /* TODO */ - i->SubSystem[Index].ProcessId = 0; /* TODO */ - Client = Client->Next; - } - } - - RtlLeaveCriticalSection (& SmpClientDirectory.Lock); - return STATUS_SUCCESS; -} - -/********************************************************************** - * SmGetSubSystemInformation/1 - */ -NTSTATUS FASTCALL -SmGetSubSystemInformation (PSM_SUBSYSTEM_INFORMATION i) -{ - DPRINT("SM: %s called\n", __FUNCTION__); - - return STATUS_NOT_IMPLEMENTED; -} - -/* EOF */ +/* $Id$ + * + * client.c - Session Manager client Management + * + * ReactOS Operating System + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ +#define NTOS_MODE_USER +#include +#include "smss.h" +#include + +#define NDEBUG +#include + +/* Private ADT */ + + +struct _SM_CLIENT_DIRECTORY +{ + RTL_CRITICAL_SECTION Lock; + ULONG Count; + PSM_CLIENT_DATA Client; + PSM_CLIENT_DATA CandidateClient; + +} SmpClientDirectory; + + +/********************************************************************** + * SmInitializeClientManagement/0 + */ +NTSTATUS +SmInitializeClientManagement (VOID) +{ + DPRINT("SM: %s called\n", __FUNCTION__); + RtlInitializeCriticalSection(& SmpClientDirectory.Lock); + SmpClientDirectory.Count = 0; + SmpClientDirectory.Client = NULL; + SmpClientDirectory.CandidateClient = NULL; + return STATUS_SUCCESS; + +} +/********************************************************************** + * SmpSetClientInitialized/1 + */ +VOID FASTCALL +SmpSetClientInitialized (PSM_CLIENT_DATA Client) +{ + Client->Flags |= SM_CLIENT_FLAG_INITIALIZED; +} +/********************************************************************** + * SmpLookupClient/2 PRIVATE + * + * DESCRIPTION + * Lookup the subsystem server descriptor given its image ID. + * + * ARGUMENTS + * SubsystemId: IMAGE_SUBSYSTEM_xxx + * Parent: optional: caller provided storage for the + * the pointer to the SM_CLIENT_DATA which + * Next field contains the value returned by + * the function (on success). + * + * RETURN VALUES + * NULL on error; otherwise a pointer to the SM_CLIENT_DATA + * looked up object. + * + * WARNING + * SmpClientDirectory.Lock must be held by the caller. + */ +static PSM_CLIENT_DATA FASTCALL +SmpLookupClient (USHORT SubsystemId, + PSM_CLIENT_DATA * Parent) +{ + PSM_CLIENT_DATA Client = NULL; + + DPRINT("SM: %s(%d) called\n", __FUNCTION__, SubsystemId); + + if(NULL != Parent) + { + *Parent = NULL; + } + if (SmpClientDirectory.Count > 0) + { + Client = SmpClientDirectory.Client; + while (NULL != Client) + { + if (SubsystemId == Client->SubsystemId) + { + break; + } + if(NULL != Parent) + { + *Parent = Client; + } + Client = Client->Next; + } + } + return Client; +} +/********************************************************************** + * SmBeginClientInitialization/1 + * + * DESCRIPTION + * Check if the candidate client matches the begin session + * message from the subsystem process. + * + * ARGUMENTS + * Request: message received by \SmApiPort + * ClientData: + * + * RETURN VALUES + * NTSTATUS + */ +NTSTATUS STDCALL +SmBeginClientInitialization (IN PSM_PORT_MESSAGE Request, + OUT PSM_CLIENT_DATA * ClientData) +{ + NTSTATUS Status = STATUS_SUCCESS; + PSM_CONNECT_DATA ConnectData = SmpGetConnectData (Request); + ULONG SbApiPortNameSize = SM_CONNECT_DATA_SIZE(*Request); + + + DPRINT("SM: %s called\n", __FUNCTION__); + + RtlEnterCriticalSection (& SmpClientDirectory.Lock); + /* + * Is there a subsystem bootstrap in progress? + */ + if (SmpClientDirectory.CandidateClient) + { + PROCESS_BASIC_INFORMATION pbi; + + RtlZeroMemory (& pbi, sizeof pbi); + Status = NtQueryInformationProcess (Request->Header.ClientId.UniqueProcess, + ProcessBasicInformation, + & pbi, + sizeof pbi, + NULL); + if (NT_SUCCESS(Status)) + { + SmpClientDirectory.CandidateClient->ServerProcessId = + (ULONG) pbi.UniqueProcessId; + } + } + else + { + RtlFreeHeap (SmpHeap, 0, SmpClientDirectory.CandidateClient); + DPRINT1("SM: %s: subsys booting with no descriptor!\n", __FUNCTION__); + Status = STATUS_NOT_FOUND; + RtlLeaveCriticalSection (& SmpClientDirectory.Lock); + return Status; + } + /* + * Check if a client for the ID already exist. + */ + if (SmpLookupClient(ConnectData->SubSystemId, NULL)) + { + DPRINT("SM: %s: attempt to register again subsystem %d.\n", + __FUNCTION__, + ConnectData->SubSystemId); + return STATUS_UNSUCCESSFUL; + } + DPRINT("SM: %s: registering subsystem ID=%d \n", + __FUNCTION__, ConnectData->SubSystemId); + + /* + * Initialize the client data + */ + SmpClientDirectory.CandidateClient->SubsystemId = ConnectData->SubSystemId; + /* SM && DBG auto-initializes; other subsystems are required to call + * SM_API_COMPLETE_SESSION via SMDLL. */ + if ((IMAGE_SUBSYSTEM_NATIVE == SmpClientDirectory.CandidateClient->SubsystemId) || + (IMAGE_SUBSYSTEM_UNKNOWN == SmpClientDirectory.CandidateClient->SubsystemId)) + { + SmpSetClientInitialized (SmpClientDirectory.CandidateClient); + } + if (SbApiPortNameSize > 0) + { + RtlCopyMemory (SmpClientDirectory.CandidateClient->SbApiPortName, + ConnectData->SbName, + SbApiPortNameSize); + } + /* + * Insert the new descriptor in the + * client directory. + */ + if (NULL == SmpClientDirectory.Client) + { + SmpClientDirectory.Client = SmpClientDirectory.CandidateClient; + } else { + PSM_CLIENT_DATA pCD = NULL; + + for (pCD=SmpClientDirectory.Client; + (NULL != pCD->Next); + pCD = pCD->Next); + pCD->Next = SmpClientDirectory.CandidateClient; + } + SmpClientDirectory.CandidateClient->Next = NULL; + /* + * Increment the number of active subsystems. + */ + ++ SmpClientDirectory.Count; + /* + * Notify to the caller the reference to the client data. + */ + if (ClientData) + { + *ClientData = SmpClientDirectory.CandidateClient; + } + /* + * Free the slot for the candidate subsystem. + */ + SmpClientDirectory.CandidateClient = NULL; + + RtlLeaveCriticalSection (& SmpClientDirectory.Lock); + + return STATUS_SUCCESS; +} +/********************************************************************** + * SmCompleteClientInitialization/1 + * + * DESCRIPTION + * Lookup the subsystem server descriptor given the process ID + * of the subsystem server process. + */ +NTSTATUS STDCALL +SmCompleteClientInitialization (ULONG ProcessId) +{ + NTSTATUS Status = STATUS_SUCCESS; + PSM_CLIENT_DATA Client = NULL; + + DPRINT("SM: %s called\n", __FUNCTION__); + + RtlEnterCriticalSection (& SmpClientDirectory.Lock); + if (SmpClientDirectory.Count > 0) + { + Client = SmpClientDirectory.Client; + while (NULL != Client) + { + if (ProcessId == Client->ServerProcessId) + { + SmpSetClientInitialized (Client); + break; + } + Client = Client->Next; + } + Status = STATUS_NOT_FOUND; + } + RtlLeaveCriticalSection (& SmpClientDirectory.Lock); + return Status; +} + +/********************************************************************** + * SmpCreateClient/1 + * + * DESCRIPTION + * Create a "candidate" client. Client descriptor will enter the + * client directory only at the end of the registration + * procedure. Otherwise, we will kill the associated process. + * + * ARGUMENTS + * ProcessHandle: handle of the subsystem server process. + * + * RETURN VALUE + * NTSTATUS: + */ +NTSTATUS STDCALL +SmCreateClient (PRTL_PROCESS_INFO ProcessInfo, PWSTR ProgramName) +{ + NTSTATUS Status = STATUS_SUCCESS; + + + DPRINT("SM: %s(%lx) called\n", __FUNCTION__, ProcessInfo->ProcessHandle); + RtlEnterCriticalSection (& SmpClientDirectory.Lock); + /* + * Check if the candidate client slot is empty. + */ + if (NULL != SmpClientDirectory.CandidateClient) + { + DPRINT1("SM: %s: CandidateClient pending!\n", __FUNCTION__); + RtlLeaveCriticalSection (& SmpClientDirectory.Lock); + return STATUS_UNSUCCESSFUL; + } + /* + * Allocate the storage for client data + */ + SmpClientDirectory.CandidateClient = + RtlAllocateHeap (SmpHeap, + HEAP_ZERO_MEMORY, + sizeof (SM_CLIENT_DATA)); + if (NULL == SmpClientDirectory.CandidateClient) + { + DPRINT("SM: %s(%lx): out of memory!\n", + __FUNCTION__, ProcessInfo->ProcessHandle); + Status = STATUS_NO_MEMORY; + } + else + { + /* Initialize the candidate client. */ + RtlInitializeCriticalSection(& SmpClientDirectory.CandidateClient->Lock); + SmpClientDirectory.CandidateClient->ServerProcess = + (HANDLE) ProcessInfo->ProcessHandle; + SmpClientDirectory.CandidateClient->ServerProcessId = + (ULONG) ProcessInfo->ClientId.UniqueProcess; + } + /* + * Copy the program name + */ + RtlCopyMemory (SmpClientDirectory.CandidateClient->ProgramName, + ProgramName, + SM_SB_NAME_MAX_LENGTH); + RtlLeaveCriticalSection (& SmpClientDirectory.Lock); + return Status; +} + +/********************************************************************** + * SmpDestroyClient/1 + * + * 1. close any handle + * 2. kill client process + * 3. release resources + */ +NTSTATUS STDCALL +SmDestroyClient (ULONG SubsystemId) +{ + NTSTATUS Status = STATUS_SUCCESS; + PSM_CLIENT_DATA Parent = NULL; + PSM_CLIENT_DATA Client = NULL; + + DPRINT("SM: %s called\n", __FUNCTION__); + + RtlEnterCriticalSection (& SmpClientDirectory.Lock); + Client = SmpLookupClient (SubsystemId, & Parent); + if(NULL == Client) + { + DPRINT1("SM: %s: del req for non existent subsystem (id=%d)\n", + __FUNCTION__, SubsystemId); + Status = STATUS_NOT_FOUND; + } + else + { + /* 1st in the list? */ + if(NULL == Parent) + { + SmpClientDirectory.Client = Client->Next; + } + else + { + if(NULL != Parent) + { + Parent->Next = Client->Next; + } else { + DPRINT1("SM: %s: n-th has no parent!\n", __FUNCTION__); + Status = STATUS_UNSUCCESSFUL; /* FIXME */ + } + } + /* TODO: send shutdown or kill */ + NtTerminateProcess (Client->ServerProcess, 0); //FIXME + RtlFreeHeap (SmpHeap, 0, Client); + -- SmpClientDirectory.Count; + } + RtlLeaveCriticalSection (& SmpClientDirectory.Lock); + return Status; +} + +/* === Utilities for SmQryInfo === */ + +/********************************************************************** + * SmGetClientBasicInformation/1 + */ +NTSTATUS FASTCALL +SmGetClientBasicInformation (PSM_BASIC_INFORMATION i) +{ + INT Index = 0; + PSM_CLIENT_DATA ClientData = NULL; + + DPRINT("SM: %s called\n", __FUNCTION__); + + RtlEnterCriticalSection (& SmpClientDirectory.Lock); + + i->SubSystemCount = SmpClientDirectory.Count; + i->Unused = 0; + + if (SmpClientDirectory.Count > 0) + { + ClientData = SmpClientDirectory.Client; + while ((NULL != ClientData) && (Index < SM_QRYINFO_MAX_SS_COUNT)) + { + i->SubSystem[Index].Id = ClientData->SubsystemId; + i->SubSystem[Index].Flags = ClientData->Flags; + i->SubSystem[Index].ProcessId = ClientData->ServerProcessId; + ClientData = ClientData->Next; + } + } + + RtlLeaveCriticalSection (& SmpClientDirectory.Lock); + return STATUS_SUCCESS; +} + +/********************************************************************** + * SmGetSubSystemInformation/1 + */ +NTSTATUS FASTCALL +SmGetSubSystemInformation (PSM_SUBSYSTEM_INFORMATION i) +{ + NTSTATUS Status = STATUS_SUCCESS; + PSM_CLIENT_DATA ClientData = NULL; + + DPRINT("SM: %s called\n", __FUNCTION__); + + RtlEnterCriticalSection (& SmpClientDirectory.Lock); + ClientData = SmpLookupClient (i->SubSystemId, NULL); + if (NULL == ClientData) + { + Status = STATUS_NOT_FOUND; + } + else + { + i->Flags = ClientData->Flags; + i->ProcessId = ClientData->ServerProcessId; + RtlCopyMemory (i->NameSpaceRootNode, + ClientData->SbApiPortName, + (SM_QRYINFO_MAX_ROOT_NODE * sizeof(i->NameSpaceRootNode[0]))); + } + RtlLeaveCriticalSection (& SmpClientDirectory.Lock); + return Status; +} + +/* EOF */ diff --git a/reactos/subsys/smss/debug.c b/reactos/subsys/smss/debug.c index abff1600955..562985311d3 100644 --- a/reactos/subsys/smss/debug.c +++ b/reactos/subsys/smss/debug.c @@ -1,173 +1,173 @@ -/* $Id: smss.c 12852 2005-01-06 13:58:04Z mf $ - * - * debug.c - Session Manager debug messages switch and router - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ -#define NTOS_MODE_USER -#include -#include -#include "smss.h" - -#define NDEBUG -#include - - -/* GLOBALS ***********************************************************/ - -HANDLE DbgSsApiPort = (HANDLE) 0; -HANDLE DbgUiApiPort = (HANDLE) 0; - -/* FUNCTIONS *********************************************************/ - -static VOID STDCALL -DbgSsApiPortThread (PVOID dummy) -{ - NTSTATUS Status = STATUS_SUCCESS; - LPC_MAX_MESSAGE Request = {{0}}; - - while (TRUE) - { - Status = NtListenPort (DbgSsApiPort, & Request.Header); - if (!NT_SUCCESS(Status)) - { - DPRINT1("SM: %s: NtListenPort() failed! (Status==x%08lx)\n", __FUNCTION__, Status); - break; - } - /* TODO */ - } - NtTerminateThread(NtCurrentThread(),Status); -} - -static VOID STDCALL -DbgUiApiPortThread (PVOID dummy) -{ - NTSTATUS Status = STATUS_SUCCESS; - LPC_MAX_MESSAGE Request = {{0}}; - - while (TRUE) - { - Status = NtListenPort (DbgUiApiPort, & Request.Header); - if (!NT_SUCCESS(Status)) - { - DPRINT1("SM: %s: NtListenPort() failed! (Status==x%08lx)\n", __FUNCTION__, Status); - break; - } - /* TODO */ - } - NtTerminateThread(NtCurrentThread(),Status); -} - -static NTSTATUS STDCALL -SmpCreatePT (IN OUT PHANDLE hPort, - IN LPWSTR wcPortName, - IN ULONG ulMaxDataSize, - IN ULONG ulMaxMessageSize, - IN ULONG ulPoolCharge OPTIONAL, - IN VOID (STDCALL * procServingThread)(PVOID) OPTIONAL, - IN OUT PHANDLE phServingThread OPTIONAL) -{ - NTSTATUS Status = STATUS_SUCCESS; - UNICODE_STRING PortName = {0}; - OBJECT_ATTRIBUTES ObjectAttributes; - HANDLE Thread = (HANDLE) 0; - CLIENT_ID Cid = {0, 0}; - - RtlInitUnicodeString (& PortName, wcPortName); - InitializeObjectAttributes (& ObjectAttributes, - & PortName, - PORT_ALL_ACCESS, - NULL, - NULL); - Status = NtCreatePort (hPort, - & ObjectAttributes, - ulMaxDataSize, - ulMaxMessageSize, - ulPoolCharge); - if(STATUS_SUCCESS != Status) - { - return Status; - } - /* Create thread for DbgSsApiPort */ - RtlCreateUserThread(NtCurrentProcess(), - NULL, - FALSE, - 0, - NULL, - NULL, - (PTHREAD_START_ROUTINE) procServingThread, - hPort, - & Thread, - & Cid); - if((HANDLE) 0 == Thread) - { - NtClose(*hPort); - Status = STATUS_UNSUCCESSFUL; - } - if(NULL != phServingThread) - { - *phServingThread = Thread; - } - return Status; -} - -NTSTATUS -SmInitializeDbgSs (VOID) -{ - NTSTATUS Status = STATUS_SUCCESS; - HANDLE hDbgSsApiPortThread = (HANDLE) 0; - - DPRINT("SM: %s called\n", __FUNCTION__); - - /* Create the \DbgSsApiPort object (LPC) */ - Status = SmpCreatePT(& DbgSsApiPort, - SM_DBGSS_PORT_NAME, - 0, /* MaxDataSize */ - 0, /* MaxMessageSize */ - 0, /* PoolCharge */ - DbgSsApiPortThread, - & hDbgSsApiPortThread); - if(!NT_SUCCESS(Status)) - { - DPRINT("SM: %s: DBGSS port not created\n",__FUNCTION__); - return Status; - } - /* Create the \DbgUiApiPort object (LPC) */ - Status = SmpCreatePT(& DbgUiApiPort, - SM_DBGUI_PORT_NAME, - 0, /* MaxDataSize */ - 0, /* MaxMessageSize */ - 0, /* PoolCharge */ - DbgUiApiPortThread, - NULL); - if(!NT_SUCCESS(Status)) - { - DPRINT("SM: %s: DBGUI port not created\n",__FUNCTION__); - NtClose (hDbgSsApiPortThread); - NtClose (DbgSsApiPort); - return Status; - } - return STATUS_SUCCESS; -} - -/* EOF */ - +/* $Id$ + * + * debug.c - Session Manager debug messages switch and router + * + * ReactOS Operating System + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ +#define NTOS_MODE_USER +#include +#include +#include "smss.h" + +#define NDEBUG +#include + + +/* GLOBALS ***********************************************************/ + +HANDLE DbgSsApiPort = (HANDLE) 0; +HANDLE DbgUiApiPort = (HANDLE) 0; + +/* FUNCTIONS *********************************************************/ + +static VOID STDCALL +DbgSsApiPortThread (PVOID dummy) +{ + NTSTATUS Status = STATUS_SUCCESS; + LPC_MAX_MESSAGE Request = {{0}}; + + while (TRUE) + { + Status = NtListenPort (DbgSsApiPort, & Request.Header); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SM: %s: NtListenPort() failed! (Status==x%08lx)\n", __FUNCTION__, Status); + break; + } + /* TODO */ + } + NtTerminateThread(NtCurrentThread(),Status); +} + +static VOID STDCALL +DbgUiApiPortThread (PVOID dummy) +{ + NTSTATUS Status = STATUS_SUCCESS; + LPC_MAX_MESSAGE Request = {{0}}; + + while (TRUE) + { + Status = NtListenPort (DbgUiApiPort, & Request.Header); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SM: %s: NtListenPort() failed! (Status==x%08lx)\n", __FUNCTION__, Status); + break; + } + /* TODO */ + } + NtTerminateThread(NtCurrentThread(),Status); +} + +static NTSTATUS STDCALL +SmpCreatePT (IN OUT PHANDLE hPort, + IN LPWSTR wcPortName, + IN ULONG ulMaxDataSize, + IN ULONG ulMaxMessageSize, + IN ULONG ulPoolCharge OPTIONAL, + IN VOID (STDCALL * procServingThread)(PVOID) OPTIONAL, + IN OUT PHANDLE phServingThread OPTIONAL) +{ + NTSTATUS Status = STATUS_SUCCESS; + UNICODE_STRING PortName = {0}; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE Thread = (HANDLE) 0; + CLIENT_ID Cid = {0, 0}; + + RtlInitUnicodeString (& PortName, wcPortName); + InitializeObjectAttributes (& ObjectAttributes, + & PortName, + PORT_ALL_ACCESS, + NULL, + NULL); + Status = NtCreatePort (hPort, + & ObjectAttributes, + ulMaxDataSize, + ulMaxMessageSize, + ulPoolCharge); + if(STATUS_SUCCESS != Status) + { + return Status; + } + /* Create thread for DbgSsApiPort */ + RtlCreateUserThread(NtCurrentProcess(), + NULL, + FALSE, + 0, + NULL, + NULL, + (PTHREAD_START_ROUTINE) procServingThread, + hPort, + & Thread, + & Cid); + if((HANDLE) 0 == Thread) + { + NtClose(*hPort); + Status = STATUS_UNSUCCESSFUL; + } + if(NULL != phServingThread) + { + *phServingThread = Thread; + } + return Status; +} + +NTSTATUS +SmInitializeDbgSs (VOID) +{ + NTSTATUS Status = STATUS_SUCCESS; + HANDLE hDbgSsApiPortThread = (HANDLE) 0; + + DPRINT("SM: %s called\n", __FUNCTION__); + + /* Create the \DbgSsApiPort object (LPC) */ + Status = SmpCreatePT(& DbgSsApiPort, + SM_DBGSS_PORT_NAME, + 0, /* MaxDataSize */ + 0, /* MaxMessageSize */ + 0, /* PoolCharge */ + DbgSsApiPortThread, + & hDbgSsApiPortThread); + if(!NT_SUCCESS(Status)) + { + DPRINT("SM: %s: DBGSS port not created\n",__FUNCTION__); + return Status; + } + /* Create the \DbgUiApiPort object (LPC) */ + Status = SmpCreatePT(& DbgUiApiPort, + SM_DBGUI_PORT_NAME, + 0, /* MaxDataSize */ + 0, /* MaxMessageSize */ + 0, /* PoolCharge */ + DbgUiApiPortThread, + NULL); + if(!NT_SUCCESS(Status)) + { + DPRINT("SM: %s: DBGUI port not created\n",__FUNCTION__); + NtClose (hDbgSsApiPortThread); + NtClose (DbgSsApiPort); + return Status; + } + return STATUS_SUCCESS; +} + +/* EOF */ + diff --git a/reactos/subsys/smss/initdosdev.c b/reactos/subsys/smss/initdosdev.c index f2698e94f57..091af25b4cf 100644 --- a/reactos/subsys/smss/initdosdev.c +++ b/reactos/subsys/smss/initdosdev.c @@ -1,109 +1,109 @@ -/* $Id: init.c 13449 2005-02-06 21:55:07Z ea $ - * - * initdosdev.c - Define symbolic links to kernel devices (MS-DOS names). - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ - -#include "smss.h" - -#define NDEBUG -#include - -static NTSTATUS STDCALL -SmpDosDevicesQueryRoutine(PWSTR ValueName, - ULONG ValueType, - PVOID ValueData, - ULONG ValueLength, - PVOID Context, - PVOID EntryContext) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING DeviceName; - UNICODE_STRING LinkName; - HANDLE LinkHandle; - WCHAR LinkBuffer[80]; - NTSTATUS Status; - - DPRINT("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength); - DPRINT("ValueData '%S'\n", (PWSTR)ValueData); - - if (ValueType != REG_SZ) - { - return(STATUS_SUCCESS); - } - - swprintf(LinkBuffer, - L"\\??\\%s", - ValueName); - RtlInitUnicodeString(&LinkName, - LinkBuffer); - RtlInitUnicodeString(&DeviceName, - (PWSTR)ValueData); - - DPRINT("SM: Linking %wZ --> %wZ\n", - &LinkName, - &DeviceName); - - /* create symbolic link */ - InitializeObjectAttributes(&ObjectAttributes, - &LinkName, - OBJ_PERMANENT, - NULL, - NULL); - Status = NtCreateSymbolicLinkObject(&LinkHandle, - SYMBOLIC_LINK_ALL_ACCESS, - &ObjectAttributes, - &DeviceName); - if (!NT_SUCCESS(Status)) - { - DPRINT1("%s: NtCreateSymbolicLink( %wZ --> %wZ ) failed!\n", - __FUNCTION__, - &LinkName, - &DeviceName); - } - NtClose(LinkHandle); - - return(Status); -} - - -NTSTATUS -SmInitDosDevices(VOID) -{ - RTL_QUERY_REGISTRY_TABLE QueryTable[2]; - NTSTATUS Status; - - RtlZeroMemory(&QueryTable, - sizeof(QueryTable)); - - QueryTable[0].QueryRoutine = SmpDosDevicesQueryRoutine; - - Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, - L"\\Session Manager\\DOS Devices", - QueryTable, - NULL, - NULL); - return(Status); -} - -/* EOF */ +/* $Id$ + * + * initdosdev.c - Define symbolic links to kernel devices (MS-DOS names). + * + * ReactOS Operating System + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ + +#include "smss.h" + +#define NDEBUG +#include + +static NTSTATUS STDCALL +SmpDosDevicesQueryRoutine(PWSTR ValueName, + ULONG ValueType, + PVOID ValueData, + ULONG ValueLength, + PVOID Context, + PVOID EntryContext) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING DeviceName; + UNICODE_STRING LinkName; + HANDLE LinkHandle; + WCHAR LinkBuffer[80]; + NTSTATUS Status; + + DPRINT("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength); + DPRINT("ValueData '%S'\n", (PWSTR)ValueData); + + if (ValueType != REG_SZ) + { + return(STATUS_SUCCESS); + } + + swprintf(LinkBuffer, + L"\\??\\%s", + ValueName); + RtlInitUnicodeString(&LinkName, + LinkBuffer); + RtlInitUnicodeString(&DeviceName, + (PWSTR)ValueData); + + DPRINT("SM: Linking %wZ --> %wZ\n", + &LinkName, + &DeviceName); + + /* create symbolic link */ + InitializeObjectAttributes(&ObjectAttributes, + &LinkName, + OBJ_PERMANENT, + NULL, + NULL); + Status = NtCreateSymbolicLinkObject(&LinkHandle, + SYMBOLIC_LINK_ALL_ACCESS, + &ObjectAttributes, + &DeviceName); + if (!NT_SUCCESS(Status)) + { + DPRINT1("%s: NtCreateSymbolicLink( %wZ --> %wZ ) failed!\n", + __FUNCTION__, + &LinkName, + &DeviceName); + } + NtClose(LinkHandle); + + return(Status); +} + + +NTSTATUS +SmInitDosDevices(VOID) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[2]; + NTSTATUS Status; + + RtlZeroMemory(&QueryTable, + sizeof(QueryTable)); + + QueryTable[0].QueryRoutine = SmpDosDevicesQueryRoutine; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, + L"\\Session Manager\\DOS Devices", + QueryTable, + NULL, + NULL); + return(Status); +} + +/* EOF */ diff --git a/reactos/subsys/smss/initenv.c b/reactos/subsys/smss/initenv.c index 97341d30b5a..28c4160da9e 100644 --- a/reactos/subsys/smss/initenv.c +++ b/reactos/subsys/smss/initenv.c @@ -1,139 +1,139 @@ -/* $Id: init.c 13449 2005-02-06 21:55:07Z ea $ - * - * initenv.c - Environment initialization - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ - -#include "smss.h" - -#define NDEBUG -#include - -/* GLOBALS */ - -PWSTR SmSystemEnvironment = NULL; - - -/* FUNCTIONS */ - -NTSTATUS -SmCreateEnvironment(VOID) -{ - return RtlCreateEnvironment(FALSE, &SmSystemEnvironment); -} - - -static NTSTATUS -SmpSetEnvironmentVariable(PVOID Context, - PWSTR ValueName, - PVOID ValueData) -{ - UNICODE_STRING EnvVariable; - UNICODE_STRING EnvValue; - - RtlInitUnicodeString(&EnvVariable, - ValueName); - RtlInitUnicodeString(&EnvValue, - (PWSTR)ValueData); - RtlSetEnvironmentVariable(Context, - &EnvVariable, - &EnvValue); - - return(STATUS_SUCCESS); -} - - -static NTSTATUS STDCALL -SmpEnvironmentQueryRoutine(PWSTR ValueName, - ULONG ValueType, - PVOID ValueData, - ULONG ValueLength, - PVOID Context, - PVOID EntryContext) -{ - DPRINT("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength); - DPRINT("ValueData '%S'\n", (PWSTR)ValueData); - - if (ValueType != REG_SZ) - { - return(STATUS_SUCCESS); - } - return SmpSetEnvironmentVariable(Context,ValueName,ValueData); -} - - -NTSTATUS -SmSetEnvironmentVariables(VOID) -{ - RTL_QUERY_REGISTRY_TABLE QueryTable[2]; - WCHAR ValueBuffer[MAX_PATH]; - NTSTATUS Status; - - /* - * The following environment variables must be set prior to reading - * other variables from the registry. - * - * Variables (example): - * SystemRoot = "C:\reactos" - * SystemDrive = "C:" - */ - - /* Copy system root into value buffer */ - wcscpy(ValueBuffer, - SharedUserData->NtSystemRoot); - - /* Set SystemRoot = "C:\reactos" */ - SmpSetEnvironmentVariable(&SmSystemEnvironment,L"SystemRoot",ValueBuffer); - - /* Cut off trailing path */ - ValueBuffer[2] = 0; - - /* Set SystemDrive = "C:" */ - SmpSetEnvironmentVariable(&SmSystemEnvironment,L"SystemDrive",ValueBuffer); - - /* Read system environment from the registry. */ - RtlZeroMemory(&QueryTable, - sizeof(QueryTable)); - - QueryTable[0].QueryRoutine = SmpEnvironmentQueryRoutine; - - Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, - L"\\Session Manager\\Environment", - QueryTable, - &SmSystemEnvironment, - SmSystemEnvironment); - - return(Status); -} - -/********************************************************************** - * Set environment variables from registry - */ -NTSTATUS -SmUpdateEnvironment(VOID) -{ - /* TODO */ - return STATUS_SUCCESS; -} - -/* EOF */ +/* $Id$ + * + * initenv.c - Environment initialization + * + * ReactOS Operating System + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ + +#include "smss.h" + +#define NDEBUG +#include + +/* GLOBALS */ + +PWSTR SmSystemEnvironment = NULL; + + +/* FUNCTIONS */ + +NTSTATUS +SmCreateEnvironment(VOID) +{ + return RtlCreateEnvironment(FALSE, &SmSystemEnvironment); +} + + +static NTSTATUS +SmpSetEnvironmentVariable(PVOID Context, + PWSTR ValueName, + PVOID ValueData) +{ + UNICODE_STRING EnvVariable; + UNICODE_STRING EnvValue; + + RtlInitUnicodeString(&EnvVariable, + ValueName); + RtlInitUnicodeString(&EnvValue, + (PWSTR)ValueData); + RtlSetEnvironmentVariable(Context, + &EnvVariable, + &EnvValue); + + return(STATUS_SUCCESS); +} + + +static NTSTATUS STDCALL +SmpEnvironmentQueryRoutine(PWSTR ValueName, + ULONG ValueType, + PVOID ValueData, + ULONG ValueLength, + PVOID Context, + PVOID EntryContext) +{ + DPRINT("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength); + DPRINT("ValueData '%S'\n", (PWSTR)ValueData); + + if (ValueType != REG_SZ) + { + return(STATUS_SUCCESS); + } + return SmpSetEnvironmentVariable(Context,ValueName,ValueData); +} + + +NTSTATUS +SmSetEnvironmentVariables(VOID) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[2]; + WCHAR ValueBuffer[MAX_PATH]; + NTSTATUS Status; + + /* + * The following environment variables must be set prior to reading + * other variables from the registry. + * + * Variables (example): + * SystemRoot = "C:\reactos" + * SystemDrive = "C:" + */ + + /* Copy system root into value buffer */ + wcscpy(ValueBuffer, + SharedUserData->NtSystemRoot); + + /* Set SystemRoot = "C:\reactos" */ + SmpSetEnvironmentVariable(&SmSystemEnvironment,L"SystemRoot",ValueBuffer); + + /* Cut off trailing path */ + ValueBuffer[2] = 0; + + /* Set SystemDrive = "C:" */ + SmpSetEnvironmentVariable(&SmSystemEnvironment,L"SystemDrive",ValueBuffer); + + /* Read system environment from the registry. */ + RtlZeroMemory(&QueryTable, + sizeof(QueryTable)); + + QueryTable[0].QueryRoutine = SmpEnvironmentQueryRoutine; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, + L"\\Session Manager\\Environment", + QueryTable, + &SmSystemEnvironment, + SmSystemEnvironment); + + return(Status); +} + +/********************************************************************** + * Set environment variables from registry + */ +NTSTATUS +SmUpdateEnvironment(VOID) +{ + /* TODO */ + return STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/subsys/smss/initheap.c b/reactos/subsys/smss/initheap.c index 7d62ed4919f..87b0eb70451 100644 --- a/reactos/subsys/smss/initheap.c +++ b/reactos/subsys/smss/initheap.c @@ -1,47 +1,47 @@ -/* $Id: init.c 13449 2005-02-06 21:55:07Z ea $ - * - * initenv.c - Create the SM private heap - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ - -#include "smss.h" - -#define NDEBUG -#include - -HANDLE SmpHeap = NULL; - -NTSTATUS -SmCreateHeap(VOID) -{ - /* Create our own heap */ - SmpHeap = RtlCreateHeap(HEAP_GROWABLE, - NULL, - 65536, - 65536, - NULL, - NULL); - return (NULL == SmpHeap) ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS; -} - -/* EOF */ +/* $Id$ + * + * initenv.c - Create the SM private heap + * + * ReactOS Operating System + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ + +#include "smss.h" + +#define NDEBUG +#include + +HANDLE SmpHeap = NULL; + +NTSTATUS +SmCreateHeap(VOID) +{ + /* Create our own heap */ + SmpHeap = RtlCreateHeap(HEAP_GROWABLE, + NULL, + 65536, + 65536, + NULL, + NULL); + return (NULL == SmpHeap) ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/subsys/smss/initmv.c b/reactos/subsys/smss/initmv.c index aa78ea5e187..d4e132334b5 100644 --- a/reactos/subsys/smss/initmv.c +++ b/reactos/subsys/smss/initmv.c @@ -1,44 +1,52 @@ -/* $Id: init.c 13449 2005-02-06 21:55:07Z ea $ - * - * initmv.c - Process the file rename list - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ - -#include "smss.h" - -#define NDEBUG -#include - -NTSTATUS -SmProcessFileRenameList(VOID) -{ - DPRINT("SmProcessFileRenameList() called\n"); - - /* FIXME: implement it! */ - - DPRINT("SmProcessFileRenameList() done\n"); - - return(STATUS_SUCCESS); -} - -/* EOF */ +/* $Id$ + * + * initmv.c - Process the file rename list + * + * ReactOS Operating System + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ + + +#include "smss.h" + +#define NDEBUG +#include + +NTSTATUS +SmProcessFileRenameList(VOID) +{ + DPRINT("SmProcessFileRenameList() called\n"); + + /* FIXME: implement it! */ +/* + * open HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\FileRenameOperations + * for each item in its value + * clone the old file in the new name, + * delete the source. + * + */ + + DPRINT("SmProcessFileRenameList() done\n"); + + return(STATUS_SUCCESS); +} + +/* EOF */ diff --git a/reactos/subsys/smss/initobdir.c b/reactos/subsys/smss/initobdir.c index 0a1c6ad558e..1eb45a0d0ae 100644 --- a/reactos/subsys/smss/initobdir.c +++ b/reactos/subsys/smss/initobdir.c @@ -1,91 +1,91 @@ -/* $Id: init.c 13449 2005-02-06 21:55:07Z ea $ - * - * initobdir.c - Session Manager object directories - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ -#include "smss.h" - -#define NDEBUG -#include - -static NTSTATUS STDCALL -SmpObjectDirectoryQueryRoutine(PWSTR ValueName, - ULONG ValueType, - PVOID ValueData, - ULONG ValueLength, - PVOID Context, - PVOID EntryContext) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING UnicodeString; - HANDLE WindowsDirectory; - NTSTATUS Status = STATUS_SUCCESS; - -#ifndef NDEBUG - DbgPrint("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength); - DbgPrint("ValueData '%S'\n", (PWSTR)ValueData); -#endif - if (ValueType != REG_SZ) - { - return(STATUS_SUCCESS); - } - - RtlInitUnicodeString(&UnicodeString, - (PWSTR)ValueData); - - InitializeObjectAttributes(&ObjectAttributes, - &UnicodeString, - 0, - NULL, - NULL); - - Status = ZwCreateDirectoryObject(&WindowsDirectory, - 0, - &ObjectAttributes); - - return(Status); -} - - -NTSTATUS -SmCreateObjectDirectories(VOID) -{ - RTL_QUERY_REGISTRY_TABLE QueryTable[2]; - NTSTATUS Status; - - RtlZeroMemory(&QueryTable, - sizeof(QueryTable)); - - QueryTable[0].Name = L"ObjectDirectories"; - QueryTable[0].QueryRoutine = SmpObjectDirectoryQueryRoutine; - - Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, - SM_REGISTRY_ROOT_NAME, - QueryTable, - NULL, - NULL); - - return(Status); -} - -/* EOF */ +/* $Id$ + * + * initobdir.c - Session Manager object directories + * + * ReactOS Operating System + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ +#include "smss.h" + +#define NDEBUG +#include + +static NTSTATUS STDCALL +SmpObjectDirectoryQueryRoutine(PWSTR ValueName, + ULONG ValueType, + PVOID ValueData, + ULONG ValueLength, + PVOID Context, + PVOID EntryContext) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING UnicodeString; + HANDLE WindowsDirectory; + NTSTATUS Status = STATUS_SUCCESS; + +#ifndef NDEBUG + DbgPrint("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength); + DbgPrint("ValueData '%S'\n", (PWSTR)ValueData); +#endif + if (ValueType != REG_SZ) + { + return(STATUS_SUCCESS); + } + + RtlInitUnicodeString(&UnicodeString, + (PWSTR)ValueData); + + InitializeObjectAttributes(&ObjectAttributes, + &UnicodeString, + 0, + NULL, + NULL); + + Status = ZwCreateDirectoryObject(&WindowsDirectory, + 0, + &ObjectAttributes); + + return(Status); +} + + +NTSTATUS +SmCreateObjectDirectories(VOID) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[2]; + NTSTATUS Status; + + RtlZeroMemory(&QueryTable, + sizeof(QueryTable)); + + QueryTable[0].Name = L"ObjectDirectories"; + QueryTable[0].QueryRoutine = SmpObjectDirectoryQueryRoutine; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, + SM_REGISTRY_ROOT_NAME, + QueryTable, + NULL, + NULL); + + return(Status); +} + +/* EOF */ diff --git a/reactos/subsys/smss/initpage.c b/reactos/subsys/smss/initpage.c index 69d672e21b7..ec0533e48aa 100644 --- a/reactos/subsys/smss/initpage.c +++ b/reactos/subsys/smss/initpage.c @@ -1,127 +1,127 @@ -/* $Id: init.c 13449 2005-02-06 21:55:07Z ea $ - * - * initpage.c - - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ -#include "smss.h" -#include -#include - -#define NDEBUG -#include - -static NTSTATUS STDCALL -SmpPagingFilesQueryRoutine(PWSTR ValueName, - ULONG ValueType, - PVOID ValueData, - ULONG ValueLength, - PVOID Context, - PVOID EntryContext) -{ - UNICODE_STRING FileName; - LARGE_INTEGER InitialSize; - LARGE_INTEGER MaximumSize; - NTSTATUS Status; - LPWSTR p; - - DPRINT("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength); - DPRINT("ValueData '%S'\n", (PWSTR)ValueData); - - if (ValueType != REG_SZ) - { - return(STATUS_SUCCESS); - } - - /* - * Format: "[ [ ]]" - */ - if ((p = wcschr(ValueData, ' ')) != NULL) - { - *p = L'\0'; - InitialSize.QuadPart = wcstoul(p + 1, &p, 0) * 256 * 4096; - if (*p == ' ') - { - MaximumSize.QuadPart = wcstoul(p + 1, NULL, 0) * 256 * 4096; - } - else - MaximumSize = InitialSize; - } - else - { - InitialSize.QuadPart = 50 * 4096; - MaximumSize.QuadPart = 80 * 4096; - } - - if (!RtlDosPathNameToNtPathName_U ((LPWSTR)ValueData, - &FileName, - NULL, - NULL)) - { - return (STATUS_SUCCESS); - } - - DPRINT("SMSS: Created paging file %wZ with size %dKB\n", - &FileName, InitialSize.QuadPart / 1024); - Status = NtCreatePagingFile(&FileName, - &InitialSize, - &MaximumSize, - 0); - - RtlFreeUnicodeString(&FileName); - - return(STATUS_SUCCESS); -} - - -NTSTATUS -SmCreatePagingFiles(VOID) -{ - RTL_QUERY_REGISTRY_TABLE QueryTable[2]; - NTSTATUS Status; - - DPRINT("SM: creating system paging files\n"); - /* - * Disable paging file on MiniNT/Live CD. - */ - if (RtlCheckRegistryKey(RTL_REGISTRY_CONTROL, L"MiniNT") == STATUS_SUCCESS) - { - return STATUS_SUCCESS; - } - - RtlZeroMemory(&QueryTable, - sizeof(QueryTable)); - - QueryTable[0].Name = L"PagingFiles"; - QueryTable[0].QueryRoutine = SmpPagingFilesQueryRoutine; - - Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, - L"\\Session Manager\\Memory Management", - QueryTable, - NULL, - NULL); - - return(Status); -} - - -/* EOF */ +/* $Id$ + * + * initpage.c - + * + * ReactOS Operating System + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ +#include "smss.h" +#include +#include + +#define NDEBUG +#include + +static NTSTATUS STDCALL +SmpPagingFilesQueryRoutine(PWSTR ValueName, + ULONG ValueType, + PVOID ValueData, + ULONG ValueLength, + PVOID Context, + PVOID EntryContext) +{ + UNICODE_STRING FileName; + LARGE_INTEGER InitialSize; + LARGE_INTEGER MaximumSize; + NTSTATUS Status; + LPWSTR p; + + DPRINT("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength); + DPRINT("ValueData '%S'\n", (PWSTR)ValueData); + + if (ValueType != REG_SZ) + { + return(STATUS_SUCCESS); + } + + /* + * Format: "[ [ ]]" + */ + if ((p = wcschr(ValueData, ' ')) != NULL) + { + *p = L'\0'; + InitialSize.QuadPart = wcstoul(p + 1, &p, 0) * 256 * 4096; + if (*p == ' ') + { + MaximumSize.QuadPart = wcstoul(p + 1, NULL, 0) * 256 * 4096; + } + else + MaximumSize = InitialSize; + } + else + { + InitialSize.QuadPart = 50 * 4096; + MaximumSize.QuadPart = 80 * 4096; + } + + if (!RtlDosPathNameToNtPathName_U ((LPWSTR)ValueData, + &FileName, + NULL, + NULL)) + { + return (STATUS_SUCCESS); + } + + DPRINT("SMSS: Created paging file %wZ with size %dKB\n", + &FileName, InitialSize.QuadPart / 1024); + Status = NtCreatePagingFile(&FileName, + &InitialSize, + &MaximumSize, + 0); + + RtlFreeUnicodeString(&FileName); + + return(STATUS_SUCCESS); +} + + +NTSTATUS +SmCreatePagingFiles(VOID) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[2]; + NTSTATUS Status; + + DPRINT("SM: creating system paging files\n"); + /* + * Disable paging file on MiniNT/Live CD. + */ + if (RtlCheckRegistryKey(RTL_REGISTRY_CONTROL, L"MiniNT") == STATUS_SUCCESS) + { + return STATUS_SUCCESS; + } + + RtlZeroMemory(&QueryTable, + sizeof(QueryTable)); + + QueryTable[0].Name = L"PagingFiles"; + QueryTable[0].QueryRoutine = SmpPagingFilesQueryRoutine; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, + L"\\Session Manager\\Memory Management", + QueryTable, + NULL, + NULL); + + return(Status); +} + + +/* EOF */ diff --git a/reactos/subsys/smss/initreg.c b/reactos/subsys/smss/initreg.c index 76ab72014c7..4d62827fe40 100644 --- a/reactos/subsys/smss/initreg.c +++ b/reactos/subsys/smss/initreg.c @@ -1,41 +1,41 @@ -/* $Id: init.c 13449 2005-02-06 21:55:07Z ea $ - * - * initenv.c - Hive loading - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ - -#include "smss.h" - -#define NDEBUG -#include - -NTSTATUS -SmInitializeRegistry(VOID) -{ - DPRINT("SM: %s: initializing registry\n", __FUNCTION__); - - /* Load remaining registry hives */ - return NtInitializeRegistry(FALSE); -} - -/* EOF */ +/* $Id$ + * + * initenv.c - Hive loading + * + * ReactOS Operating System + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ + +#include "smss.h" + +#define NDEBUG +#include + +NTSTATUS +SmInitializeRegistry(VOID) +{ + DPRINT("SM: %s: initializing registry\n", __FUNCTION__); + + /* Load remaining registry hives */ + return NtInitializeRegistry(FALSE); +} + +/* EOF */ diff --git a/reactos/subsys/smss/initrun.c b/reactos/subsys/smss/initrun.c index 1c0ecdc01bc..5b59db9db5a 100644 --- a/reactos/subsys/smss/initrun.c +++ b/reactos/subsys/smss/initrun.c @@ -1,151 +1,153 @@ -/* $Id: init.c 13449 2005-02-06 21:55:07Z ea $ - * - * initrun.c - Run all programs in the boot execution list - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ - -#include "smss.h" - -#define NDEBUG -#include - -HANDLE Children[2] = {0, 0}; /* csrss, winlogon */ - - -/********************************************************************** - * SmpRunBootAppsQueryRoutine/6 - */ -static NTSTATUS STDCALL -SmpRunBootAppsQueryRoutine(PWSTR ValueName, - ULONG ValueType, - PVOID ValueData, - ULONG ValueLength, - PVOID Context, - PVOID EntryContext) -{ - WCHAR Description [MAX_PATH]; - WCHAR ImageName [MAX_PATH]; - WCHAR ImagePath [MAX_PATH]; - WCHAR CommandLine [MAX_PATH]; - PWSTR p1, p2; - ULONG len; - NTSTATUS Status; - - DPRINT("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength); - DPRINT("ValueData '%S'\n", (PWSTR)ValueData); - - if (ValueType != REG_SZ) - { - return(STATUS_SUCCESS); - } - - /* Extract the description */ - p1 = wcschr((PWSTR)ValueData, L' '); - len = p1 - (PWSTR)ValueData; - memcpy(Description,ValueData, len * sizeof(WCHAR)); - Description[len] = 0; - - /* Extract the image name */ - p1++; - p2 = wcschr(p1, L' '); - if (p2 != NULL) - len = p2 - p1; - else - len = wcslen(p1); - memcpy(ImageName, p1, len * sizeof(WCHAR)); - ImageName[len] = 0; - - /* Extract the command line */ - if (p2 == NULL) - { - CommandLine[0] = 0; - } - else - { - p2++; - wcscpy(CommandLine, p2); - } - - DPRINT("Running %S...\n", Description); - DPRINT("ImageName: '%S'\n", ImageName); - DPRINT("CommandLine: '%S'\n", CommandLine); - - /* initialize executable path */ - wcscpy(ImagePath, L"\\SystemRoot\\system32\\"); - wcscat(ImagePath, ImageName); - wcscat(ImagePath, L".exe"); - - /* Create NT process */ - Status = SmCreateUserProcess (ImagePath, - CommandLine, - TRUE, /* wait */ - NULL, - TRUE, /* terminate */ - NULL); - - return(STATUS_SUCCESS); -} - - -/********************************************************************** - * SmRunBootApplications/0 - * - * DESCRIPTION - * - * Run native applications listed in the registry. - * - * Key: - * \Registry\Machine\SYSTEM\CurrentControlSet\Control\Session Manager - * - * Value (format: " ": - * BootExecute = "autocheck autochk *" - */ -NTSTATUS -SmRunBootApplications(VOID) -{ - RTL_QUERY_REGISTRY_TABLE QueryTable[2]; - NTSTATUS Status; - - RtlZeroMemory(&QueryTable, - sizeof(QueryTable)); - - QueryTable[0].Name = L"BootExecute"; - QueryTable[0].QueryRoutine = SmpRunBootAppsQueryRoutine; - - Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, - L"\\Session Manager", - QueryTable, - NULL, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("%s: RtlQueryRegistryValues() failed! (Status %lx)\n", - __FUNCTION__, - Status); - } - - return(Status); -} - - -/* EOF */ +/* $Id$ + * + * initrun.c - Run all programs in the boot execution list + * + * ReactOS Operating System + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ + +#include "smss.h" + +#define NDEBUG +#include + +//HANDLE Children[2] = {0, 0}; /* csrss, winlogon */ + + +/********************************************************************** + * SmpRunBootAppsQueryRoutine/6 + */ +static NTSTATUS STDCALL +SmpRunBootAppsQueryRoutine(PWSTR ValueName, + ULONG ValueType, + PVOID ValueData, + ULONG ValueLength, + PVOID Context, + PVOID EntryContext) +{ + WCHAR Description [MAX_PATH]; + WCHAR ImageName [MAX_PATH]; + WCHAR ImagePath [MAX_PATH]; + WCHAR CommandLine [MAX_PATH]; + PWSTR p1, p2; + ULONG len; + NTSTATUS Status; + + DPRINT("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength); + DPRINT("ValueData '%S'\n", (PWSTR)ValueData); + + if (ValueType != REG_SZ) + { + return(STATUS_SUCCESS); + } + + /* Extract the description */ + p1 = wcschr((PWSTR)ValueData, L' '); + len = p1 - (PWSTR)ValueData; + memcpy(Description,ValueData, len * sizeof(WCHAR)); + Description[len] = 0; + + /* Extract the image name */ + p1++; + p2 = wcschr(p1, L' '); + if (p2 != NULL) + len = p2 - p1; + else + len = wcslen(p1); + memcpy(ImageName, p1, len * sizeof(WCHAR)); + ImageName[len] = 0; + + /* Extract the command line */ + if (p2 == NULL) + { + CommandLine[0] = 0; + } + else + { + p2++; + wcscpy(CommandLine, p2); + } + + DPRINT("Running %S...\n", Description); + DPRINT("ImageName: '%S'\n", ImageName); + DPRINT("CommandLine: '%S'\n", CommandLine); + + /* initialize executable path */ + wcscpy(ImagePath, L"\\SystemRoot\\system32\\"); + wcscat(ImagePath, ImageName); + wcscat(ImagePath, L".exe"); + + /* Create NT process */ + Status = SmCreateUserProcess (ImagePath, + CommandLine, + TRUE, /* wait */ + NULL, NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SM: %s: running '$S' failed (Status=0x%08lx)\n", + __FUNCTION__, Status); + } + return(STATUS_SUCCESS); +} + + +/********************************************************************** + * SmRunBootApplications/0 + * + * DESCRIPTION + * + * Run native applications listed in the registry. + * + * Key: + * \Registry\Machine\SYSTEM\CurrentControlSet\Control\Session Manager + * + * Value (format: " ": + * BootExecute = "autocheck autochk *" + */ +NTSTATUS +SmRunBootApplications(VOID) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[2]; + NTSTATUS Status; + + RtlZeroMemory(&QueryTable, + sizeof(QueryTable)); + + QueryTable[0].Name = L"BootExecute"; + QueryTable[0].QueryRoutine = SmpRunBootAppsQueryRoutine; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, + L"\\Session Manager", + QueryTable, + NULL, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("%s: RtlQueryRegistryValues() failed! (Status %lx)\n", + __FUNCTION__, + Status); + } + + return(Status); +} + + +/* EOF */ diff --git a/reactos/subsys/smss/initss.c b/reactos/subsys/smss/initss.c index 464cfe6d689..0c2f338ffa8 100644 --- a/reactos/subsys/smss/initss.c +++ b/reactos/subsys/smss/initss.c @@ -1,202 +1,219 @@ -/* $Id: init.c 13449 2005-02-06 21:55:07Z ea $ - * - * initss.c - Load the subsystems - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ - - -#include "smss.h" - -#include - -#define NDEBUG -#include - -/* SM handle for its own \SmApiPort */ -HANDLE hSmApiPort = (HANDLE) 0; - - -/* TODO: - * - * a) look if a special option is set for smss.exe in - * HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options - */ - -/********************************************************************** - * SmpRegisterSmss/0 - * - * DESCRIPTION - * Make smss register with itself for IMAGE_SUBSYSTEM_NATIVE - * (programmatically). This also opens hSmApiPort to be used - * in loading required subsystems. - */ - -static NTSTATUS -SmpRegisterSmss(VOID) -{ - NTSTATUS Status = STATUS_SUCCESS; - UNICODE_STRING SbApiPortName = {0,0,NULL}; - - - DPRINT("SM: %s called\n",__FUNCTION__); - - RtlInitUnicodeString (& SbApiPortName, L""); - Status = SmConnectApiPort(& SbApiPortName, - (HANDLE) -1, /* SM has no SB port */ - IMAGE_SUBSYSTEM_NATIVE, - & hSmApiPort); - if(!NT_SUCCESS(Status)) - { - DPRINT("SM: %s: SMLIB!SmConnectApiPort failed (Status=0x%08lx)\n", - __FUNCTION__,Status); - return Status; - } - DPRINT("SM self registered\n"); - /* - * Note that you don't need to call complete session - * because connection handling code autocompletes - * the client structure for IMAGE_SUBSYSTEM_NATIVE. - */ - return Status; -} - - -/********************************************************************** - * SmpLoadKernelModeSubsystem/0 - */ -static NTSTATUS -SmpLoadKernelModeSubsystem (VOID) -{ - NTSTATUS Status = STATUS_SUCCESS; - WCHAR Data [MAX_PATH + 1]; - ULONG DataLength = sizeof Data; - ULONG DataType = 0; - - - DPRINT("SM: %s called\n", __FUNCTION__); - - Status = SmLookupSubsystem (L"Kmode", - Data, - & DataLength, - & DataType, - TRUE); - if((STATUS_SUCCESS == Status) && (DataLength > sizeof Data[0])) - { - WCHAR ImagePath [MAX_PATH + 1] = {0}; - SYSTEM_LOAD_AND_CALL_IMAGE ImageInfo; - - wcscpy (ImagePath, L"\\??\\"); - wcscat (ImagePath, Data); - RtlZeroMemory (& ImageInfo, sizeof ImageInfo); - RtlInitUnicodeString (& ImageInfo.ModuleName, ImagePath); - Status = NtSetSystemInformation(SystemLoadAndCallImage, - & ImageInfo, - sizeof ImageInfo); - if(!NT_SUCCESS(Status)) - { - DPRINT("SM: %s: loading Kmode failed (Status=0x%08lx)\n", - __FUNCTION__, Status); - } - } - return Status; -} - -/********************************************************************** - * SmpLoadRequiredSubsystems/0 - */ -static NTSTATUS -SmpLoadRequiredSubsystems (VOID) -{ - NTSTATUS Status = STATUS_SUCCESS; - WCHAR Data [MAX_PATH + 1]; - ULONG DataLength = sizeof Data; - ULONG DataType = 0; - - - DPRINT("SM: %s called\n", __FUNCTION__); - - RtlZeroMemory (Data, DataLength); - Status = SmLookupSubsystem (L"Required", - Data, - & DataLength, - & DataType, - FALSE); - if((STATUS_SUCCESS == Status) && (DataLength > sizeof Data[0])) - { - PWCHAR Name = NULL; - ULONG Offset = 0; - - for (Name = Data; (Offset < DataLength); ) - { - if(L'\0' != *Name) - { - UNICODE_STRING Program; - - /* Run the current program */ - RtlInitUnicodeString (& Program, Name); - Status = SmExecuteProgram (hSmApiPort, & Program); - if(!NT_SUCCESS(Status)) - { - DPRINT1("SM: %s failed to run '%S' program (Status=0x%08lx)\n", - __FUNCTION__, Name, Status); - } - /* Look for the next program */ - while ((L'\0' != *Name) && (Offset < DataLength)) - { - ++ Name; - ++ Offset; - } - } - ++ Name; - ++ Offset; - } - } - - return Status; -} - -/********************************************************************** - * SmLoadSubsystems/0 - */ -NTSTATUS -SmLoadSubsystems(VOID) -{ - NTSTATUS Status = STATUS_SUCCESS; - - - DPRINT("SM: loading subsystems\n"); - - /* SM self registers */ - Status = SmpRegisterSmss(); - if(!NT_SUCCESS(Status)) return Status; - /* Load Kmode subsystem (aka win32k.sys) */ - Status = SmpLoadKernelModeSubsystem(); - if(!NT_SUCCESS(Status)) return Status; - /* Load Required subsystems (Debug Windows) */ - Status = SmpLoadRequiredSubsystems(); - if(!NT_SUCCESS(Status)) return Status; - /* done */ - return Status; -} - -/* EOF */ +/* $Id$ + * + * initss.c - Load the subsystems + * + * ReactOS Operating System + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ + + +#include "smss.h" + +#include + +#define NDEBUG +#include + +/* SM handle for its own \SmApiPort */ +HANDLE hSmApiPort = (HANDLE) 0; + + +/* TODO: + * + * a) look if a special option is set for smss.exe in + * HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options + */ + +/********************************************************************** + * SmpRegisterSmss/0 + * + * DESCRIPTION + * Make smss register with itself for IMAGE_SUBSYSTEM_NATIVE + * (programmatically). This also opens hSmApiPort to be used + * in loading required subsystems. + */ + +static NTSTATUS +SmpRegisterSmss(VOID) +{ + NTSTATUS Status = STATUS_SUCCESS; + RTL_PROCESS_INFO ProcessInfo; + + + DPRINT("SM: %s called\n",__FUNCTION__); + + RtlZeroMemory (& ProcessInfo, sizeof ProcessInfo); + ProcessInfo.Size = sizeof ProcessInfo; + ProcessInfo.ProcessHandle = (HANDLE) SmSsProcessId; + ProcessInfo.ClientId.UniqueProcess = (HANDLE) SmSsProcessId; + DPRINT("SM: %s: ProcessInfo.ProcessHandle=%lx\n", + __FUNCTION__,ProcessInfo.ProcessHandle); + Status = SmCreateClient (& ProcessInfo, L"Session Manager"); + if (NT_SUCCESS(Status)) + { + UNICODE_STRING SbApiPortName = {0,0,NULL}; + + RtlInitUnicodeString (& SbApiPortName, L""); + Status = SmConnectApiPort(& SbApiPortName, + (HANDLE) -1, /* SM has no SB port */ + IMAGE_SUBSYSTEM_NATIVE, + & hSmApiPort); + if(!NT_SUCCESS(Status)) + { + DPRINT("SM: %s: SMLIB!SmConnectApiPort failed (Status=0x%08lx)\n", + __FUNCTION__,Status); + return Status; + } + DPRINT("SM self registered\n"); + } + else + { + DPRINT1("SM: %s: SmCreateClient failed (Status=0x%08lx)\n", + __FUNCTION__, Status); + } + /* + * Note that you don't need to call complete session + * because connection handling code autocompletes + * the client structure for IMAGE_SUBSYSTEM_NATIVE. + */ + return Status; +} + + +/********************************************************************** + * SmpLoadKernelModeSubsystem/0 + */ +static NTSTATUS +SmpLoadKernelModeSubsystem (VOID) +{ + NTSTATUS Status = STATUS_SUCCESS; + WCHAR Data [MAX_PATH + 1]; + ULONG DataLength = sizeof Data; + ULONG DataType = 0; + + + DPRINT("SM: %s called\n", __FUNCTION__); + + Status = SmLookupSubsystem (L"Kmode", + Data, + & DataLength, + & DataType, + TRUE); + if((STATUS_SUCCESS == Status) && (DataLength > sizeof Data[0])) + { + WCHAR ImagePath [MAX_PATH + 1] = {0}; + SYSTEM_LOAD_AND_CALL_IMAGE ImageInfo; + + wcscpy (ImagePath, L"\\??\\"); + wcscat (ImagePath, Data); + RtlZeroMemory (& ImageInfo, sizeof ImageInfo); + RtlInitUnicodeString (& ImageInfo.ModuleName, ImagePath); + Status = NtSetSystemInformation(SystemLoadAndCallImage, + & ImageInfo, + sizeof ImageInfo); + if(!NT_SUCCESS(Status)) + { + DPRINT("SM: %s: loading Kmode failed (Status=0x%08lx)\n", + __FUNCTION__, Status); + } + } + return Status; +} + +/********************************************************************** + * SmpLoadRequiredSubsystems/0 + */ +static NTSTATUS +SmpLoadRequiredSubsystems (VOID) +{ + NTSTATUS Status = STATUS_SUCCESS; + WCHAR Data [MAX_PATH + 1]; + ULONG DataLength = sizeof Data; + ULONG DataType = 0; + + + DPRINT("SM: %s called\n", __FUNCTION__); + + RtlZeroMemory (Data, DataLength); + Status = SmLookupSubsystem (L"Required", + Data, + & DataLength, + & DataType, + FALSE); + if((STATUS_SUCCESS == Status) && (DataLength > sizeof Data[0])) + { + PWCHAR Name = NULL; + ULONG Offset = 0; + + for (Name = Data; (Offset < DataLength); ) + { + if(L'\0' != *Name) + { + UNICODE_STRING Program; + + /* Run the current program */ + RtlInitUnicodeString (& Program, Name); + Status = SmExecuteProgram (hSmApiPort, & Program); + if(!NT_SUCCESS(Status)) + { + DPRINT1("SM: %s failed to run '%S' program (Status=0x%08lx)\n", + __FUNCTION__, Name, Status); + } + /* Look for the next program */ + while ((L'\0' != *Name) && (Offset < DataLength)) + { + ++ Name; + ++ Offset; + } + } + ++ Name; + ++ Offset; + } + } + + return Status; +} + +/********************************************************************** + * SmLoadSubsystems/0 + */ +NTSTATUS +SmLoadSubsystems(VOID) +{ + NTSTATUS Status = STATUS_SUCCESS; + + + DPRINT("SM: loading subsystems\n"); + + /* SM self registers */ + Status = SmpRegisterSmss(); + if(!NT_SUCCESS(Status)) return Status; + /* Load Kmode subsystem (aka win32k.sys) */ + Status = SmpLoadKernelModeSubsystem(); + if(!NT_SUCCESS(Status)) return Status; + /* Load Required subsystems (Debug Windows) */ + Status = SmpLoadRequiredSubsystems(); + if(!NT_SUCCESS(Status)) return Status; + /* done */ + return Status; +} + +/* EOF */ diff --git a/reactos/subsys/smss/initwkdll.c b/reactos/subsys/smss/initwkdll.c index df35724ea27..237c25e7b43 100644 --- a/reactos/subsys/smss/initwkdll.c +++ b/reactos/subsys/smss/initwkdll.c @@ -1,254 +1,254 @@ -/* $Id: init.c 13449 2005-02-06 21:55:07Z ea $ - * - * initwkdll.c - Load the well known DLLs - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ - -#include "smss.h" - -#define NDEBUG -#include - -static NTSTATUS STDCALL -SmpKnownDllsQueryRoutine(PWSTR ValueName, - ULONG ValueType, - PVOID ValueData, - ULONG ValueLength, - PVOID Context, - PVOID EntryContext) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - UNICODE_STRING ImageName; - HANDLE FileHandle; - HANDLE SectionHandle; - NTSTATUS Status; - - DPRINT("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength); - DPRINT("ValueData '%S' Context %p EntryContext %p\n", (PWSTR)ValueData, Context, EntryContext); - - /* Ignore the 'DllDirectory' value */ - if (!_wcsicmp(ValueName, L"DllDirectory")) - return STATUS_SUCCESS; - - /* Open the DLL image file */ - RtlInitUnicodeString(&ImageName, - ValueData); - InitializeObjectAttributes(&ObjectAttributes, - &ImageName, - OBJ_CASE_INSENSITIVE, - (HANDLE)Context, - NULL); - Status = NtOpenFile(&FileHandle, - SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); - return STATUS_SUCCESS; - } - - DPRINT("Opened file %wZ successfully\n", &ImageName); - - /* Check for valid image checksum */ - Status = LdrVerifyImageMatchesChecksum (FileHandle, - 0, - 0, - 0); - if (Status == STATUS_IMAGE_CHECKSUM_MISMATCH) - { - /* Raise a hard error (crash the system/BSOD) */ - NtRaiseHardError (Status, - 0, - 0, - 0, - 0, - 0); - } - else if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to check the image checksum\n"); - - NtClose(SectionHandle); - NtClose(FileHandle); - - return STATUS_SUCCESS; - } - - InitializeObjectAttributes(&ObjectAttributes, - &ImageName, - OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, - (HANDLE)EntryContext, - NULL); - Status = NtCreateSection(&SectionHandle, - SECTION_ALL_ACCESS, - &ObjectAttributes, - NULL, - PAGE_EXECUTE, - SEC_IMAGE, - FileHandle); - if (NT_SUCCESS(Status)) - { - DPRINT("Created section successfully\n"); - NtClose(SectionHandle); - } - - NtClose(FileHandle); - - return STATUS_SUCCESS; -} - - -NTSTATUS -SmLoadKnownDlls(VOID) -{ - RTL_QUERY_REGISTRY_TABLE QueryTable[2]; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK IoStatusBlock; - UNICODE_STRING DllDosPath; - UNICODE_STRING DllNtPath; - UNICODE_STRING Name; - HANDLE ObjectDirHandle; - HANDLE FileDirHandle; - HANDLE SymlinkHandle; - NTSTATUS Status; - - - DPRINT("SM: loading well-known DLLs\n"); - - DPRINT("SmLoadKnownDlls() called\n"); - - /* Create 'KnownDlls' object directory */ - RtlInitUnicodeString(&Name, - L"\\KnownDlls"); - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF, - NULL, - NULL); - Status = NtCreateDirectoryObject(&ObjectDirHandle, - DIRECTORY_ALL_ACCESS, - &ObjectAttributes); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtCreateDirectoryObject() failed (Status %lx)\n", Status); - return Status; - } - - RtlInitUnicodeString(&DllDosPath, NULL); - - RtlZeroMemory(&QueryTable, - sizeof(QueryTable)); - - QueryTable[0].Name = L"DllDirectory"; - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; - QueryTable[0].EntryContext = &DllDosPath; - - Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, - L"\\Session Manager\\KnownDlls", - QueryTable, - NULL, - SmSystemEnvironment); - if (!NT_SUCCESS(Status)) - { - DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); - return Status; - } - - DPRINT("DllDosPath: '%wZ'\n", &DllDosPath); - - if (!RtlDosPathNameToNtPathName_U(DllDosPath.Buffer, - &DllNtPath, - NULL, - NULL)) - { - DPRINT1("RtlDosPathNameToNtPathName_U() failed\n"); - return STATUS_OBJECT_NAME_INVALID; - } - - DPRINT("DllNtPath: '%wZ'\n", &DllNtPath); - - /* Open the dll path directory */ - InitializeObjectAttributes(&ObjectAttributes, - &DllNtPath, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = NtOpenFile(&FileDirHandle, - SYNCHRONIZE | FILE_READ_DATA, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtOpenFile(%wZ) failed (Status %lx)\n", &DllNtPath, Status); - return Status; - } - - /* Link 'KnownDllPath' the dll path directory */ - RtlInitUnicodeString(&Name, - L"KnownDllPath"); - InitializeObjectAttributes(&ObjectAttributes, - &Name, - OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF, - ObjectDirHandle, - NULL); - Status = NtCreateSymbolicLinkObject(&SymlinkHandle, - SYMBOLIC_LINK_ALL_ACCESS, - &ObjectAttributes, - &DllDosPath); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtCreateSymbolicLink() failed (Status %lx)\n", Status); - return Status; - } - - NtClose(SymlinkHandle); - - RtlZeroMemory(&QueryTable, - sizeof(QueryTable)); - - QueryTable[0].QueryRoutine = SmpKnownDllsQueryRoutine; - QueryTable[0].EntryContext = ObjectDirHandle; - - Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, - L"\\Session Manager\\KnownDlls", - QueryTable, - (PVOID)FileDirHandle, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); - } - - DPRINT("SmLoadKnownDlls() done\n"); - - return Status; -} - - -/* EOF */ +/* $Id$ + * + * initwkdll.c - Load the well known DLLs + * + * ReactOS Operating System + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ + +#include "smss.h" + +#define NDEBUG +#include + +static NTSTATUS STDCALL +SmpKnownDllsQueryRoutine(PWSTR ValueName, + ULONG ValueType, + PVOID ValueData, + ULONG ValueLength, + PVOID Context, + PVOID EntryContext) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING ImageName; + HANDLE FileHandle; + HANDLE SectionHandle; + NTSTATUS Status; + + DPRINT("ValueName '%S' Type %lu Length %lu\n", ValueName, ValueType, ValueLength); + DPRINT("ValueData '%S' Context %p EntryContext %p\n", (PWSTR)ValueData, Context, EntryContext); + + /* Ignore the 'DllDirectory' value */ + if (!_wcsicmp(ValueName, L"DllDirectory")) + return STATUS_SUCCESS; + + /* Open the DLL image file */ + RtlInitUnicodeString(&ImageName, + ValueData); + InitializeObjectAttributes(&ObjectAttributes, + &ImageName, + OBJ_CASE_INSENSITIVE, + (HANDLE)Context, + NULL); + Status = NtOpenFile(&FileHandle, + SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtOpenFile() failed (Status %lx)\n", Status); + return STATUS_SUCCESS; + } + + DPRINT("Opened file %wZ successfully\n", &ImageName); + + /* Check for valid image checksum */ + Status = LdrVerifyImageMatchesChecksum (FileHandle, + 0, + 0, + 0); + if (Status == STATUS_IMAGE_CHECKSUM_MISMATCH) + { + /* Raise a hard error (crash the system/BSOD) */ + NtRaiseHardError (Status, + 0, + 0, + 0, + 0, + 0); + } + else if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to check the image checksum\n"); + + NtClose(SectionHandle); + NtClose(FileHandle); + + return STATUS_SUCCESS; + } + + InitializeObjectAttributes(&ObjectAttributes, + &ImageName, + OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, + (HANDLE)EntryContext, + NULL); + Status = NtCreateSection(&SectionHandle, + SECTION_ALL_ACCESS, + &ObjectAttributes, + NULL, + PAGE_EXECUTE, + SEC_IMAGE, + FileHandle); + if (NT_SUCCESS(Status)) + { + DPRINT("Created section successfully\n"); + NtClose(SectionHandle); + } + + NtClose(FileHandle); + + return STATUS_SUCCESS; +} + + +NTSTATUS +SmLoadKnownDlls(VOID) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[2]; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING DllDosPath; + UNICODE_STRING DllNtPath; + UNICODE_STRING Name; + HANDLE ObjectDirHandle; + HANDLE FileDirHandle; + HANDLE SymlinkHandle; + NTSTATUS Status; + + + DPRINT("SM: loading well-known DLLs\n"); + + DPRINT("SmLoadKnownDlls() called\n"); + + /* Create 'KnownDlls' object directory */ + RtlInitUnicodeString(&Name, + L"\\KnownDlls"); + InitializeObjectAttributes(&ObjectAttributes, + &Name, + OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF, + NULL, + NULL); + Status = NtCreateDirectoryObject(&ObjectDirHandle, + DIRECTORY_ALL_ACCESS, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtCreateDirectoryObject() failed (Status %lx)\n", Status); + return Status; + } + + RtlInitUnicodeString(&DllDosPath, NULL); + + RtlZeroMemory(&QueryTable, + sizeof(QueryTable)); + + QueryTable[0].Name = L"DllDirectory"; + QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + QueryTable[0].EntryContext = &DllDosPath; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, + L"\\Session Manager\\KnownDlls", + QueryTable, + NULL, + SmSystemEnvironment); + if (!NT_SUCCESS(Status)) + { + DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); + return Status; + } + + DPRINT("DllDosPath: '%wZ'\n", &DllDosPath); + + if (!RtlDosPathNameToNtPathName_U(DllDosPath.Buffer, + &DllNtPath, + NULL, + NULL)) + { + DPRINT1("RtlDosPathNameToNtPathName_U() failed\n"); + return STATUS_OBJECT_NAME_INVALID; + } + + DPRINT("DllNtPath: '%wZ'\n", &DllNtPath); + + /* Open the dll path directory */ + InitializeObjectAttributes(&ObjectAttributes, + &DllNtPath, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = NtOpenFile(&FileDirHandle, + SYNCHRONIZE | FILE_READ_DATA, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtOpenFile(%wZ) failed (Status %lx)\n", &DllNtPath, Status); + return Status; + } + + /* Link 'KnownDllPath' the dll path directory */ + RtlInitUnicodeString(&Name, + L"KnownDllPath"); + InitializeObjectAttributes(&ObjectAttributes, + &Name, + OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF, + ObjectDirHandle, + NULL); + Status = NtCreateSymbolicLinkObject(&SymlinkHandle, + SYMBOLIC_LINK_ALL_ACCESS, + &ObjectAttributes, + &DllDosPath); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtCreateSymbolicLink() failed (Status %lx)\n", Status); + return Status; + } + + NtClose(SymlinkHandle); + + RtlZeroMemory(&QueryTable, + sizeof(QueryTable)); + + QueryTable[0].QueryRoutine = SmpKnownDllsQueryRoutine; + QueryTable[0].EntryContext = ObjectDirHandle; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, + L"\\Session Manager\\KnownDlls", + QueryTable, + (PVOID)FileDirHandle, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); + } + + DPRINT("SmLoadKnownDlls() done\n"); + + return Status; +} + + +/* EOF */ diff --git a/reactos/subsys/smss/print.c b/reactos/subsys/smss/print.c index fccc3ac37d6..d727e5f4ef1 100644 --- a/reactos/subsys/smss/print.c +++ b/reactos/subsys/smss/print.c @@ -1,56 +1,56 @@ -/* $Id: print.c 12852 2005-01-06 13:58:04Z mf $ - * - * print.c - Print on the blue screen - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ -#define NTOS_MODE_USER -#include - -VOID STDCALL DisplayString(LPCWSTR lpwString) -{ - UNICODE_STRING us; - - RtlInitUnicodeString (&us, lpwString); - ZwDisplayString (&us); -} - -VOID STDCALL PrintString (char* fmt, ...) -{ - char buffer[512]; - va_list ap; - UNICODE_STRING UnicodeString; - ANSI_STRING AnsiString; - - va_start(ap, fmt); - vsprintf(buffer, fmt, ap); - va_end(ap); - - RtlInitAnsiString (&AnsiString, buffer); - RtlAnsiStringToUnicodeString (&UnicodeString, - &AnsiString, - TRUE); - NtDisplayString(&UnicodeString); - RtlFreeUnicodeString (&UnicodeString); -} - -/* EOF */ +/* $Id$ + * + * print.c - Print on the blue screen + * + * ReactOS Operating System + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ +#define NTOS_MODE_USER +#include + +VOID STDCALL DisplayString(LPCWSTR lpwString) +{ + UNICODE_STRING us; + + RtlInitUnicodeString (&us, lpwString); + ZwDisplayString (&us); +} + +VOID STDCALL PrintString (char* fmt, ...) +{ + char buffer[512]; + va_list ap; + UNICODE_STRING UnicodeString; + ANSI_STRING AnsiString; + + va_start(ap, fmt); + vsprintf(buffer, fmt, ap); + va_end(ap); + + RtlInitAnsiString (&AnsiString, buffer); + RtlAnsiStringToUnicodeString (&UnicodeString, + &AnsiString, + TRUE); + NtDisplayString(&UnicodeString); + RtlFreeUnicodeString (&UnicodeString); +} + +/* EOF */ diff --git a/reactos/subsys/smss/smapi.c b/reactos/subsys/smss/smapi.c index ed2979631a8..17e169e2fa0 100644 --- a/reactos/subsys/smss/smapi.c +++ b/reactos/subsys/smss/smapi.c @@ -52,12 +52,13 @@ SmpHandleConnectionRequest (PSM_PORT_MESSAGE Request); #endif /********************************************************************** - * SmpCallback/2 + * SmpCallbackServer/2 * - * The SM calls back a previously connected subsystem process to - * authorizes it to bootstrap (initialize). The SM connects to a - * named LPC port which name was sent in the connection data by the - * candidate subsystem server process. + * DESCRIPTION + * The SM calls back a previously connected subsystem process to + * authorize it to bootstrap (initialize). The SM connects to a + * named LPC port which name was sent in the connection data by + * the candidate subsystem server process. */ static NTSTATUS SmpCallbackServer (PSM_PORT_MESSAGE Request, @@ -72,7 +73,8 @@ SmpCallbackServer (PSM_PORT_MESSAGE Request, DPRINT("SM: %s called\n", __FUNCTION__); - if(IMAGE_SUBSYSTEM_NATIVE == ConnectData->SubSystemId) + if ( (IMAGE_SUBSYSTEM_UNKNOWN == ConnectData->SubSystemId) || + (IMAGE_SUBSYSTEM_NATIVE == ConnectData->SubSystemId)) { DPRINT("SM: %s: we do not need calling back SM!\n", __FUNCTION__); @@ -210,12 +212,10 @@ SmpHandleConnectionRequest (PSM_PORT_MESSAGE Request) { DPRINT("SM: %s: id = %d\n", __FUNCTION__, ConnectData->SubSystemId); /* - * SmCreateClient/2 is called here explicitly to *fail*. - * If it succeeds, there is something wrong in the - * connection request. An environment subsystem *never* - * registers twice. (security issue) + * SmBeginClientInitialization/2 will succeed only if there + * is a candidate client ready. */ - Status = SmCreateClient (Request, & ClientData); + Status = SmBeginClientInitialization (Request, & ClientData); if(STATUS_SUCCESS == Status) { DPRINT("SM: %s: ClientData = 0x%08lx\n", @@ -310,7 +310,7 @@ SmpHandleConnectionRequest (PSM_PORT_MESSAGE Request) * * DECRIPTION * Due to differences in LPC implementation between NT and ROS, - * we need a thread to listen for connection request that + * we need a thread to listen to for connection request that * creates a new thread for each connected port. This is not * necessary in NT LPC, because server side connected ports are * never used to receive requests. diff --git a/reactos/subsys/smss/smapicomp.c b/reactos/subsys/smss/smapicomp.c index 94abeb96ef1..7b8d9efd59b 100644 --- a/reactos/subsys/smss/smapicomp.c +++ b/reactos/subsys/smss/smapicomp.c @@ -1,50 +1,54 @@ -/* $Id: $ - * - * smapicomp.c - SM_API_COMPLETE_SESSION - * - * Reactos Session Manager - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ -#include "smss.h" - -#define NDEBUG -#include - - -/********************************************************************** - * SmCompSes/1 API - */ -SMAPI(SmCompSes) -{ - NTSTATUS Status = STATUS_SUCCESS; - - DPRINT("SM: %s called\n", __FUNCTION__); - - Status = SmCompleteClientInitialization (Request->Header.ClientId.UniqueProcess); - if(!NT_SUCCESS(Status)) - { - Request->SmHeader.Status = STATUS_UNSUCCESSFUL; - } - return Status; -} - - -/* EOF */ +/* $Id$ + * + * smapicomp.c - SM_API_COMPLETE_SESSION + * + * Reactos Session Manager + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ +#include "smss.h" + +#define NDEBUG +#include + + +/********************************************************************** + * SmCompSes/1 API + */ +SMAPI(SmCompSes) +{ + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("SM: %s called\n", __FUNCTION__); + + DPRINT("SM: %s: ClientId.UniqueProcess=%lx\n", + __FUNCTION__, Request->Header.ClientId.UniqueProcess); + Status = SmCompleteClientInitialization ((ULONG) Request->Header.ClientId.UniqueProcess); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SM: %s: NtQueryInformationProcess failed (Status=0x%08lx)\n", + __FUNCTION__, Status); + } + Request->SmHeader.Status = Status; + return STATUS_SUCCESS; +} + + +/* EOF */ diff --git a/reactos/subsys/smss/smapiexec.c b/reactos/subsys/smss/smapiexec.c index f74ac34b3b9..3d185b87794 100644 --- a/reactos/subsys/smss/smapiexec.c +++ b/reactos/subsys/smss/smapiexec.c @@ -1,320 +1,390 @@ -/* $Id$ - * - * smapiexec.c - SM_API_EXECUTE_PROGRAM - * - * Reactos Session Manager - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ -#include "smss.h" - -#define NDEBUG -#include - -/********************************************************************** - * SmCreateUserProcess/5 - * - */ -NTSTATUS STDCALL -SmCreateUserProcess (LPWSTR ImagePath, - LPWSTR CommandLine, - BOOLEAN WaitForIt, - PLARGE_INTEGER Timeout OPTIONAL, - BOOLEAN TerminateIt, - PRTL_PROCESS_INFO UserProcessInfo OPTIONAL - ) -{ - UNICODE_STRING ImagePathString = {0}; - UNICODE_STRING CommandLineString = {0}; - PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL; - RTL_PROCESS_INFO ProcessInfo = {0}; - PRTL_PROCESS_INFO pProcessInfo = & ProcessInfo; - NTSTATUS Status = STATUS_SUCCESS; - - - DPRINT("SM: %s called\n",__FUNCTION__); - - RtlInitUnicodeString (& ImagePathString, ImagePath); - RtlInitUnicodeString (& CommandLineString, CommandLine); - - RtlCreateProcessParameters(& ProcessParameters, - & ImagePathString, - NULL, - NULL, - & CommandLineString, - SmSystemEnvironment, - NULL, - NULL, - NULL, - NULL); - - if(NULL != UserProcessInfo) - { - /* Use caller provided storage */ - pProcessInfo = UserProcessInfo; - } - - Status = RtlCreateUserProcess (& ImagePathString, - OBJ_CASE_INSENSITIVE, - ProcessParameters, - NULL, - NULL, - NULL, - FALSE, - NULL, - NULL, - pProcessInfo); - - RtlDestroyProcessParameters (ProcessParameters); - - if (!NT_SUCCESS(Status)) - { - DPRINT1("SM: %s: Running \"%S\" failed (Status=0x%08lx)\n", - __FUNCTION__, ImagePathString.Buffer, Status); - return Status; - } - - ZwResumeThread(pProcessInfo->ThreadHandle, NULL); - - - /* Wait for process termination */ - if(WaitForIt) - { - NtWaitForSingleObject (pProcessInfo->ProcessHandle, - FALSE, - Timeout); - } - - /* Terminate process */ - if(TerminateIt) - { - NtClose(pProcessInfo->ThreadHandle); - NtClose(pProcessInfo->ProcessHandle); - } - return STATUS_SUCCESS; -} - -/********************************************************************** - * NAME - * SmLookupSubsystem/5 - * - * DESCRIPTION - * Read from the registry key - * \Registry\SYSTEM\CurrentControlSet\Control\Session Manager\Subsystems - * the value which name is Name. - * - * ARGUMENTS - * Name: name of the program to run, that is a value's name in - * the SM registry key Subsystems; - * Data: what the registry gave back for Name; - * DataLength: how much Data the registry returns; - * DataType: what is Data? - * Expand: set it TRUE if you want this function to use the env - * to possibly expand Data before giving it back. - */ -NTSTATUS STDCALL -SmLookupSubsystem (IN PWSTR Name, - IN OUT PWSTR Data, - IN OUT PULONG DataLength, - IN OUT PULONG DataType, - IN BOOLEAN Expand) -{ - NTSTATUS Status = STATUS_SUCCESS; - UNICODE_STRING usKeyName = {0}; - OBJECT_ATTRIBUTES Oa = {0}; - HANDLE hKey = (HANDLE) 0; - - DPRINT("SM: %s(Name='%S') called\n", __FUNCTION__, Name); - /* - * Prepare the key name to scan and - * related object attributes. - */ - RtlInitUnicodeString (& usKeyName, - L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\SubSystems"); - - InitializeObjectAttributes (& Oa, - & usKeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - /* - * Open the key. This MUST NOT fail, if the - * request is for a legitimate subsystem. - */ - Status = NtOpenKey (& hKey, - MAXIMUM_ALLOWED, - & Oa); - if(NT_SUCCESS(Status)) - { - UNICODE_STRING usValueName = {0}; - WCHAR KeyValueInformation [1024] = {L'\0'}; - ULONG ResultLength = 0L; - PKEY_VALUE_PARTIAL_INFORMATION - kvpi = (PKEY_VALUE_PARTIAL_INFORMATION) KeyValueInformation; - - - RtlInitUnicodeString (& usValueName, Name); - Status = NtQueryValueKey (hKey, - & usValueName, - KeyValuePartialInformation, - KeyValueInformation, - sizeof KeyValueInformation, - & ResultLength); - if(NT_SUCCESS(Status)) - { - DPRINT("nkvpi.TitleIndex = %ld\n", kvpi->TitleIndex); - DPRINT("kvpi.Type = %ld\n", kvpi->Type); - DPRINT("kvpi.DataLength = %ld\n", kvpi->DataLength); - - if((NULL != Data) && (NULL != DataLength) && (NULL != DataType)) - { - *DataType = kvpi->Type; - if((Expand) && (REG_EXPAND_SZ == *DataType)) - { - UNICODE_STRING Source; - WCHAR DestinationBuffer [2048] = {0}; - UNICODE_STRING Destination; - ULONG Length = 0; - - DPRINT("SM: %s: value will be expanded\n", __FUNCTION__); - - Source.Length = kvpi->DataLength; - Source.MaximumLength = kvpi->DataLength; - Source.Buffer = (PWCHAR) & kvpi->Data; - - Destination.Length = 0; - Destination.MaximumLength = sizeof DestinationBuffer; - Destination.Buffer = DestinationBuffer; - - Status = RtlExpandEnvironmentStrings_U (SmSystemEnvironment, - & Source, - & Destination, - & Length); - if(NT_SUCCESS(Status)) - { - *DataLength = min(*DataLength, Destination.Length); - RtlCopyMemory (Data, Destination.Buffer, *DataLength); - } - - }else{ - DPRINT("SM: %s: value won't be expanded\n", __FUNCTION__); - *DataLength = min(*DataLength, kvpi->DataLength); - RtlCopyMemory (Data, & kvpi->Data, *DataLength); - } - *DataType = kvpi->Type; - }else{ - DPRINT1("SM: %s: Data or DataLength or DataType is NULL!\n", __FUNCTION__); - Status = STATUS_INVALID_PARAMETER; - } - }else{ - DPRINT1("%s: NtQueryValueKey failed (Status=0x%08lx)\n", __FUNCTION__, Status); - } - NtClose (hKey); - }else{ - DPRINT1("%s: NtOpenKey failed (Status=0x%08lx)\n", __FUNCTION__, Status); - } - return Status; -} - - -/********************************************************************** - * SmExecPgm/1 API - */ -SMAPI(SmExecPgm) -{ - PSM_PORT_MESSAGE_EXECPGM ExecPgm = NULL; - WCHAR Name [SM_EXEXPGM_MAX_LENGTH + 1]; - NTSTATUS Status = STATUS_SUCCESS; - - DPRINT("SM: %s called\n",__FUNCTION__); - - if(NULL == Request) - { - DPRINT1("SM: %s: Request == NULL!\n", __FUNCTION__); - return STATUS_INVALID_PARAMETER; - } - DPRINT("SM: %s called from CID(%lx|%lx)\n", - __FUNCTION__, Request->Header.ClientId.UniqueProcess, - Request->Header.ClientId.UniqueThread); - ExecPgm = & Request->Request.ExecPgm; - /* Check if the name lenght is valid */ - if((ExecPgm->NameLength > 0) && - (ExecPgm->NameLength <= SM_EXEXPGM_MAX_LENGTH) && - TRUE /* TODO: check LPC payload size */) - { - - RtlZeroMemory (Name, sizeof Name); - RtlCopyMemory (Name, - ExecPgm->Name, - (sizeof ExecPgm->Name[0] * ExecPgm->NameLength)); - DPRINT("SM: %s: Name='%S'\n", __FUNCTION__, Name); - /* - * Check if program name is internal - * (Is this correct? Debug is in the registry too) - */ - if(0 == _wcsicmp(L"DEBUG", Name)) - { - /* - * Initialize DBGSS. - * NOTE: probably in early prototypes it was an - * independent process; now it is embedded in the - * SM for performance or security. - */ - Request->SmHeader.Status = SmInitializeDbgSs(); - } - else - { - WCHAR Data [MAX_PATH + 1] = {0}; - ULONG DataLength = sizeof Data; - ULONG DataType = REG_EXPAND_SZ; - - /* Lookup Name in the registry */ - Status = SmLookupSubsystem (Name, - Data, - & DataLength, - & DataType, - TRUE); /* expand */ - if(NT_SUCCESS(Status)) - { - WCHAR ImagePath [MAX_PATH + 1] = {0}; - - wcscpy (ImagePath, L"\\??\\"); - wcscat (ImagePath, Data); - - /* Create native process */ - Request->SmHeader.Status = SmCreateUserProcess(ImagePath, - L"", /* FIXME */ - FALSE, /* wait */ - NULL, - FALSE, /* terminate */ - NULL); - }else{ - Request->SmHeader.Status = Status; - } - } - } - else - { - Request->SmHeader.Status = Status = STATUS_INVALID_PARAMETER; - } - return Status; -} - -/* EOF */ +/* $Id$ + * + * smapiexec.c - SM_API_EXECUTE_PROGRAM + * + * Reactos Session Manager + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ +#include "smss.h" + +#define NDEBUG +#include + +/********************************************************************** + * SmCreateUserProcess/5 + * + * DESCRIPTION + * + * ARGUMENTS + * ImagePath: bsolute path of the image to run; + * CommandLine: arguments and options for ImagePath; + * WaitForIt: TRUE for boot time processes and FALSE for + * subsystems bootstrapping; + * Timeout: optional: used if WaitForIt==TRUE; + * ProcessHandle: optional: a duplicated handle for + the child process (storage provided by the caller). + * + * RETURN VALUE + * NTSTATUS: + * + */ +NTSTATUS STDCALL +SmCreateUserProcess (LPWSTR ImagePath, + LPWSTR CommandLine, + BOOLEAN WaitForIt, + PLARGE_INTEGER Timeout OPTIONAL, + PRTL_PROCESS_INFO UserProcessInfo OPTIONAL) +{ + UNICODE_STRING ImagePathString = {0}; + UNICODE_STRING CommandLineString = {0}; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters = NULL; + RTL_PROCESS_INFO ProcessInfo = {0}; + PRTL_PROCESS_INFO pProcessInfo = & ProcessInfo; + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("SM: %s called\n", __FUNCTION__); + + if (NULL != UserProcessInfo) + { + pProcessInfo = UserProcessInfo; + } + + RtlInitUnicodeString (& ImagePathString, ImagePath); + RtlInitUnicodeString (& CommandLineString, CommandLine); + + RtlCreateProcessParameters(& ProcessParameters, + & ImagePathString, + NULL, + NULL, + & CommandLineString, + SmSystemEnvironment, + NULL, + NULL, + NULL, + NULL); + + Status = RtlCreateUserProcess (& ImagePathString, + OBJ_CASE_INSENSITIVE, + ProcessParameters, + NULL, + NULL, + NULL, + FALSE, + NULL, + NULL, + pProcessInfo); + + RtlDestroyProcessParameters (ProcessParameters); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("SM: %s: Running \"%S\" failed (Status=0x%08lx)\n", + __FUNCTION__, ImagePathString.Buffer, Status); + return Status; + } + /* + * It the caller is *not* interested in the child info, + * resume it immediately. + */ + if (NULL == UserProcessInfo) + { + Status = NtResumeThread (ProcessInfo.ThreadHandle, NULL); + if(!NT_SUCCESS(Status)) + { + DPRINT1("SM: %s: NtResumeThread failed (Status=0x%08lx)\n", + __FUNCTION__, Status); + } + } + else + { + HANDLE DupProcessHandle = (HANDLE) 0; + + Status = NtDuplicateObject (NtCurrentProcess(), + pProcessInfo->ProcessHandle, + NtCurrentProcess(), + & DupProcessHandle, + PROCESS_ALL_ACCESS, + 0, 0); + if(!NT_SUCCESS(Status)) + { + DPRINT1("SM: %s: NtDuplicateObject failed (Status=0x%08lx)\n", + __FUNCTION__, Status); + } + pProcessInfo->ProcessHandle = DupProcessHandle; + + } + + /* Wait for process termination */ + if (WaitForIt) + { + Status = NtWaitForSingleObject (pProcessInfo->ProcessHandle, + FALSE, + Timeout); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SM: %s: NtWaitForSingleObject failed with Status=0x%08lx\n", + __FUNCTION__, Status); + } + + } + return Status; +} + +/********************************************************************** + * NAME + * SmLookupSubsystem/5 + * + * DESCRIPTION + * Read from the registry key + * \Registry\SYSTEM\CurrentControlSet\Control\Session Manager\Subsystems + * the value which name is Name. + * + * ARGUMENTS + * Name: name of the program to run, that is a value's name in + * the SM registry key Subsystems; + * Data: what the registry gave back for Name; + * DataLength: how much Data the registry returns; + * DataType: what is Data? + * Expand: set it TRUE if you want this function to use the env + * to possibly expand Data before giving it back. + */ +NTSTATUS STDCALL +SmLookupSubsystem (IN PWSTR Name, + IN OUT PWSTR Data, + IN OUT PULONG DataLength, + IN OUT PULONG DataType, + IN BOOLEAN Expand) +{ + NTSTATUS Status = STATUS_SUCCESS; + UNICODE_STRING usKeyName = {0}; + OBJECT_ATTRIBUTES Oa = {0}; + HANDLE hKey = (HANDLE) 0; + + DPRINT("SM: %s(Name='%S') called\n", __FUNCTION__, Name); + /* + * Prepare the key name to scan and + * related object attributes. + */ + RtlInitUnicodeString (& usKeyName, + L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\SubSystems"); + + InitializeObjectAttributes (& Oa, + & usKeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + /* + * Open the key. This MUST NOT fail, if the + * request is for a legitimate subsystem. + */ + Status = NtOpenKey (& hKey, + MAXIMUM_ALLOWED, + & Oa); + if(NT_SUCCESS(Status)) + { + UNICODE_STRING usValueName = {0}; + WCHAR KeyValueInformation [1024] = {L'\0'}; + ULONG ResultLength = 0L; + PKEY_VALUE_PARTIAL_INFORMATION + kvpi = (PKEY_VALUE_PARTIAL_INFORMATION) KeyValueInformation; + + + RtlInitUnicodeString (& usValueName, Name); + Status = NtQueryValueKey (hKey, + & usValueName, + KeyValuePartialInformation, + KeyValueInformation, + sizeof KeyValueInformation, + & ResultLength); + if(NT_SUCCESS(Status)) + { + DPRINT("nkvpi.TitleIndex = %ld\n", kvpi->TitleIndex); + DPRINT("kvpi.Type = %ld\n", kvpi->Type); + DPRINT("kvpi.DataLength = %ld\n", kvpi->DataLength); + + if((NULL != Data) && (NULL != DataLength) && (NULL != DataType)) + { + *DataType = kvpi->Type; + if((Expand) && (REG_EXPAND_SZ == *DataType)) + { + UNICODE_STRING Source; + WCHAR DestinationBuffer [2048] = {0}; + UNICODE_STRING Destination; + ULONG Length = 0; + + DPRINT("SM: %s: value will be expanded\n", __FUNCTION__); + + Source.Length = kvpi->DataLength; + Source.MaximumLength = kvpi->DataLength; + Source.Buffer = (PWCHAR) & kvpi->Data; + + Destination.Length = 0; + Destination.MaximumLength = sizeof DestinationBuffer; + Destination.Buffer = DestinationBuffer; + + Status = RtlExpandEnvironmentStrings_U (SmSystemEnvironment, + & Source, + & Destination, + & Length); + if(NT_SUCCESS(Status)) + { + *DataLength = min(*DataLength, Destination.Length); + RtlCopyMemory (Data, Destination.Buffer, *DataLength); + } + + }else{ + DPRINT("SM: %s: value won't be expanded\n", __FUNCTION__); + *DataLength = min(*DataLength, kvpi->DataLength); + RtlCopyMemory (Data, & kvpi->Data, *DataLength); + } + *DataType = kvpi->Type; + }else{ + DPRINT1("SM: %s: Data or DataLength or DataType is NULL!\n", __FUNCTION__); + Status = STATUS_INVALID_PARAMETER; + } + }else{ + DPRINT1("%s: NtQueryValueKey failed (Status=0x%08lx)\n", __FUNCTION__, Status); + } + NtClose (hKey); + }else{ + DPRINT1("%s: NtOpenKey failed (Status=0x%08lx)\n", __FUNCTION__, Status); + } + return Status; +} + + +/********************************************************************** + * SmExecPgm/1 API + */ +SMAPI(SmExecPgm) +{ + PSM_PORT_MESSAGE_EXECPGM ExecPgm = NULL; + WCHAR Name [SM_EXEXPGM_MAX_LENGTH + 1]; + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("SM: %s called\n",__FUNCTION__); + + if(NULL == Request) + { + DPRINT1("SM: %s: Request == NULL!\n", __FUNCTION__); + return STATUS_INVALID_PARAMETER; + } + DPRINT("SM: %s called from CID(%lx|%lx)\n", + __FUNCTION__, Request->Header.ClientId.UniqueProcess, + Request->Header.ClientId.UniqueThread); + ExecPgm = & Request->Request.ExecPgm; + /* Check if the name lenght is valid */ + if((ExecPgm->NameLength > 0) && + (ExecPgm->NameLength <= SM_EXEXPGM_MAX_LENGTH) && + TRUE /* TODO: check LPC payload size */) + { + WCHAR Data [MAX_PATH + 1] = {0}; + ULONG DataLength = sizeof Data; + ULONG DataType = REG_EXPAND_SZ; + + + RtlZeroMemory (Name, sizeof Name); + RtlCopyMemory (Name, + ExecPgm->Name, + (sizeof ExecPgm->Name[0] * ExecPgm->NameLength)); + DPRINT("SM: %s: Name='%S'\n", __FUNCTION__, Name); + /* Lookup Name in the registry */ + Status = SmLookupSubsystem (Name, + Data, + & DataLength, + & DataType, + TRUE); /* expand */ + if(NT_SUCCESS(Status)) + { + /* Is the subsystem definition non-empty? */ + if (DataLength > sizeof Data[0]) + { + WCHAR ImagePath [MAX_PATH + 1] = {0}; + PWCHAR CommandLine = ImagePath; + RTL_PROCESS_INFO ProcessInfo = {0}; + + wcscpy (ImagePath, L"\\??\\"); + wcscat (ImagePath, Data); + /* + * Look for the beginning of the command line. + */ + for (; (*CommandLine != L'\0') && (*CommandLine != L' '); + CommandLine ++); + for (; *CommandLine == L' '; CommandLine ++) + { + *CommandLine = L'\0'; + } + /* + * Create a native process (suspended). + */ + ProcessInfo.Size = sizeof ProcessInfo; + Request->SmHeader.Status = + SmCreateUserProcess(ImagePath, + CommandLine, + FALSE, /* wait */ + NULL, /* timeout */ + & ProcessInfo); + if (NT_SUCCESS(Request->SmHeader.Status)) + { + Status = SmCreateClient (& ProcessInfo, Name); + if (NT_SUCCESS(Status)) + { + Status = NtResumeThread (ProcessInfo.ThreadHandle, NULL); + if (!NT_SUCCESS(Status)) + { + //Status = SmDestroyClient TODO + } + } else { + DPRINT1("SM: %s: SmCreateClient failed (Status=0x%08lx)\n", + __FUNCTION__, Status); + } + } + } + else + { + /* + * OK, the definition is empty, but check + * if it is the name of an embedded subsystem. + */ + if(0 == _wcsicmp(L"DEBUG", Name)) + { + /* + * Initialize the embedded DBGSS. + */ + Request->SmHeader.Status = SmInitializeDbgSs(); + } + else + { + /* + * Badly defined subsystem. Check the registry! + */ + Request->SmHeader.Status = STATUS_NOT_FOUND; + } + } + } else { + /* It couldn't lookup the Name! */ + Request->SmHeader.Status = Status; + } + } + return Status; +} + +/* EOF */ diff --git a/reactos/subsys/smss/smapiquery.c b/reactos/subsys/smss/smapiquery.c index d1c402de757..5b8af3b7876 100644 --- a/reactos/subsys/smss/smapiquery.c +++ b/reactos/subsys/smss/smapiquery.c @@ -1,71 +1,71 @@ -/* $Id$ - * - * smapiquery.c - SM_API_QUERY_INFORMATION - * - * Reactos Session Manager - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ -#include "smss.h" - -#define NDEBUG -#include - - -/********************************************************************** - * SmQryInfo/1 API - */ -SMAPI(SmQryInfo) -{ - NTSTATUS Status = STATUS_SUCCESS; - - DPRINT("SM: %s called\n", __FUNCTION__); - - switch (Request->Request.QryInfo.SmInformationClass) - { - case SmBasicInformation: - if(Request->Request.QryInfo.DataLength != sizeof (SM_BASIC_INFORMATION)) - { - Request->Reply.QryInfo.DataLength = sizeof (SM_BASIC_INFORMATION); - Request->SmHeader.Status = STATUS_INFO_LENGTH_MISMATCH; - }else{ - Request->SmHeader.Status = - SmGetClientBasicInformation (& Request->Reply.QryInfo.BasicInformation); - } - break; - case SmSubSystemInformation: - if(Request->Request.QryInfo.DataLength != sizeof (SM_SUBSYSTEM_INFORMATION)) - { - Request->Reply.QryInfo.DataLength = sizeof (SM_SUBSYSTEM_INFORMATION); - Request->SmHeader.Status = STATUS_INFO_LENGTH_MISMATCH; - }else{ - Request->SmHeader.Status = - SmGetSubSystemInformation (& Request->Reply.QryInfo.SubSystemInformation); - } - break; - default: - Request->SmHeader.Status = STATUS_NOT_IMPLEMENTED; - break; - } - return Status; -} - - -/* EOF */ +/* $Id$ + * + * smapiquery.c - SM_API_QUERY_INFORMATION + * + * Reactos Session Manager + * + * -------------------------------------------------------------------- + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * -------------------------------------------------------------------- + */ +#include "smss.h" + +#define NDEBUG +#include + + +/********************************************************************** + * SmQryInfo/1 API + */ +SMAPI(SmQryInfo) +{ + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("SM: %s called\n", __FUNCTION__); + + switch (Request->Request.QryInfo.SmInformationClass) + { + case SmBasicInformation: + if(Request->Request.QryInfo.DataLength != sizeof (SM_BASIC_INFORMATION)) + { + Request->Reply.QryInfo.DataLength = sizeof (SM_BASIC_INFORMATION); + Request->SmHeader.Status = STATUS_INFO_LENGTH_MISMATCH; + }else{ + Request->SmHeader.Status = + SmGetClientBasicInformation (& Request->Reply.QryInfo.BasicInformation); + } + break; + case SmSubSystemInformation: + if(Request->Request.QryInfo.DataLength != sizeof (SM_SUBSYSTEM_INFORMATION)) + { + Request->Reply.QryInfo.DataLength = sizeof (SM_SUBSYSTEM_INFORMATION); + Request->SmHeader.Status = STATUS_INFO_LENGTH_MISMATCH; + }else{ + Request->SmHeader.Status = + SmGetSubSystemInformation (& Request->Reply.QryInfo.SubSystemInformation); + } + break; + default: + Request->SmHeader.Status = STATUS_NOT_IMPLEMENTED; + break; + } + return Status; +} + + +/* EOF */ diff --git a/reactos/subsys/smss/smss.c b/reactos/subsys/smss/smss.c index 03d8d37b212..627677a1c85 100644 --- a/reactos/subsys/smss/smss.c +++ b/reactos/subsys/smss/smss.c @@ -30,16 +30,18 @@ #define NDEBUG #include -HANDLE SmSsProcessId = 0; +ULONG SmSsProcessId = 0; /* Native image's entry point */ VOID STDCALL NtProcessStartup(PPEB Peb) { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; PROCESS_BASIC_INFORMATION PBI = {0}; +PrintString("*** EXPERIMENTAL ***\n"); + PrintString("ReactOS Session Manager %s (Build %s)\n", KERNEL_RELEASE_STR, KERNEL_VERSION_BUILD_STR); @@ -52,7 +54,7 @@ NtProcessStartup(PPEB Peb) NULL); if(NT_SUCCESS(Status)) { - SmSsProcessId = PBI.UniqueProcessId; + SmSsProcessId = (ULONG) PBI.UniqueProcessId; } /* Initialize the system */ Status = InitSessionManager(); diff --git a/reactos/subsys/smss/smss.h b/reactos/subsys/smss/smss.h index 6b1bb4018af..bc099bf1d36 100644 --- a/reactos/subsys/smss/smss.h +++ b/reactos/subsys/smss/smss.h @@ -6,11 +6,8 @@ #include #include -#define CHILD_CSRSS 0 -#define CHILD_WINLOGON 1 - /* smss.c */ -extern HANDLE SmSsProcessId; +extern ULONG SmSsProcessId; /* init.c */ NTSTATUS InitSessionManager(VOID); @@ -63,8 +60,7 @@ NTSTATUS STDCALL SmCreateUserProcess(LPWSTR ImagePath, LPWSTR CommandLine, BOOLEAN WaitForIt, PLARGE_INTEGER Timeout OPTIONAL, - BOOLEAN TerminateIt, - PRTL_PROCESS_INFO ProcessInfo OPTIONAL); + PRTL_PROCESS_INFO UserProcessInfo OPTIONAL); NTSTATUS STDCALL SmLookupSubsystem (IN PWSTR Name, IN OUT PWSTR Data, @@ -80,22 +76,30 @@ NTSTATUS FASTCALL SmCompSes(PSM_PORT_MESSAGE); NTSTATUS FASTCALL SmQryInfo(PSM_PORT_MESSAGE); /* client.c */ +#define SM_CLIENT_FLAG_CANDIDATE 0x8000 +#define SM_CLIENT_FLAG_INITIALIZED 0x0001 +#define SM_CLIENT_FLAG_REQUIRED 0x0002 typedef struct _SM_CLIENT_DATA { - USHORT SubsystemId; - BOOL Initialized; - HANDLE ServerProcess; - HANDLE ApiPort; - HANDLE ApiPortThread; - HANDLE SbApiPort; - WCHAR SbApiPortName [SM_SB_NAME_MAX_LENGTH]; - struct _SM_CLIENT_DATA * Next; + RTL_CRITICAL_SECTION Lock; + WCHAR ProgramName [SM_SB_NAME_MAX_LENGTH]; + USHORT SubsystemId; + WORD Flags; + WORD Unused; + ULONG ServerProcessId; + HANDLE ServerProcess; + HANDLE ApiPort; + HANDLE ApiPortThread; + HANDLE SbApiPort; + WCHAR SbApiPortName [SM_SB_NAME_MAX_LENGTH]; + struct _SM_CLIENT_DATA * Next; } SM_CLIENT_DATA, *PSM_CLIENT_DATA; -NTSTATUS SmInitializeClientManagement(VOID); -NTSTATUS STDCALL SmCreateClient(PSM_PORT_MESSAGE,PSM_CLIENT_DATA*); -NTSTATUS STDCALL SmDestroyClient(ULONG); -NTSTATUS STDCALL SmCompleteClientInitialization (HANDLE hProcess); +NTSTATUS SmInitializeClientManagement (VOID); +NTSTATUS STDCALL SmCreateClient (PRTL_PROCESS_INFO,PWSTR); +NTSTATUS STDCALL SmDestroyClient (ULONG); +NTSTATUS STDCALL SmBeginClientInitialization (PSM_PORT_MESSAGE,PSM_CLIENT_DATA*); +NTSTATUS STDCALL SmCompleteClientInitialization (ULONG); NTSTATUS FASTCALL SmGetClientBasicInformation (PSM_BASIC_INFORMATION); NTSTATUS FASTCALL SmGetSubSystemInformation (PSM_SUBSYSTEM_INFORMATION); diff --git a/reactos/subsys/system/cmd/En.rc b/reactos/subsys/system/cmd/En.rc index 63d53c801a1..31ee13d3d7a 100644 --- a/reactos/subsys/system/cmd/En.rc +++ b/reactos/subsys/system/cmd/En.rc @@ -42,11 +42,11 @@ CALL [drive:][path]filename [batch-parameter]\n\n\ STRING_CD_HELP, "Changes the current directory or displays it's name\n\n\ CHDIR [drive:][path]\n\ -CHDIR[..|-]\n\ +CHDIR[..|.]\n\ CD [drive:][path]\n\ -CD[..|-]\n\n\ +CD[..|.]\n\n\ .. parent directory\n\ - - previous directory\n\n\ + . previous directory\n\n\ Type CD drive: to display the current directory on the specified drive.\n\ Type CD without a parameter to display the current drive and directory." diff --git a/reactos/subsys/system/cmd/dir.c b/reactos/subsys/system/cmd/dir.c index 9726a7ff7f8..4bf5a41d2d1 100644 --- a/reactos/subsys/system/cmd/dir.c +++ b/reactos/subsys/system/cmd/dir.c @@ -1668,7 +1668,7 @@ TCHAR szMsg[RC_STRING_MAX_SIZE]; if (ptrStartNode == NULL) { #ifdef _DEBUG - ConErrPrintf("DEBUG: Cannot allocate memory for ptrStartNode!\n"); + ConErrPrintf(_T("DEBUG: Cannot allocate memory for ptrStartNode!\n")); #endif return 1; /* Error cannot allocate memory for 1st object */ } @@ -1688,7 +1688,7 @@ TCHAR szMsg[RC_STRING_MAX_SIZE]; if (ptrNextNode->ptrNext == NULL) { #ifdef _DEBUG - ConErrPrintf("DEBUG: Cannot allocate memory for ptrNextNode->ptrNext!\n"); + ConErrPrintf(_T("DEBUG: Cannot allocate memory for ptrNextNode->ptrNext!\n")); #endif while (ptrStartNode) { @@ -1748,7 +1748,7 @@ TCHAR szMsg[RC_STRING_MAX_SIZE]; if (ptrFileArray == NULL) { #ifdef _DEBUG - ConErrPrintf("DEBUG: Cannot allocate memory for ptrFileArray!\n"); + ConErrPrintf(_T("DEBUG: Cannot allocate memory for ptrFileArray!\n")); #endif while (ptrStartNode) { diff --git a/reactos/subsys/system/cmd/internal.c b/reactos/subsys/system/cmd/internal.c index 0716205eef4..572f5220682 100644 --- a/reactos/subsys/system/cmd/internal.c +++ b/reactos/subsys/system/cmd/internal.c @@ -156,8 +156,12 @@ INT cmd_chdir (LPTSTR cmd, LPTSTR param) { LPTSTR dir; /* pointer to the directory to change to */ LPTSTR lpOldPath; - LPTSTR endofstring; /* pointer to the null character in the directory to change to */ - LPTSTR lastquote; /* pointer to the last quotation mark in the directory to change to */ + size_t size, str_len; + WIN32_FIND_DATA FileData; + HANDLE hSearch; + DWORD dwAttrs; + BOOL fFinished = FALSE; + /*Should we better declare a variable containing _tsclen(dir) ? It's used a few times, but on the other hand paths are generally not very long*/ @@ -171,17 +175,38 @@ INT cmd_chdir (LPTSTR cmd, LPTSTR param) /* The whole param string is our parameter these days. The only thing we do is eliminating every quotation mark */ /* Is it safe to change the characters param is pointing to? I presume it is, as there doesn't seem to be any post-processing of it after the function call (what would that accomplish?) */ + + size = _tcscspn(param, _T("\"") ); + str_len = _tcslen(param)-1; - dir=param; - endofstring=dir+_tcslen(dir); - - while ((lastquote = _tcsrchr(dir, _T('\"')))) + if ((param[size] == _T('"')) && (str_len >1)) { - endofstring--; - memmove(lastquote,lastquote+1,endofstring-lastquote); - *endofstring=_T('\0'); + + if (size==0) + { + _tcsncpy(param,¶m[size+1],str_len); + param[str_len] = _T('\0'); + } + + size = _tcscspn(param, _T("\"") ); + if (param[size] == _T('"')) + { + param[size] = _T('\0'); + } + } + str_len = _tcslen(param); + if (str_len==1) + { + if (param[0] == _T('*')) + { + param[0] = _T('.'); + } + } + + dir=param; + /* if doing a CD and no parameters given, print out current directory */ if (!dir || !dir[0]) { @@ -231,6 +256,49 @@ INT cmd_chdir (LPTSTR cmd, LPTSTR param) if (!SetCurrentDirectory (dir)) { + + hSearch = FindFirstFile(dir, &FileData); + if (hSearch == INVALID_HANDLE_VALUE) + { + ConOutFormatMessage(GetLastError()); + free (lpOldPath); + lpOldPath = NULL; + return 1; + } + + + while (!fFinished) + { + dwAttrs = GetFileAttributes(FileData.cFileName); +#ifdef _DEBUG + DebugPrintf(_T("Search found folder :%s\n"),FileData.cFileName); +#endif + if ((dwAttrs & FILE_ATTRIBUTE_DIRECTORY)) + { + FindClose(hSearch); + // change folder + if (!SetCurrentDirectory (FileData.cFileName)) + { + ConOutFormatMessage(GetLastError()); + free (lpOldPath); + lpOldPath = NULL; + return 1; + } + + + return 0; + } + + else if (!FindNextFile(hSearch, &FileData)) + { + FindClose(hSearch); + ConOutFormatMessage(GetLastError()); + free (lpOldPath); + lpOldPath = NULL; + return 1; + } + } + //ErrorMessage (GetLastError(), _T("CD")); ConOutFormatMessage(GetLastError()); diff --git a/reactos/subsys/system/dhcp/dhclient.c b/reactos/subsys/system/dhcp/dhclient.c index 8c77c35150c..50f1c1a264d 100644 --- a/reactos/subsys/system/dhcp/dhclient.c +++ b/reactos/subsys/system/dhcp/dhclient.c @@ -71,7 +71,7 @@ #define middlechar(c) (borderchar(c) || hyphenchar(c)) #define domainchar(c) ((c) > 0x20 && (c) < 0x7f) -unsigned long debug_trace_level = DEBUG_ULTRA; +unsigned long debug_trace_level = 0; /* DEBUG_ULTRA */ time_t cur_time; time_t default_lease_time = 43200; /* 12 hours... */ @@ -661,7 +661,7 @@ dhcpoffer(struct packet *packet) struct interface_info *ip = packet->interface; struct client_lease *lease, *lp; int i; - int arp_timeout_needed, stop_selecting; + int arp_timeout_needed = 0, stop_selecting; char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ? "DHCPOFFER" : "BOOTREPLY"; diff --git a/reactos/subsys/system/dhcp/dispatch.c b/reactos/subsys/system/dhcp/dispatch.c index 439bc5bc94f..82a6c76284f 100644 --- a/reactos/subsys/system/dhcp/dispatch.c +++ b/reactos/subsys/system/dhcp/dispatch.c @@ -186,8 +186,10 @@ dispatch(void) if (errno == EAGAIN || errno == EINTR) { time(&cur_time); continue; - } else + } else { error("poll: %m"); + break; + } } /* Get the current time... */ diff --git a/reactos/subsys/system/explorer/explorer-cz.rc b/reactos/subsys/system/explorer/explorer-cz.rc new file mode 100644 index 00000000000..07603eabd91 --- /dev/null +++ b/reactos/subsys/system/explorer/explorer-cz.rc @@ -0,0 +1,493 @@ +///////////////////////////////////////////////////////////////////////////// +// Czech resources +// Translated by denzil + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CZE) +#ifdef _WIN32 +LANGUAGE LANG_CZECH, SUBLANG_DEFAULT +#pragma code_page(1250) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDM_MDIFRAME MENU PRELOAD DISCARDABLE +BEGIN + POPUP "&Soubor" + BEGIN + MENUITEM "&Ukonèit", ID_FILE_EXIT + END + POPUP "&Zobrazení" + BEGIN + MENUITEM "&Lišta nástrojù", ID_VIEW_TOOL_BAR + MENUITEM "&Extra Bar", ID_VIEW_EXTRA_BAR + MENUITEM "L&išta diskù", ID_VIEW_DRIVE_BAR, CHECKED + MENUITEM "&Boèní lišta", ID_VIEW_SIDE_BAR + MENUITEM "&Status Bar", ID_VIEW_STATUSBAR + MENUITEM SEPARATOR + MENUITEM "&Aktualizovat\tF5", ID_REFRESH + MENUITEM "&Celá obrazovka\tCtrl+Shift+S", ID_VIEW_FULLSCREEN + MENUITEM "SDI", ID_VIEW_SDI + END + POPUP "&Okno" + BEGIN + MENUITEM "&Nové Okno", ID_WINDOW_NEW + MENUITEM "&Kaskádovat\tShift+F5", ID_WINDOW_CASCADE + MENUITEM "&Uspoøádat vodorovnì", ID_WINDOW_TILE_HORZ + MENUITEM "U&spoøádat svisle\tShift+F4", ID_WINDOW_TILE_VERT + MENUITEM "Us&poøádat automaticky", ID_WINDOW_AUTOSORT + MENUITEM "Usp&oøádat symboly", ID_WINDOW_ARRANGE + END + POPUP "&Nástroje" + BEGIN + MENUITEM "&Nastavení", ID_TOOLS_OPTIONS + END + POPUP "&Pomoc" + BEGIN + MENUITEM "&Prùzkumník &FAQ...", ID_EXPLORER_FAQ + MENUITEM "O p&rùzkumníku...", ID_ABOUT_EXPLORER + MENUITEM "&O OS...", ID_ABOUT_WINDOWS + END +END + +IDM_WINEFILE MENU FIXED IMPURE +BEGIN + POPUP "&Soubor" + BEGIN + MENUITEM "&Otevøít\tEnter", 101 + MENUITEM "&Pøesunout...\tF7", 106 + MENUITEM "&Kopírovat...\tF8", 107 + MENUITEM "&Ve schránce...\tF9", 118 + MENUITEM "&Smazat\tDel", 108 + MENUITEM "Pø&ejmenovat...", 109 + MENUITEM "&Vlastnosti...\tAlt+Enter", ID_EDIT_PROPERTIES + MENUITEM SEPARATOR + MENUITEM "Ko&mprimovat...", 119 + MENUITEM "Dekomp&rimovat...", 120 + MENUITEM SEPARATOR + MENUITEM "Sp&ustit...", ID_EXECUTE + MENUITEM "&Tisknout...", 102 + MENUITEM "&Asociovat...", 103 + MENUITEM SEPARATOR + MENUITEM "Vytvoøit adresáø...", ID_EXECUTE + MENUITEM "&Hledat...", 104 + MENUITEM "&Vybrat soubory...", 116 + MENUITEM SEPARATOR + MENUITEM "Ukonèit\tAlt+X", ID_FILE_EXIT + END + POPUP "&Disk" + BEGIN + MENUITEM "&Kopírovat disk...", 201 + MENUITEM "&Jmenovka disku...", 202 + MENUITEM SEPARATOR + MENUITEM "&Formátovat disk...", 203 + MENUITEM SEPARATOR + MENUITEM "&Pipojit síový disk", 252 + MENUITEM "&Odpojit síový disk", 253 + MENUITEM SEPARATOR + MENUITEM "&Sdílet jako...", 254 + MENUITEM "&Zrušit sdílení...", 255 + MENUITEM SEPARATOR + MENUITEM "Z&volit disk...", 251 + END + POPUP "&Adresáøe" + BEGIN + MENUITEM "&Další úroveò\t+", 301 + MENUITEM "&Rozbalit strom\t*", 302 + MENUITEM "R&ozbalit vše\tCtrl+*", 303 + MENUITEM "&Sbalit strom\t-", 304 + MENUITEM SEPARATOR + MENUITEM "O&znaèit potomky", 505 + END + POPUP "&Zobrazení" + BEGIN + MENUITEM "&Strom a adresáøe", 413 + MENUITEM "&Jen strom", 411 + MENUITEM "J&en adresáøe", 412 + MENUITEM SEPARATOR + MENUITEM "&Rozdìlit", 414 + MENUITEM SEPARATOR + MENUITEM "&Jméno", ID_VIEW_NAME + MENUITEM "&Všechny detaily", ID_VIEW_ALL_ATTRIBUTES + , CHECKED + MENUITEM "Èást&eèné detaily...", ID_VIEW_SELECTED_ATTRIBUTES + MENUITEM SEPARATOR + MENUITEM "Tøídit podle jmé&na", 404 + MENUITEM "Tøídit podle &druhu", 405 + MENUITEM "Tøídit podle ve&likosti", 406 + MENUITEM "Tøídit podle &data", 407 + MENUITEM SEPARATOR + MENUITEM "&Tøídit podle...", 409 + END + POPUP "&Nastavení" + BEGIN + MENUITEM "&Potvtrzování...", 65535 + MENUITEM "Pí&smo...", 65535 + MENUITEM "&Upravit lištu nástrojù...", 65535 + MENUITEM SEPARATOR + MENUITEM "&Lišta nástrojù", ID_VIEW_TOOL_BAR, CHECKED + MENUITEM "L&išta diskù", ID_VIEW_DRIVE_BAR, CHECKED + MENUITEM "&Boèní lišta", ID_VIEW_SIDE_BAR + MENUITEM "&Status Bar", ID_VIEW_STATUSBAR, CHECKED + MENUITEM "&Celá obrazovka\tCtrl+Shift+S", ID_VIEW_FULLSCREEN + MENUITEM SEPARATOR + MENUITEM "S&ymbol po bìhu", 65535 + MENUITEM "&Uložit zmìny pøi ukonèení", 511 + END + POPUP "&Zabezpeèení" + BEGIN + MENUITEM "&Pøístup...", 605 + MENUITEM "&Logování...", 606 + MENUITEM "&Vlastník...", 607 + END + POPUP "&Okno" + BEGIN + MENUITEM "&Nové okno", ID_WINDOW_NEW + MENUITEM "&Kaskádovat\tCtrl+F5", ID_WINDOW_CASCADE + MENUITEM "&Uspoøádat vodorovnì", ID_WINDOW_TILE_HORZ + MENUITEM "U&spoøádat svisle\tCtrl+F4", ID_WINDOW_TILE_VERT + MENUITEM "Us&poøádat automaticky", ID_WINDOW_AUTOSORT + MENUITEM "Usp&oøádat symboly", ID_WINDOW_ARRANGE + MENUITEM "&Aktualizovat\tF5", ID_REFRESH + END + POPUP "&?" + BEGIN + MENUITEM "&Témata nápovìdy\tF1", ID_HELP + MENUITEM "&Hledat v nápovìdì...\tF1", ID_HELP + MENUITEM "&Jak používat nápovìdu\tF1", ID_HELP_USING + MENUITEM SEPARATOR + MENUITEM "&Informace o Winefile...", ID_ABOUT_WINEFILE + END +END + +IDM_DESKTOPBAR MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Nastavení...", ID_DESKTOPBAR_SETTINGS + MENUITEM "&Správce úloh...", ID_TASKMGR + MENUITEM SEPARATOR + MENUITEM "&O Exploreru...", ID_ABOUT_EXPLORER + END +END + +IDM_VOLUME MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Otevøít ovládání hlasitosti", ID_TRAY_VOLUME + MENUITEM "&Upravit vlastnosti zvuku", ID_VOLUME_PROPERTIES + END +END + +IDM_NOTIFYAREA MENU DISCARDABLE +BEGIN + POPUP "" + BEGIN + MENUITEM "&Zobrazit skryté ikony", ID_SHOW_HIDDEN_ICONS + MENUITEM "Z&obrazit ikonu tlaèítka", ID_SHOW_ICON_BUTTON + MENUITEM "&Nastavit upozornìní...", ID_CONFIG_NOTIFYAREA + MENUITEM "N&astavit datum a èas...", ID_CONFIG_TIME + MENUITEM SEPARATOR + MENUITEM "&O prùzkuníku...", ID_ABOUT_EXPLORER + END +END + +IDM_SDIFRAME MENU PRELOAD DISCARDABLE +BEGIN + POPUP "&Soubor" + BEGIN + MENUITEM "&Ukonèit", ID_FILE_EXIT + END + POPUP "&Zobrazení" + BEGIN + MENUITEM "&Lišta nástrojù", ID_VIEW_TOOL_BAR + MENUITEM "&Boèní lišta", ID_VIEW_SIDE_BAR, GRAYED + MENUITEM "&Status lišta", ID_VIEW_STATUSBAR + MENUITEM SEPARATOR + MENUITEM "&Aktualizovat\tF5", ID_REFRESH + MENUITEM "Celá obrazovka\tCtrl+Shift+S", ID_VIEW_FULLSCREEN + MENUITEM "&MDI", ID_VIEW_MDI + END + POPUP "&Nástroje" + BEGIN + MENUITEM "&Nastavení", ID_TOOLS_OPTIONS + END + POPUP "&Pomoc" + BEGIN + MENUITEM "Prùzkumník &FAQ...", ID_EXPLORER_FAQ + MENUITEM "O &prùzkumníku...", ID_ABOUT_EXPLORER + MENUITEM "O &OS...", ID_ABOUT_WINDOWS + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_EXECUTE DIALOG FIXED IMPURE 15, 13, 210, 63 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Spustit" +FONT 8, "MS Shell Dlg" +BEGIN + CONTROL "",101,"Static",SS_SIMPLE | SS_NOPREFIX,3,6,162,10 + CONTROL "&Command:",-1,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,3, + 18,60,10 + EDITTEXT 201,3,29,134,12,ES_AUTOHSCROLL + CONTROL "As &Symbol",214,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,3, + 45,71,12 + DEFPUSHBUTTON "&Spustit",1,158,6,47,14 + PUSHBUTTON "&Zrušit",2,158,23,47,14 + PUSHBUTTON "&Pomoc",254,158,43,47,14 +END + +IDD_SEARCH_PROGRAM DIALOGEX 0, 0, 200, 65 +STYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | + WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "Hledat program v nabídce Start" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LTEXT "&Filter:",IDC_STATIC,7,9,18,8 + EDITTEXT IDC_FILTER,34,7,100,14,ES_AUTOHSCROLL + CONTROL "List1",IDC_PROGRAMS_FOUND,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SORTASCENDING | WS_BORDER | + WS_TABSTOP,7,25,186,33 + PUSHBUTTON "&Vyhledat",IDC_CHECK_ENTRIES,143,7,50,14 +END + +IDD_DESKBAR_DESKTOP DIALOG DISCARDABLE 0, 0, 212, 194 +STYLE WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Vlastnosti plochy" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Prosím zvolte si zpùsob zarovnání ikon:", + IDC_STATIC,7,7,166,8 + CONTROL "left/top dwn",IDC_ICON_ALIGN_0,"Button",BS_OWNERDRAW | + BS_BOTTOM | WS_TABSTOP,7,25,46,44 + CONTROL "left/top right",IDC_ICON_ALIGN_1,"Button",BS_OWNERDRAW | + BS_BOTTOM | WS_TABSTOP,57,25,46,44 + CONTROL "right/top left",IDC_ICON_ALIGN_2,"Button",BS_OWNERDRAW | + BS_BOTTOM | WS_TABSTOP,110,25,46,44 + CONTROL "rig./top dwn",IDC_ICON_ALIGN_3,"Button",BS_OWNERDRAW | + BS_BOTTOM | WS_TABSTOP,159,25,46,44 + CONTROL "left/bot. up",IDC_ICON_ALIGN_4,"Button",BS_OWNERDRAW | + BS_BOTTOM | WS_TABSTOP,7,73,46,44 + CONTROL "left/bot. right",IDC_ICON_ALIGN_5,"Button",BS_OWNERDRAW | + BS_BOTTOM | WS_TABSTOP,57,73,46,44 + CONTROL "right/bot. left",IDC_ICON_ALIGN_6,"Button",BS_OWNERDRAW | + BS_BOTTOM | WS_TABSTOP,110,73,46,44 + CONTROL "rig./bot. dwn",IDC_ICON_ALIGN_7,"Button",BS_OWNERDRAW | + BS_BOTTOM | WS_TABSTOP,159,73,46,44 + CONTROL "border down",IDC_ICON_ALIGN_8,"Button",BS_OWNERDRAW | + BS_BOTTOM | WS_TABSTOP,7,121,46,44 + CONTROL "border H/V",IDC_ICON_ALIGN_9,"Button",BS_OWNERDRAW | + BS_BOTTOM | WS_TABSTOP,57,121,46,44 + CONTROL "round about",IDC_ICON_ALIGN_10,"Button",BS_OWNERDRAW | + BS_BOTTOM | WS_TABSTOP,110,121,46,44 + CONTROL "",IDC_ICON_ALIGN_11,"Button",BS_OWNERDRAW | BS_BOTTOM | + WS_TABSTOP,159,121,46,44 + CONTROL "Zobrazit verzi",ID_DESKTOP_VERSION,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,177,91,10 +END + +IDD_DESKBAR_TASKBAR DIALOG DISCARDABLE 0, 0, 210, 194 +STYLE WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Vlastnosti panelu úloh" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "&Zobrazit èas",ID_SHOW_CLOCK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,152,52,10 + CONTROL "&Skrýt neaktivní ikony", + ID_HIDE_INACTIVE_ICONS,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,174,111,10 + PUSHBUTTON "&Upozornìní...",ID_CONFIG_NOTIFYAREA,153,173,50,14 +END + +IDD_DESKBAR_STARTMENU DIALOG DISCARDABLE 0, 0, 210, 194 +STYLE WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Vlastnosti nabídky Start" +FONT 8, "MS Sans Serif" +BEGIN +END + +IDD_NOTIFYAREA DIALOGEX 0, 0, 208, 174 +STYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | + WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "Nastavení ikon v oblasti upozoròování" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Tree1",IDC_NOTIFY_ICONS,"SysTreeView32",TVS_HASLINES | + TVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,7,7,194,31 + LTEXT "&Tooltip Text:",IDC_LABEL1,7,44,40,8 + EDITTEXT IDC_NOTIFY_TOOLTIP,58,42,143,14,ES_AUTOHSCROLL + LTEXT "W&indow Title:",IDC_LABEL2,7,63,44,8 + EDITTEXT IDC_NOTIFY_TITLE,58,60,143,14,ES_AUTOHSCROLL + LTEXT "&Module Path:",IDC_LABEL3,7,81,43,8 + EDITTEXT IDC_NOTIFY_MODULE,58,78,143,14,ES_AUTOHSCROLL + GROUPBOX "&Display Mode",IDC_LABEL4,7,96,157,28 + CONTROL "&show",IDC_NOTIFY_SHOW,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,15,108,33,10 + CONTROL "&hide",IDC_NOTIFY_HIDE,"Button",BS_AUTORADIOBUTTON,66, + 108,29,10 + CONTROL "a&utohide",IDC_NOTIFY_AUTOHIDE,"Button", + BS_AUTORADIOBUTTON,112,108,43,10 + ICON "",IDC_PICTURE,173,101,21,20 + LTEXT "&Last Change:",IDC_LABEL6,7,132,43,8 + EDITTEXT IDC_LAST_CHANGE,59,129,105,14,ES_AUTOHSCROLL | + ES_READONLY + CONTROL "sho&w hidden",ID_SHOW_HIDDEN_ICONS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,154,56,10 + DEFPUSHBUTTON "&Nastavit",IDOK,91,153,50,14,WS_GROUP + PUSHBUTTON "&Zrušit",IDCANCEL,151,153,50,14 +END + +IDD_MDI_SDI DIALOGEX 0, 0, 188, 126 +STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "Volba MDI / SDI módu" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LTEXT "Prosím zvolte si Vámi upøednostòovaný zpùsob zobrazení oken prùzkumníka:", + IDC_STATIC,7,7,160,8 + CONTROL "&MDI (Mnoho dokumentový interface)",IDC_MDI,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,7,30,121,10 + CONTROL "&SDI (Jedno dokumentový interface)",IDC_SDI,"Button", + BS_AUTORADIOBUTTON,7,53,115,10 + LTEXT "Toto nastavení bude použito jako implicitní pro všechny okna prùzkumníka.", + IDC_STATIC,7,76,174,22 + DEFPUSHBUTTON "&Nastavit",IDOK,29,105,50,14,WS_GROUP + PUSHBUTTON "&Zrušit",IDCANCEL,106,105,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_SEARCH_PROGRAM, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 193 + TOPMARGIN, 7 + BOTTOMMARGIN, 58 + END + + IDD_DESKBAR_DESKTOP, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 205 + TOPMARGIN, 7 + BOTTOMMARGIN, 187 + END + + IDD_DESKBAR_TASKBAR, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 203 + TOPMARGIN, 7 + BOTTOMMARGIN, 187 + END + + IDD_DESKBAR_STARTMENU, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 203 + TOPMARGIN, 7 + BOTTOMMARGIN, 187 + END + + IDD_NOTIFYAREA, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 201 + TOPMARGIN, 7 + BOTTOMMARGIN, 167 + END + + IDD_MDI_SDI, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 181 + TOPMARGIN, 7 + BOTTOMMARGIN, 119 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_TITLE "Reactos prùzkumník" + IDS_START "Start" + IDS_LOGOFF "Odhlásit se..." + IDS_TERMINATE "Ukonèit ReactOS prùzkumník" + IDS_SHUTDOWN "Vypnout..." + IDS_LAUNCH "Spustit..." + IDS_START_HELP "Pomoc" + IDS_SEARCH_FILES "Hledat..." + IDS_DOCUMENTS "Dokumenty" + IDS_FAVORITES "Oblíbené" + IDS_PROGRAMS "Programy" + IDS_SETTINGS "Nastavení" + IDS_EXPLORE "Prozkoumat" + IDS_EMPTY "(Prázdné)" + IDS_RECENT "Nedávné dokumenty" + IDS_ADMIN "Administrace" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_NETWORK "Sí" + IDS_CONNECTIONS "Síové spojení" + IDS_DRIVES "Disky" + IDS_SEARCH_COMPUTER "Hledat..." + IDS_SETTINGS_MENU "Nastavení" + IDS_CONTROL_PANEL "Ovládací panel" + IDS_PRINTERS "Tiskárny" + IDS_BROWSE "Prohlížet soubory" + IDS_SEARCH_PRG "Search Program..." + IDS_ALL_USERS "Všichni uživatelé\\" + IDS_SEARCH "Hledat" + IDS_ABOUT_EXPLORER "&O prùzkumníku..." + IDS_LAUNCH_MANY_PROGRAMS + "Spustili jste více než jeden program.\nJste si jisti, že je chcete spustit všechny?" + IDS_DESKTOPBAR_SETTINGS "Nastavení plochy" + IDS_DESKTOP "Plocha" + IDS_TASKBAR "Panel úloh" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_STARTMENU "Nabídka Start" + IDS_MINIMIZE_ALL "minimalizovat všechna okna" + IDS_DESKTOP_NUM "Plocha %d" + IDS_VOLUME "Hlasitost" + IDS_ITEMS_CUR "souèasné položky" + IDS_ITEMS_CONFIGURED "nastavení" + IDS_ITEMS_VISIBLE "viditelné" + IDS_ITEMS_HIDDEN "skryté" + IDS_NOTIFY_SHOW "zobrazit" + IDS_NOTIFY_HIDE "skrýt" + IDS_NOTIFY_AUTOHIDE "skrývat automaticky" + IDS_SHOW_HIDDEN_ICONS "Zobrazit skryté ikony" + IDS_HIDE_ICONS "Skrýt ikony" +END + +#endif // Czech resources +///////////////////////////////////////////////////////////////////////////// + diff --git a/reactos/subsys/system/explorer/explorer_intres.rc b/reactos/subsys/system/explorer/explorer_intres.rc index 7e38de50aed..a31c36059ad 100644 --- a/reactos/subsys/system/explorer/explorer_intres.rc +++ b/reactos/subsys/system/explorer/explorer_intres.rc @@ -509,6 +509,7 @@ BEGIN "END\r\n" "#endif\r\n" "\r\n" + "#include ""explorer-cz.rc""\r\n" "#include ""explorer-jp.rc""\r\n" "\r\n" "#ifndef __WINDRES__\r\n" @@ -2311,6 +2312,7 @@ IDS_EXPLORER_VERSION_STR "ROS Explorer Ansi%0s" END #endif +#include "explorer-cz.rc" #include "explorer-jp.rc" #ifndef __WINDRES__ diff --git a/reactos/subsys/system/sm/En.rc b/reactos/subsys/system/sm/En.rc new file mode 100644 index 00000000000..af05f47224d --- /dev/null +++ b/reactos/subsys/system/sm/En.rc @@ -0,0 +1,57 @@ +#include "resource.h" +/* + * Moved all hardcoded strings to En.rc. + * By Magnus Olsen 2005 magnus@itkonsult-olsen.com + */ + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT +STRINGTABLE DISCARDABLE +{ +IDS_boot, "boot subsystem_name" + +IDS_help, "help [command]" + +IDS_info, "info [subsystem_id]" + +IDS_reboot, "reboot subsystem_id" + +IDS_shutdown,"shutdown subsystem_id" + + + +IDS_boot_msg, "bootstrap an optional environment subsystem;" + +IDS_help_msg, "print help for command;" + +IDS_info_msg, "print information about a booted subsystem\n\ +if subsystem_id is omitted, a list of booted\n\ +environment subsystems is printed." + +IDS_reboot_msg, "reboot an optional environment subsystem;" +IDS_shutdown_msg, "shutdown an optional environment subsystem;" + +IDS_Unknown, "Unknown command '%s'.\n" + +IDS_Status, "Status 0x%08lx\n" + +IDS_SM1, "SM SubSystem Directory\n\n\ +SSID PID Flags\n\ +---- -------- ------------\n" + +IDS_SM2, "%04x %08lx %04x\n" + +IDS_ID, "SubSystem ID: %d\n\ + Flags: %04x\n\ + Process ID: %ld\n" + +IDS_Not_Imp, "not implemented\n" + +IDS_Mangers, "ReactOS/Win32 Session Manager Control Tool\n\n" + +IDS_USING, "Usage:\n\ +\tsm\n\ +\tsm help [command]\n\ +\tsm command [arguments]\n\n'sm help' will print the list of valid commands.\n" + +IDS_FAILS_MNG, "Failed to connect to the Session Manager! (Status=0x%08lx)\n" +} diff --git a/reactos/subsys/system/sm/resource.h b/reactos/subsys/system/sm/resource.h new file mode 100644 index 00000000000..382cf52f9d7 --- /dev/null +++ b/reactos/subsys/system/sm/resource.h @@ -0,0 +1,27 @@ + + + +#define RC_STRING_MAX_SIZE 200 +#define IDS_boot 100 +#define IDS_help 101 +#define IDS_info 102 +#define IDS_reboot 103 +#define IDS_shutdown 104 +#define IDS_boot_msg 205 +#define IDS_help_msg 206 +#define IDS_info_msg 207 +#define IDS_reboot_msg 208 +#define IDS_shutdown_msg 209 + +#define IDS_Unknown 300 +#define IDS_Not_Imp 301 +#define IDS_ID 302 +#define IDS_SM2 303 +#define IDS_SM1 304 +#define IDS_Status 305 +#define IDS_Mangers 306 +#define IDS_USING 307 +#define IDS_FAILS_MNG 308 + + +/* EOF */ diff --git a/reactos/subsys/system/sm/sm.c b/reactos/subsys/system/sm/sm.c index 507da336e8a..31a6d888b27 100644 --- a/reactos/subsys/system/sm/sm.c +++ b/reactos/subsys/system/sm/sm.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include "resource.h" #define NTOS_MODE_USER #include @@ -39,10 +41,10 @@ HANDLE hSmApiPort = (HANDLE) 0; typedef struct _SM_CMD_DESCRIPTOR { - const char * Name; - int (*EntryPoint)(int,char**); - const char * Synopsis; - const char * Description; + TCHAR Name[RC_STRING_MAX_SIZE]; + int (*EntryPoint)(int,TCHAR**); + TCHAR Synopsis[RC_STRING_MAX_SIZE]; + TCHAR Description[RC_STRING_MAX_SIZE]; } SM_CMD_DESCRIPTOR, *PSM_CMD_DESCRIPTOR; @@ -55,16 +57,19 @@ SM_CMD_DECL(shutdown); /* internal commands directory */ SM_CMD_DESCRIPTOR Command [] = { - {"boot", SM_CMD(boot), "boot subsystem_name", "bootstrap an optional environment subsystem;"}, - {"help", SM_CMD(help), "help [command]", "print help for command;"}, - {"info", SM_CMD(info), "info [subsystem_id]", "print information about a booted subsystem\n" + {"boot", SM_CMD(boot), _T("boot subsystem_name"), _T("bootstrap an optional environment subsystem;")}, + {"help", SM_CMD(help), _T("help [command]"), _T("print help for command;")}, + {"info", SM_CMD(info), _T("info [subsystem_id]"), _T("print information about a booted subsystem\n" "if subsystem_id is omitted, a list of booted\n" - "environment subsystems is printed."}, - {"reboot", SM_CMD(reboot), "reboot subsystem_id", "reboot an optional environment subsystem;"}, - {"shutdown", SM_CMD(shutdown), "shutdown subsystem_id", "shutdown an optional environment subsystem;"}, + "environment subsystems is printed.")}, + {"reboot", SM_CMD(reboot), _T("reboot subsystem_id"), _T("reboot an optional environment subsystem;")}, + {"shutdown", SM_CMD(shutdown), _T("shutdown subsystem_id"), _T("shutdown an optional environment subsystem;")}, }; -PSM_CMD_DESCRIPTOR LookupCommand (const char * CommandName) +TCHAR UsageMessage[RC_STRING_MAX_SIZE]; +void loadlang(PSM_CMD_DESCRIPTOR ); + +PSM_CMD_DESCRIPTOR LookupCommand (const TCHAR * CommandName) { int i; const int command_count = (sizeof Command / sizeof Command[0]); @@ -73,14 +78,16 @@ PSM_CMD_DESCRIPTOR LookupCommand (const char * CommandName) for (i=0; (i < command_count); i ++) { - if (0 == strcmp(CommandName, Command[i].Name)) + if (0 == _tcscmp(CommandName, Command[i].Name)) { break; } } if (i == command_count) { - fprintf(stderr, "Unknown command '%s'.\n", CommandName); + LoadString( GetModuleHandle(NULL), IDS_Unknown, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + + _ftprintf(stderr, _T("%s '%s'.\n"), UsageMessage, CommandName); return NULL; } return & Command [i]; @@ -97,18 +104,26 @@ SM_CMD_DECL(boot) if (3 == argc) { +#ifndef _UNICODE RtlInitAnsiString (& ProgramA, argv[2]); RtlAnsiStringToUnicodeString (& ProgramW, & ProgramA, TRUE); Status = SmExecuteProgram (hSmApiPort, & ProgramW); RtlFreeUnicodeString (& ProgramW); +#else + ProgramW = &argv[2]; + Status = SmExecuteProgram (hSmApiPort, & ProgramW); +#endif if (STATUS_SUCCESS != Status) { - printf ("Status 0x%08lx\n", Status); + LoadString( GetModuleHandle(NULL), IDS_Status, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + + _tprintf(UsageMessage, Status); } + } else { - argv[2]="boot"; + argv[2]=_T("boot"); return SM_CMD_CALL(help,3,argv); } return rc; @@ -125,7 +140,7 @@ SM_CMD_DECL(help) case 2: for (i=0; (i < (sizeof Command / sizeof Command[0])); i ++) { - printf("%s\n", Command[i].Synopsis); + _tprintf(_T("%s\n"), Command[i].Synopsis); } break; case 3: @@ -135,7 +150,7 @@ SM_CMD_DECL(help) rc = EXIT_FAILURE; break; } - printf("%s\n%s\n\n%s\n", + _tprintf(_T("%s\n%s\n\n%s\n"), cmd->Name, cmd->Synopsis, cmd->Description); @@ -180,27 +195,29 @@ SM_CMD_DECL(info) & ReturnDataLength); if (STATUS_SUCCESS != Status) { - printf ("Status 0x%08lx\n", Status); + LoadString( GetModuleHandle(NULL), IDS_Status, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + _tprintf(UsageMessage, Status); return EXIT_FAILURE; } switch (argc) { case 2: - printf ("SM SubSystem Directory\n\n"); - printf ("SSID PID Flags\n"); - printf ("---- -------- ------------\n"); + LoadString( GetModuleHandle(NULL), IDS_SM1, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + _tprintf(UsageMessage); + + LoadString( GetModuleHandle(NULL), IDS_SM2, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); for (i = 0; i < Info.bi.SubSystemCount; i ++) { - printf ("%04x %08lx %04x\n", + _tprintf(UsageMessage, Info.bi.SubSystem[i].Id, Info.bi.SubSystem[i].ProcessId, Info.bi.SubSystem[i].Flags); } break; case 3: - printf ("SubSystem ID: %d\n", Info.ssi.SubSystemId); - printf (" Flags: %04x\n", Info.ssi.Flags); - printf (" Process ID: %ld\n", Info.ssi.ProcessId); + LoadString( GetModuleHandle(NULL), IDS_ID, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + + _tprintf (UsageMessage, Info.ssi.SubSystemId, Info.ssi.Flags, Info.ssi.ProcessId); wprintf(L" NSRootNode: '%s'\n", Info.ssi.NameSpaceRootNode); break; default: @@ -212,8 +229,10 @@ SM_CMD_DECL(info) SM_CMD_DECL(shutdown) { int rc = EXIT_SUCCESS; - - fprintf(stderr,"not implemented\n"); + + LoadString( GetModuleHandle(NULL), IDS_Not_Imp, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + + _ftprintf(stderr,UsageMessage); return rc; } @@ -228,19 +247,18 @@ SM_CMD_DECL(reboot) } /* print command's synopsys */ -int print_synopsys (int argc, char *argv[]) +int print_synopsys (int argc, TCHAR *argv[]) { - fprintf (stderr, "ReactOS/Win32 Session Manager Control Tool\n\n"); - printf ("Usage:\n" - "\tsm\n" - "\tsm help [command]\n" - "\tsm command [arguments]\n\n" - "'sm help' will print the list of valid commands.\n"); + LoadString( GetModuleHandle(NULL), IDS_Mangers, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + _ftprintf (stderr, UsageMessage); + + LoadString( GetModuleHandle(NULL), IDS_USING, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + _tprintf (UsageMessage); return EXIT_SUCCESS; } /* parse and execute */ -int pande (int argc, char *argv[]) +int pande (int argc, TCHAR *argv[]) { PSM_CMD_DESCRIPTOR Command = NULL; NTSTATUS Status = STATUS_SUCCESS; @@ -258,12 +276,26 @@ int pande (int argc, char *argv[]) /* ...and execute it */ return Command->EntryPoint (argc, argv); } - fprintf (stderr, "Failed to connect to the Session Manager! (Status=0x%08lx)\n", Status); + LoadString( GetModuleHandle(NULL), IDS_FAILS_MNG, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + _ftprintf (stderr, UsageMessage, Status); + return EXIT_FAILURE; } -int main (int argc, char *argv[]) +void loadlang(PSM_CMD_DESCRIPTOR cmd) { + int i=0; + if (cmd==NULL) return; + for (i=0;i < 5; i++) + { + LoadString( GetModuleHandle(NULL), IDS_boot+i, (LPTSTR) &cmd->Synopsis[i],RC_STRING_MAX_SIZE); + } +} + +int _tmain (int argc, TCHAR *argv[]) +{ + loadlang(Command); + return (1==argc) ? print_synopsys (argc, argv) : pande (argc, argv); diff --git a/reactos/subsys/system/sm/sm.rc b/reactos/subsys/system/sm/sm.rc index 0de4b780892..75b5e5d5a6a 100644 --- a/reactos/subsys/system/sm/sm.rc +++ b/reactos/subsys/system/sm/sm.rc @@ -1,4 +1,8 @@ +#include #define REACTOS_STR_FILE_DESCRIPTION "ReactOS/Win32 Session Manager Control Tool\0" #define REACTOS_STR_INTERNAL_NAME "sm\0" #define REACTOS_STR_ORIGINAL_FILENAME "sm.exe\0" #include + +#include "En.rc" + diff --git a/reactos/subsys/system/usetup/cabinet.c b/reactos/subsys/system/usetup/cabinet.c index c876a6ea6aa..094fc7699b0 100755 --- a/reactos/subsys/system/usetup/cabinet.c +++ b/reactos/subsys/system/usetup/cabinet.c @@ -46,30 +46,21 @@ static WCHAR CabinetNext[256]; // Filename of next cabinet static WCHAR DiskNext[256]; // Label of cabinet in file CabinetNext static ULONG FolderUncompSize = 0; // Uncompressed size of folder static ULONG BytesLeftInBlock = 0; // Number of bytes left in current block -static BOOL ReuseBlock = FALSE; static WCHAR DestPath[MAX_PATH]; static HANDLE FileHandle; +static HANDLE FileSectionHandle; +static PUCHAR FileBuffer; +static ULONG DestFileSize; +static ULONG FileSize; static BOOL FileOpen = FALSE; -static CFHEADER CABHeader; +static PCFHEADER PCABHeader; +static PCFFOLDER CabinetFolders; static ULONG CabinetReserved = 0; static ULONG FolderReserved = 0; static ULONG DataReserved = 0; -static PCFFOLDER_NODE FolderListHead = NULL; -static PCFFOLDER_NODE FolderListTail = NULL; -static PCFFOLDER_NODE CurrentFolderNode = NULL; -static PCFDATA_NODE CurrentDataNode = NULL; -static PCFFILE_NODE FileListHead = NULL; -static PCFFILE_NODE FileListTail = NULL; static ULONG CodecId; static PCABINET_CODEC_UNCOMPRESS CodecUncompress = NULL; static BOOL CodecSelected = FALSE; -static PVOID InputBuffer = NULL; -static PVOID CurrentIBuffer = NULL; // Current offset in input buffer -static ULONG CurrentIBufferSize = 0; // Bytes left in input buffer -static PVOID OutputBuffer = NULL; -static PVOID CurrentOBuffer = NULL; // Current offset in output buffer -static ULONG CurrentOBufferSize = 0; // Bytes left in output buffer -static BOOL RestartSearch = FALSE; static ULONG LastFileOffset = 0; // Uncompressed offset of last extracted file static PCABINET_OVERWRITE OverwriteHandler = NULL; static PCABINET_EXTRACT ExtractHandler = NULL; @@ -94,20 +85,23 @@ void* calloc(size_t _nmemb, size_t _size) ULONG RawCodecUncompress(PVOID OutputBuffer, - PVOID InputBuffer, - ULONG InputLength, - PULONG OutputLength) + PVOID InputBuffer, + PLONG InputLength, + PLONG OutputLength) /* * FUNCTION: Uncompresses data in a buffer * ARGUMENTS: * OutputBuffer = Pointer to buffer to place uncompressed data * InputBuffer = Pointer to buffer with data to be uncompressed - * InputLength = Length of input buffer - * OutputLength = Address of buffer to place size of uncompressed data + * InputLength = Length of input buffer before, and amount consumed after + * Negative to indicate that this is not the start of a new block + * OutputLength = Length of output buffer before, amount filled after + * Negative to indicate that this is not the end of the block */ { - memcpy(OutputBuffer, InputBuffer, InputLength); - *OutputLength = InputLength; + LONG In = abs(*InputLength), Out = abs(*OutputLength); + memcpy(OutputBuffer, InputBuffer, In < Out ? In : Out); + *InputLength = *OutputLength = In < Out ? In : Out; return CS_SUCCESS; } @@ -116,70 +110,80 @@ RawCodecUncompress(PVOID OutputBuffer, ULONG MSZipCodecUncompress(PVOID OutputBuffer, - PVOID InputBuffer, - ULONG InputLength, - PULONG OutputLength) + PVOID InputBuffer, + PLONG InputLength, + PLONG OutputLength) /* * FUNCTION: Uncompresses data in a buffer * ARGUMENTS: * OutputBuffer = Pointer to buffer to place uncompressed data * InputBuffer = Pointer to buffer with data to be uncompressed - * InputLength = Length of input buffer - * OutputLength = Address of buffer to place size of uncompressed data + * InputLength = Length of input buffer before, and amount consumed after + * Negative to indicate that this is not the start of a new block + * OutputLength = Length of output buffer before, amount filled after + * Negative to indicate that this is not the end of the block */ { USHORT Magic; INT Status; - DPRINT("InputLength (%d).\n", InputLength); + DPRINT("MSZipCodecUncompress( OutputBuffer = %x, InputBuffer = %x, InputLength = %d, OutputLength = %d.\n", OutputBuffer, InputBuffer, *InputLength, *OutputLength); + if( *InputLength > 0 ) + { + Magic = *((PUSHORT)InputBuffer); - Magic = *((PUSHORT)InputBuffer); + if (Magic != MSZIP_MAGIC) + { + DPRINT("Bad MSZIP block header magic (0x%X)\n", Magic); + return CS_BADSTREAM; + } + + ZStream.next_in = (PUCHAR)((ULONG)InputBuffer + 2); + ZStream.avail_in = *InputLength - 2; + ZStream.next_out = (PUCHAR)OutputBuffer; + ZStream.avail_out = abs(*OutputLength); - if (Magic != MSZIP_MAGIC) - { - DPRINT("Bad MSZIP block header magic (0x%X)\n", Magic); - return CS_BADSTREAM; - } - - ZStream.next_in = (PUCHAR)((ULONG)InputBuffer + 2); - ZStream.avail_in = InputLength - 2; - ZStream.next_out = (PUCHAR)OutputBuffer; - ZStream.avail_out = CAB_BLOCKSIZE + 12; - - /* WindowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. - */ - Status = inflateInit2(&ZStream, -MAX_WBITS); - if (Status != Z_OK) - { - DPRINT("inflateInit2() returned (%d).\n", Status); - return CS_BADSTREAM; - } - - while ((ZStream.total_out < CAB_BLOCKSIZE + 12) && - (ZStream.total_in < InputLength - 2)) - { - Status = inflate(&ZStream, Z_NO_FLUSH); - if (Status == Z_STREAM_END) break; - if (Status != Z_OK) - { - DPRINT("inflate() returned (%d) (%s).\n", Status, ZStream.msg); - if (Status == Z_MEM_ERROR) - return CS_NOMEMORY; - return CS_BADSTREAM; - } - } + /* WindowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + */ + Status = inflateInit2(&ZStream, -MAX_WBITS); + if (Status != Z_OK) + { + DPRINT("inflateInit2() returned (%d).\n", Status); + return CS_BADSTREAM; + } + ZStream.total_in = 2; + } + else { + ZStream.avail_in = -*InputLength; + ZStream.next_in = (PUCHAR)InputBuffer; + ZStream.next_out = (PUCHAR)OutputBuffer; + ZStream.avail_out = abs(*OutputLength); + ZStream.total_in = 0; + } + ZStream.total_out = 0; + Status = inflate(&ZStream, Z_SYNC_FLUSH ); + if (Status != Z_OK && Status != Z_STREAM_END) + { + DPRINT("inflate() returned (%d) (%s).\n", Status, ZStream.msg); + if (Status == Z_MEM_ERROR) + return CS_NOMEMORY; + return CS_BADSTREAM; + } + if( *OutputLength > 0 ) + { + Status = inflateEnd(&ZStream); + if (Status != Z_OK) + { + DPRINT("inflateEnd() returned (%d).\n", Status); + return CS_BADSTREAM; + } + } *OutputLength = ZStream.total_out; - - Status = inflateEnd(&ZStream); - if (Status != Z_OK) - { - DPRINT("inflateEnd() returned (%d).\n", Status); - return CS_BADSTREAM; - } + *InputLength = ZStream.total_in; return CS_SUCCESS; } @@ -197,97 +201,14 @@ void MSZipFree (voidpf opaque, voidpf address) RtlFreeHeap(ProcessHeap, 0, address); } - -static DWORD -SeekInFile(HANDLE hFile, - LONG lDistanceToMove, - PLONG lpDistanceToMoveHigh, - DWORD dwMoveMethod, - PNTSTATUS Status) -{ - FILE_POSITION_INFORMATION FilePosition; - FILE_STANDARD_INFORMATION FileStandard; - NTSTATUS errCode; - IO_STATUS_BLOCK IoStatusBlock; - LARGE_INTEGER Distance; - - DPRINT("SeekInFile(hFile %x, lDistanceToMove %d, dwMoveMethod %d)\n", - hFile,lDistanceToMove,dwMoveMethod); - - Distance.u.LowPart = lDistanceToMove; - if (lpDistanceToMoveHigh) - { - Distance.u.HighPart = *lpDistanceToMoveHigh; - } - else if (lDistanceToMove >= 0) - { - Distance.u.HighPart = 0; - } - else - { - Distance.u.HighPart = -1; - } - - if (dwMoveMethod == SEEK_CURRENT) - { - NtQueryInformationFile(hFile, - &IoStatusBlock, - &FilePosition, - sizeof(FILE_POSITION_INFORMATION), - FilePositionInformation); - FilePosition.CurrentByteOffset.QuadPart += Distance.QuadPart; - } - else if (dwMoveMethod == SEEK_END) - { - NtQueryInformationFile(hFile, - &IoStatusBlock, - &FileStandard, - sizeof(FILE_STANDARD_INFORMATION), - FileStandardInformation); - FilePosition.CurrentByteOffset.QuadPart = - FileStandard.EndOfFile.QuadPart + Distance.QuadPart; - } - else if ( dwMoveMethod == SEEK_BEGIN ) - { - FilePosition.CurrentByteOffset.QuadPart = Distance.QuadPart; - } - -// DPRINT1("GOTO FILE OFFSET: %I64d\n", FilePosition.CurrentByteOffset.QuadPart); - - errCode = NtSetInformationFile(hFile, - &IoStatusBlock, - &FilePosition, - sizeof(FILE_POSITION_INFORMATION), - FilePositionInformation); - if (!NT_SUCCESS(errCode)) - { - if (Status != NULL) - { - *Status = errCode; - } - return -1; - } - - if (lpDistanceToMoveHigh != NULL) - { - *lpDistanceToMoveHigh = FilePosition.CurrentByteOffset.u.HighPart; - } - if (Status != NULL) - { - *Status = STATUS_SUCCESS; - } - return FilePosition.CurrentByteOffset.u.LowPart; -} - - static BOOL ConvertSystemTimeToFileTime( - CONST SYSTEMTIME * lpSystemTime, + CONST SYSTEMTIME * lpSystemTime, LPFILETIME lpFileTime) { TIME_FIELDS TimeFields; LARGE_INTEGER liTime; - + TimeFields.Year = lpSystemTime->wYear; TimeFields.Month = lpSystemTime->wMonth; TimeFields.Day = lpSystemTime->wDay; @@ -295,7 +216,7 @@ ConvertSystemTimeToFileTime( TimeFields.Minute = lpSystemTime->wMinute; TimeFields.Second = lpSystemTime->wSecond; TimeFields.Milliseconds = lpSystemTime->wMilliseconds; - + if (RtlTimeFieldsToTime(&TimeFields, &liTime)) { lpFileTime->dwLowDateTime = liTime.u.LowPart; @@ -315,21 +236,21 @@ ConvertDosDateTimeToFileTime( PDOSTIME pdtime = (PDOSTIME) &wFatTime; PDOSDATE pddate = (PDOSDATE) &wFatDate; SYSTEMTIME SystemTime; - + if (lpFileTime == NULL) return FALSE; - + SystemTime.wMilliseconds = 0; SystemTime.wSecond = pdtime->Second; SystemTime.wMinute = pdtime->Minute; SystemTime.wHour = pdtime->Hour; - + SystemTime.wDay = pddate->Day; SystemTime.wMonth = pddate->Month; SystemTime.wYear = 1980 + pddate->Year; - + ConvertSystemTimeToFileTime(&SystemTime,lpFileTime); - + return TRUE; } @@ -345,9 +266,9 @@ GetFileName(PWCHAR Path) */ { ULONG i, j; - + j = i = 0; - + while (Path [i++]) { if (Path[i - 1] == L'\\') j = i; @@ -366,10 +287,10 @@ RemoveFileName(PWCHAR Path) { PWCHAR FileName; DWORD i; - + i = 0; FileName = GetFileName(Path + i); - + if ((FileName != (Path + i)) && (FileName [-1] == L'\\')) FileName--; if ((FileName == (Path + i)) && (FileName [0] == L'\\')) @@ -379,7 +300,7 @@ RemoveFileName(PWCHAR Path) static BOOL -SetAttributesOnFile(PCFFILE_NODE File, HANDLE hFile) +SetAttributesOnFile(PCFFILE File, HANDLE hFile) /* * FUNCTION: Sets attributes on a file * ARGUMENTS: @@ -393,19 +314,19 @@ SetAttributesOnFile(PCFFILE_NODE File, HANDLE hFile) NTSTATUS NtStatus; ULONG Attributes = 0; - if (File->File.Attributes & CAB_ATTRIB_READONLY) + if (File->Attributes & CAB_ATTRIB_READONLY) Attributes |= FILE_ATTRIBUTE_READONLY; - if (File->File.Attributes & CAB_ATTRIB_HIDDEN) + if (File->Attributes & CAB_ATTRIB_HIDDEN) Attributes |= FILE_ATTRIBUTE_HIDDEN; - if (File->File.Attributes & CAB_ATTRIB_SYSTEM) + if (File->Attributes & CAB_ATTRIB_SYSTEM) Attributes |= FILE_ATTRIBUTE_SYSTEM; - if (File->File.Attributes & CAB_ATTRIB_DIRECTORY) + if (File->Attributes & CAB_ATTRIB_DIRECTORY) Attributes |= FILE_ATTRIBUTE_DIRECTORY; - if (File->File.Attributes & CAB_ATTRIB_ARCHIVE) + if (File->Attributes & CAB_ATTRIB_ARCHIVE) Attributes |= FILE_ATTRIBUTE_ARCHIVE; NtStatus = NtQueryInformationFile(hFile, @@ -435,697 +356,6 @@ SetAttributesOnFile(PCFFILE_NODE File, HANDLE hFile) return NT_SUCCESS(NtStatus); } - -static ULONG -ReadBlock(PVOID Buffer, - ULONG Size, - PULONG BytesRead) -/* - * FUNCTION: Read a block of data from file - * ARGUMENTS: - * Buffer = Pointer to data buffer - * Size = Length of data buffer - * BytesRead = Pointer to ULONG that on return will contain - * number of bytes read - * RETURNS: - * Status of operation - */ -{ - IO_STATUS_BLOCK IoStatusBlock; - NTSTATUS NtStatus; - - NtStatus = NtReadFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - Buffer, - Size, - NULL, - NULL); - if (!NT_SUCCESS(NtStatus)) - { - DPRINT("ReadBlock for %d bytes failed (%x)\n", Size, NtStatus); - *BytesRead = 0; - return CAB_STATUS_INVALID_CAB; - } - *BytesRead = Size; - return CAB_STATUS_SUCCESS; -} - - -static PCFFOLDER_NODE -NewFolderNode() -/* - * FUNCTION: Creates a new folder node - * RETURNS: - * Pointer to node if there was enough free memory available, otherwise NULL - */ -{ - PCFFOLDER_NODE Node; - - Node = (PCFFOLDER_NODE)RtlAllocateHeap (ProcessHeap, 0, sizeof(CFFOLDER_NODE)); - if (!Node) - return NULL; - - RtlZeroMemory(Node, sizeof(CFFOLDER_NODE)); - - Node->Folder.CompressionType = CAB_COMP_NONE; - - Node->Prev = FolderListTail; - - if (FolderListTail != NULL) - { - FolderListTail->Next = Node; - } - else - { - FolderListHead = Node; - } - FolderListTail = Node; - - return Node; -} - - -static PCFFILE_NODE -NewFileNode() -/* - * FUNCTION: Creates a new file node - * ARGUMENTS: - * FolderNode = Pointer to folder node to bind file to - * RETURNS: - * Pointer to node if there was enough free memory available, otherwise NULL - */ -{ - PCFFILE_NODE Node; - - Node = (PCFFILE_NODE)RtlAllocateHeap (ProcessHeap, 0, sizeof(CFFILE_NODE)); - if (!Node) - return NULL; - - RtlZeroMemory(Node, sizeof(CFFILE_NODE)); - - Node->Prev = FileListTail; - - if (FileListTail != NULL) - { - FileListTail->Next = Node; - } - else - { - FileListHead = Node; - } - FileListTail = Node; - - return Node; -} - - -static PCFDATA_NODE -NewDataNode(PCFFOLDER_NODE FolderNode) -/* - * FUNCTION: Creates a new data block node - * ARGUMENTS: - * FolderNode = Pointer to folder node to bind data block to - * RETURNS: - * Pointer to node if there was enough free memory available, otherwise NULL - */ -{ - PCFDATA_NODE Node; - - Node = (PCFDATA_NODE)RtlAllocateHeap (ProcessHeap, 0, sizeof(CFDATA_NODE)); - if (!Node) - return NULL; - - RtlZeroMemory(Node, sizeof(CFDATA_NODE)); - - Node->Prev = FolderNode->DataListTail; - - if (FolderNode->DataListTail != NULL) - { - FolderNode->DataListTail->Next = Node; - } - else - { - FolderNode->DataListHead = Node; - } - FolderNode->DataListTail = Node; - - return Node; -} - - -static VOID -DestroyDataNodes(PCFFOLDER_NODE FolderNode) -/* - * FUNCTION: Destroys data block nodes bound to a folder node - * ARGUMENTS: - * FolderNode = Pointer to folder node - */ -{ - PCFDATA_NODE PrevNode; - PCFDATA_NODE NextNode; - - NextNode = FolderNode->DataListHead; - while (NextNode != NULL) - { - PrevNode = NextNode->Next; - RtlFreeHeap(ProcessHeap, 0, NextNode); - NextNode = PrevNode; - } - FolderNode->DataListHead = NULL; - FolderNode->DataListTail = NULL; -} - - -static VOID -DestroyFileNodes() -/* - * FUNCTION: Destroys file nodes - * ARGUMENTS: - * FolderNode = Pointer to folder node - */ -{ - PCFFILE_NODE PrevNode; - PCFFILE_NODE NextNode; - - NextNode = FileListHead; - while (NextNode != NULL) - { - PrevNode = NextNode->Next; - if (NextNode->FileName) - RtlFreeHeap(ProcessHeap, 0, NextNode->FileName); - RtlFreeHeap(ProcessHeap, 0, NextNode); - NextNode = PrevNode; - } - FileListHead = NULL; - FileListTail = NULL; -} - - -#if 0 -static VOID -DestroyDeletedFileNodes() -/* - * FUNCTION: Destroys file nodes that are marked for deletion - */ -{ - PCFFILE_NODE CurNode; - PCFFILE_NODE NextNode; - - CurNode = FileListHead; - while (CurNode != NULL) - { - NextNode = CurNode->Next; - - if (CurNode->Delete) - { - if (CurNode->Prev != NULL) - { - CurNode->Prev->Next = CurNode->Next; - } - else - { - FileListHead = CurNode->Next; - if (FileListHead) - FileListHead->Prev = NULL; - } - - if (CurNode->Next != NULL) - { - CurNode->Next->Prev = CurNode->Prev; - } - else - { - FileListTail = CurNode->Prev; - if (FileListTail) - FileListTail->Next = NULL; - } - - DPRINT("Deleting file: '%S'\n", CurNode->FileName); - - if (CurNode->FileName) - RtlFreeHeap(ProcessHeap, 0, CurNode->FileName); - RtlFreeHeap(ProcessHeap, 0, CurNode); - } - CurNode = NextNode; - } -} -#endif - -static VOID -DestroyFolderNodes() -/* - * FUNCTION: Destroys folder nodes - */ -{ - PCFFOLDER_NODE PrevNode; - PCFFOLDER_NODE NextNode; - - NextNode = FolderListHead; - while (NextNode != NULL) - { - PrevNode = NextNode->Next; - DestroyDataNodes(NextNode); - RtlFreeHeap(ProcessHeap, 0, NextNode); - NextNode = PrevNode; - } - FolderListHead = NULL; - FolderListTail = NULL; -} - -#if 0 -static VOID -DestroyDeletedFolderNodes() -/* - * FUNCTION: Destroys folder nodes that are marked for deletion - */ -{ - PCFFOLDER_NODE CurNode; - PCFFOLDER_NODE NextNode; - - CurNode = FolderListHead; - while (CurNode != NULL) - { - NextNode = CurNode->Next; - - if (CurNode->Delete) - { - if (CurNode->Prev != NULL) - { - CurNode->Prev->Next = CurNode->Next; - } - else - { - FolderListHead = CurNode->Next; - if (FolderListHead) - FolderListHead->Prev = NULL; - } - - if (CurNode->Next != NULL) - { - CurNode->Next->Prev = CurNode->Prev; - } - else - { - FolderListTail = CurNode->Prev; - if (FolderListTail) - FolderListTail->Next = NULL; - } - - DestroyDataNodes(CurNode); - RtlFreeHeap(ProcessHeap, 0, CurNode); - } - CurNode = NextNode; - } -} -#endif - -static PCFFOLDER_NODE -LocateFolderNode(ULONG Index) -/* - * FUNCTION: Locates a folder node - * ARGUMENTS: - * Index = Folder index - * RETURNS: - * Pointer to folder node or NULL if the folder node was not found - */ -{ - PCFFOLDER_NODE Node; - - switch (Index) - { - case CAB_FILE_SPLIT: - return FolderListTail; - - case CAB_FILE_CONTINUED: - case CAB_FILE_PREV_NEXT: - return FolderListHead; - } - - Node = FolderListHead; - while (Node != NULL) - { - if (Node->Index == Index) - return Node; - Node = Node->Next; - } - return NULL; -} - - -static ULONG -GetAbsoluteOffset(PCFFILE_NODE File) -/* - * FUNCTION: Returns the absolute offset of a file - * ARGUMENTS: - * File = Pointer to CFFILE_NODE structure for file - * RETURNS: - * Status of operation - */ -{ - PCFDATA_NODE Node; - - DPRINT("FileName '%S' FileOffset (0x%X) FileSize (%d).\n", - (PWCHAR)File->FileName, - (UINT)File->File.FileOffset, - (UINT)File->File.FileSize); - - Node = CurrentFolderNode->DataListHead; - while (Node != NULL) - { - DPRINT("GetAbsoluteOffset(): Comparing (0x%X, 0x%X) (%d).\n", - (UINT)Node->UncompOffset, - (UINT)Node->UncompOffset + Node->Data.UncompSize, - (UINT)Node->Data.UncompSize); - - /* Node->Data.UncompSize will be 0 if the block is split - (ie. it is the last block in this cabinet) */ - if ((Node->Data.UncompSize == 0) || - ((File->File.FileOffset >= Node->UncompOffset) && - (File->File.FileOffset < Node->UncompOffset + - Node->Data.UncompSize))) - { - File->DataBlock = Node; - return CAB_STATUS_SUCCESS; - } - - Node = Node->Next; - } - return CAB_STATUS_INVALID_CAB; -} - - -static ULONG -LocateFile(PWCHAR FileName, - PCFFILE_NODE *File) -/* - * FUNCTION: Locates a file in the cabinet - * ARGUMENTS: - * FileName = Pointer to string with name of file to locate - * File = Address of pointer to CFFILE_NODE structure to fill - * RETURNS: - * Status of operation - * NOTES: - * Current folder is set to the folder of the file - */ -{ - PCFFILE_NODE Node; - ULONG Status; - - DPRINT("FileName '%S'\n", FileName); - - Node = FileListHead; - while (Node != NULL) - { - if (_wcsicmp(FileName, Node->FileName) == 0) - { - CurrentFolderNode = LocateFolderNode(Node->File.FileControlID); - if (!CurrentFolderNode) - { - DPRINT("Folder with index number (%d) not found.\n", - (UINT)Node->File.FileControlID); - return CAB_STATUS_INVALID_CAB; - } - - if (Node->DataBlock == NULL) - { - Status = GetAbsoluteOffset(Node); - } - else - Status = CAB_STATUS_SUCCESS; - *File = Node; - return Status; - } - Node = Node->Next; - } - return CAB_STATUS_NOFILE; -} - - -static ULONG -ReadString(PWCHAR String, ULONG MaxLength) -/* - * FUNCTION: Reads a NULL-terminated string from the cabinet - * ARGUMENTS: - * String = Pointer to buffer to place string - * MaxLength = Maximum length of string - * RETURNS: - * Status of operation - */ -{ - NTSTATUS NtStatus; - ULONG BytesRead; - ULONG Offset; - ULONG Status; - ULONG Size; - BOOL Found; - CHAR buf[MAX_PATH]; - ANSI_STRING as; - UNICODE_STRING us; - - Offset = 0; - Found = FALSE; - do - { - Size = ((Offset + 32) <= MaxLength)? 32 : MaxLength - Offset; - - if (Size == 0) - { - DPRINT("Too long a filename.\n"); - return CAB_STATUS_INVALID_CAB; - } - - Status = ReadBlock((PCFDATA)&buf[Offset], Size, &BytesRead); - if ((Status != CAB_STATUS_SUCCESS) || (BytesRead != Size)) - { - DPRINT("Cannot read from file (%d).\n", (UINT)Status); - return CAB_STATUS_INVALID_CAB; - } - - for (Size = Offset; Size < Offset + BytesRead; Size++) - { - if (buf[Size] == '\0') - { - Found = TRUE; - break; - } - } - - Offset += BytesRead; - } while (!Found); - - /* Back up some bytes */ - Size = (BytesRead - Size) - 1; - SeekInFile(FileHandle, -(LONG)Size, NULL, SEEK_CURRENT, &NtStatus); - if (!NT_SUCCESS(NtStatus)) - { - DPRINT("SeekInFile() failed (%x).\n", NtStatus); - return CAB_STATUS_INVALID_CAB; - } - - RtlInitAnsiString(&as, buf); - us.Buffer = String; - us.MaximumLength = MaxLength * sizeof(WCHAR); - us.Length = 0; - - RtlAnsiStringToUnicodeString(&us, &as, FALSE); - - return CAB_STATUS_SUCCESS; -} - - -static ULONG -ReadFileTable(VOID) -/* - * FUNCTION: Reads the file table from the cabinet file - * RETURNS: - * Status of operation - */ -{ - ULONG i; - ULONG Status; - ULONG BytesRead; - PCFFILE_NODE File; - NTSTATUS NtStatus; - - DPRINT("Reading file table at absolute offset (0x%X).\n", - CABHeader.FileTableOffset); - - /* Seek to file table */ - SeekInFile(FileHandle, CABHeader.FileTableOffset, NULL, SEEK_BEGIN, &NtStatus); - if (!NT_SUCCESS(NtStatus)) - { - DPRINT("SeekInFile() failed (%x).\n", NtStatus); - return CAB_STATUS_INVALID_CAB; - } - - for (i = 0; i < CABHeader.FileCount; i++) - { - File = NewFileNode(); - if (!File) - { - DPRINT("Insufficient memory.\n"); - return CAB_STATUS_NOMEMORY; - } - - if ((Status = ReadBlock(&File->File, sizeof(CFFILE), - &BytesRead)) != CAB_STATUS_SUCCESS) { - DPRINT("Cannot read from file (%d).\n", (UINT)Status); - return CAB_STATUS_INVALID_CAB; - } - - File->FileName = (PWCHAR)RtlAllocateHeap(ProcessHeap, 0, MAX_PATH * sizeof(WCHAR)); - if (!File->FileName) - { - DPRINT("Insufficient memory.\n"); - return CAB_STATUS_NOMEMORY; - } - - /* Read file name */ - Status = ReadString(File->FileName, MAX_PATH); - if (Status != CAB_STATUS_SUCCESS) - return Status; - - DPRINT("Found file '%S' at uncompressed offset (0x%X). Size (%d bytes) ControlId (0x%X).\n", - (PWCHAR)File->FileName, - (UINT)File->File.FileOffset, - (UINT)File->File.FileSize, - (UINT)File->File.FileControlID); - } - return CAB_STATUS_SUCCESS; -} - - -static ULONG -ReadDataBlocks(PCFFOLDER_NODE FolderNode) -/* - * FUNCTION: Reads all CFDATA blocks for a folder from the cabinet file - * ARGUMENTS: - * FolderNode = Pointer to CFFOLDER_NODE structure for folder - * RETURNS: - * Status of operation - */ -{ - ULONG AbsoluteOffset; - ULONG UncompOffset; - PCFDATA_NODE Node; - NTSTATUS NtStatus; - ULONG BytesRead; - ULONG Status; - ULONG i; - - DPRINT("Reading data blocks for folder (%d) at absolute offset (0x%X).\n", - FolderNode->Index, FolderNode->Folder.DataOffset); - - AbsoluteOffset = FolderNode->Folder.DataOffset; - UncompOffset = FolderNode->UncompOffset; - - for (i = 0; i < FolderNode->Folder.DataBlockCount; i++) - { - Node = NewDataNode(FolderNode); - if (!Node) - { - DPRINT("Insufficient memory.\n"); - return CAB_STATUS_NOMEMORY; - } - - /* Seek to data block */ - SeekInFile(FileHandle, AbsoluteOffset, NULL, SEEK_BEGIN, &NtStatus); - if (!NT_SUCCESS(NtStatus)) - { - DPRINT("SeekInFile() failed (%x).\n", NtStatus); - return CAB_STATUS_INVALID_CAB; - } - - if ((Status = ReadBlock(&Node->Data, sizeof(CFDATA), - &BytesRead)) != CAB_STATUS_SUCCESS) - { - DPRINT("Cannot read from file (%d).\n", (UINT)Status); - return CAB_STATUS_INVALID_CAB; - } - - DPRINT("AbsOffset (0x%X) UncompOffset (0x%X) Checksum (0x%X) CompSize (%d) UncompSize (%d).\n", - (UINT)AbsoluteOffset, - (UINT)UncompOffset, - (UINT)Node->Data.Checksum, - (UINT)Node->Data.CompSize, - (UINT)Node->Data.UncompSize); - - Node->AbsoluteOffset = AbsoluteOffset; - Node->UncompOffset = UncompOffset; - - AbsoluteOffset += sizeof(CFDATA) + Node->Data.CompSize; - UncompOffset += Node->Data.UncompSize; - } - - FolderUncompSize = UncompOffset; - - return CAB_STATUS_SUCCESS; -} - -#if 0 -static ULONG -ComputeChecksum(PVOID Buffer, - UINT Size, - ULONG Seed) -/* - * FUNCTION: Computes checksum for data block - * ARGUMENTS: - * Buffer = Pointer to data buffer - * Size = Length of data buffer - * Seed = Previously computed checksum - * RETURNS: - * Checksum of buffer - */ -{ - INT UlongCount; // Number of ULONGs in block - ULONG Checksum; // Checksum accumulator - PBYTE pb; - ULONG ul; - - /* FIXME: Doesn't seem to be correct. EXTRACT.EXE - won't accept checksums computed by this routine */ - - DPRINT("Checksumming buffer (0x%X) Size (%d)\n", (UINT)Buffer, Size); - - UlongCount = Size / 4; // Number of ULONGs - Checksum = Seed; // Init checksum - pb = (PBYTE)Buffer; // Start at front of data block - - /* Checksum integral multiple of ULONGs */ - while (UlongCount-- > 0) - { - /* NOTE: Build ULONG in big/little-endian independent manner */ - ul = *pb++; // Get low-order byte - ul |= (((ULONG)(*pb++)) << 8); // Add 2nd byte - ul |= (((ULONG)(*pb++)) << 16); // Add 3nd byte - ul |= (((ULONG)(*pb++)) << 24); // Add 4th byte - - Checksum ^= ul; // Update checksum - } - - /* Checksum remainder bytes */ - ul = 0; - switch (Size % 4) - { - case 3: - ul |= (((ULONG)(*pb++)) << 16); // Add 3rd byte - case 2: - ul |= (((ULONG)(*pb++)) << 8); // Add 2nd byte - case 1: - ul |= *pb++; // Get low-order byte - default: - break; - } - Checksum ^= ul; // Update checksum - - /* Return computed checksum */ - return Checksum; -} -#endif - static ULONG CloseCabinet(VOID) /* @@ -1134,23 +364,14 @@ CloseCabinet(VOID) * Status of operation */ { - DestroyFileNodes(); - - DestroyFolderNodes(); - - if (InputBuffer) + if (FileBuffer) { - RtlFreeHeap(ProcessHeap, 0, InputBuffer); - InputBuffer = NULL; + NtUnmapViewOfSection( NtCurrentProcess(), FileBuffer ); + NtClose( FileSectionHandle ); + NtClose( FileHandle ); + FileBuffer = NULL; } - - if (OutputBuffer) - { - RtlFreeHeap(ProcessHeap, 0, OutputBuffer); - OutputBuffer = NULL; - } - - NtClose(FileHandle); + return 0; } @@ -1167,32 +388,16 @@ CabinetInitialize(VOID) FileOpen = FALSE; wcscpy(DestPath, L""); - - FolderListHead = NULL; - FolderListTail = NULL; - FileListHead = NULL; - FileListTail = NULL; - + CodecId = CAB_CODEC_RAW; CodecSelected = TRUE; - - OutputBuffer = NULL; - CurrentOBuffer = NULL; - CurrentOBufferSize = 0; - InputBuffer = NULL; - CurrentIBuffer = NULL; - CurrentIBufferSize = 0; - + FolderUncompSize = 0; BytesLeftInBlock = 0; CabinetReserved = 0; FolderReserved = 0; DataReserved = 0; - ReuseBlock = FALSE; - CurrentFolderNode = NULL; - CurrentDataNode = NULL; CabinetReservedArea = NULL; - RestartSearch = FALSE; LastFileOffset = 0; } @@ -1221,7 +426,7 @@ CabinetNormalizePath(PWCHAR Path, { ULONG n; BOOL OK = TRUE; - + if ((n = wcslen(Path)) && (Path[n - 1] != L'\\') && (OK = ((n + 1) < Length))) @@ -1291,24 +496,18 @@ CabinetOpen(VOID) * Status of operation */ { - WCHAR CabinetFileName[256]; - PCFFOLDER_NODE FolderNode; - ULONG Status; - ULONG Index; - + PUCHAR Buffer; + UNICODE_STRING ustring; + ANSI_STRING astring; + if (!FileOpen) { OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING FileName; NTSTATUS NtStatus; - ULONG BytesRead; ULONG Size; - - OutputBuffer = RtlAllocateHeap(ProcessHeap, 0, CAB_BLOCKSIZE + 12); // This should be enough - if (!OutputBuffer) - return CAB_STATUS_NOMEMORY; - + RtlInitUnicodeString(&FileName, CabinetName); @@ -1319,168 +518,137 @@ CabinetOpen(VOID) NULL); NtStatus = NtOpenFile(&FileHandle, - GENERIC_READ, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_NONALERT); + GENERIC_READ | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT); if (!NT_SUCCESS(NtStatus)) { DPRINT("Cannot open file (%S) (%x).\n", CabinetName, NtStatus); return CAB_STATUS_CANNOT_OPEN; } - FileOpen = TRUE; - /* Load CAB header */ - if ((Status = ReadBlock(&CABHeader, sizeof(CFHEADER), &BytesRead)) != CAB_STATUS_SUCCESS) - { - DPRINT("Cannot read from file (%d).\n", (UINT)Status); - return CAB_STATUS_INVALID_CAB; - } - + NtStatus = NtCreateSection(&FileSectionHandle, + SECTION_ALL_ACCESS, + 0, + 0, + PAGE_READONLY, + SEC_COMMIT, + FileHandle); + if(!NT_SUCCESS(NtStatus)) + { + DPRINT("NtCreateSection failed: %x\n", NtStatus); + return CAB_STATUS_NOMEMORY; + } + FileBuffer = 0; + FileSize = 0; + NtStatus = NtMapViewOfSection(FileSectionHandle, + NtCurrentProcess(), + (PVOID *)&FileBuffer, + 0, + 0, + 0, + &FileSize, + ViewUnmap, + 0, + PAGE_READONLY); + if(!NT_SUCCESS(NtStatus)) + { + DPRINT("NtMapViewOfSection failed: %x\n", NtStatus); + return CAB_STATUS_NOMEMORY; + } + DPRINT( "Cabinet file %S opened and mapped to %x\n", CabinetName, FileBuffer ); + PCABHeader = (PCFHEADER)FileBuffer; + /* Check header */ - if ((BytesRead != sizeof(CFHEADER)) || - (CABHeader.Signature != CAB_SIGNATURE ) || - (CABHeader.Version != CAB_VERSION ) || - (CABHeader.FolderCount == 0 ) || - (CABHeader.FileCount == 0 ) || - (CABHeader.FileTableOffset < sizeof(CFHEADER))) { - CloseCabinet(); - DPRINT("File has invalid header.\n"); - return CAB_STATUS_INVALID_CAB; - } - + if(FileSize <= sizeof(CFHEADER) || + PCABHeader->Signature != CAB_SIGNATURE || + PCABHeader->Version != CAB_VERSION || + PCABHeader->FolderCount == 0 || + PCABHeader->FileCount == 0 || + PCABHeader->FileTableOffset < sizeof(CFHEADER)) + { + CloseCabinet(); + DPRINT("File has invalid header.\n"); + return CAB_STATUS_INVALID_CAB; + } + Size = 0; - + Buffer = (PUCHAR)(PCABHeader+1); /* Read/skip any reserved bytes */ - if (CABHeader.Flags & CAB_FLAG_RESERVE) + if (PCABHeader->Flags & CAB_FLAG_RESERVE) { - if ((Status = ReadBlock(&Size, sizeof(ULONG), &BytesRead)) != CAB_STATUS_SUCCESS) - { - DPRINT("Cannot read from file (%d).\n", (UINT)Status); - return CAB_STATUS_INVALID_CAB; - } - CabinetReserved = Size & 0xFFFF; - FolderReserved = (Size >> 16) & 0xFF; - DataReserved = (Size >> 24) & 0xFF; - + CabinetReserved = *(PUSHORT)Buffer; + Buffer += 2; + FolderReserved = *Buffer; + Buffer++; + DataReserved = *Buffer; + Buffer++; if (CabinetReserved > 0) { - CabinetReservedArea = RtlAllocateHeap(ProcessHeap, 0, CabinetReserved); - if (!CabinetReservedArea) - { - return CAB_STATUS_NOMEMORY; - } - - if ((Status = ReadBlock(CabinetReservedArea, CabinetReserved, &BytesRead)) != CAB_STATUS_SUCCESS) - { - DPRINT("Cannot read from file (%d).\n", (UINT)Status); - return CAB_STATUS_INVALID_CAB; - } + CabinetReservedArea = Buffer; + Buffer += CabinetReserved; } -#if 0 - SeekInFile(FileHandle, CabinetReserved, NULL, SEEK_CURRENT, &NtStatus); - if (!NT_SUCCESS(NtStatus)) - { - DPRINT("SeekInFile() failed (%x).\n", NtStatus); - return CAB_STATUS_INVALID_CAB; - } -#endif } - - if ((CABHeader.Flags & CAB_FLAG_HASPREV) > 0) + + if (PCABHeader->Flags & CAB_FLAG_HASPREV) { - /* Read name of previous cabinet */ - Status = ReadString(CabinetFileName, 256); - if (Status != CAB_STATUS_SUCCESS) - return Status; - /* The previous cabinet file is in the same directory as the current */ wcscpy(CabinetPrev, CabinetName); RemoveFileName(CabinetPrev); CabinetNormalizePath(CabinetPrev, 256); - wcscat(CabinetPrev, CabinetFileName); + RtlInitAnsiString( &astring, (LPSTR)Buffer ); + ustring.Length = wcslen( CabinetPrev ); + ustring.Buffer = CabinetPrev + ustring.Length; + ustring.MaximumLength = sizeof( CabinetPrev ) - ustring.Length; + RtlAnsiStringToUnicodeString( &ustring, &astring, FALSE ); + Buffer += astring.Length + 1; - /* Read label of previous disk */ - Status = ReadString(DiskPrev, 256); - if (Status != CAB_STATUS_SUCCESS) - return Status; + /* Read label of prev disk */ + RtlInitAnsiString( &astring, (LPSTR)Buffer ); + ustring.Length = 0; + ustring.Buffer = DiskPrev; + ustring.MaximumLength = sizeof( DiskPrev ); + RtlAnsiStringToUnicodeString( &ustring, &astring, FALSE ); + Buffer += astring.Length + 1; } else { wcscpy(CabinetPrev, L""); wcscpy(DiskPrev, L""); } - - if ((CABHeader.Flags & CAB_FLAG_HASNEXT) > 0) + + if (PCABHeader->Flags & CAB_FLAG_HASNEXT) { - /* Read name of next cabinet */ - Status = ReadString(CabinetFileName, 256); - if (Status != CAB_STATUS_SUCCESS) - return Status; - /* The next cabinet file is in the same directory as the previous */ wcscpy(CabinetNext, CabinetName); RemoveFileName(CabinetNext); CabinetNormalizePath(CabinetNext, 256); - wcscat(CabinetNext, CabinetFileName); + RtlInitAnsiString( &astring, (LPSTR)Buffer ); + ustring.Length = wcslen( CabinetNext ); + ustring.Buffer = CabinetNext + ustring.Length; + ustring.MaximumLength = sizeof( CabinetNext ) - ustring.Length; + RtlAnsiStringToUnicodeString( &ustring, &astring, FALSE ); + Buffer += astring.Length + 1; /* Read label of next disk */ - Status = ReadString(DiskNext, 256); - if (Status != CAB_STATUS_SUCCESS) - return Status; + RtlInitAnsiString( &astring, (LPSTR)Buffer ); + ustring.Length = 0; + ustring.Buffer = DiskNext; + ustring.MaximumLength = sizeof( DiskNext ); + RtlAnsiStringToUnicodeString( &ustring, &astring, FALSE ); + Buffer += astring.Length + 1; } else { wcscpy(CabinetNext, L""); wcscpy(DiskNext, L""); } - - /* Read all folders */ - for (Index = 0; Index < CABHeader.FolderCount; Index++) - { - FolderNode = NewFolderNode(); - if (!FolderNode) - { - DPRINT("Insufficient resources.\n"); - return CAB_STATUS_NOMEMORY; - } - - if (Index == 0) - FolderNode->UncompOffset = FolderUncompSize; - - FolderNode->Index = Index; - - if ((Status = ReadBlock(&FolderNode->Folder, - sizeof(CFFOLDER), &BytesRead)) != CAB_STATUS_SUCCESS) - { - DPRINT("Cannot read from file (%d).\n", (UINT)Status); - return CAB_STATUS_INVALID_CAB; - } - } - - /* Read file entries */ - Status = ReadFileTable(); - if (Status != CAB_STATUS_SUCCESS) - { - DPRINT("ReadFileTable() failed (%d).\n", (UINT)Status); - return Status; - } - - /* Read data blocks for all folders */ - FolderNode = FolderListHead; - while (FolderNode != NULL) - { - Status = ReadDataBlocks(FolderNode); - if (Status != CAB_STATUS_SUCCESS) - { - DPRINT("ReadDataBlocks() failed (%d).\n", (UINT)Status); - return Status; - } - FolderNode = FolderNode->Next; - } + CabinetFolders = (PCFFOLDER)Buffer; } + DPRINT( "CabinetOpen returning SUCCESS\n" ); return CAB_STATUS_SUCCESS; } @@ -1495,12 +663,6 @@ CabinetClose(VOID) { CloseCabinet(); - if (CabinetReservedArea != NULL) - { - RtlFreeHeap(ProcessHeap, 0, CabinetReservedArea); - CabinetReservedArea = NULL; - } - FileOpen = FALSE; } } @@ -1508,7 +670,7 @@ CabinetClose(VOID) ULONG CabinetFindFirst(PWCHAR FileName, - PCAB_SEARCH Search) + PCAB_SEARCH Search) /* * FUNCTION: Finds the first file in the cabinet that matches a search criteria * ARGUMENTS: @@ -1518,9 +680,10 @@ CabinetFindFirst(PWCHAR FileName, * Status of operation */ { - RestartSearch = FALSE; + DPRINT( "CabinetFindFirst( FileName = %S )\n", FileName ); wcsncpy(Search->Search, FileName, MAX_PATH); - Search->Next = FileListHead; + wcsncpy(Search->Cabinet, CabinetName, MAX_PATH); + Search->File = 0; return CabinetFindNext(Search); } @@ -1536,172 +699,212 @@ CabinetFindNext(PCAB_SEARCH Search) */ { ULONG Status; + PCFFILE Prev; + ANSI_STRING AnsiString; + UNICODE_STRING UnicodeString; + WCHAR FileName[MAX_PATH]; - if (RestartSearch) - { - Search->Next = FileListHead; + if( wcscmp( Search->Cabinet, CabinetName ) != 0 ) + Search->File = 0; // restart search of cabinet has changed since last find + if( !Search->File ) + { + // starting new search or cabinet + Search->File = (PCFFILE)(FileBuffer + PCABHeader->FileTableOffset); + Search->Index = 0; + Prev = 0; + } + else Prev = Search->File; + while(1) + { + // look at each file in the archive and see if we found a match + if( Search->File->FolderIndex == 0xFFFD || Search->File->FolderIndex == 0xFFFF ) + { + // skip files continued from previous cab + DPRINT("Skipping file (%s) FileOffset (0x%X) LastFileOffset (0x%X).\n", + (char *)(Search->File + 1), Search->File->FileOffset, LastFileOffset); + } + else { + // FIXME: check for match against search criteria + if( Search->File != Prev ) + { + // don't match the file we started with + if( wcscmp( Search->Search, L"*" ) == 0 ) + { + // take any file + break; + } + else { + // otherwise, try to match the exact file name + RtlInitAnsiString( &AnsiString, Search->File->FileName ); + UnicodeString.Buffer = FileName; + UnicodeString.Length = 0; + UnicodeString.MaximumLength = sizeof( FileName ); + RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE ); + if( wcscmp( Search->Search, UnicodeString.Buffer ) == 0 ) + break; + } + } + } + // if we make it here we found no match, so move to the next file + Search->Index++; + if( Search->Index >= PCABHeader->FileCount ) + { + // we have reached the end of this cabinet, try to open the next + DPRINT( "End of cabinet reached\n" ); + if (wcslen(DiskNext) > 0) + { + CloseCabinet(); + + CabinetSetCabinetName(CabinetNext); + wcscpy( Search->Cabinet, CabinetName ); + + if (DiskChangeHandler != NULL) + { + DiskChangeHandler(CabinetNext, DiskNext); + } + + Status = CabinetOpen(); + if (Status != CAB_STATUS_SUCCESS) + return Status; - /* Skip split files already extracted */ - while ((Search->Next) && - (Search->Next->File.FileControlID > CAB_FILE_MAX_FOLDER) && - (Search->Next->File.FileOffset <= LastFileOffset)) - { - DPRINT("Skipping file (%s) FileOffset (0x%X) LastFileOffset (0x%X).\n", - Search->Next->FileName, Search->Next->File.FileOffset, LastFileOffset); - Search->Next = Search->Next->Next; - } - - RestartSearch = FALSE; - } - - /* FIXME: Check search criteria */ - - if (!Search->Next) - { - if (wcslen(DiskNext) > 0) - { - CloseCabinet(); - - CabinetSetCabinetName(CabinetNext); - - if (DiskChangeHandler != NULL) - { - DiskChangeHandler(CabinetNext, DiskNext); - } - - Status = CabinetOpen(); - if (Status != CAB_STATUS_SUCCESS) - return Status; - - Search->Next = FileListHead; - if (!Search->Next) - return CAB_STATUS_NOFILE; - } - else - { - return CAB_STATUS_NOFILE; - } - } - - Search->File = &Search->Next->File; - Search->FileName = Search->Next->FileName; - Search->Next = Search->Next->Next; + } + else + { + return CAB_STATUS_NOFILE; + } + // starting new search or cabinet + Search->File = (PCFFILE)(FileBuffer + PCABHeader->FileTableOffset); + Search->Index = 0; + Prev = 0; + } + else Search->File = (PCFFILE)(strchr( (char *)(Search->File + 1), 0 ) + 1); + } + DPRINT( "Found file %s\n", Search->File->FileName ); return CAB_STATUS_SUCCESS; } -ULONG -CabinetExtractFile(PWCHAR FileName) +int Validate() +{ + return (int)RtlValidateHeap(ProcessHeap, 0, 0); +} + +ULONG CabinetExtractFile( PCAB_SEARCH Search ) /* * FUNCTION: Extracts a file from the cabinet * ARGUMENTS: - * FileName = Pointer to buffer with name of file + * Search = Pointer to PCAB_SEARCH structure used to locate the file * RETURNS * Status of operation */ { - ULONG Size; - ULONG Offset; - ULONG BytesRead; - ULONG BytesToRead; - ULONG BytesWritten; - ULONG BytesSkipped; - ULONG BytesToWrite; - ULONG TotalBytesRead; - ULONG CurrentOffset; - PUCHAR Buffer; - PUCHAR CurrentBuffer; + ULONG Size; // remaining file bytes to decompress + ULONG CurrentOffset; // current uncompressed offset within the folder + PUCHAR CurrentBuffer; // current pointer to compressed data in the block + LONG RemainingBlock; // remaining comp data in the block HANDLE DestFile; - PCFFILE_NODE File; - CFDATA CFData; + HANDLE DestFileSection; + PVOID DestFileBuffer; // mapped view of dest file + PVOID CurrentDestBuffer; // pointer to the current position in the dest view + PCFDATA CFData; // current data block ULONG Status; - BOOL Skip; FILETIME FileTime; WCHAR DestName[MAX_PATH]; - WCHAR TempName[MAX_PATH]; - PWCHAR s; NTSTATUS NtStatus; UNICODE_STRING UnicodeString; + ANSI_STRING AnsiString; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; FILE_BASIC_INFORMATION FileBasic; + PCFFOLDER CurrentFolder; + LARGE_INTEGER MaxDestFileSize; + LONG InputLength, OutputLength; + char Junk[512]; - Status = LocateFile(FileName, &File); - if (Status != CAB_STATUS_SUCCESS) + if( wcscmp( Search->Cabinet, CabinetName ) != 0 ) + { + // the file is not in the current cabinet + DPRINT( "File is not in this cabinet ( %S != %S )\n", Search->Cabinet, CabinetName ); + return CAB_STATUS_NOFILE; + } + // look up the folder that the file specifies + if( Search->File->FolderIndex == 0xFFFD || Search->File->FolderIndex == 0xFFFF ) + { + // folder is continued from previous cabinet, that shouldn't happen here + return CAB_STATUS_NOFILE; + } + else if( Search->File->FolderIndex == 0xFFFE ) + { + // folder is the last in this cabinet and continues into next + CurrentFolder = &CabinetFolders[PCABHeader->FolderCount-1]; + } + else { + // folder is completely contained within this cabinet + CurrentFolder = &CabinetFolders[Search->File->FolderIndex]; + } + switch (CurrentFolder->CompressionType & CAB_COMP_MASK) { - DPRINT("Cannot locate file (%d).\n", (UINT)Status); - return Status; - } - - LastFileOffset = File->File.FileOffset; - - switch (CurrentFolderNode->Folder.CompressionType & CAB_COMP_MASK) - { - case CAB_COMP_NONE: - CabinetSelectCodec(CAB_CODEC_RAW); - break; - case CAB_COMP_MSZIP: - CabinetSelectCodec(CAB_CODEC_MSZIP); - break; - default: - return CAB_STATUS_UNSUPPCOMP; - } - - DPRINT("Extracting file at uncompressed offset (0x%X) Size (%d bytes) AO (0x%X) UO (0x%X).\n", - (UINT)File->File.FileOffset, - (UINT)File->File.FileSize, - (UINT)File->DataBlock->AbsoluteOffset, - (UINT)File->DataBlock->UncompOffset); - - wcscpy(DestName, DestPath); - wcscat(DestName, FileName); - - while (NULL != (s = wcsstr(DestName, L"\\.\\"))) - { - memmove(s, s + 2, (wcslen(s + 2) + 1) *sizeof(WCHAR)); + case CAB_COMP_NONE: + CabinetSelectCodec(CAB_CODEC_RAW); + break; + case CAB_COMP_MSZIP: + CabinetSelectCodec(CAB_CODEC_MSZIP); + break; + default: + return CAB_STATUS_UNSUPPCOMP; } + + DPRINT("Extracting file at uncompressed offset (0x%X) Size (%d bytes)).\n", + (UINT)Search->File->FileOffset, + (UINT)Search->File->FileSize); + RtlInitAnsiString( &AnsiString, Search->File->FileName ); + wcscpy( DestName, DestPath ); + UnicodeString.MaximumLength = sizeof( DestName ) - wcslen( DestName ); + UnicodeString.Buffer = DestName + wcslen( DestName ); + UnicodeString.Length = 0; + RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE ); /* Create destination file, fail if it already exists */ RtlInitUnicodeString(&UnicodeString, - DestName); + DestName); InitializeObjectAttributes(&ObjectAttributes, - &UnicodeString, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); + &UnicodeString, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); NtStatus = NtCreateFile(&DestFile, - GENERIC_WRITE|FILE_READ_ATTRIBUTES, - &ObjectAttributes, - &IoStatusBlock, - NULL, - FILE_ATTRIBUTE_NORMAL, - 0, - FILE_CREATE, - FILE_SYNCHRONOUS_IO_NONALERT, - NULL, - 0); + GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_CREATE, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0); if (!NT_SUCCESS(NtStatus)) { DPRINT("NtCreateFile() failed (%S) (%x).\n", DestName, NtStatus); /* If file exists, ask to overwrite file */ - if (OverwriteHandler == NULL || OverwriteHandler(&File->File, FileName)) + if (OverwriteHandler == NULL || OverwriteHandler(Search->File, DestName)) { /* Create destination file, overwrite if it already exists */ NtStatus = NtCreateFile(&DestFile, - GENERIC_WRITE|FILE_READ_ATTRIBUTES, - &ObjectAttributes, - &IoStatusBlock, - NULL, - FILE_ATTRIBUTE_NORMAL, - 0, - FILE_OVERWRITE, - FILE_SYNCHRONOUS_IO_ALERT, - NULL, - 0); + GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_OVERWRITE, + FILE_SYNCHRONOUS_IO_ALERT, + NULL, + 0); if (!NT_SUCCESS(NtStatus)) { DPRINT("NtCreateFile() failed 2 (%S) (%x).\n", DestName, NtStatus); @@ -1714,315 +917,149 @@ CabinetExtractFile(PWCHAR FileName) return CAB_STATUS_FILE_EXISTS; } } - - if (!ConvertDosDateTimeToFileTime(File->File.FileDate, File->File.FileTime, &FileTime)) + MaxDestFileSize.QuadPart = Search->File->FileSize; + NtStatus = NtCreateSection(&DestFileSection, + SECTION_ALL_ACCESS, + 0, + &MaxDestFileSize, + PAGE_READWRITE, + SEC_COMMIT, + DestFile); + if(!NT_SUCCESS(NtStatus)) + { + DPRINT("NtCreateSection failed: %x\n", NtStatus); + Status = CAB_STATUS_NOMEMORY; + goto CloseDestFile; + } + DestFileBuffer = 0; + DestFileSize = 0; + NtStatus = NtMapViewOfSection(DestFileSection, + NtCurrentProcess(), + &DestFileBuffer, + 0, + 0, + 0, + &DestFileSize, + ViewUnmap, + 0, + PAGE_READWRITE); + if(!NT_SUCCESS(NtStatus)) + { + DPRINT("NtMapViewOfSection failed: %x\n", NtStatus); + Status = CAB_STATUS_NOMEMORY; + goto CloseDestFileSection; + } + CurrentDestBuffer = DestFileBuffer; + if (!ConvertDosDateTimeToFileTime(Search->File->FileDate, Search->File->FileTime, &FileTime)) { - NtClose(DestFile); DPRINT("DosDateTimeToFileTime() failed.\n"); - return CAB_STATUS_CANNOT_WRITE; + Status = CAB_STATUS_CANNOT_WRITE; + goto UnmapDestFile; } NtStatus = NtQueryInformationFile(DestFile, - &IoStatusBlock, - &FileBasic, - sizeof(FILE_BASIC_INFORMATION), - FileBasicInformation); - if (!NT_SUCCESS(Status)) + &IoStatusBlock, + &FileBasic, + sizeof(FILE_BASIC_INFORMATION), + FileBasicInformation); + if (!NT_SUCCESS(NtStatus)) { DPRINT("NtQueryInformationFile() failed (%x).\n", NtStatus); } else { memcpy(&FileBasic.LastAccessTime, &FileTime, sizeof(FILETIME)); - + NtStatus = NtSetInformationFile(DestFile, - &IoStatusBlock, - &FileBasic, - sizeof(FILE_BASIC_INFORMATION), - FileBasicInformation); + &IoStatusBlock, + &FileBasic, + sizeof(FILE_BASIC_INFORMATION), + FileBasicInformation); if (!NT_SUCCESS(NtStatus)) { DPRINT("NtSetInformationFile() failed (%x).\n", NtStatus); } } - SetAttributesOnFile(File, DestFile); - - Buffer = RtlAllocateHeap(ProcessHeap, 0, CAB_BLOCKSIZE + 12); // This should be enough - if (!Buffer) - { - NtClose(DestFile); - DPRINT("Insufficient memory.\n"); - return CAB_STATUS_NOMEMORY; - } - + SetAttributesOnFile(Search->File, DestFile); + /* Call extract event handler */ if (ExtractHandler != NULL) { - ExtractHandler(&File->File, FileName); + ExtractHandler(Search->File, DestName); } - - /* Search to start of file */ - Offset = SeekInFile(FileHandle, - File->DataBlock->AbsoluteOffset, - NULL, - SEEK_BEGIN, - &NtStatus); - if (!NT_SUCCESS(NtStatus)) + // find the starting block of the file + // start with the first data block of the folder + CFData = (PCFDATA)(CabinetFolders[Search->File->FolderIndex].DataOffset + FileBuffer); + CurrentOffset = 0; + while( CurrentOffset + CFData->UncompSize <= Search->File->FileOffset ) + { + // walk the data blocks until we reach the one containing the start of the file + CurrentOffset += CFData->UncompSize; + CFData = (PCFDATA)((char *)(CFData+1) + DataReserved + CFData->CompSize); + } + // now decompress and discard any data in the block before the start of the file + CurrentBuffer = ((unsigned char *)(CFData+1)) + DataReserved; // start of comp data + RemainingBlock = CFData->CompSize; + InputLength = RemainingBlock; + while( CurrentOffset < Search->File->FileOffset ) + { + // compute remaining uncomp bytes to start of file, bounded by sizeof junk + OutputLength = Search->File->FileOffset - CurrentOffset; + if( OutputLength > sizeof( Junk ) ) + OutputLength = sizeof( Junk ); + OutputLength = -OutputLength; // negate to signal NOT end of block + CodecUncompress( Junk, + CurrentBuffer, + &InputLength, + &OutputLength ); + CurrentOffset += OutputLength; // add the uncomp bytes extracted to current folder offset + CurrentBuffer += InputLength; // add comp bytes consumed to CurrentBuffer + RemainingBlock -= InputLength; // subtract bytes consumed from bytes remaining in block + InputLength = -RemainingBlock; // neg for resume decompression of the same block + } + // now CurrentBuffer points to the first comp byte of the file, so we can begin decompressing + + Size = Search->File->FileSize; // Size = remaining uncomp bytes of the file to decompress + while(Size > 0) { - DPRINT("SeekInFile() failed (%x).\n", NtStatus); - return CAB_STATUS_INVALID_CAB; - } - - Size = File->File.FileSize; - Offset = File->File.FileOffset; - CurrentOffset = File->DataBlock->UncompOffset; - - Skip = TRUE; - - ReuseBlock = (CurrentDataNode == File->DataBlock); - if (Size > 0) - { - do - { - DPRINT("CO (0x%X) ReuseBlock (%d) Offset (0x%X) Size (%d) BytesLeftInBlock (%d)\n", - File->DataBlock->UncompOffset, (UINT)ReuseBlock, Offset, Size, - BytesLeftInBlock); - - if (/*(CurrentDataNode != File->DataBlock) &&*/ (!ReuseBlock) || (BytesLeftInBlock <= 0)) - { - DPRINT("Filling buffer. ReuseBlock (%d)\n", (UINT)ReuseBlock); - - CurrentBuffer = Buffer; - TotalBytesRead = 0; - do - { - DPRINT("Size (%d bytes).\n", Size); - - if (((Status = ReadBlock(&CFData, sizeof(CFDATA), &BytesRead)) != - CAB_STATUS_SUCCESS) || (BytesRead != sizeof(CFDATA))) - { - NtClose(DestFile); - RtlFreeHeap(ProcessHeap, 0, Buffer); - DPRINT("Cannot read from file (%d).\n", (UINT)Status); - return CAB_STATUS_INVALID_CAB; - } - - DPRINT("Data block: Checksum (0x%X) CompSize (%d bytes) UncompSize (%d bytes) Offset (0x%X).\n", - (UINT)CFData.Checksum, - (UINT)CFData.CompSize, - (UINT)CFData.UncompSize, - (UINT)SeekInFile(FileHandle, 0, NULL, SEEK_CURRENT, &NtStatus)); - - //ASSERT(CFData.CompSize <= CAB_BLOCKSIZE + 12); - - BytesToRead = CFData.CompSize; - - DPRINT("Read: (0x%X,0x%X).\n", - CurrentBuffer, Buffer); - - if (((Status = ReadBlock(CurrentBuffer, BytesToRead, &BytesRead)) != - CAB_STATUS_SUCCESS) || (BytesToRead != BytesRead)) - { - NtClose(DestFile); - RtlFreeHeap(ProcessHeap, 0, Buffer); - DPRINT("Cannot read from file (%d).\n", (UINT)Status); - return CAB_STATUS_INVALID_CAB; - } - - /* FIXME: Does not work with files generated by makecab.exe */ -/* - if (CFData.Checksum != 0) - { - ULONG Checksum = ComputeChecksum(CurrentBuffer, BytesRead, 0); - if (Checksum != CFData.Checksum) - { - NtClose(DestFile); - RtlFreeHeap(ProcessHeap, 0, Buffer); - DPRINT("Bad checksum (is 0x%X, should be 0x%X).\n", - Checksum, CFData.Checksum); - return CAB_STATUS_INVALID_CAB; - } - } -*/ - TotalBytesRead += BytesRead; - - CurrentBuffer += BytesRead; - - if (CFData.UncompSize == 0) - { - if (wcslen(DiskNext) == 0) - return CAB_STATUS_NOFILE; - - /* CloseCabinet() will destroy all file entries so in case - FileName refers to the FileName field of a CFFOLDER_NODE - structure, we have to save a copy of the filename */ - wcscpy(TempName, FileName); - - CloseCabinet(); - - CabinetSetCabinetName(CabinetNext); - - if (DiskChangeHandler != NULL) - { - DiskChangeHandler(CabinetNext, DiskNext); - } - - Status = CabinetOpen(); - if (Status != CAB_STATUS_SUCCESS) - return Status; - - /* The first data block of the file will not be - found as it is located in the previous file */ - Status = LocateFile(TempName, &File); - if (Status == CAB_STATUS_NOFILE) - { - DPRINT("Cannot locate file (%d).\n", (UINT)Status); - return Status; - } - - /* The file is continued in the first data block in the folder */ - File->DataBlock = CurrentFolderNode->DataListHead; - - /* Search to start of file */ - SeekInFile(FileHandle, - File->DataBlock->AbsoluteOffset, - NULL, - SEEK_BEGIN, - &NtStatus); - if (!NT_SUCCESS(NtStatus)) - { - DPRINT("SeekInFile() failed (%x).\n", NtStatus); - return CAB_STATUS_INVALID_CAB; - } - - DPRINT("Continuing extraction of file at uncompressed offset (0x%X) Size (%d bytes) AO (0x%X) UO (0x%X).\n", - (UINT)File->File.FileOffset, - (UINT)File->File.FileSize, - (UINT)File->DataBlock->AbsoluteOffset, - (UINT)File->DataBlock->UncompOffset); - - CurrentDataNode = File->DataBlock; - ReuseBlock = TRUE; - - RestartSearch = TRUE; - } - } while (CFData.UncompSize == 0); - - DPRINT("TotalBytesRead (%d).\n", TotalBytesRead); - - Status = CodecUncompress(OutputBuffer, Buffer, TotalBytesRead, &BytesToWrite); - if (Status != CS_SUCCESS) - { - NtClose(DestFile); - RtlFreeHeap(ProcessHeap, 0, Buffer); - DPRINT("Cannot uncompress block.\n"); - if (Status == CS_NOMEMORY) - return CAB_STATUS_NOMEMORY; - return CAB_STATUS_INVALID_CAB; - } - - if (BytesToWrite != CFData.UncompSize) - { - DPRINT("BytesToWrite (%d) != CFData.UncompSize (%d)\n", - BytesToWrite, CFData.UncompSize); - return CAB_STATUS_INVALID_CAB; - } - - BytesLeftInBlock = BytesToWrite; - } - else - { - DPRINT("Using same buffer. ReuseBlock (%d)\n", (UINT)ReuseBlock); - - BytesToWrite = BytesLeftInBlock; - - DPRINT("Seeking to absolute offset 0x%X.\n", - CurrentDataNode->AbsoluteOffset + sizeof(CFDATA) + - CurrentDataNode->Data.CompSize); - - if (((Status = ReadBlock(&CFData, sizeof(CFDATA), &BytesRead)) != - CAB_STATUS_SUCCESS) || (BytesRead != sizeof(CFDATA))) - { - NtClose(DestFile); - RtlFreeHeap(ProcessHeap, 0, Buffer); - DPRINT("Cannot read from file (%d).\n", (UINT)Status); - return CAB_STATUS_INVALID_CAB; - } - - DPRINT("CFData.CompSize 0x%X CFData.UncompSize 0x%X.\n", - CFData.CompSize, CFData.UncompSize); - - /* Go to next data block */ - SeekInFile(FileHandle, - CurrentDataNode->AbsoluteOffset + sizeof(CFDATA) + - CurrentDataNode->Data.CompSize, - NULL, - SEEK_BEGIN, - &NtStatus); - if (!NT_SUCCESS(NtStatus)) - { - DPRINT("SeekInFile() failed (%x).\n", NtStatus); - return CAB_STATUS_INVALID_CAB; - } - - ReuseBlock = FALSE; - } - - if (Skip) - BytesSkipped = (Offset - CurrentOffset); - else - BytesSkipped = 0; - - BytesToWrite -= BytesSkipped; - - if (Size < BytesToWrite) - BytesToWrite = Size; - - DPRINT("Offset (0x%X) CurrentOffset (0x%X) ToWrite (%d) Skipped (%d)(%d) Size (%d).\n", - (UINT)Offset, - (UINT)CurrentOffset, - (UINT)BytesToWrite, - (UINT)BytesSkipped, (UINT)Skip, - (UINT)Size); - -// if (!WriteFile(DestFile, (PVOID)((ULONG)OutputBuffer + BytesSkipped), -// BytesToWrite, &BytesWritten, NULL) || -// (BytesToWrite != BytesWritten)) - - NtStatus = NtWriteFile(DestFile, - NULL, - NULL, - NULL, - &IoStatusBlock, - (PVOID)((ULONG)OutputBuffer + BytesSkipped), - BytesToWrite, - NULL, - NULL); - BytesWritten = BytesToWrite; - if (!NT_SUCCESS(NtStatus)) - { - DPRINT("Status 0x%X.\n", NtStatus); - - NtClose(DestFile); - RtlFreeHeap(ProcessHeap, 0, Buffer); - DPRINT("Cannot write to file.\n"); - return CAB_STATUS_CANNOT_WRITE; - } - Size -= BytesToWrite; - - CurrentOffset += BytesToWrite; - - /* Don't skip any more bytes */ - Skip = FALSE; - } while (Size > 0); - } - + OutputLength = Size; + DPRINT( "Decompressing block at %x with RemainingBlock = %d, Size = %d\n", CurrentBuffer, RemainingBlock, Size ); + Status = CodecUncompress(CurrentDestBuffer, + CurrentBuffer, + &InputLength, + &OutputLength); + if (Status != CS_SUCCESS) + { + DPRINT("Cannot uncompress block.\n"); + if(Status == CS_NOMEMORY) + Status = CAB_STATUS_NOMEMORY; + Status = CAB_STATUS_INVALID_CAB; + goto UnmapDestFile; + } + CurrentDestBuffer += OutputLength; // advance dest buffer by bytes produced + CurrentBuffer += InputLength; // advance src buffer by bytes consumed + Size -= OutputLength; // reduce remaining file bytes by bytes produced + RemainingBlock -= InputLength; // reduce remaining block size by bytes consumed + if( RemainingBlock == 0 ) + { + // used up this block, move on to the next + DPRINT( "Out of block data\n" ); + CFData = (PCFDATA)CurrentBuffer; + RemainingBlock = CFData->CompSize; + CurrentBuffer = ((unsigned char *)(CFData+1) + DataReserved); + InputLength = RemainingBlock; + } + } + Status = CAB_STATUS_SUCCESS; + UnmapDestFile: + NtUnmapViewOfSection(NtCurrentProcess(), DestFileBuffer); + CloseDestFileSection: + NtClose(DestFileSection); + CloseDestFile: NtClose(DestFile); - RtlFreeHeap(ProcessHeap, 0, Buffer); - - return CAB_STATUS_SUCCESS; + return Status; } diff --git a/reactos/subsys/system/usetup/cabinet.h b/reactos/subsys/system/usetup/cabinet.h index 10dd53c34b4..c0964a0089a 100755 --- a/reactos/subsys/system/usetup/cabinet.h +++ b/reactos/subsys/system/usetup/cabinet.h @@ -82,12 +82,13 @@ typedef struct _CFFOLDER typedef struct _CFFILE { - ULONG FileSize; // Uncompressed file size in bytes - ULONG FileOffset; // Uncompressed offset of file in the folder - WORD FileControlID; // File control ID (CAB_FILE_*) - WORD FileDate; // File date stamp, as used by DOS - WORD FileTime; // File time stamp, as used by DOS - WORD Attributes; // File attributes (CAB_ATTRIB_*) + ULONG FileSize; // Uncompressed file size in bytes + ULONG FileOffset; // Uncompressed offset of file in the folder + WORD FolderIndex; // Index number of the folder that contains this file + WORD FileDate; // File date stamp, as used by DOS + WORD FileTime; // File time stamp, as used by DOS + WORD Attributes; // File attributes (CAB_ATTRIB_*) + CHAR FileName[]; /* After this is the NULL terminated filename */ } CFFILE, *PCFFILE; @@ -102,50 +103,12 @@ typedef struct _CFDATA */ } CFDATA, *PCFDATA; -typedef struct _CFDATA_NODE -{ - struct _CFDATA_NODE *Next; - struct _CFDATA_NODE *Prev; - ULONG ScratchFilePosition; // Absolute offset in scratch file - ULONG AbsoluteOffset; // Absolute offset in cabinet - ULONG UncompOffset; // Uncompressed offset in folder - CFDATA Data; -} CFDATA_NODE, *PCFDATA_NODE; - -typedef struct _CFFOLDER_NODE -{ - struct _CFFOLDER_NODE *Next; - struct _CFFOLDER_NODE *Prev; - ULONG UncompOffset; // File size accumulator - ULONG AbsoluteOffset; - ULONG TotalFolderSize; // Total size of folder in current disk - PCFDATA_NODE DataListHead; - PCFDATA_NODE DataListTail; - ULONG Index; - BOOL Commit; // TRUE if the folder should be committed - BOOL Delete; // TRUE if marked for deletion - CFFOLDER Folder; -} CFFOLDER_NODE, *PCFFOLDER_NODE; - -typedef struct _CFFILE_NODE -{ - struct _CFFILE_NODE *Next; - struct _CFFILE_NODE *Prev; - CFFILE File; - PWCHAR FileName; - PCFDATA_NODE DataBlock; // First data block of file. NULL if not known - BOOL Commit; // TRUE if the file data should be committed - BOOL Delete; // TRUE if marked for deletion - PCFFOLDER_NODE FolderNode; // Folder this file belong to -} CFFILE_NODE, *PCFFILE_NODE; - - typedef struct _CAB_SEARCH { - WCHAR Search[MAX_PATH]; // Search criteria - PCFFILE_NODE Next; // Pointer to next node - PCFFILE File; // Pointer to current CFFILE - PWCHAR FileName; // Current filename + WCHAR Search[MAX_PATH]; // Search criteria + WCHAR Cabinet[MAX_PATH]; + USHORT Index; + PCFFILE File; // Pointer to current CFFILE } CAB_SEARCH, *PCAB_SEARCH; @@ -169,9 +132,9 @@ typedef struct _CAB_SEARCH /* Uncompresses a data block */ typedef ULONG (*PCABINET_CODEC_UNCOMPRESS)(PVOID OutputBuffer, - PVOID InputBuffer, - ULONG InputLength, - PULONG OutputLength); + PVOID InputBuffer, + PLONG InputLength, + PLONG OutputLength); /* Codec status codes */ @@ -232,7 +195,7 @@ ULONG CabinetFindFirst(PWCHAR FileName, PCAB_SEARCH Search); /* Locates the next file in the current cabinet file */ ULONG CabinetFindNext(PCAB_SEARCH Search); /* Extracts a file from the current cabinet file */ -ULONG CabinetExtractFile(PWCHAR FileName); +ULONG CabinetExtractFile(PCAB_SEARCH Search); /* Select codec engine to use */ VOID CabinetSelectCodec(ULONG Id); /* Set event handlers */ diff --git a/reactos/subsys/system/usetup/filesup.c b/reactos/subsys/system/usetup/filesup.c index 37a2af00cb1..17a04cb4200 100644 --- a/reactos/subsys/system/usetup/filesup.c +++ b/reactos/subsys/system/usetup/filesup.c @@ -107,11 +107,13 @@ SetupCopyFile(PWCHAR SourceFileName, IO_STATUS_BLOCK IoStatusBlock; FILE_STANDARD_INFORMATION FileStandard; FILE_BASIC_INFORMATION FileBasic; - FILE_POSITION_INFORMATION FilePosition; PUCHAR Buffer; ULONG RegionSize; UNICODE_STRING FileName; NTSTATUS Status; + PVOID SourceFileMap = 0; + HANDLE SourceFileSection; + ULONG SourceSectionSize = 0; Buffer = NULL; @@ -130,9 +132,10 @@ SetupCopyFile(PWCHAR SourceFileName, &IoStatusBlock, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY); - if (!NT_SUCCESS(Status)) + if(!NT_SUCCESS(Status)) { - return(Status); + DPRINT1("NtOpenFile failed: %x\n", Status); + goto done; } Status = NtQueryInformationFile(FileHandleSource, @@ -140,20 +143,48 @@ SetupCopyFile(PWCHAR SourceFileName, &FileStandard, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); - if (!NT_SUCCESS(Status)) + if(!NT_SUCCESS(Status)) { - NtClose(FileHandleSource); - return(Status); + DPRINT1("NtQueryInformationFile failed: %x\n", Status); + goto closesrc; } - Status = NtQueryInformationFile(FileHandleSource, &IoStatusBlock,&FileBasic, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); - if (!NT_SUCCESS(Status)) + if(!NT_SUCCESS(Status)) { - NtClose(FileHandleSource); - return(Status); + DPRINT1("NtQueryInformationFile failed: %x\n", Status); + goto closesrc; + } + + Status = NtCreateSection( &SourceFileSection, + SECTION_MAP_READ, + 0, + 0, + PAGE_READONLY, + 0, + FileHandleSource); + if(!NT_SUCCESS(Status)) + { + DPRINT1("NtCreateSection failed: %x\n", Status); + goto closesrc; + } + + Status = NtMapViewOfSection( SourceFileSection, + NtCurrentProcess(), + &SourceFileMap, + 0, + 0, + 0, + &SourceSectionSize, + 0, + SEC_COMMIT, + PAGE_READONLY ); + if(!NT_SUCCESS(Status)) + { + DPRINT1("NtMapViewOfSection failed: %x\n", Status); + goto closesrcsec; } RtlInitUnicodeString(&FileName, @@ -176,121 +207,55 @@ SetupCopyFile(PWCHAR SourceFileName, FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY, NULL, 0); - if (!NT_SUCCESS(Status)) + if(!NT_SUCCESS(Status)) { - NtClose(FileHandleSource); - return(Status); - } - - FilePosition.CurrentByteOffset.QuadPart = 0; - - Status = NtSetInformationFile(FileHandleSource, - &IoStatusBlock, - &FilePosition, - sizeof(FILE_POSITION_INFORMATION), - FilePositionInformation); - if (!NT_SUCCESS(Status)) - { - NtClose(FileHandleSource); - NtClose(FileHandleDest); - return(Status); - } - - Status = NtSetInformationFile(FileHandleDest, - &IoStatusBlock, - &FilePosition, - sizeof(FILE_POSITION_INFORMATION), - FilePositionInformation); - if (!NT_SUCCESS(Status)) - { - NtClose(FileHandleSource); - NtClose(FileHandleDest); - return(Status); + DPRINT1("NtCreateFile failed: %x\n", Status); + goto unmapsrcsec; } RegionSize = PAGE_ROUND_UP(FileStandard.EndOfFile.u.LowPart); - if (RegionSize > 0x100000) + IoStatusBlock.Status = 0; + Status = NtWriteFile(FileHandleDest, + 0, + 0, + 0, + &IoStatusBlock, + SourceFileMap, + RegionSize, + 0, + 0); + if(!NT_SUCCESS(Status)) { - RegionSize = 0x100000; + DPRINT1("NtWriteFile failed: %x:%x, iosb: %p src: %p, size: %x\n", Status, IoStatusBlock.Status, &IoStatusBlock, SourceFileMap, RegionSize); + goto closedest; } - Status = NtAllocateVirtualMemory(NtCurrentProcess(), - (PVOID *)&Buffer, - 2, - &RegionSize, - MEM_RESERVE | MEM_COMMIT, - PAGE_READWRITE); - if (!NT_SUCCESS(Status)) - { - NtClose(FileHandleSource); - NtClose(FileHandleDest); - return(Status); - } - - while (TRUE) - { - Status = NtReadFile(FileHandleSource, - NULL, - NULL, - NULL, - &IoStatusBlock, - Buffer, - RegionSize, - NULL, - NULL); - if (!NT_SUCCESS(Status)) - { - NtFreeVirtualMemory(NtCurrentProcess(), - (PVOID *)&Buffer, - &RegionSize, - MEM_RELEASE); - if (Status == STATUS_END_OF_FILE) - { - DPRINT("STATUS_END_OF_FILE\n"); - break; - } - NtClose(FileHandleSource); - NtClose(FileHandleDest); - return(Status); - } - - DPRINT("Bytes read %lu\n", IoStatusBlock.Information); - - Status = NtWriteFile(FileHandleDest, - NULL, - NULL, - NULL, - &IoStatusBlock, - Buffer, - IoStatusBlock.Information, - NULL, - NULL); - if (!NT_SUCCESS(Status)) - { - NtFreeVirtualMemory(NtCurrentProcess(), - (PVOID *)&Buffer, - &RegionSize, - MEM_RELEASE); - NtClose(FileHandleSource); - NtClose(FileHandleDest); - return(Status); - } - } - - /* Copy file date/time from source file */ Status = NtSetInformationFile(FileHandleDest, &IoStatusBlock, &FileBasic, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); - if (!NT_SUCCESS(Status)) + if(!NT_SUCCESS(Status)) { - DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status); + DPRINT1("NtSetInformationFile failed: %x\n", Status); + goto closedest; } - NtClose(FileHandleSource); + /* shorten the file back to it's real size after completing the write */ + NtSetInformationFile(FileHandleDest, + &IoStatusBlock, + &FileStandard.EndOfFile, + sizeof(FILE_END_OF_FILE_INFORMATION), + FileEndOfFileInformation); + closedest: NtClose(FileHandleDest); - + unmapsrcsec: + NtUnmapViewOfSection( NtCurrentProcess(), SourceFileMap ); + closesrcsec: + NtClose(SourceFileSection); + closesrc: + NtClose(FileHandleSource); + done: return(Status); } @@ -301,6 +266,7 @@ SetupExtractFile(PWCHAR CabinetFileName, PWCHAR DestinationPathName) { ULONG CabStatus; + CAB_SEARCH Search; DPRINT("SetupExtractFile(CabinetFileName %S, SourceFileName %S, DestinationPathName %S)\n", CabinetFileName, SourceFileName, DestinationPathName); @@ -343,7 +309,8 @@ SetupExtractFile(PWCHAR CabinetFileName, } CabinetSetDestinationPath(DestinationPathName); - CabStatus = CabinetExtractFile(SourceFileName); + CabinetFindFirst( SourceFileName, &Search ); + CabStatus = CabinetExtractFile(&Search); if (CabStatus != CAB_STATUS_SUCCESS) { DPRINT("Cannot extract file %S (%d)\n", SourceFileName, CabStatus); diff --git a/reactos/subsys/system/usetup/format.c b/reactos/subsys/system/usetup/format.c index cb80bccd52f..08e4b1b5303 100755 --- a/reactos/subsys/system/usetup/format.c +++ b/reactos/subsys/system/usetup/format.c @@ -107,7 +107,8 @@ FormatPartition (PUNICODE_STRING DriveRoot) ProgressBar = CreateProgressBar (6, yScreen - 14, xScreen - 7, - yScreen - 10); + yScreen - 10, + "Setup is formatting your disk"); ProgressSetStepCount (ProgressBar, 100); diff --git a/reactos/subsys/system/usetup/progress.c b/reactos/subsys/system/usetup/progress.c index 44ab69934bc..fe89af8d751 100644 --- a/reactos/subsys/system/usetup/progress.c +++ b/reactos/subsys/system/usetup/progress.c @@ -84,6 +84,78 @@ DrawBorder(PPROGRESSBAR Bar) &Written); } +static VOID +DrawThickBorder(PPROGRESSBAR Bar) +{ + COORD coPos; + ULONG Written; + SHORT i; + + /* draw upper left corner */ + coPos.X = Bar->Left; + coPos.Y = Bar->Top + 1; + FillConsoleOutputCharacter(0xC9, // '+', + 1, + coPos, + &Written); + + /* draw upper edge */ + coPos.X = Bar->Left + 1; + coPos.Y = Bar->Top + 1; + FillConsoleOutputCharacter(0xCD, // '-', + Bar->Right - Bar->Left - 1, + coPos, + &Written); + + /* draw upper right corner */ + coPos.X = Bar->Right; + coPos.Y = Bar->Top + 1; + FillConsoleOutputCharacter(0xBB, // '+', + 1, + coPos, + &Written); + + /* draw left and right edge */ + for (i = Bar->Top + 2; i < Bar->Bottom; i++) + { + coPos.X = Bar->Left; + coPos.Y = i; + FillConsoleOutputCharacter(0xBA, // '|', + 1, + coPos, + &Written); + + coPos.X = Bar->Right; + FillConsoleOutputCharacter(0xBA, //'|', + 1, + coPos, + &Written); + } + + /* draw lower left corner */ + coPos.X = Bar->Left; + coPos.Y = Bar->Bottom; + FillConsoleOutputCharacter(0xC8, // '+', + 1, + coPos, + &Written); + + /* draw lower edge */ + coPos.X = Bar->Left + 1; + coPos.Y = Bar->Bottom; + FillConsoleOutputCharacter(0xCD, // '-', + Bar->Right - Bar->Left - 1, + coPos, + &Written); + + /* draw lower right corner */ + coPos.X = Bar->Right; + coPos.Y = Bar->Bottom; + FillConsoleOutputCharacter(0xBC, // '+', + 1, + coPos, + &Written); +} static VOID DrawProgressBar(PPROGRESSBAR Bar) @@ -91,6 +163,7 @@ DrawProgressBar(PPROGRESSBAR Bar) CHAR TextBuffer[8]; COORD coPos; ULONG Written; + PROGRESSBAR BarBorder = *Bar; /* Print percentage */ sprintf(TextBuffer, "%-3lu%%", Bar->Percent); @@ -101,7 +174,18 @@ DrawProgressBar(PPROGRESSBAR Bar) 4, coPos); + /* Draw the progress bar border */ DrawBorder(Bar); + + /* Write Text Associated with Bar */ + SetTextXY(10, 24, Bar->Text); + + /* Draw the progress bar "border" border */ + BarBorder.Top -= 5; + BarBorder.Bottom += 2; + BarBorder.Right += 5; + BarBorder.Left -= 5; + DrawThickBorder(&BarBorder); /* Draw the bar */ coPos.X = Bar->Left + 1; @@ -126,7 +210,8 @@ PPROGRESSBAR CreateProgressBar(SHORT Left, SHORT Top, SHORT Right, - SHORT Bottom) + SHORT Bottom, + char* Text) { PPROGRESSBAR Bar; @@ -140,6 +225,7 @@ CreateProgressBar(SHORT Left, Bar->Top = Top; Bar->Right = Right; Bar->Bottom = Bottom; + Bar->Text = Text; Bar->Width = Bar->Right - Bar->Left + 1; diff --git a/reactos/subsys/system/usetup/progress.h b/reactos/subsys/system/usetup/progress.h index 1e4a6fb6b0f..185c2beff5f 100644 --- a/reactos/subsys/system/usetup/progress.h +++ b/reactos/subsys/system/usetup/progress.h @@ -42,6 +42,8 @@ typedef struct _PROGRESS ULONG StepCount; ULONG CurrentStep; + + CHAR *Text; } PROGRESSBAR, *PPROGRESSBAR; /* FUNCTIONS ****************************************************************/ @@ -50,7 +52,8 @@ PPROGRESSBAR CreateProgressBar(SHORT Left, SHORT Top, SHORT Right, - SHORT Bottom); + SHORT Bottom, + char* Text); VOID DestroyProgressBar(PPROGRESSBAR Bar); diff --git a/reactos/subsys/system/usetup/usetup.c b/reactos/subsys/system/usetup/usetup.c index fd08b78ef37..6f80aa14047 100644 --- a/reactos/subsys/system/usetup/usetup.c +++ b/reactos/subsys/system/usetup/usetup.c @@ -59,6 +59,7 @@ typedef enum _PAGE_NUMBER START_PAGE, INTRO_PAGE, LICENSE_PAGE, + WARNING_PAGE, INSTALL_INTRO_PAGE, // SCSI_CONTROLLER_PAGE, @@ -88,8 +89,6 @@ typedef enum _PAGE_NUMBER REPAIR_INTRO_PAGE, - EMERGENCY_INTRO_PAGE, - SUCCESS_PAGE, QUIT_PAGE, FLUSH_PAGE, @@ -710,12 +709,11 @@ IntroPage(PINPUT_RECORD Ir) SetTextXY(6, 12, "computer and prepares the second part of the setup."); SetTextXY(8, 15, "\x07 Press ENTER to install ReactOS."); - SetTextXY(8, 17, "\x07 Press L to view the licensing terms for ReactOS."); - SetTextXY(8, 19, "\x07 Press E to start the emergency console."); - SetTextXY(8, 21, "\x07 Press R to repair ReactOS."); - SetTextXY(8, 23, "\x07 Press F3 to quit without installing ReactOS."); + SetTextXY(8, 17, "\x07 Press R to repair ReactOS."); + SetTextXY(8, 19, "\x07 Press L to view the ReactOS Licensing Terms and Conditions"); + SetTextXY(8, 21, "\x07 Press F3 to quit without installing ReactOS."); - SetStatusText(" ENTER = Continue F3 = Quit"); + SetStatusText(" ENTER = Continue R = Repair F3 = Quit"); if (IsUnattendedSetup) { @@ -735,20 +733,19 @@ IntroPage(PINPUT_RECORD Ir) } else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ { - return INSTALL_INTRO_PAGE; - } - else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* L */ - { - return LICENSE_PAGE; - } - else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'E') /* E */ - { - return EMERGENCY_INTRO_PAGE; + return WARNING_PAGE; + break; } else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */ { return REPAIR_INTRO_PAGE; + break; } + else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* R */ + { + return LICENSE_PAGE; + break; + } } return INTRO_PAGE; @@ -779,61 +776,62 @@ LicensePage(PINPUT_RECORD Ir) SetTextXY(8, 23, "GNU General Public License with ReactOS please visit"); SetHighlightedTextXY(8, 25, "http://www.gnu.org/licenses/licenses.html"); - SetStatusText("ENTER = Continue F3 = Quit"); + SetStatusText(" ENTER = Return"); + + while (TRUE) + { + ConInKey(Ir); + + if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ + { + return INTRO_PAGE; + break; + } + } + + return LICENSE_PAGE; +} + +/* + * Warning Page + * RETURNS + * Continues to setup + */ +static PAGE_NUMBER +WarningPage(PINPUT_RECORD Ir) +{ + SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Warranty Statement"); + SetHighlightedTextXY(6, 8, "Warranty:"); + + SetTextXY(8, 11, "This is free software; see the source for copying conditions."); + SetTextXY(8, 12, "There is NO warranty; not even for MERCHANTABILITY or"); + SetTextXY(8, 13, "FITNESS FOR A PARTICULAR PURPOSE"); + + SetTextXY(8, 15, "For more information on ReactOS, please visit:"); + SetHighlightedTextXY(8, 16, "http://www.reactos.org"); + + SetStatusText(" F8 = Continue ESC = Exit"); while (TRUE) { ConInKey(Ir); if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && - (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ + (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F8)) /* F8 */ { - if (ConfirmQuit(Ir) == TRUE) - return QUIT_PAGE; + return INSTALL_INTRO_PAGE; break; } - else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ + else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && + (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */ { - return INTRO_PAGE; + return QUIT_PAGE; } } return LICENSE_PAGE; } -static PAGE_NUMBER -EmergencyIntroPage(PINPUT_RECORD Ir) -{ - SetTextXY(6, 8, "ReactOS Setup is in an early development phase. It does not yet"); - SetTextXY(6, 9, "support all the functions of a fully usable setup application."); - - SetTextXY(6, 12, "The emergency console is not implemented yet."); - - SetTextXY(8, 15, "\x07 Press ESC to return to the main page."); - - SetTextXY(8, 17, "\x07 Press ENTER to reboot your computer."); - - SetStatusText(" ESC = Main page ENTER = Reboot"); - - while(TRUE) - { - ConInKey(Ir); - - if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ - { - return REBOOT_PAGE; - } - else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && - (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */ - { - return INTRO_PAGE; - } - } - - return REPAIR_INTRO_PAGE; -} - - static PAGE_NUMBER RepairIntroPage(PINPUT_RECORD Ir) { @@ -842,9 +840,11 @@ RepairIntroPage(PINPUT_RECORD Ir) SetTextXY(6, 12, "The repair functions are not implemented yet."); - SetTextXY(8, 15, "\x07 Press ESC to return to the main page."); + SetTextXY(8, 15, "\x07 Press R for the Recovery Console."); + + SetTextXY(8, 17, "\x07 Press ESC to return to the main page."); - SetTextXY(8, 17, "\x07 Press ENTER to reboot your computer."); + SetTextXY(8, 19, "\x07 Press ENTER to reboot your computer."); SetStatusText(" ESC = Main page ENTER = Reboot"); @@ -856,6 +856,10 @@ RepairIntroPage(PINPUT_RECORD Ir) { return REBOOT_PAGE; } + else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */ + { + return INTRO_PAGE; + } else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */ { @@ -870,6 +874,8 @@ RepairIntroPage(PINPUT_RECORD Ir) static PAGE_NUMBER InstallIntroPage(PINPUT_RECORD Ir) { + SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup "); + SetTextXY(6, 8, "ReactOS Setup is in an early development phase. It does not yet"); SetTextXY(6, 9, "support all the functions of a fully usable setup application."); @@ -3140,11 +3146,7 @@ FileCopyCallback(PVOID Context, case SPFILENOTIFY_STARTCOPY: /* Display copy message */ - PrintTextXYN(6, 16, 60, "Copying file: %S", (PWSTR)Param1); - - PrintTextXYN(6, 18, 60, "File %lu of %lu", - CopyContext->CompletedOperations + 1, - CopyContext->TotalOperations); + SetStatusText(" \xB3 Copying file: %S", (PWSTR)Param1); break; case SPFILENOTIFY_ENDCOPY: @@ -3164,18 +3166,20 @@ FileCopyPage(PINPUT_RECORD Ir) SHORT xScreen; SHORT yScreen; - SetStatusText(" Please wait..."); + SetStatusText(" \xB3 Please wait... "); - SetTextXY(6, 8, "Copying files"); - - GetScreenSize(&xScreen, &yScreen); + SetTextXY(11, 12, "Please wait while ReactOS Setup copies files to your ReactOS"); + SetTextXY(30, 13, "installation folder."); + SetTextXY(20, 14, "This may take several minutes to complete."); + GetScreenSize(&xScreen, &yScreen); CopyContext.TotalOperations = 0; CopyContext.CompletedOperations = 0; - CopyContext.ProgressBar = CreateProgressBar(6, - yScreen - 14, - xScreen - 7, - yScreen - 10); + CopyContext.ProgressBar = CreateProgressBar(13, + 26, + xScreen - 13, + yScreen - 20, + "Setup is copying files..."); SetupCommitFileQueue(SetupFileQueue, DestinationRootPath.Buffer, @@ -3811,6 +3815,11 @@ NtProcessStartup(PPEB Peb) case LICENSE_PAGE: Page = LicensePage(&Ir); break; + + /* Warning page */ + case WARNING_PAGE: + Page = WarningPage(&Ir); + break; /* Intro page */ case INTRO_PAGE: @@ -3916,13 +3925,6 @@ NtProcessStartup(PPEB Peb) Page = RepairIntroPage(&Ir); break; - - /* Emergency pages */ - case EMERGENCY_INTRO_PAGE: - Page = EmergencyIntroPage(&Ir); - break; - - case SUCCESS_PAGE: Page = SuccessPage(&Ir); break; @@ -3943,6 +3945,7 @@ NtProcessStartup(PPEB Peb) /* Reboot */ FreeConsole(); NtShutdownSystem(ShutdownReboot); + NtTerminateProcess(NtCurrentProcess(), 0); } /* EOF */ diff --git a/reactos/subsys/system/winefile/cs.rc b/reactos/subsys/system/winefile/cs.rc index 58fe7eb3193..8f724976c22 100644 --- a/reactos/subsys/system/winefile/cs.rc +++ b/reactos/subsys/system/winefile/cs.rc @@ -86,7 +86,7 @@ IDM_WINEFILE MENU FIXED IMPURE MENUITEM "&Jen strom" , 411 MENUITEM "Jen &adresáøe" , 412 MENUITEM SEPARATOR - MENUITEM "&Rozdìlit" , 414 + MENUITEM "&Rozdìlit" , ID_VIEW_SPLIT MENUITEM SEPARATOR MENUITEM "&Jméno" , ID_VIEW_NAME MENUITEM "&Detaily všech souborù" , ID_VIEW_ALL_ATTRIBUTES, CHECKED diff --git a/reactos/subsys/system/winefile/de.rc b/reactos/subsys/system/winefile/de.rc index d3c17b33901..50a17a91659 100644 --- a/reactos/subsys/system/winefile/de.rc +++ b/reactos/subsys/system/winefile/de.rc @@ -85,7 +85,7 @@ IDM_WINEFILE MENU FIXED IMPURE MENUITEM "Nur St&ruktur" , 411 MENUITEM "Nur &Verzeichnis" , 412 MENUITEM SEPARATOR - MENUITEM "&Teilen" , 414 + MENUITEM "&Teilen" , ID_VIEW_SPLIT MENUITEM SEPARATOR MENUITEM "&Name" , ID_VIEW_NAME MENUITEM "A&lle Dateiangaben" , ID_VIEW_ALL_ATTRIBUTES, CHECKED diff --git a/reactos/subsys/system/winefile/en.rc b/reactos/subsys/system/winefile/en.rc index f7a6932131a..abf20729be0 100644 --- a/reactos/subsys/system/winefile/en.rc +++ b/reactos/subsys/system/winefile/en.rc @@ -88,7 +88,7 @@ IDM_WINEFILE MENU FIXED IMPURE MENUITEM "Tr&ee Only" , 411 MENUITEM "Directory &Only" , 412 MENUITEM SEPARATOR - MENUITEM "Sp&lit" , 414 + MENUITEM "Sp&lit" , ID_VIEW_SPLIT MENUITEM SEPARATOR MENUITEM "&Name" , ID_VIEW_NAME MENUITEM "&All File Details" , ID_VIEW_ALL_ATTRIBUTES, CHECKED diff --git a/reactos/subsys/system/winefile/es.rc b/reactos/subsys/system/winefile/es.rc index 6f16ff6fe2e..956e2cdfc24 100644 --- a/reactos/subsys/system/winefile/es.rc +++ b/reactos/subsys/system/winefile/es.rc @@ -84,7 +84,7 @@ IDM_WINEFILE MENU FIXED IMPURE MENUITEM "Árbol &sólo" , 411 MENUITEM "&Directorio sólo" , 412 MENUITEM SEPARATOR - MENUITEM "Di&vidir" , 414 + MENUITEM "Di&vidir" , ID_VIEW_SPLIT MENUITEM SEPARATOR MENUITEM "No&mbre" , ID_VIEW_NAME MENUITEM "T&odos los detalles" , ID_VIEW_ALL_ATTRIBUTES, CHECKED diff --git a/reactos/subsys/system/winefile/fr.rc b/reactos/subsys/system/winefile/fr.rc index 5b0a073cef8..d76b16f87c9 100644 --- a/reactos/subsys/system/winefile/fr.rc +++ b/reactos/subsys/system/winefile/fr.rc @@ -87,7 +87,7 @@ IDM_WINEFILE MENU FIXED IMPURE MENUITEM "&Arbre seulement" , 411 MENUITEM "&Répertoire seulement" , 412 MENUITEM SEPARATOR - MENUITEM "&Séparer" , 414 + MENUITEM "&Séparer" , ID_VIEW_SPLIT MENUITEM SEPARATOR MENUITEM "&Nom" , ID_VIEW_NAME MENUITEM "Tous &les Détails" , ID_VIEW_ALL_ATTRIBUTES, CHECKED diff --git a/reactos/subsys/system/winefile/hu.rc b/reactos/subsys/system/winefile/hu.rc index 35dd2dfdf13..d94bf5ddc7b 100644 --- a/reactos/subsys/system/winefile/hu.rc +++ b/reactos/subsys/system/winefile/hu.rc @@ -87,7 +87,7 @@ IDM_WINEFILE MENU FIXED IMPURE MENUITEM "&Könyvtárfa" , 411 MENUITEM "&Csak mappák" , 412 MENUITEM SEPARATOR - MENUITEM "&Felosztás" , 414 + MENUITEM "&Felosztás" , ID_VIEW_SPLIT MENUITEM SEPARATOR MENUITEM "&Név" , ID_VIEW_NAME MENUITEM "&Minden részlet" , ID_VIEW_ALL_ATTRIBUTES, CHECKED diff --git a/reactos/subsys/system/winefile/it.rc b/reactos/subsys/system/winefile/it.rc index dea9eedf7ca..06925782914 100644 --- a/reactos/subsys/system/winefile/it.rc +++ b/reactos/subsys/system/winefile/it.rc @@ -87,7 +87,7 @@ IDM_WINEFILE MENU FIXED IMPURE MENUITEM "So&lo Albero" , 411 MENUITEM "&Solo Directory" , 412 MENUITEM SEPARATOR - MENUITEM "Di&vidi" , 414 + MENUITEM "Di&vidi" , ID_VIEW_SPLIT MENUITEM SEPARATOR MENUITEM "&Nome" , ID_VIEW_NAME MENUITEM "&Mostra tutti i dettagli sui file" , ID_VIEW_ALL_ATTRIBUTES, CHECKED diff --git a/reactos/subsys/system/winefile/nl.rc b/reactos/subsys/system/winefile/nl.rc index 85734f8b992..75089858c1f 100644 --- a/reactos/subsys/system/winefile/nl.rc +++ b/reactos/subsys/system/winefile/nl.rc @@ -83,7 +83,7 @@ IDM_WINEFILE MENU FIXED IMPURE MENUITEM "&Alleen hierarchie" , 411 MENUITEM "Alleen &mapinhoud" , 412 MENUITEM SEPARATOR - MENUITEM "Sp&litsen" , 414 + MENUITEM "Sp&litsen" , ID_VIEW_SPLIT MENUITEM SEPARATOR MENUITEM "&Naam" , ID_VIEW_NAME MENUITEM "&Alle details" , ID_VIEW_ALL_ATTRIBUTES, CHECKED diff --git a/reactos/subsys/system/winefile/pl.rc b/reactos/subsys/system/winefile/pl.rc index 3b641134afd..a91b42e85da 100644 --- a/reactos/subsys/system/winefile/pl.rc +++ b/reactos/subsys/system/winefile/pl.rc @@ -87,7 +87,7 @@ IDM_WINEFILE MENU FIXED IMPURE MENUITEM "D&rzewo" , 411 MENUITEM "&Katalogi" , 412 MENUITEM SEPARATOR - MENUITEM "&Po³¹cz" , 414 + MENUITEM "&Po³¹cz" , ID_VIEW_SPLIT MENUITEM SEPARATOR MENUITEM "&Nazwa" , ID_VIEW_NAME MENUITEM "&Wszystkie atrybuty pliku" , ID_VIEW_ALL_ATTRIBUTES, CHECKED diff --git a/reactos/subsys/system/winefile/pt.rc b/reactos/subsys/system/winefile/pt.rc index dd58d346072..2ad7fab2e59 100644 --- a/reactos/subsys/system/winefile/pt.rc +++ b/reactos/subsys/system/winefile/pt.rc @@ -86,7 +86,7 @@ IDM_WINEFILE MENU FIXED IMPURE MENUITEM "S&omente árvore" , 411 MENUITEM "So&mente pasta" , 412 MENUITEM SEPARATOR - MENUITEM "&Dividir" , 414 + MENUITEM "&Dividir" , ID_VIEW_SPLIT MENUITEM SEPARATOR MENUITEM "&Nome" , ID_VIEW_NAME MENUITEM "&Todos os delalhes" , ID_VIEW_ALL_ATTRIBUTES, CHECKED @@ -214,7 +214,7 @@ IDM_WINEFILE MENU FIXED IMPURE MENUITEM "S&omente árvore" , 411 MENUITEM "So&mente pasta" , 412 MENUITEM SEPARATOR - MENUITEM "&Dividir" , 414 + MENUITEM "&Dividir" , ID_VIEW_SPLIT MENUITEM SEPARATOR MENUITEM "&Nome" , ID_VIEW_NAME MENUITEM "&Todos os delalhes" , ID_VIEW_ALL_ATTRIBUTES, CHECKED diff --git a/reactos/subsys/system/winefile/resource.h b/reactos/subsys/system/winefile/resource.h index acf67fb1153..0cc7d59fda3 100644 --- a/reactos/subsys/system/winefile/resource.h +++ b/reactos/subsys/system/winefile/resource.h @@ -53,6 +53,7 @@ #define ID_VIEW_SORT_TYPE 405 #define ID_VIEW_SORT_SIZE 406 #define ID_VIEW_SORT_DATE 407 +#define ID_VIEW_SPLIT 414 #define ID_SELECT_FONT 510 #define ID_VIEW_TOOL_BAR 508 #define ID_VIEW_DRIVE_BAR 507 diff --git a/reactos/subsys/system/winefile/ru.rc b/reactos/subsys/system/winefile/ru.rc index 6ab0c4ae789..be4463711d9 100644 --- a/reactos/subsys/system/winefile/ru.rc +++ b/reactos/subsys/system/winefile/ru.rc @@ -83,7 +83,7 @@ IDM_WINEFILE MENU FIXED IMPURE MENUITEM "Òîëüêî &äåðåâî" , 411 MENUITEM "Òîëüêî &ïàïêà" , 412 MENUITEM SEPARATOR - MENUITEM "Ðàç&áèòü" , 414 + MENUITEM "Ðàç&áèòü" , ID_VIEW_SPLIT MENUITEM SEPARATOR MENUITEM "È&ìÿ" , ID_VIEW_NAME MENUITEM "Â&ñå ïîäðîáíîñòè î ôàéëå" , ID_VIEW_ALL_ATTRIBUTES, CHECKED diff --git a/reactos/subsys/system/winefile/si.rc b/reactos/subsys/system/winefile/si.rc index 60a7570d194..dedc830eaa8 100644 --- a/reactos/subsys/system/winefile/si.rc +++ b/reactos/subsys/system/winefile/si.rc @@ -84,7 +84,7 @@ IDM_WINEFILE MENU FIXED IMPURE MENUITEM "Tr&ee Only" , 411 MENUITEM "Directory &Only" , 412 MENUITEM SEPARATOR - MENUITEM "Sp&lit" , 414 + MENUITEM "Sp&lit" , ID_VIEW_SPLIT MENUITEM SEPARATOR MENUITEM "&Name" , ID_VIEW_NAME MENUITEM "&All File Details" , ID_VIEW_ALL_ATTRIBUTES, CHECKED diff --git a/reactos/subsys/system/winefile/winefile.c b/reactos/subsys/system/winefile/winefile.c index a62746e36a6..516274fe36f 100644 --- a/reactos/subsys/system/winefile/winefile.c +++ b/reactos/subsys/system/winefile/winefile.c @@ -211,6 +211,8 @@ LRESULT CALLBACK TreeWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam) /* globals */ WINEFILE_GLOBALS Globals; +static int last_split; + /* some common string constants */ const static TCHAR sEmpty[] = {'\0'}; @@ -346,6 +348,15 @@ static void read_directory_win(Entry* dir, LPCTSTR path) if (hFind != INVALID_HANDLE_VALUE) { do { +#ifdef _NO_EXTENSIONS + /* hide directory entry "." */ + if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + LPCTSTR name = w32fd.cFileName; + + if (name[0]=='.' && name[1]=='\0') + continue; + } +#endif entry = alloc_entry(); if (!first_entry) @@ -361,15 +372,7 @@ static void read_directory_win(Entry* dir, LPCTSTR path) entry->scanned = FALSE; entry->level = level; -#ifdef _NO_EXTENSIONS - /* hide directory entry "." */ - if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - LPCTSTR name = entry->data.cFileName; - - if (name[0]=='.' && name[1]=='\0') - continue; - } -#else +#ifndef _NO_EXTENSIONS entry->etype = ET_WINDOWS; entry->bhfi_valid = FALSE; @@ -387,9 +390,10 @@ static void read_directory_win(Entry* dir, LPCTSTR path) #endif last = entry; - } while(FindNextFile(hFind, &entry->data)); + } while(FindNextFile(hFind, &w32fd)); - last->next = NULL; + if (last) + last->next = NULL; FindClose(hFind); } @@ -568,7 +572,8 @@ static void read_directory_unix(Entry* dir, LPCTSTR path) last = entry; } - last->next = NULL; + if (last) + last->next = NULL; call_closedir(pdir); } @@ -1219,7 +1224,7 @@ static void SortDirectory(Entry* dir, SORT_ORDER sortOrder) len++; if (len) { - array = (Entry**) HeapAlloc(GetProcessHeap(), 0, len*sizeof(Entry*)); + array = HeapAlloc(GetProcessHeap(), 0, len*sizeof(Entry*)); p = array; for(entry=dir->down; entry; entry=entry->next) @@ -1321,10 +1326,10 @@ static void read_directory(Entry* dir, LPCTSTR path, SORT_ORDER sortOrder, HWND static Entry* read_tree(Root* root, LPCTSTR path, LPITEMIDLIST pidl, LPTSTR drv, SORT_ORDER sortOrder, HWND hwnd) { - const static TCHAR sBackslash[] = {'\\', '\0'}; #if !defined(_NO_EXTENSIONS) && defined(__WINE__) const static TCHAR sSlash[] = {'/', '\0'}; #endif + const static TCHAR sBackslash[] = {'\\', '\0'}; #ifdef _SHELL_FOLDERS if (pidl) @@ -3397,7 +3402,9 @@ static void refresh_child(ChildWnd* child) static void create_drive_bar() { TBBUTTON drivebarBtn = {0, 0, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0}; +#ifndef _NO_EXTENSIONS TCHAR b1[BUFFER_LEN]; +#endif int btn = 1; PTSTR p; @@ -3755,8 +3762,6 @@ static HRESULT ShellFolderContextMenu(IShellFolder* shell_folder, HWND hwndParen LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam) { - static int last_split; - ChildWnd* child = (ChildWnd*) GetWindowLong(hwnd, GWL_USERDATA); ASSERT(child); @@ -3995,6 +4000,14 @@ LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam set_sort_order(child, SORT_DATE); break; + case ID_VIEW_SPLIT: { + last_split = child->split_pos; +#ifdef _NO_EXTENSIONS + draw_splitbar(hwnd, last_split); +#endif + SetCapture(hwnd); + break;} + default: return pane_command(pane, LOWORD(wparam)); } @@ -4244,7 +4257,6 @@ void show_frame(HWND hwndParent, int cmdshow) TCHAR path[MAX_PATH], b1[BUFFER_LEN]; ChildWnd* child; HMENU hMenuFrame, hMenuWindow; - TBBUTTON drivebarBtn = {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0}; CLIENTCREATESTRUCT ccs; diff --git a/reactos/subsys/system/winefile/winefile.h b/reactos/subsys/system/winefile/winefile.h index edb3894847d..e2d1158bdb8 100644 --- a/reactos/subsys/system/winefile/winefile.h +++ b/reactos/subsys/system/winefile/winefile.h @@ -50,12 +50,11 @@ #include /* for alloca() */ #endif +#include /* for ShellExecute() */ +#include /* for SHFormatDrive() */ + #ifndef _NO_EXTENSIONS #define _SHELL_FOLDERS - -#include -#include -#include #endif /* _NO_EXTENSIONS */ #ifndef FILE_ATTRIBUTE_NOT_CONTENT_INDEXED diff --git a/reactos/subsys/system/winefile/zh.rc b/reactos/subsys/system/winefile/zh.rc index bafd61f48fd..f82c9e9a61c 100644 --- a/reactos/subsys/system/winefile/zh.rc +++ b/reactos/subsys/system/winefile/zh.rc @@ -84,7 +84,7 @@ IDM_WINEFILE MENU FIXED IMPURE MENUITEM "½öÏÔʾĿ¼Ê÷£¨&E£©" , 411 MENUITEM "½öÏÔʾĿ¼ÄÚÈÝ£¨&O£©" , 412 MENUITEM SEPARATOR - MENUITEM "·Ö¸î£¨&L£©" , 414 + MENUITEM "·Ö¸î£¨&L£©" , ID_VIEW_SPLIT MENUITEM SEPARATOR MENUITEM "ÎļþÃûÃû£¨&N£©" , ID_VIEW_NAME MENUITEM "ÎļþÏêϤÁÐ±í£¨&A£©" , ID_VIEW_ALL_ATTRIBUTES, CHECKED diff --git a/reactos/subsys/win32k/include/csr.h b/reactos/subsys/win32k/include/csr.h index 4f727f7937f..8110d773c49 100644 --- a/reactos/subsys/win32k/include/csr.h +++ b/reactos/subsys/win32k/include/csr.h @@ -15,7 +15,11 @@ extern PEPROCESS CsrProcess; extern NTSTATUS FASTCALL CsrInit(void); extern NTSTATUS FASTCALL CsrNotify(PCSRSS_API_REQUEST Request, PCSRSS_API_REPLY Reply); extern NTSTATUS FASTCALL CsrCloseHandle(HANDLE Handle); -extern NTSTATUS STDCALL CsrInsertObject(PVOID, PACCESS_STATE, ACCESS_MASK, ULONG, PVOID*, PHANDLE); +NTSTATUS +STDCALL +CsrInsertObject(HANDLE ObjectHandle, + ACCESS_MASK DesiredAccess, + PHANDLE Handle); #endif /* CSR_H_INCLUDED */ diff --git a/reactos/subsys/win32k/include/msgqueue.h b/reactos/subsys/win32k/include/msgqueue.h index 6a51d017f7e..d9e7eeb7a80 100644 --- a/reactos/subsys/win32k/include/msgqueue.h +++ b/reactos/subsys/win32k/include/msgqueue.h @@ -239,6 +239,8 @@ VOID STDCALL MsqRemoveWindowMessagesFromQueue(PVOID pWindow); /* F*(&$ headers, if(InterlockedDecrement(&(MsgQueue)->References) == 0) \ { \ DPRINT("Free message queue 0x%x\n", (MsgQueue)); \ + if ((MsgQueue)->NewMessages != NULL) \ + ObDereferenceObject((MsgQueue)->NewMessages); \ if ((MsgQueue)->NewMessagesHandle != NULL) \ ZwClose((MsgQueue)->NewMessagesHandle); \ ExFreePool((MsgQueue)); \ diff --git a/reactos/subsys/win32k/ntuser/csr.c b/reactos/subsys/win32k/ntuser/csr.c index 892cd1e8c20..e2687c19045 100644 --- a/reactos/subsys/win32k/ntuser/csr.c +++ b/reactos/subsys/win32k/ntuser/csr.c @@ -11,7 +11,7 @@ static HANDLE WindowsApiPort = NULL; PEPROCESS CsrProcess = NULL; - + NTSTATUS FASTCALL CsrInit(void) { @@ -76,35 +76,48 @@ CsrNotify(PCSRSS_API_REQUEST Request, PCSRSS_API_REPLY Reply) return Status; } -NTSTATUS STDCALL -CsrInsertObject(PVOID Object, - PACCESS_STATE PassedAccessState, +NTSTATUS +STDCALL +CsrInsertObject(HANDLE ObjectHandle, ACCESS_MASK DesiredAccess, - ULONG AdditionalReferences, - PVOID* ReferencedObject, PHANDLE Handle) { NTSTATUS Status; - PEPROCESS OldProcess; - - /* Switch to the process in which the handle is valid */ - OldProcess = PsGetCurrentProcess(); - if (CsrProcess != OldProcess) - { - KeAttachProcess(CsrProcess); - } - - Status = ObInsertObject(Object, - PassedAccessState, - DesiredAccess, - AdditionalReferences, - ReferencedObject, - Handle); - - if (CsrProcess != OldProcess) - { - KeDetachProcess(); - } + HANDLE CsrProcessHandle; + OBJECT_ATTRIBUTES ObjectAttributes; + CLIENT_ID Cid; + + /* Put CSR'S CID */ + Cid.UniqueProcess = CsrProcess->UniqueProcessId; + Cid.UniqueThread = 0; + + /* Empty Attributes */ + InitializeObjectAttributes(&ObjectAttributes, + NULL, + 0, + NULL, + NULL); + + /* Get a Handle to Csrss */ + Status = ZwOpenProcess(&CsrProcessHandle, + PROCESS_DUP_HANDLE, + &ObjectAttributes, + &Cid); + + if ((NT_SUCCESS(Status))) + { + /* Duplicate the Handle */ + Status = ZwDuplicateObject(NtCurrentProcess(), + ObjectHandle, + CsrProcessHandle, + Handle, + DesiredAccess, + TRUE, + 0); + + /* Close our handle to CSRSS */ + ZwClose(CsrProcessHandle); + } return Status; } diff --git a/reactos/subsys/win32k/ntuser/desktop.c b/reactos/subsys/win32k/ntuser/desktop.c index 3a6d1f00d82..b65a81916f7 100644 --- a/reactos/subsys/win32k/ntuser/desktop.c +++ b/reactos/subsys/win32k/ntuser/desktop.c @@ -843,11 +843,8 @@ NtUserCreateDesktop( * Create a handle for CSRSS and notify CSRSS */ Request.Type = CSRSS_CREATE_DESKTOP; - Status = CsrInsertObject((PVOID)DesktopObject, - NULL, + Status = CsrInsertObject(Desktop, GENERIC_ALL, - 0, - NULL, (HANDLE*)&Request.Data.CreateDesktopRequest.DesktopHandle); if (! NT_SUCCESS(Status)) { diff --git a/reactos/subsys/win32k/objects/dc.c b/reactos/subsys/win32k/objects/dc.c index b17c7b8f90c..bb1a2228328 100644 --- a/reactos/subsys/win32k/objects/dc.c +++ b/reactos/subsys/win32k/objects/dc.c @@ -2494,7 +2494,6 @@ IntEnumDisplaySettings( return TRUE; } - LONG FASTCALL IntChangeDisplaySettings( @@ -2507,7 +2506,10 @@ IntChangeDisplaySettings( BOOLEAN NoReset = FALSE; BOOLEAN Reset = FALSE; BOOLEAN SetPrimary = FALSE; - LONG Ret; + LONG Ret=0; + NTSTATUS Status ; + + DPRINT1("display flag : %x\n",dwflags); if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY) { @@ -2527,29 +2529,78 @@ IntChangeDisplaySettings( if (Reset && NoReset) return DISP_CHANGE_BADFLAGS; - switch (dwflags) + if (dwflags == 0) { - case 0: /* Dynamically change graphics mode */ - Ret = DISP_CHANGE_FAILED; - break; + /* Dynamically change graphics mode */ + DPRINT1("flag 0 UNIMPLEMENT \n"); + return DISP_CHANGE_FAILED; + } - case CDS_FULLSCREEN: /* Given mode is temporary */ - Ret = DISP_CHANGE_FAILED; - break; + if ((dwflags & CDS_TEST) == CDS_TEST) + { + /* Test reslution */ + dwflags &= ~CDS_TEST; + DPRINT1("flag CDS_TEST UNIMPLEMENT"); + Ret = DISP_CHANGE_FAILED; + } + + if ((dwflags & CDS_FULLSCREEN) == CDS_FULLSCREEN) + { + DEVMODE lpDevMode; + /* Full Screen */ + dwflags &= ~CDS_FULLSCREEN; + DPRINT1("flag CDS_FULLSCREEN partially implemented"); + Ret = DISP_CHANGE_FAILED; - case CDS_UPDATEREGISTRY: - { + lpDevMode.dmBitsPerPel =0; + lpDevMode.dmPelsWidth =0; + lpDevMode.dmPelsHeight =0; + lpDevMode.dmDriverExtra =0; + + lpDevMode.dmSize = sizeof(DEVMODE); + Status = IntEnumDisplaySettings(pDeviceName, ENUM_CURRENT_SETTINGS, &lpDevMode, 0); + if (!NT_SUCCESS(Status)) return DISP_CHANGE_FAILED; + + DPRINT1("Req Mode : %d x %d x %d\n", DevMode->dmPelsWidth,DevMode->dmPelsHeight,DevMode->dmBitsPerPel); + DPRINT1("Current Mode : %d x %d x %d\n", lpDevMode.dmPelsWidth,lpDevMode.dmPelsHeight, lpDevMode.dmBitsPerPel); + + + if ((lpDevMode.dmBitsPerPel == DevMode->dmBitsPerPel) && + (lpDevMode.dmPelsWidth == DevMode->dmPelsWidth) && + (lpDevMode.dmPelsHeight == DevMode->dmPelsHeight)) + Ret = DISP_CHANGE_SUCCESSFUL; + } + + if ((dwflags & CDS_VIDEOPARAMETERS) == CDS_VIDEOPARAMETERS) + { + dwflags &= ~CDS_VIDEOPARAMETERS; + if (lParam == NULL) Ret=DISP_CHANGE_BADPARAM; + else + { + DPRINT1("flag CDS_VIDEOPARAMETERS UNIMPLEMENT"); + Ret = DISP_CHANGE_FAILED; + } + + } + + if ((dwflags & CDS_UPDATEREGISTRY) == CDS_UPDATEREGISTRY) + { + UNICODE_STRING ObjectName; UNICODE_STRING KernelModeName; WCHAR KernelModeNameBuffer[256]; UNICODE_STRING RegistryKey; WCHAR RegistryKeyBuffer[512]; - PDEVICE_OBJECT DeviceObject; - NTSTATUS Status; + PDEVICE_OBJECT DeviceObject; ULONG LastSlash; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE DevInstRegKey; ULONG NewValue; + + + DPRINT1("set CDS_UPDATEREGISTRY \n"); + + dwflags &= ~CDS_UPDATEREGISTRY; /* Get device name (pDeviceName is "\.\xxx") */ for (LastSlash = pDeviceName->Length / sizeof(WCHAR); LastSlash > 0; LastSlash--) @@ -2557,7 +2608,8 @@ IntChangeDisplaySettings( if (pDeviceName->Buffer[LastSlash - 1] == L'\\') break; } - if (LastSlash == 0) return DISP_CHANGE_FAILED; + + if (LastSlash == 0) return DISP_CHANGE_RESTART; ObjectName = *pDeviceName; ObjectName.Length -= LastSlash * sizeof(WCHAR); ObjectName.MaximumLength -= LastSlash * sizeof(WCHAR); @@ -2569,8 +2621,10 @@ IntChangeDisplaySettings( /* Open \??\xxx (ex: "\??\DISPLAY1") */ Status = RtlAppendUnicodeToString(&KernelModeName, L"\\??\\"); + if (!NT_SUCCESS(Status)) return DISP_CHANGE_FAILED; Status = RtlAppendUnicodeStringToString(&KernelModeName, &ObjectName); + if (!NT_SUCCESS(Status)) return DISP_CHANGE_FAILED; Status = ObReferenceObjectByName( &KernelModeName, @@ -2581,6 +2635,7 @@ IntChangeDisplaySettings( KernelMode, NULL, (PVOID*)&DeviceObject); + if (!NT_SUCCESS(Status)) return DISP_CHANGE_FAILED; /* Get associated driver name (ex: "VBE") */ for (LastSlash = DeviceObject->DriverObject->DriverName.Length / sizeof(WCHAR); LastSlash > 0; LastSlash--) @@ -2588,6 +2643,7 @@ IntChangeDisplaySettings( if (DeviceObject->DriverObject->DriverName.Buffer[LastSlash - 1] == L'\\') break; } + if (LastSlash == 0) { ObDereferenceObject(DeviceObject); return DISP_CHANGE_FAILED; } ObjectName = DeviceObject->DriverObject->DriverName; ObjectName.Length -= LastSlash * sizeof(WCHAR); @@ -2601,11 +2657,14 @@ IntChangeDisplaySettings( /* Open registry key */ Status = RtlAppendUnicodeToString(&RegistryKey, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services\\"); + if (!NT_SUCCESS(Status)) { ObDereferenceObject(DeviceObject); return DISP_CHANGE_FAILED; } Status = RtlAppendUnicodeStringToString(&RegistryKey, &ObjectName); + if (!NT_SUCCESS(Status)) { ObDereferenceObject(DeviceObject); return DISP_CHANGE_FAILED; } Status = RtlAppendUnicodeToString(&RegistryKey, L"\\Device0"); + if (!NT_SUCCESS(Status)) { ObDereferenceObject(DeviceObject); return DISP_CHANGE_FAILED; } InitializeObjectAttributes(&ObjectAttributes, &RegistryKey, @@ -2619,47 +2678,34 @@ IntChangeDisplaySettings( { RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.BitsPerPel"); NewValue = DevMode->dmBitsPerPel; - Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue)); + Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue)); } if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSWIDTH) { RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.XResolution"); - NewValue = DevMode->dmPelsWidth; - Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue)); + NewValue = DevMode->dmPelsWidth; + Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue)); } if (NT_SUCCESS(Status) && DevMode->dmFields & DM_PELSHEIGHT) { RtlInitUnicodeString(&RegistryKey, L"DefaultSettings.YResolution"); NewValue = DevMode->dmPelsHeight; - Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue)); + Status = ZwSetValueKey(DevInstRegKey, &RegistryKey, 0, REG_DWORD, &NewValue, sizeof(NewValue)); } ZwClose(DevInstRegKey); if (NT_SUCCESS(Status)) Ret = DISP_CHANGE_RESTART; else - Ret = DISP_CHANGE_FAILED; - break; + /* return DISP_CHANGE_NOTUPDATED when we can save to reg only vaild for NT */ + Ret = DISP_CHANGE_NOTUPDATED; + } - - case CDS_TEST: /* Test if the mode could be set */ - Ret = DISP_CHANGE_FAILED; - break; - -#ifdef CDS_VIDEOPARAMETERS - case CDS_VIDEOPARAMETERS: - if (lParam == NULL) - return DISP_CHANGE_BADPARAM; - Ret = DISP_CHANGE_FAILED; - break; -#endif - - default: + + if (dwflags != 0) Ret = DISP_CHANGE_BADFLAGS; - break; - } return Ret; } diff --git a/reactos/tools/cabman/dfp.cxx b/reactos/tools/cabman/dfp.cxx index 6d5dcce9805..bce030f4eb3 100755 --- a/reactos/tools/cabman/dfp.cxx +++ b/reactos/tools/cabman/dfp.cxx @@ -331,8 +331,8 @@ unsigned long CDFParser::Parse() } else { /* File copy */ Status = PerformFileCopy(); - - if (Status == CAB_STATUS_FAILURE) { + + if (Status != CAB_STATUS_SUCCESS) { printf("Directive file contains errors at line %d.\n", (unsigned int)CurrentLine); DPRINT(MID_TRACE, ("Error while copying file.\n")); } diff --git a/reactos/tools/cabman/main.cxx b/reactos/tools/cabman/main.cxx index 703a7740fdb..6ceba018dcb 100755 --- a/reactos/tools/cabman/main.cxx +++ b/reactos/tools/cabman/main.cxx @@ -325,9 +325,9 @@ bool CCABManager::CreateCabinet() return false; } - Parse(); + Status = Parse(); - return true; + return (Status == CAB_STATUS_SUCCESS ? true : false); } diff --git a/reactos/tools/rbuild/backend/mingw/modulehandler.cpp b/reactos/tools/rbuild/backend/mingw/modulehandler.cpp index ba5bbad9c9a..4bd0e6e7b89 100644 --- a/reactos/tools/rbuild/backend/mingw/modulehandler.cpp +++ b/reactos/tools/rbuild/backend/mingw/modulehandler.cpp @@ -981,21 +981,20 @@ MingwModuleHandler::GenerateWinebuildCommands ( dependencies.c_str () ); fprintf ( fMakefile, "\t$(ECHO_WINEBLD)\n" ); fprintf ( fMakefile, - "\t%s --def=%s -o %s\n", + "\t%s -o %s --def -E %s\n", "$(Q)$(WINEBUILD_TARGET)", - sourceFilename.c_str (), - def_file.c_str () ); - + def_file.c_str (), + sourceFilename.c_str () ); fprintf ( fMakefile, "%s: %s $(WINEBUILD_TARGET)\n", stub_file.c_str (), sourceFilename.c_str () ); fprintf ( fMakefile, "\t$(ECHO_WINEBLD)\n" ); fprintf ( fMakefile, - "\t%s --pedll=%s -o %s\n", + "\t%s -o %s --pedll %s\n", "$(Q)$(WINEBUILD_TARGET)", - sourceFilename.c_str (), - stub_file.c_str () ); + stub_file.c_str (), + sourceFilename.c_str () ); } string diff --git a/reactos/tools/rsym.c b/reactos/tools/rsym.c index 1b61aaaa1f8..a69ef711dbb 100644 --- a/reactos/tools/rsym.c +++ b/reactos/tools/rsym.c @@ -146,13 +146,20 @@ ConvertStabs(ULONG *SymbolsCount, PROSSYM_ENTRY *SymbolsBase, StabEntry = StabSymbolsBase; Count = StabSymbolsLength / sizeof(STAB_ENTRY); + *SymbolsCount = 0; + if (Count == 0) + { + /* No symbol info */ + *SymbolsBase = NULL; + return 0; + } + *SymbolsBase = malloc(Count * sizeof(ROSSYM_ENTRY)); if (NULL == *SymbolsBase) { fprintf(stderr, "Failed to allocate memory for converted .stab symbols\n"); return 1; } - *SymbolsCount = 0; LastFunctionAddress = 0; First = 1; @@ -330,13 +337,18 @@ MergeStabsAndCoffs(ULONG *MergedSymbolCount, PROSSYM_ENTRY *MergedSymbols, ULONG_PTR StabFunctionStartAddress; ULONG StabFunctionStringOffset, NewStabFunctionStringOffset; + *MergedSymbolCount = 0; + if (StabSymbolsCount == 0) + { + *MergedSymbols = NULL; + return 0; + } *MergedSymbols = malloc(StabSymbolsCount * sizeof(ROSSYM_ENTRY)); if (NULL == *MergedSymbols) { fprintf(stderr, "Unable to allocate memory for merged symbols\n"); return 1; } - *MergedSymbolCount = 0; StabFunctionStartAddress = 0; StabFunctionStringOffset = 0; @@ -368,7 +380,8 @@ MergeStabsAndCoffs(ULONG *MergedSymbolCount, PROSSYM_ENTRY *MergedSymbols, CoffIndex++; } NewStabFunctionStringOffset = (*MergedSymbols)[*MergedSymbolCount].FunctionOffset; - if (CoffSymbols[CoffIndex].Address < (*MergedSymbols)[*MergedSymbolCount].Address + if (CoffSymbolsCount > 0 && + CoffSymbols[CoffIndex].Address < (*MergedSymbols)[*MergedSymbolCount].Address && StabFunctionStartAddress < CoffSymbols[CoffIndex].Address && 0 != CoffSymbols[CoffIndex].FunctionOffset) { @@ -627,32 +640,38 @@ CreateOutputFile(FILE *OutFile, void *InData, OutOptHeader->FileAlignment); } - RosSymFileLength = ROUND_UP(RosSymLength, OutOptHeader->FileAlignment); - memcpy(CurrentSectionHeader->Name, ".rossym", 8); /* We're lucky: string is exactly 8 bytes long */ - CurrentSectionHeader->Misc.VirtualSize = RosSymLength; - CurrentSectionHeader->VirtualAddress = OutOptHeader->SizeOfImage; - CurrentSectionHeader->SizeOfRawData = RosSymFileLength; - CurrentSectionHeader->PointerToRawData = RosSymOffset; - CurrentSectionHeader->PointerToRelocations = 0; - CurrentSectionHeader->PointerToLinenumbers = 0; - CurrentSectionHeader->NumberOfRelocations = 0; - CurrentSectionHeader->NumberOfLinenumbers = 0; - CurrentSectionHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE - | IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_TYPE_NOLOAD; - OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress + - CurrentSectionHeader->Misc.VirtualSize, - OutOptHeader->SectionAlignment); - (OutFileHeader->NumberOfSections)++; - - PaddedRosSym = malloc(RosSymFileLength); - if (NULL == PaddedRosSym) + if (RosSymLength > 0) { - fprintf(stderr, "Failed to allocate %lu bytes for padded .rossym\n", RosSymFileLength); - return 1; - } - memcpy(PaddedRosSym, RosSymSection, RosSymLength); - memset((char *) PaddedRosSym + RosSymLength, '\0', RosSymFileLength - RosSymLength); + RosSymFileLength = ROUND_UP(RosSymLength, OutOptHeader->FileAlignment); + memcpy(CurrentSectionHeader->Name, ".rossym", 8); /* We're lucky: string is exactly 8 bytes long */ + CurrentSectionHeader->Misc.VirtualSize = RosSymLength; + CurrentSectionHeader->VirtualAddress = OutOptHeader->SizeOfImage; + CurrentSectionHeader->SizeOfRawData = RosSymFileLength; + CurrentSectionHeader->PointerToRawData = RosSymOffset; + CurrentSectionHeader->PointerToRelocations = 0; + CurrentSectionHeader->PointerToLinenumbers = 0; + CurrentSectionHeader->NumberOfRelocations = 0; + CurrentSectionHeader->NumberOfLinenumbers = 0; + CurrentSectionHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE + | IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_TYPE_NOLOAD; + OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress + + CurrentSectionHeader->Misc.VirtualSize, + OutOptHeader->SectionAlignment); + (OutFileHeader->NumberOfSections)++; + PaddedRosSym = malloc(RosSymFileLength); + if (NULL == PaddedRosSym) + { + fprintf(stderr, "Failed to allocate %lu bytes for padded .rossym\n", RosSymFileLength); + return 1; + } + memcpy(PaddedRosSym, RosSymSection, RosSymLength); + memset((char *) PaddedRosSym + RosSymLength, '\0', RosSymFileLength - RosSymLength); + } + else + { + PaddedRosSym = NULL; + } CheckSum = 0; for (i = 0; i < StartOfRawData / 2; i++) { @@ -666,7 +685,7 @@ CreateOutputFile(FILE *OutFile, void *InData, { Data = (void *) ProcessedRelocs; } - else if (Section + 1 == OutFileHeader->NumberOfSections) + else if (RosSymLength > 0 && Section + 1 == OutFileHeader->NumberOfSections) { Data = (void *) PaddedRosSym; } @@ -700,7 +719,7 @@ CreateOutputFile(FILE *OutFile, void *InData, { Data = (void *) ProcessedRelocs; } - else if (Section + 1 == OutFileHeader->NumberOfSections) + else if (RosSymLength > 0 && Section + 1 == OutFileHeader->NumberOfSections) { Data = (void *) PaddedRosSym; } @@ -719,7 +738,10 @@ CreateOutputFile(FILE *OutFile, void *InData, } } - free(PaddedRosSym); + if (PaddedRosSym) + { + free(PaddedRosSym); + } free(OutHeader); return 0; @@ -833,7 +855,10 @@ int main(int argc, char* argv[]) CoffsLength, CoffBase, CoffStringsLength, CoffStringBase, ImageBase, PEFileHeader, PESectionHeaders)) { - free(StabSymbols); + if (StabSymbols) + { + free(StabSymbols); + } free(StringBase); free(FileData); exit(1); @@ -843,43 +868,61 @@ int main(int argc, char* argv[]) StabSymbolsCount, StabSymbols, CoffSymbolsCount, CoffSymbols)) { - free(CoffSymbols); - free(StabSymbols); + if (CoffSymbols) + { + free(CoffSymbols); + } + if (StabSymbols) + { + free(StabSymbols); + } free(StringBase); free(FileData); exit(1); } - free(CoffSymbols); - free(StabSymbols); - - RosSymLength = sizeof(SYMBOLFILE_HEADER) + MergedSymbolsCount * sizeof(ROSSYM_ENTRY) - + StringsLength; - RosSymSection = malloc(RosSymLength); - if (NULL == RosSymSection) + if (CoffSymbols) { - free(MergedSymbols); - free(StringBase); - free(FileData); - fprintf(stderr, "Unable to allocate memory for .rossym section\n"); - exit(1); + free(CoffSymbols); } - memset(RosSymSection, '\0', RosSymLength); + if (StabSymbols) + { + free(StabSymbols); + } + if (MergedSymbolsCount == 0) + { + RosSymLength = 0; + RosSymSection = NULL; + } + else + { + RosSymLength = sizeof(SYMBOLFILE_HEADER) + MergedSymbolsCount * sizeof(ROSSYM_ENTRY) + + StringsLength; + RosSymSection = malloc(RosSymLength); + if (NULL == RosSymSection) + { + free(MergedSymbols); + free(StringBase); + free(FileData); + fprintf(stderr, "Unable to allocate memory for .rossym section\n"); + exit(1); + } + memset(RosSymSection, '\0', RosSymLength); - SymbolFileHeader = (PSYMBOLFILE_HEADER) RosSymSection; - SymbolFileHeader->SymbolsOffset = sizeof(SYMBOLFILE_HEADER); - SymbolFileHeader->SymbolsLength = MergedSymbolsCount * sizeof(ROSSYM_ENTRY); - SymbolFileHeader->StringsOffset = SymbolFileHeader->SymbolsOffset + SymbolFileHeader->SymbolsLength; - SymbolFileHeader->StringsLength = StringsLength; + SymbolFileHeader = (PSYMBOLFILE_HEADER) RosSymSection; + SymbolFileHeader->SymbolsOffset = sizeof(SYMBOLFILE_HEADER); + SymbolFileHeader->SymbolsLength = MergedSymbolsCount * sizeof(ROSSYM_ENTRY); + SymbolFileHeader->StringsOffset = SymbolFileHeader->SymbolsOffset + SymbolFileHeader->SymbolsLength; + SymbolFileHeader->StringsLength = StringsLength; - memcpy((char *) RosSymSection + SymbolFileHeader->SymbolsOffset, MergedSymbols, - SymbolFileHeader->SymbolsLength); - memcpy((char *) RosSymSection + SymbolFileHeader->StringsOffset, StringBase, - SymbolFileHeader->StringsLength); + memcpy((char *) RosSymSection + SymbolFileHeader->SymbolsOffset, MergedSymbols, + SymbolFileHeader->SymbolsLength); + memcpy((char *) RosSymSection + SymbolFileHeader->StringsOffset, StringBase, + SymbolFileHeader->StringsLength); - free(MergedSymbols); + free(MergedSymbols); + } free(StringBase); - out = fopen(path2, "wb"); if (out == NULL) { @@ -893,13 +936,19 @@ int main(int argc, char* argv[]) PESectionHeaders, RosSymLength, RosSymSection)) { fclose(out); - free(RosSymSection); + if (RosSymSection) + { + free(RosSymSection); + } free(FileData); exit(1); } fclose(out); - free(RosSymSection); + if (RosSymSection) + { + free(RosSymSection); + } free(FileData); return 0; diff --git a/reactos/tools/winebuild/Makefile b/reactos/tools/winebuild/Makefile index 6d7cec5f718..2b9596a22f7 100644 --- a/reactos/tools/winebuild/Makefile +++ b/reactos/tools/winebuild/Makefile @@ -22,7 +22,7 @@ OBJECTS = \ CLEAN_FILES = *.o $(TARGET) -HOST_CFLAGS = $(HOSTARCH) -D__USE_W32API -I$(PATH_TO_TOP)/include/wine +HOST_CFLAGS = $(HOSTARCH) -D__USE_W32API -I$(PATH_TO_TOP)/include/wine -I$(PATH_TO_TOP)/include %.o: %.c $(HOST_CC) $(HOST_CFLAGS) -c $< -o $@ diff --git a/reactos/tools/winebuild/build.h b/reactos/tools/winebuild/build.h index d6af3a0fbd2..10573db60cf 100644 --- a/reactos/tools/winebuild/build.h +++ b/reactos/tools/winebuild/build.h @@ -133,7 +133,7 @@ typedef struct #define STACK32OFFSET(reg) STRUCTOFFSET(STACK32FRAME,reg) /* Offset of the stack pointer relative to %fs:(0) */ -#define STACKOFFSET (STRUCTOFFSET(TEB,cur_stack)) +#define STACKOFFSET (STRUCTOFFSET(TEB,WOW32Reserved)) #define MAX_ORDINALS 65535 @@ -148,6 +148,7 @@ extern void *xmalloc (size_t size); extern void *xrealloc (void *ptr, size_t size); extern char *xstrdup( const char *str ); extern char *strupper(char *s); +extern int strendswith(const char* str, const char* end); extern void fatal_error( const char *msg, ... ) __attribute__ ((__format__ (__printf__, 1, 2))); extern void fatal_perror( const char *msg, ... ) @@ -167,16 +168,22 @@ extern void free_dll_spec( DLLSPEC *spec ); extern const char *make_c_identifier( const char *str ); extern int get_alignment(int alignBoundary); -extern void add_import_dll( const char *name, int delay ); +extern void add_import_dll( const char *name, const char *filename ); +extern void add_delayed_import( const char *name ); extern void add_ignore_symbol( const char *name ); extern void read_undef_symbols( char **argv ); extern int resolve_imports( DLLSPEC *spec ); -extern int output_imports( FILE *outfile, DLLSPEC *spec ); +extern int output_imports( FILE *outfile, DLLSPEC *spec, int *nb_delayed ); extern int load_res32_file( const char *name, DLLSPEC *spec ); extern void output_resources( FILE *outfile, DLLSPEC *spec ); extern void load_res16_file( const char *name, DLLSPEC *spec ); -extern int output_res16_data( FILE *outfile, DLLSPEC *spec ); -extern int output_res16_directory( unsigned char *buffer, DLLSPEC *spec ); +extern unsigned int get_res16_data_size( DLLSPEC *spec, unsigned int res_offset, + unsigned int alignment ); +extern unsigned int output_res16_data( unsigned char **ret_buf, DLLSPEC *spec, + unsigned int res_offset, unsigned int alignment ); +extern unsigned int get_res16_directory_size( DLLSPEC *spec ); +extern unsigned int output_res16_directory( unsigned char **ret_buf, DLLSPEC *spec, + unsigned int res_offset, unsigned int alignment ); extern void output_dll_init( FILE *outfile, const char *constructor, const char *destructor ); extern void BuildRelays16( FILE *outfile ); diff --git a/reactos/tools/winebuild/import.c b/reactos/tools/winebuild/import.c index 0a6aff1b3d1..c442e1da461 100644 --- a/reactos/tools/winebuild/import.c +++ b/reactos/tools/winebuild/import.c @@ -26,16 +26,29 @@ #include #include #include +#ifdef HAVE_SYS_STAT_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif #include "winglue.h" +//#include "wine/exception.h" #include "build.h" +#ifndef EXCEPTION_NONCONTINUABLE +#define EXCEPTION_NONCONTINUABLE 1 +#endif + +#define EXCEPTION_WINE_STUB 0x80000100 /* stub entry point called */ + struct import { - DLLSPEC *spec; /* description of the imported dll */ + DLLSPEC *spec; /* description of the imported dll */ + char *full_name; /* full name of the input file */ + dev_t dev; /* device/inode of the input file */ + ino_t ino; int delay; /* delay or not dll loading ? */ ORDDEF **exports; /* functions exported from this dll */ int nb_exports; /* number of exported functions */ @@ -58,6 +71,8 @@ static int nb_imports = 0; /* number of imported dlls (delayed or not) */ static int nb_delayed = 0; /* number of delayed dlls */ static int total_imports = 0; /* total number of imported functions */ static int total_delayed = 0; /* total number of imported functions in delayed DLLs */ +static char **delayed_imports; /* names of delayed import dlls */ +static int nb_delayed_imports; /* size of the delayed_imports array */ /* list of symbols that are ignored by default */ static const char * const default_ignored_symbols[] = @@ -187,6 +202,7 @@ static void free_imports( struct import *imp ) free( imp->exports ); free( imp->imports ); free_dll_spec( imp->spec ); + free( imp->full_name ); free( imp ); } @@ -196,16 +212,28 @@ static void remove_ld_tmp_file(void) if (ld_tmp_file) unlink( ld_tmp_file ); } +/* check whether a given dll is imported in delayed mode */ +static int is_delayed_import( const char *name ) +{ + int i; + + for (i = 0; i < nb_delayed_imports; i++) + { + if (!strcmp( delayed_imports[i], name )) return 1; + } + return 0; +} + /* check whether a given dll has already been imported */ -static int is_already_imported( const char *name ) +static struct import *is_already_imported( const char *name ) { int i; for (i = 0; i < nb_imports; i++) { - if (!strcmp( dll_imports[i]->spec->file_name, name )) return 1; + if (!strcmp( dll_imports[i]->spec->file_name, name )) return dll_imports[i]; } - return 0; + return NULL; } /* open the .so library for a given dll in a specified path */ @@ -227,8 +255,8 @@ static char *try_library_path( const char *path, const char *name ) return NULL; } -/* open the .so library for a given dll */ -static char *open_library( const char *name ) +/* find the .def import library for a given dll */ +static char *find_library( const char *name ) { char *fullname; int i; @@ -242,24 +270,36 @@ static char *open_library( const char *name ) } /* read in the list of exported symbols of an import library */ -static int read_import_lib( const char *name, struct import *imp ) +static int read_import_lib( struct import *imp ) { FILE *f; - char *fullname; int i, ret; + struct stat stat; + struct import *prev_imp; DLLSPEC *spec = imp->spec; - imp->exports = NULL; - imp->nb_exports = 0; - - fullname = open_library( name ); - f = open_input_file( NULL, fullname ); - free( fullname ); - + f = open_input_file( NULL, imp->full_name ); + fstat( fileno(f), &stat ); + imp->dev = stat.st_dev; + imp->ino = stat.st_ino; ret = parse_def_file( f, spec ); close_input_file( f ); if (!ret) return 0; - if (is_already_imported( spec->file_name )) return 0; + + /* check if we already imported that library from a different file */ + if ((prev_imp = is_already_imported( spec->file_name ))) + { + if (prev_imp->dev != imp->dev || prev_imp->ino != imp->ino) + fatal_error( "%s and %s have the same export name '%s'\n", + prev_imp->full_name, imp->full_name, spec->file_name ); + return 0; /* the same file was already loaded, ignore this one */ + } + + if (is_delayed_import( spec->file_name )) + { + imp->delay = 1; + nb_delayed++; + } imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) ); @@ -277,32 +317,47 @@ static int read_import_lib( const char *name, struct import *imp ) return 1; } -/* add a dll to the list of imports */ -void add_import_dll( const char *name, int delay ) +/* build the dll exported name from the import lib name or path */ +static char *get_dll_name( const char *name, const char *filename ) { - struct import *imp; - char *fullname; + char *ret; - fullname = xmalloc( strlen(name) + 5 ); - strcpy( fullname, name ); - if (!strchr( fullname, '.' )) strcat( fullname, ".dll" ); - - /* check if we already imported it */ - if (is_already_imported( fullname )) + if (filename) { - free( fullname ); - return; + const char *basename = strrchr( filename, '/' ); + if (!basename) basename = filename; + else basename++; + if (!strncmp( basename, "lib", 3 )) basename += 3; + ret = xmalloc( strlen(basename) + 5 ); + strcpy( ret, basename ); + if (strendswith( ret, ".def" )) ret[strlen(ret)-4] = 0; } + else + { + ret = xmalloc( strlen(name) + 5 ); + strcpy( ret, name ); + } + if (!strchr( ret, '.' )) strcat( ret, ".dll" ); + return ret; +} + +/* add a dll to the list of imports */ +void add_import_dll( const char *name, const char *filename ) +{ + struct import *imp = xmalloc( sizeof(*imp) ); - imp = xmalloc( sizeof(*imp) ); imp->spec = alloc_dll_spec(); - imp->spec->file_name = fullname; - imp->delay = delay; + imp->spec->file_name = get_dll_name( name, filename ); + imp->delay = 0; imp->imports = NULL; imp->nb_imports = 0; - if (delay) nb_delayed++; + imp->exports = NULL; + imp->nb_exports = 0; - if (read_import_lib( name, imp )) + if (filename) imp->full_name = xstrdup( filename ); + else imp->full_name = find_library( name ); + + if (read_import_lib( imp )) { dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) ); dll_imports[nb_imports++] = imp; @@ -314,6 +369,21 @@ void add_import_dll( const char *name, int delay ) } } +/* add a library to the list of delayed imports */ +void add_delayed_import( const char *name ) +{ + struct import *imp; + char *fullname = get_dll_name( name, NULL ); + + delayed_imports = xrealloc( delayed_imports, (nb_delayed_imports+1) * sizeof(*delayed_imports) ); + delayed_imports[nb_delayed_imports++] = fullname; + if ((imp = is_already_imported( fullname )) && !imp->delay) + { + imp->delay = 1; + nb_delayed++; + } +} + /* remove an imported dll, based on its index in the dll_imports array */ static void remove_import_dll( int index ) { @@ -438,7 +508,7 @@ static int add_extra_symbol( const char **extras, int *count, const char *name, static void add_extra_undef_symbols( const DLLSPEC *spec ) { const char *extras[10]; - int i, count = 0, nb_stubs = 0, nb_regs = 0; + int i, count = 0, nb_stubs = 0; int kernel_imports = 0, ntdll_imports = 0; sort_symbols( undef_symbols, nb_undef_symbols ); @@ -447,7 +517,6 @@ static void add_extra_undef_symbols( const DLLSPEC *spec ) { ORDDEF *odp = &spec->entry_points[i]; if (odp->type == TYPE_STUB) nb_stubs++; - if (odp->flags & FLAG_REGISTER) nb_regs++; } /* add symbols that will be contained in the spec file itself */ @@ -467,16 +536,16 @@ static void add_extra_undef_symbols( const DLLSPEC *spec ) if (nb_delayed) { kernel_imports += add_extra_symbol( extras, &count, "LoadLibraryA", spec ); + kernel_imports += add_extra_symbol( extras, &count, "FreeLibrary", spec ); kernel_imports += add_extra_symbol( extras, &count, "GetProcAddress", spec ); + kernel_imports += add_extra_symbol( extras, &count, "RaiseException", spec ); } - if (nb_regs) - ntdll_imports += add_extra_symbol( extras, &count, "__wine_call_from_32_regs", spec ); - if (nb_delayed || nb_stubs) + if (nb_stubs) ntdll_imports += add_extra_symbol( extras, &count, "RtlRaiseException", spec ); /* make sure we import the dlls that contain these functions */ - if (kernel_imports) add_import_dll( "kernel32", 0 ); - if (ntdll_imports) add_import_dll( "ntdll", 0 ); + if (kernel_imports) add_import_dll( "kernel32", NULL ); + if (ntdll_imports) add_import_dll( "ntdll", NULL ); if (count) { @@ -777,10 +846,10 @@ static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec ) if (!nb_delayed) goto done; + fprintf( outfile, "static void *__wine_delay_imp_hmod[%d];\n", nb_delayed ); for (i = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; - fprintf( outfile, "static void *__wine_delay_imp_%d_hmod;\n", i); for (j = 0; j < dll_imports[i]->nb_imports; j++) { ORDDEF *odp = dll_imports[i]->imports[j]; @@ -807,7 +876,7 @@ static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec ) for (i = j = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; - fprintf( outfile, " { 0, \"%s\", &__wine_delay_imp_%d_hmod, &delay_imports.IAT[%d], &delay_imports.INT[%d], 0, 0, 0 },\n", + fprintf( outfile, " { 0, \"%s\", &__wine_delay_imp_hmod[%d], &delay_imports.IAT[%d], &delay_imports.INT[%d], 0, 0, 0 },\n", dll_imports[i]->spec->file_name, i, j, j ); j += dll_imports[i]->nb_imports; } @@ -839,21 +908,7 @@ static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec ) } fprintf( outfile, " }\n};\n\n" ); - /* check if there's some stub defined. if so, exception struct - * is already defined, so don't emit it twice - */ - for (i = 0; i < spec->nb_entry_points; i++) if (spec->entry_points[i].type == TYPE_STUB) break; - - if (i == spec->nb_entry_points) { - fprintf( outfile, "struct exc_record {\n" ); - fprintf( outfile, " unsigned int code, flags;\n" ); - fprintf( outfile, " void *rec, *addr;\n" ); - fprintf( outfile, " unsigned int params;\n" ); - fprintf( outfile, " const void *info[15];\n" ); - fprintf( outfile, "};\n\n" ); - fprintf( outfile, "extern void __stdcall RtlRaiseException( struct exc_record * );\n" ); - } - + fprintf( outfile, "extern void __stdcall RaiseException(unsigned int, unsigned int, unsigned int, const void *args[]);\n" ); fprintf( outfile, "extern void * __stdcall LoadLibraryA(const char*);\n"); fprintf( outfile, "extern void * __stdcall GetProcAddress(void *, const char*);\n"); fprintf( outfile, "\n" ); @@ -871,20 +926,12 @@ static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec ) fprintf( outfile, " /* patch IAT with final value */\n" ); fprintf( outfile, " return *pIAT = fn;\n" ); fprintf( outfile, " else {\n"); - fprintf( outfile, " struct exc_record rec;\n" ); - fprintf( outfile, " rec.code = 0x80000100;\n" ); - fprintf( outfile, " rec.flags = 1;\n" ); - fprintf( outfile, " rec.rec = 0;\n" ); - fprintf( outfile, " rec.params = 2;\n" ); - fprintf( outfile, " rec.info[0] = imd->szName;\n" ); - fprintf( outfile, " rec.info[1] = *pINT;\n" ); - fprintf( outfile, "#ifdef __GNUC__\n" ); - fprintf( outfile, " rec.addr = __builtin_return_address(1);\n" ); - fprintf( outfile, "#else\n" ); - fprintf( outfile, " rec.addr = 0;\n" ); - fprintf( outfile, "#endif\n" ); - fprintf( outfile, " for (;;) RtlRaiseException( &rec );\n" ); - fprintf( outfile, " return 0; /* shouldn't go here */\n" ); + fprintf( outfile, " const void *args[2];\n" ); + fprintf( outfile, " args[0] = imd->szName;\n" ); + fprintf( outfile, " args[1] = *pINT;\n" ); + fprintf( outfile, " RaiseException( 0x%08x, %d, 2, args );\n", + EXCEPTION_WINE_STUB, EXCEPTION_NONCONTINUABLE ); + fprintf( outfile, " return 0;\n" ); fprintf( outfile, " }\n}\n\n" ); fprintf( outfile, "#ifndef __GNUC__\n" ); @@ -1100,8 +1147,8 @@ static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec ) /* output the import and delayed import tables of a Win32 module * returns number of DLLs exported in 'immediate' mode */ -int output_imports( FILE *outfile, DLLSPEC *spec ) +int output_imports( FILE *outfile, DLLSPEC *spec, int *nb_delayed ) { - output_delayed_imports( outfile, spec ); - return output_immediate_imports( outfile ); + *nb_delayed = output_delayed_imports( outfile, spec ); + return output_immediate_imports( outfile ); } diff --git a/reactos/tools/winebuild/main.c b/reactos/tools/winebuild/main.c index 8d4466d85c3..3f98a88a46c 100644 --- a/reactos/tools/winebuild/main.c +++ b/reactos/tools/winebuild/main.c @@ -97,7 +97,6 @@ static void set_dll_file_name( const char *name, DLLSPEC *spec ) { if (!strcmp( p, ".spec" ) || !strcmp( p, ".def" )) *p = 0; } - if (!strchr( spec->file_name, '.' )) strcat( spec->file_name, ".dll" ); } /* set the dll subsystem */ @@ -143,6 +142,7 @@ static const char usage_str[] = " -C --source-dir=DIR Look for source files in DIR\n" " -d --delay-lib=LIB Import the specified library in delayed mode\n" " -D SYM Ignored for C flags compatibility\n" +" -E --export=FILE Export the symbols defined in the .spec or .def file\n" " -e --entry=FUNC Set the DLL entry point function (default: DllMain)\n" " -f FLAGS Compiler flags (only -fPIC is supported)\n" " -F --filename=DLLFILE Set the DLL filename (default: from input file name)\n" @@ -164,9 +164,9 @@ static const char usage_str[] = " --version Print the version and exit\n" " -w --warnings Turn on warnings\n" "\nMode options:\n" -" --dll=FILE Build a .c file from a .spec or .def file\n" -" --def=FILE.SPEC Build a .def file from a spec file\n" -" --exe=NAME Build a .c file for the named executable\n" +" --dll Build a .c file from a .spec or .def file\n" +" --def Build a .def file from a .spec file\n" +" --exe Build a .c file for an executable\n" " --debug [FILES] Build a .c file with the debug channels declarations\n" " --relay16 Build the 16-bit relay assembly routines\n" " --relay32 Build the 32-bit relay assembly routines\n" @@ -188,13 +188,13 @@ enum long_options_values LONG_OPT_PEDLL }; -static const char short_options[] = "C:D:F:H:I:K:L:M:N:d:e:f:hi:kl:m:o:r:w"; +static const char short_options[] = "C:D:E:F:H:I:K:L:M:N:d:e:f:hi:kl:m:o:r:w"; static const struct option long_options[] = { - { "dll", 1, 0, LONG_OPT_DLL }, - { "def", 1, 0, LONG_OPT_DEF }, - { "exe", 1, 0, LONG_OPT_EXE }, + { "dll", 0, 0, LONG_OPT_DLL }, + { "def", 0, 0, LONG_OPT_DEF }, + { "exe", 0, 0, LONG_OPT_EXE }, { "debug", 0, 0, LONG_OPT_DEBUG }, { "ld-cmd", 1, 0, LONG_OPT_LDCMD }, { "nm-cmd", 1, 0, LONG_OPT_NMCMD }, @@ -206,6 +206,7 @@ static const struct option long_options[] = /* aliases for short options */ { "source-dir", 1, 0, 'C' }, { "delay-lib", 1, 0, 'd' }, + { "export", 1, 0, 'E' }, { "entry", 1, 0, 'e' }, { "filename", 1, 0, 'F' }, { "help", 0, 0, 'h' }, @@ -250,6 +251,10 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec ) case 'D': /* ignored */ break; + case 'E': + spec_file_name = xstrdup( optarg ); + set_dll_file_name( optarg, spec ); + break; case 'F': spec->file_name = xstrdup( optarg ); break; @@ -278,7 +283,7 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec ) spec->dll_name = xstrdup( optarg ); break; case 'd': - add_import_dll( optarg, 1 ); + add_delayed_import( optarg ); break; case 'e': spec->init_func = xstrdup( optarg ); @@ -307,7 +312,7 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec ) kill_at = 1; break; case 'l': - add_import_dll( optarg, 0 ); + add_import_dll( optarg, NULL ); break; case 'o': if (unlink( optarg ) == -1 && errno != ENOENT) @@ -326,21 +331,12 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec ) break; case LONG_OPT_DLL: set_exec_mode( MODE_DLL ); - spec_file_name = xstrdup( optarg ); - set_dll_file_name( optarg, spec ); break; case LONG_OPT_DEF: set_exec_mode( MODE_DEF ); - spec_file_name = xstrdup( optarg ); - set_dll_file_name( optarg, spec ); break; case LONG_OPT_EXE: set_exec_mode( MODE_EXE ); - if ((p = strrchr( optarg, '/' ))) p++; - else p = optarg; - spec->file_name = xmalloc( strlen(p) + 5 ); - strcpy( spec->file_name, p ); - if (!strchr( spec->file_name, '.' )) strcat( spec->file_name, ".exe" ); if (!spec->subsystem) spec->subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; break; case LONG_OPT_DEBUG: @@ -374,6 +370,10 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec ) break; } } + + if (spec->file_name && !strchr( spec->file_name, '.' )) + strcat( spec->file_name, exec_mode == MODE_EXE ? ".exe" : ".dll" ); + return &argv[optind]; } @@ -408,16 +408,33 @@ static void load_resources( char *argv[], DLLSPEC *spec ) } } +/* add input files that look like import libs to the import list */ +static void load_import_libs( char *argv[] ) +{ + char **ptr, **last; + + for (ptr = last = argv; *ptr; ptr++) + { + if (strendswith( *ptr, ".def" )) + add_import_dll( NULL, *ptr ); + else + *last++ = *ptr; /* not an import dll, keep it in the list */ + } + *last = NULL; +} + static int parse_input_file( DLLSPEC *spec ) { FILE *input_file = open_input_file( NULL, spec_file_name ); char *extension = strrchr( spec_file_name, '.' ); + int result; if (extension && !strcmp( extension, ".def" )) - return parse_def_file( input_file, spec ); + result = parse_def_file( input_file, spec ); else - return parse_spec_file( input_file, spec ); + result = parse_spec_file( input_file, spec ); close_input_file( input_file ); + return result; } @@ -442,6 +459,8 @@ int main(int argc, char **argv) case MODE_DLL: spec->characteristics |= IMAGE_FILE_DLL; load_resources( argv, spec ); + load_import_libs( argv ); + if (!spec_file_name) fatal_error( "missing .spec file\n" ); if (!parse_input_file( spec )) break; switch (spec->type) { @@ -457,13 +476,17 @@ int main(int argc, char **argv) break; case MODE_EXE: if (spec->type == SPEC_WIN16) fatal_error( "Cannot build 16-bit exe files\n" ); + if (!spec->file_name) fatal_error( "executable must be named via the -F option\n" ); load_resources( argv, spec ); + load_import_libs( argv ); + if (spec_file_name && !parse_input_file( spec )) break; read_undef_symbols( argv ); BuildSpec32File( output_file, spec ); break; case MODE_DEF: if (argv[0]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] ); if (spec->type == SPEC_WIN16) fatal_error( "Cannot yet build .def file for 16-bit dlls\n" ); + if (!spec_file_name) fatal_error( "missing .spec file\n" ); if (!parse_input_file( spec )) break; BuildDef32File( output_file, spec ); break; diff --git a/reactos/tools/winebuild/parser.c b/reactos/tools/winebuild/parser.c index a998777d873..424a0ef499b 100644 --- a/reactos/tools/winebuild/parser.c +++ b/reactos/tools/winebuild/parser.c @@ -511,6 +511,12 @@ static int parse_spec_ordinal( int ordinal, DLLSPEC *spec ) odp->ordinal = ordinal; } + if (spec->type == SPEC_WIN32 && odp->flags & FLAG_REGISTER) + { + error( "-register flag not supported for Win32 entry points\n" ); + goto error; + } + if (odp->type == TYPE_STDCALL && !(odp->flags & FLAG_PRIVATE)) { if (!strcmp( odp->name, "DllRegisterServer" ) || diff --git a/reactos/tools/winebuild/relay.c b/reactos/tools/winebuild/relay.c index 6548714b43d..abac75ae4d9 100644 --- a/reactos/tools/winebuild/relay.c +++ b/reactos/tools/winebuild/relay.c @@ -27,7 +27,7 @@ #include #include "thread.h" -#include "stackframe.h" +#include "wine/winbase16.h" #include "build.h" diff --git a/reactos/tools/winebuild/res16.c b/reactos/tools/winebuild/res16.c index a5fd5849132..87a16029687 100644 --- a/reactos/tools/winebuild/res16.c +++ b/reactos/tools/winebuild/res16.c @@ -20,6 +20,7 @@ #include "config.h" +#include #include #include #include @@ -39,9 +40,6 @@ #include "winglue.h" #include "build.h" -#define ALIGNMENT 2 /* alignment for resource data */ -#define ALIGN_MASK ((1 << ALIGNMENT) - 1) - /* Unicode string or integer id */ struct string_id { @@ -265,48 +263,115 @@ static void output_string( unsigned char **buffer, const char *str ) while (len--) put_byte( buffer, *str++ ); } -/* output the resource data */ -int output_res16_data( FILE *outfile, DLLSPEC *spec ) +/* get the resource data total size */ +unsigned int get_res16_data_size( DLLSPEC *spec, unsigned int res_offset, unsigned int alignment ) { const struct resource *res; - unsigned char *buffer, *p; - unsigned int i; - int total; + unsigned int i, total; + unsigned int align_mask = (1 << alignment) - 1; if (!spec->nb_resources) return 0; - for (i = total = 0, res = spec->resources; i < spec->nb_resources; i++, res++) - total += (res->data_size + ALIGN_MASK) & ~ALIGN_MASK; + /* add padding at the beginning if needed so that resources are properly aligned */ + total = ((res_offset + align_mask) & ~align_mask) - res_offset; - buffer = p = xmalloc( total ); for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++) - { - memcpy( p, res->data, res->data_size ); - p += res->data_size; - while ((int)p & ALIGN_MASK) *p++ = 0; - } - dump_bytes( outfile, buffer, total, "resource_data", 1 ); - free( buffer ); + total += (res->data_size + align_mask) & ~align_mask; + return total; } -/* output the resource definitions */ -int output_res16_directory( unsigned char *buffer, DLLSPEC *spec ) +/* output the resource data */ +unsigned int output_res16_data( unsigned char **ret_buf, DLLSPEC *spec, + unsigned int res_offset, unsigned int alignment ) { - int offset, res_offset = 0; - unsigned int i, j; + const struct resource *res; + unsigned char *p; + unsigned int i, total, padding; + unsigned int align_mask = (1 << alignment) - 1; + + if (!spec->nb_resources) return 0; + + /* add padding at the beginning if needed so that resources are properly aligned */ + padding = ((res_offset + align_mask) & ~align_mask) - res_offset; + + for (i = total = 0, res = spec->resources; i < spec->nb_resources; i++, res++) + total += (res->data_size + align_mask) & ~align_mask; + + *ret_buf = p = xmalloc( total + padding ); + memset( p, 0, padding ); + p += padding; + for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++) + { + unsigned int size = (res->data_size + align_mask) & ~align_mask; + memcpy( p, res->data, res->data_size ); + memset( p + res->data_size, 0, size - res->data_size ); + p += size; + } + return total; +} + +/* get the resource definitions total size */ +unsigned int get_res16_directory_size( DLLSPEC *spec ) +{ + unsigned int i, j, total_size; struct res_tree *tree; const struct res_type *type; const struct resource *res; - unsigned char *start = buffer; tree = build_resource_tree( spec ); + total_size = 4; /* alignment + terminator */ + total_size += tree->nb_types * 8; /* typeinfo structures */ + total_size += spec->nb_resources * 12; /* nameinfo structures */ + + for (i = 0, type = tree->types; i < tree->nb_types; i++, type++) + { + if (type->type->str) total_size += strlen(type->type->str) + 1; + for (j = 0, res = type->res; j < type->nb_names; j++, res++) + if (res->name.str) total_size += strlen(res->name.str) + 1; + } + total_size++; /* final terminator */ + if (total_size & 1) total_size++; + return total_size; +} + +/* output the resource definitions */ +unsigned int output_res16_directory( unsigned char **ret_buf, DLLSPEC *spec, + unsigned int res_offset, unsigned int alignment ) +{ + int offset; + unsigned int i, j, total_size; + unsigned int align_mask = (1 << alignment) - 1; + struct res_tree *tree; + const struct res_type *type; + const struct resource *res; + unsigned char *buffer; + + tree = build_resource_tree( spec ); + + /* make sure data offset is properly aligned */ + res_offset = (res_offset + align_mask) & ~align_mask; + + /* first compute total size */ + offset = 4; /* alignment + terminator */ offset += tree->nb_types * 8; /* typeinfo structures */ offset += spec->nb_resources * 12; /* nameinfo structures */ - put_word( &buffer, ALIGNMENT ); + total_size = offset; + + for (i = 0, type = tree->types; i < tree->nb_types; i++, type++) + { + if (type->type->str) total_size += strlen(type->type->str) + 1; + for (j = 0, res = type->res; j < type->nb_names; j++, res++) + if (res->name.str) total_size += strlen(res->name.str) + 1; + } + total_size++; /* final terminator */ + if (total_size & 1) total_size++; + *ret_buf = buffer = xmalloc( total_size ); + + put_word( &buffer, alignment ); /* type and name structures */ @@ -326,8 +391,8 @@ int output_res16_directory( unsigned char *buffer, DLLSPEC *spec ) for (j = 0, res = type->res; j < type->nb_names; j++, res++) { - put_word( &buffer, res_offset >> ALIGNMENT ); - put_word( &buffer, (res->data_size + ALIGN_MASK) >> ALIGNMENT ); + put_word( &buffer, res_offset >> alignment ); + put_word( &buffer, (res->data_size + align_mask) >> alignment ); put_word( &buffer, res->memopt ); if (res->name.str) { @@ -338,7 +403,7 @@ int output_res16_directory( unsigned char *buffer, DLLSPEC *spec ) put_word( &buffer, res->name.id | 0x8000 ); put_word( &buffer, 0 ); put_word( &buffer, 0 ); - res_offset += (res->data_size + ALIGN_MASK) & ~ALIGN_MASK; + res_offset += (res->data_size + align_mask) & ~align_mask; } } put_word( &buffer, 0 ); /* terminator */ @@ -354,8 +419,9 @@ int output_res16_directory( unsigned char *buffer, DLLSPEC *spec ) } } put_byte( &buffer, 0 ); /* names terminator */ - if ((buffer - start) & 1) put_byte( &buffer, 0 ); /* align on word boundary */ + if ((buffer - *ret_buf) & 1) put_byte( &buffer, 0 ); /* align on word boundary */ + assert( buffer - *ret_buf == total_size ); free_resource_tree( tree ); - return buffer - start; + return total_size; } diff --git a/reactos/tools/winebuild/spec16.c b/reactos/tools/winebuild/spec16.c index aae4d8f5b97..d8871ea0050 100644 --- a/reactos/tools/winebuild/spec16.c +++ b/reactos/tools/winebuild/spec16.c @@ -28,9 +28,7 @@ #include #include "wine/exception.h" -#include "stackframe.h" -#include "builtin16.h" -#include "module.h" +#include "wine/winbase16.h" #include "build.h" @@ -76,230 +74,95 @@ static void output_file_header( FILE *outfile ) /******************************************************************* - * StoreVariableCode - * - * Store a list of ints into a byte array. + * output_entry_table */ -static int StoreVariableCode( unsigned char *buffer, int size, ORDDEF *odp ) +static int output_entry_table( unsigned char **ret_buff, DLLSPEC *spec ) { - int i; + int i, prev = 0, prev_sel = -1; + unsigned char *pstr, *buffer; + unsigned char *bundle = NULL; - switch(size) - { - case 1: - for (i = 0; i < odp->u.var.n_values; i++) - buffer[i] = odp->u.var.values[i]; - break; - case 2: - for (i = 0; i < odp->u.var.n_values; i++) - ((unsigned short *)buffer)[i] = odp->u.var.values[i]; - break; - case 4: - for (i = 0; i < odp->u.var.n_values; i++) - ((unsigned int *)buffer)[i] = odp->u.var.values[i]; - break; - } - return odp->u.var.n_values * size; -} + buffer = xmalloc( spec->limit * 5 ); /* we use at most 5 bytes per entry-point */ + pstr = buffer; - -/******************************************************************* - * BuildModule16 - * - * Build the in-memory representation of a 16-bit NE module, and dump it - * as a byte stream into the assembly code. - */ -static int BuildModule16( FILE *outfile, int max_code_offset, - int max_data_offset, DLLSPEC *spec ) -{ - int i; - char *buffer; - NE_MODULE *pModule; - SEGTABLEENTRY *pSegment; - OFSTRUCT *pFileInfo; - BYTE *pstr; - ET_BUNDLE *bundle = 0; - ET_ENTRY entry; - - /* Module layout: - * NE_MODULE Module - * OFSTRUCT File information - * SEGTABLEENTRY Segment 1 (code) - * SEGTABLEENTRY Segment 2 (data) - * WORD[2] Resource table (empty) - * BYTE[2] Imported names (empty) - * BYTE[n] Resident names table - * BYTE[n] Entry table - */ - - buffer = xmalloc( 0x10000 ); - memset( buffer, 0, 0x10000 ); - - pModule = (NE_MODULE *)buffer; - pModule->magic = IMAGE_OS2_SIGNATURE; - pModule->count = 1; - pModule->next = 0; - pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN | NE_FFLAGS_LIBMODULE; - pModule->dgroup = 2; - pModule->heap_size = spec->heap_size; - pModule->stack_size = 0; - pModule->ip = 0; - pModule->cs = 0; - pModule->sp = 0; - pModule->ss = 0; - pModule->seg_count = 2; - pModule->modref_count = 0; - pModule->nrname_size = 0; - pModule->modref_table = 0; - pModule->nrname_fpos = 0; - pModule->moveable_entries = 0; - pModule->alignment = 0; - pModule->truetype = 0; - pModule->os_flags = NE_OSFLAGS_WINDOWS; - pModule->misc_flags = 0; - pModule->dlls_to_init = 0; - pModule->nrname_handle = 0; - pModule->min_swap_area = 0; - pModule->expected_version = 0; - pModule->module32 = 0; - pModule->self = 0; - pModule->self_loading_sel = 0; - - /* File information */ - - pFileInfo = (OFSTRUCT *)(pModule + 1); - pModule->fileinfo = (int)pFileInfo - (int)pModule; - memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) ); - pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) - + strlen(spec->file_name); - strcpy( pFileInfo->szPathName, spec->file_name ); - pstr = (char *)pFileInfo + pFileInfo->cBytes + 1; - - /* Segment table */ - - pstr = (char *)(((long)pstr + 3) & ~3); - pSegment = (SEGTABLEENTRY *)pstr; - pModule->seg_table = (int)pSegment - (int)pModule; - pSegment->filepos = 0; - pSegment->size = max_code_offset; - pSegment->flags = 0; - pSegment->minsize = max_code_offset; - pSegment->hSeg = 0; - pSegment++; - - pModule->dgroup_entry = (int)pSegment - (int)pModule; - pSegment->filepos = 0; - pSegment->size = max_data_offset; - pSegment->flags = NE_SEGFLAGS_DATA; - pSegment->minsize = max_data_offset; - pSegment->hSeg = 0; - pSegment++; - - /* Resource table */ - - pstr = (char *)pSegment; - pstr = (char *)(((long)pstr + 3) & ~3); - pModule->res_table = (int)pstr - (int)pModule; - pstr += output_res16_directory( pstr, spec ); - - /* Imported names table */ - - pstr = (char *)(((long)pstr + 3) & ~3); - pModule->import_table = (int)pstr - (int)pModule; - *pstr++ = 0; - *pstr++ = 0; - - /* Resident names table */ - - pstr = (char *)(((long)pstr + 3) & ~3); - pModule->name_table = (int)pstr - (int)pModule; - /* First entry is module name */ - *pstr = strlen( spec->dll_name ); - strcpy( pstr + 1, spec->dll_name ); - strupper( pstr + 1 ); - pstr += *pstr + 1; - *pstr++ = 0; - *pstr++ = 0; - /* Store all ordinals */ - for (i = 1; i <= spec->limit; i++) - { - ORDDEF *odp = spec->ordinals[i]; - WORD ord = i; - if (!odp || !odp->name[0]) continue; - *pstr = strlen( odp->name ); - strcpy( pstr + 1, odp->name ); - strupper( pstr + 1 ); - pstr += *pstr + 1; - memcpy( pstr, &ord, sizeof(WORD) ); - pstr += sizeof(WORD); - } - *pstr++ = 0; - - /* Entry table */ - - pstr = (char *)(((long)pstr + 3) & ~3); - pModule->entry_table = (int)pstr - (int)pModule; for (i = 1; i <= spec->limit; i++) { int selector = 0; + WORD offset; ORDDEF *odp = spec->ordinals[i]; if (!odp) continue; - switch (odp->type) - { + switch (odp->type) + { case TYPE_CDECL: case TYPE_PASCAL: case TYPE_VARARGS: case TYPE_STUB: selector = 1; /* Code selector */ break; - case TYPE_VARIABLE: selector = 2; /* Data selector */ break; - case TYPE_ABS: selector = 0xfe; /* Constant selector */ break; - default: - selector = 0; /* Invalid selector */ - break; + continue; } - if ( !selector ) - continue; - - if ( bundle && bundle->last+1 == i ) - bundle->last++; - else + if (!bundle || prev + 1 != i || prev_sel != selector || *bundle == 255) { - pstr = (char *)(((long)pstr + 1) & ~1); - if ( bundle ) - bundle->next = (char *)pstr - (char *)pModule; + /* need to start a new bundle */ - bundle = (ET_BUNDLE *)pstr; - bundle->first = i-1; - bundle->last = i; - bundle->next = 0; - pstr += sizeof(ET_BUNDLE); + if (prev + 1 != i) + { + int skip = i - (prev + 1); + while (skip > 255) + { + *pstr++ = 255; + *pstr++ = 0; + skip -= 255; + } + *pstr++ = skip; + *pstr++ = 0; + } + + bundle = pstr; + *pstr++ = 0; + *pstr++ = selector; + prev_sel = selector; } - - /* FIXME: is this really correct ?? */ - entry.type = 0xff; /* movable */ - entry.flags = 3; /* exported & public data */ - entry.segnum = selector; - entry.offs = odp->offset; - memcpy( pstr, &entry, sizeof(ET_ENTRY) ); - pstr += sizeof(ET_ENTRY); + /* output the entry */ + *pstr++ = 3; /* flags: exported & public data */ + offset = odp->offset; + memcpy( pstr, &offset, sizeof(WORD) ); + pstr += sizeof(WORD); + (*bundle)++; /* increment bundle entry count */ + prev = i; } *pstr++ = 0; + if ((pstr - buffer) & 1) *pstr++ = 0; + *ret_buff = xrealloc( buffer, pstr - buffer ); + return pstr - buffer; +} - /* Dump the module content */ - pstr = (char *)(((long)pstr + 3) & ~3); - dump_bytes( outfile, (char *)pModule, (int)pstr - (int)pModule, "Module", 0 ); - return (int)pstr - (int)pModule; +/******************************************************************* + * output_bytes + */ +static void output_bytes( FILE *outfile, const void *buffer, unsigned int size ) +{ + unsigned int i; + const unsigned char *ptr = buffer; + + fprintf( outfile, " {" ); + for (i = 0; i < size; i++) + { + if (!(i & 7)) fprintf( outfile, "\n " ); + fprintf( outfile, " 0x%02x", *ptr++ ); + if (i < size - 1) fprintf( outfile, "," ); + } + fprintf( outfile, "\n },\n" ); } @@ -510,25 +373,12 @@ static void output_stub_funcs( FILE *outfile, const DLLSPEC *spec ) fprintf( outfile, "static void __wine_unimplemented( const char *func ) __attribute__((noreturn));\n" ); fprintf( outfile, "#endif\n" ); fprintf( outfile, "static void __wine_unimplemented( const char *func )\n{\n" ); - fprintf( outfile, " struct exc_record {\n" ); - fprintf( outfile, " unsigned int code, flags;\n" ); - fprintf( outfile, " void *rec, *addr;\n" ); - fprintf( outfile, " unsigned int params;\n" ); - fprintf( outfile, " const void *info[15];\n" ); - fprintf( outfile, " } rec;\n\n" ); - fprintf( outfile, " extern void __stdcall RtlRaiseException( struct exc_record * );\n\n" ); - fprintf( outfile, " rec.code = 0x%08x;\n", EXCEPTION_WINE_STUB ); - fprintf( outfile, " rec.flags = %d;\n", EH_NONCONTINUABLE ); - fprintf( outfile, " rec.rec = 0;\n" ); - fprintf( outfile, " rec.params = 2;\n" ); - fprintf( outfile, " rec.info[0] = \"%s\";\n", spec->file_name ); - fprintf( outfile, " rec.info[1] = func;\n" ); - fprintf( outfile, "#ifdef __GNUC__\n" ); - fprintf( outfile, " rec.addr = __builtin_return_address(1);\n" ); - fprintf( outfile, "#else\n" ); - fprintf( outfile, " rec.addr = 0;\n" ); - fprintf( outfile, "#endif\n" ); - fprintf( outfile, " for (;;) RtlRaiseException( &rec );\n}\n\n" ); + fprintf( outfile, " extern void __stdcall RaiseException( unsigned int, unsigned int, unsigned int, const void ** );\n" ); + fprintf( outfile, " const void *args[2];\n" ); + fprintf( outfile, " args[0] = \"%s\";\n", spec->file_name ); + fprintf( outfile, " args[1] = func;\n" ); + fprintf( outfile, " for (;;) RaiseException( 0x%08x, %d, 2, args );\n}\n\n", + EXCEPTION_WINE_STUB, EH_NONCONTINUABLE ); break; } for (i = 0; i <= spec->limit; i++) @@ -554,8 +404,17 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) { ORDDEF **type, **typelist; int i, nFuncs, nTypes; - int code_offset, data_offset, module_size, res_size; - unsigned char *data; + unsigned char *resdir_buffer, *resdata_buffer, *et_buffer, *data_buffer; + unsigned char string[256]; + unsigned int ne_offset, segtable_offset, impnames_offset; + unsigned int entrypoint_size, callfrom_size; + unsigned int code_size, code_offset; + unsigned int data_size, data_offset; + unsigned int resnames_size, resnames_offset; + unsigned int resdir_size, resdir_offset; + unsigned int resdata_size, resdata_offset, resdata_align; + unsigned int et_size, et_offset; + char constructor[100], destructor[100]; #ifdef __i386__ unsigned short code_selector = get_cs(); @@ -569,9 +428,9 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) fprintf( outfile, "extern void __wine_call_from_16_regs();\n" ); fprintf( outfile, "extern void __wine_call_from_16_thunk();\n" ); - data = (unsigned char *)xmalloc( 0x10000 ); - memset( data, 0, 16 ); - data_offset = 16; + data_buffer = xmalloc( 0x10000 ); + memset( data_buffer, 0, 16 ); + data_size = 16; if (!spec->dll_name) /* set default name from file name */ { @@ -624,28 +483,160 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) } #endif - /* Output the DLL functions prototypes */ + /* compute code and data sizes, set offsets, and output prototypes */ + +#ifdef __i386__ + entrypoint_size = 2 + 5 + 4; /* pushw bp + pushl target + call */ + callfrom_size = 5 + 7 + 4 + 8; /* pushl relay + lcall cs:glue + lret n + args */ +#else + entrypoint_size = 4 + 4; /* target + call */ + callfrom_size = 4 + 8; /* lret n + args */ +#endif + code_size = nTypes * callfrom_size; for (i = 0; i <= spec->limit; i++) { ORDDEF *odp = spec->ordinals[i]; if (!odp) continue; - switch(odp->type) + switch (odp->type) { + case TYPE_ABS: + odp->offset = LOWORD(odp->u.abs.value); + break; + case TYPE_VARIABLE: + odp->offset = data_size; + memcpy( data_buffer + data_size, odp->u.var.values, odp->u.var.n_values * sizeof(int) ); + data_size += odp->u.var.n_values * sizeof(int); + break; case TYPE_CDECL: case TYPE_PASCAL: case TYPE_VARARGS: fprintf( outfile, "extern void %s();\n", odp->link_name ); + /* fall through */ + case TYPE_STUB: + odp->offset = code_size; + code_size += entrypoint_size; break; default: + assert(0); break; } } + data_buffer = xrealloc( data_buffer, data_size ); /* free unneeded data */ - /* Output code segment */ + /* Output the module structure */ + + /* DOS header */ fprintf( outfile, "\n#include \"pshpack1.h\"\n" ); - fprintf( outfile, "\nstatic struct code_segment\n{\n" ); + fprintf( outfile, "static const struct module_data\n{\n" ); + fprintf( outfile, " struct\n {\n" ); + fprintf( outfile, " unsigned short e_magic;\n" ); + fprintf( outfile, " unsigned short e_cblp;\n" ); + fprintf( outfile, " unsigned short e_cp;\n" ); + fprintf( outfile, " unsigned short e_crlc;\n" ); + fprintf( outfile, " unsigned short e_cparhdr;\n" ); + fprintf( outfile, " unsigned short e_minalloc;\n" ); + fprintf( outfile, " unsigned short e_maxalloc;\n" ); + fprintf( outfile, " unsigned short e_ss;\n" ); + fprintf( outfile, " unsigned short e_sp;\n" ); + fprintf( outfile, " unsigned short e_csum;\n" ); + fprintf( outfile, " unsigned short e_ip;\n" ); + fprintf( outfile, " unsigned short e_cs;\n" ); + fprintf( outfile, " unsigned short e_lfarlc;\n" ); + fprintf( outfile, " unsigned short e_ovno;\n" ); + fprintf( outfile, " unsigned short e_res[4];\n" ); + fprintf( outfile, " unsigned short e_oemid;\n" ); + fprintf( outfile, " unsigned short e_oeminfo;\n" ); + fprintf( outfile, " unsigned short e_res2[10];\n" ); + fprintf( outfile, " unsigned int e_lfanew;\n" ); + fprintf( outfile, " } dos_header;\n" ); + + /* NE header */ + + ne_offset = 64; + fprintf( outfile, " struct\n {\n" ); + fprintf( outfile, " unsigned short ne_magic;\n" ); + fprintf( outfile, " unsigned char ne_ver;\n" ); + fprintf( outfile, " unsigned char ne_rev;\n" ); + fprintf( outfile, " unsigned short ne_enttab;\n" ); + fprintf( outfile, " unsigned short ne_cbenttab;\n" ); + fprintf( outfile, " int ne_crc;\n" ); + fprintf( outfile, " unsigned short ne_flags;\n" ); + fprintf( outfile, " unsigned short ne_autodata;\n" ); + fprintf( outfile, " unsigned short ne_heap;\n" ); + fprintf( outfile, " unsigned short ne_stack;\n" ); + fprintf( outfile, " unsigned int ne_csip;\n" ); + fprintf( outfile, " unsigned int ne_sssp;\n" ); + fprintf( outfile, " unsigned short ne_cseg;\n" ); + fprintf( outfile, " unsigned short ne_cmod;\n" ); + fprintf( outfile, " unsigned short ne_cbnrestab;\n" ); + fprintf( outfile, " unsigned short ne_segtab;\n" ); + fprintf( outfile, " unsigned short ne_rsrctab;\n" ); + fprintf( outfile, " unsigned short ne_restab;\n" ); + fprintf( outfile, " unsigned short ne_modtab;\n" ); + fprintf( outfile, " unsigned short ne_imptab;\n" ); + fprintf( outfile, " unsigned int ne_nrestab;\n" ); + fprintf( outfile, " unsigned short ne_cmovent;\n" ); + fprintf( outfile, " unsigned short ne_align;\n" ); + fprintf( outfile, " unsigned short ne_cres;\n" ); + fprintf( outfile, " unsigned char ne_exetyp;\n" ); + fprintf( outfile, " unsigned char ne_flagsothers;\n" ); + fprintf( outfile, " unsigned short ne_pretthunks;\n" ); + fprintf( outfile, " unsigned short ne_psegrefbytes;\n" ); + fprintf( outfile, " unsigned short ne_swaparea;\n" ); + fprintf( outfile, " unsigned short ne_expver;\n" ); + fprintf( outfile, " } os2_header;\n" ); + + /* segment table */ + + segtable_offset = 64; + fprintf( outfile, " struct\n {\n" ); + fprintf( outfile, " unsigned short filepos;\n" ); + fprintf( outfile, " unsigned short size;\n" ); + fprintf( outfile, " unsigned short flags;\n" ); + fprintf( outfile, " unsigned short minsize;\n" ); + fprintf( outfile, " } segtable[2];\n" ); + + /* resource directory */ + + resdir_offset = segtable_offset + 2 * 8; + resdir_size = get_res16_directory_size( spec ); + fprintf( outfile, " unsigned char resdir[%d];\n", resdir_size ); + + /* resident names table */ + + resnames_offset = resdir_offset + resdir_size; + fprintf( outfile, " struct\n {\n" ); + fprintf( outfile, " struct { unsigned char len; char name[%d]; unsigned short ord; } name_0;\n", + strlen( spec->dll_name ) ); + resnames_size = 3 + strlen( spec->dll_name ); + for (i = 1; i <= spec->limit; i++) + { + ORDDEF *odp = spec->ordinals[i]; + if (!odp || !odp->name[0]) continue; + fprintf( outfile, " struct { unsigned char len; char name[%d]; unsigned short ord; } name_%d;\n", + strlen(odp->name), i ); + resnames_size += 3 + strlen( odp->name ); + } + fprintf( outfile, " unsigned char name_last[%d];\n", 2 - (resnames_size & 1) ); + resnames_size = (resnames_size + 2) & ~1; + fprintf( outfile, " } resnames;\n" ); + + /* imported names table */ + + impnames_offset = resnames_offset + resnames_size; + fprintf( outfile, " unsigned char impnames[2];\n" ); + + /* entry table */ + + et_offset = impnames_offset + 2; + et_size = output_entry_table( &et_buffer, spec ); + fprintf( outfile, " unsigned char entry_table[%d];\n", et_size ); + + /* code segment */ + + code_offset = et_offset + et_size; fprintf( outfile, " struct {\n" ); #ifdef __i386__ fprintf( outfile, " unsigned char pushl;\n" ); /* pushl $relay */ @@ -667,10 +658,110 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) fprintf( outfile, " unsigned short call;\n" ); /* call CALLFROM16 */ fprintf( outfile, " short callfrom16;\n" ); fprintf( outfile, " } entry[%d];\n", nFuncs ); - fprintf( outfile, "} code_segment =\n{\n {\n" ); - code_offset = 0; + /* data segment */ + data_offset = code_offset + code_size; + fprintf( outfile, " unsigned char data_segment[%d];\n", data_size ); + if (data_offset + data_size >= 0x10000) + fatal_error( "Not supported yet: 16-bit module data larger than 64K\n" ); + + /* resource data */ + + resdata_offset = ne_offset + data_offset + data_size; + for (resdata_align = 0; resdata_align < 16; resdata_align++) + { + unsigned int size = get_res16_data_size( spec, resdata_offset, resdata_align ); + if ((resdata_offset + size) >> resdata_align <= 0xffff) break; + } + output_res16_directory( &resdir_buffer, spec, resdata_offset, resdata_align ); + resdata_size = output_res16_data( &resdata_buffer, spec, resdata_offset, resdata_align ); + if (resdata_size) fprintf( outfile, " unsigned char resources[%d];\n", resdata_size ); + + /* Output the module data */ + + /* DOS header */ + + fprintf( outfile, "} module =\n{\n {\n" ); + fprintf( outfile, " 0x%04x,\n", IMAGE_DOS_SIGNATURE ); /* e_magic */ + fprintf( outfile, " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n" ); + fprintf( outfile, " { 0, 0, 0, 0, }, 0, 0,\n" ); + fprintf( outfile, " { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },\n" ); + fprintf( outfile, " sizeof(module.dos_header)\n" ); /* e_lfanew */ + + /* NE header */ + + fprintf( outfile, " },\n {\n" ); + fprintf( outfile, " 0x%04x,\n", IMAGE_OS2_SIGNATURE ); /* ne_magic */ + fprintf( outfile, " 0, 0,\n" ); + fprintf( outfile, " %d,\n", et_offset ); /* ne_enttab */ + fprintf( outfile, " sizeof(module.entry_table),\n" ); /* ne_cbenttab */ + fprintf( outfile, " 0,\n" ); /* ne_crc */ + fprintf( outfile, " 0x%04x,\n", /* ne_flags */ + NE_FFLAGS_SINGLEDATA | NE_FFLAGS_LIBMODULE ); + fprintf( outfile, " 2,\n" ); /* ne_autodata */ + fprintf( outfile, " %d,\n", spec->heap_size ); /* ne_heap */ + fprintf( outfile, " 0, 0, 0,\n" ); + fprintf( outfile, " 2,\n" ); /* ne_cseg */ + fprintf( outfile, " 0,\n" ); /* ne_cmod */ + fprintf( outfile, " 0,\n" ); /* ne_cbnrestab */ + fprintf( outfile, " %d,\n", segtable_offset ); /* ne_segtab */ + fprintf( outfile, " %d,\n", resdir_offset ); /* ne_rsrctab */ + fprintf( outfile, " %d,\n", resnames_offset ); /* ne_restab */ + fprintf( outfile, " %d,\n", impnames_offset ); /* ne_modtab */ + fprintf( outfile, " %d,\n", impnames_offset ); /* ne_imptab */ + fprintf( outfile, " 0,\n" ); /* ne_nrestab */ + fprintf( outfile, " 0,\n" ); /* ne_cmovent */ + fprintf( outfile, " 0,\n" ); /* ne_align */ + fprintf( outfile, " 0,\n" ); /* ne_cres */ + fprintf( outfile, " 0x%04x,\n", NE_OSFLAGS_WINDOWS ); /* ne_exetyp */ + fprintf( outfile, " 0x%04x,\n", NE_AFLAGS_FASTLOAD ); /* ne_flagsothers */ + fprintf( outfile, " 0,\n" ); /* ne_pretthunks */ + fprintf( outfile, " 0,\n" ); /* ne_psegrefbytes */ + fprintf( outfile, " 0,\n" ); /* ne_swaparea */ + fprintf( outfile, " 0\n" ); /* ne_expver */ + fprintf( outfile, " },\n" ); + + /* segment table */ + + fprintf( outfile, " {\n" ); + fprintf( outfile, " { %d, %d, 0x%04x, %d },\n", + ne_offset + code_offset, code_size, NE_SEGFLAGS_32BIT, code_size ); + fprintf( outfile, " { %d, %d, 0x%04x, %d },\n", + ne_offset + data_offset, data_size, NE_SEGFLAGS_DATA, data_size ); + fprintf( outfile, " },\n" ); + + /* resource directory */ + + output_bytes( outfile, resdir_buffer, resdir_size ); + free( resdir_buffer ); + + /* resident names table */ + + fprintf( outfile, " {\n" ); + strcpy( string, spec->dll_name ); + fprintf( outfile, " { %d, \"%s\", 0 },\n", strlen(string), strupper(string) ); + for (i = 1; i <= spec->limit; i++) + { + ORDDEF *odp = spec->ordinals[i]; + if (!odp || !odp->name[0]) continue; + strcpy( string, odp->name ); + fprintf( outfile, " { %d, \"%s\", %d },\n", strlen(string), strupper(string), i ); + } + fprintf( outfile, " { 0 }\n },\n" ); + + /* imported names table */ + + fprintf( outfile, " { 0, 0 },\n" ); + + /* entry table */ + + output_bytes( outfile, et_buffer, et_size ); + free( et_buffer ); + + /* code segment */ + + fprintf( outfile, " {\n" ); for ( i = 0; i < nTypes; i++ ) { char profile[101], *arg; @@ -732,7 +823,6 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) fprintf( outfile, " { 0xcb66, 0x9090, { 0x%08x, 0x%08x } },\n", arg_types[0], arg_types[1] ); #endif - code_offset += sizeof(CALLFROM16); } fprintf( outfile, " },\n {\n" ); @@ -742,15 +832,6 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) if (!odp) continue; switch (odp->type) { - case TYPE_ABS: - odp->offset = LOWORD(odp->u.abs.value); - break; - - case TYPE_VARIABLE: - odp->offset = data_offset; - data_offset += StoreVariableCode( data + data_offset, 4, odp); - break; - case TYPE_CDECL: case TYPE_PASCAL: case TYPE_VARARGS: @@ -759,57 +840,38 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) assert( type ); fprintf( outfile, " /* %s.%d */ ", spec->dll_name, i ); + fprintf( outfile, #ifdef __i386__ - fprintf( outfile, "{ 0x5566, 0x68, %s, 0xe866, %d /* %s */ },\n", + "{ 0x5566, 0x68, %s, 0xe866, %d /* %s */ },\n", #else - fprintf( outfile, "{ %s, 0xe866, %d, /* %s */ },\n", + "{ %s, 0xe866, %d, /* %s */ },\n", #endif odp->link_name, - (type-typelist)*sizeof(CALLFROM16) - - (code_offset + sizeof(ENTRYPOINT16)), + (type - typelist) * callfrom_size - (odp->offset + entrypoint_size), get_function_name( odp ) ); - - odp->offset = code_offset; - code_offset += sizeof(ENTRYPOINT16); break; - - default: - fprintf(stderr,"build: function type %d not available for Win16\n", - odp->type); - exit(1); + default: + break; } } + fprintf( outfile, " },\n" ); - fprintf( outfile, " }\n};\n" ); - /* Output data segment */ + /* data_segment */ - dump_bytes( outfile, data, data_offset, "Data_Segment", 0 ); + output_bytes( outfile, data_buffer, data_size ); + free( data_buffer ); - /* Build the module */ + /* resource data */ - module_size = BuildModule16( outfile, code_offset, data_offset, spec ); - res_size = output_res16_data( outfile, spec ); + if (resdata_size) + { + output_bytes( outfile, resdata_buffer, resdata_size ); + free( resdata_buffer ); + } - /* Output the DLL descriptor */ - - fprintf( outfile, "#include \"poppack.h\"\n\n" ); - - fprintf( outfile, "static const struct dll_descriptor\n{\n" ); - fprintf( outfile, " unsigned char *module_start;\n" ); - fprintf( outfile, " int module_size;\n" ); - fprintf( outfile, " struct code_segment *code_start;\n" ); - fprintf( outfile, " unsigned char *data_start;\n" ); - fprintf( outfile, " const char *owner;\n" ); - fprintf( outfile, " const unsigned char *rsrc;\n" ); - fprintf( outfile, "} descriptor =\n{\n" ); - fprintf( outfile, " Module,\n" ); - fprintf( outfile, " sizeof(Module),\n" ); - fprintf( outfile, " &code_segment,\n" ); - fprintf( outfile, " Data_Segment,\n" ); - fprintf( outfile, " \"%s\",\n", spec->owner_name ); - fprintf( outfile, " %s\n", res_size ? "resource_data" : "0" ); fprintf( outfile, "};\n" ); + fprintf( outfile, "#include \"poppack.h\"\n\n" ); /* Output the DLL constructor */ @@ -820,13 +882,13 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) fprintf( outfile, "void %s(void)\n" "{\n" - " extern void __wine_register_dll_16( const struct dll_descriptor *descr );\n" - " __wine_register_dll_16( &descriptor );\n" - "}\n", constructor ); + " extern void __wine_dll_register_16( const struct module_data *, const char * );\n" + " __wine_dll_register_16( &module, \"%s\" );\n" + "}\n", constructor, spec->file_name ); fprintf( outfile, "void %s(void)\n" "{\n" - " extern void __wine_unregister_dll_16( const struct dll_descriptor *descr );\n" - " __wine_unregister_dll_16( &descriptor );\n" + " extern void __wine_dll_unregister_16( const struct module_data * );\n" + " __wine_dll_unregister_16( &module );\n" "}\n", destructor ); } diff --git a/reactos/tools/winebuild/spec32.c b/reactos/tools/winebuild/spec32.c index 6fb1f4ae0ef..6c3e1ee88dd 100644 --- a/reactos/tools/winebuild/spec32.c +++ b/reactos/tools/winebuild/spec32.c @@ -176,9 +176,7 @@ static int output_exports( FILE *outfile, int nr_exports, DLLSPEC *spec ) case TYPE_CDECL: if (!(odp->flags & FLAG_FORWARD)) { - fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") "\\n\"\n", - (odp->flags & FLAG_REGISTER) ? make_internal_name( odp, spec, "regs" ) - : odp->link_name ); + fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") "\\n\"\n", odp->link_name ); } else { @@ -261,7 +259,6 @@ static int output_exports( FILE *outfile, int nr_exports, DLLSPEC *spec ) { ORDDEF *odp = spec->ordinals[i]; unsigned int j, args, mask = 0; - const char *name; /* skip nonexistent entry points */ if (!odp) goto ignore; @@ -277,22 +274,20 @@ static int output_exports( FILE *outfile, int nr_exports, DLLSPEC *spec ) } if ((odp->flags & FLAG_RET64) && (j < 16)) mask |= 0x80000000; - name = odp->link_name; args = strlen(odp->u.func.arg_types) * sizeof(int); - if (odp->flags & FLAG_REGISTER) name = make_internal_name( odp, spec, "regs" ); switch(odp->type) { case TYPE_STDCALL: - fprintf( outfile, " \"\\tjmp " __ASM_NAME("%s") "\\n\"\n", name ); + fprintf( outfile, " \"\\tjmp " __ASM_NAME("%s") "\\n\"\n", odp->link_name ); fprintf( outfile, " \"\\tret $%d\\n\"\n", args ); - fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") ",0x%08x\\n\"\n", name, mask ); + fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") ",0x%08x\\n\"\n", odp->link_name, mask ); break; case TYPE_CDECL: - fprintf( outfile, " \"\\tjmp " __ASM_NAME("%s") "\\n\"\n", name ); + fprintf( outfile, " \"\\tjmp " __ASM_NAME("%s") "\\n\"\n", odp->link_name ); fprintf( outfile, " \"\\tret\\n\"\n" ); fprintf( outfile, " \"\\t" __ASM_SHORT " %d\\n\"\n", args ); - fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") ",0x%08x\\n\"\n", name, mask ); + fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") ",0x%08x\\n\"\n", odp->link_name, mask ); break; default: assert(0); @@ -367,38 +362,6 @@ static void output_stub_funcs( FILE *outfile, DLLSPEC *spec ) } -/******************************************************************* - * output_register_funcs - * - * Output the functions for register entry points - */ -static void output_register_funcs( FILE *outfile, DLLSPEC *spec ) -{ - const char *name; - int i; - - for (i = 0; i < spec->nb_entry_points; i++) - { - const ORDDEF *odp = &spec->entry_points[i]; - if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL) continue; - if (!(odp->flags & FLAG_REGISTER)) continue; - if (odp->flags & FLAG_FORWARD) continue; - name = make_internal_name( odp, spec, "regs" ); - fprintf( outfile, - "asm(\".align %d\\n\\t\"\n" - " \"" __ASM_FUNC("%s") "\\n\\t\"\n" - " \"" __ASM_NAME("%s") ":\\n\\t\"\n" - " \"call " __ASM_NAME("__wine_call_from_32_regs") "\\n\\t\"\n" - " \".long " __ASM_NAME("%s") "\\n\\t\"\n" - " \".byte %d,%d\");\n", - get_alignment(4), - name, name, odp->link_name, - strlen(odp->u.func.arg_types) * sizeof(int), - (odp->type == TYPE_CDECL) ? 0 : (strlen(odp->u.func.arg_types) * sizeof(int)) ); - } -} - - /******************************************************************* * output_dll_init * @@ -499,7 +462,7 @@ void output_dll_init( FILE *outfile, const char *constructor, const char *destru void BuildSpec32File( FILE *outfile, DLLSPEC *spec ) { int exports_size = 0; - int nr_exports, nr_imports; + int nr_exports, nr_imports, nr_delayed; DWORD page_size; const char *init_func = spec->init_func; @@ -561,10 +524,6 @@ void BuildSpec32File( FILE *outfile, DLLSPEC *spec ) fprintf( outfile, "static void __asm__dummy(void) {\n" ); fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" ); - /* Output code for all register functions */ - - output_register_funcs( outfile, spec ); - /* Output the exports and relay entry points */ exports_size = output_exports( outfile, nr_exports, spec ); @@ -576,7 +535,7 @@ void BuildSpec32File( FILE *outfile, DLLSPEC *spec ) /* Output the DLL imports */ - nr_imports = output_imports( outfile, spec ); + nr_imports = output_imports( outfile, spec, &nr_delayed ); /* Output the resources */ @@ -626,10 +585,20 @@ void BuildSpec32File( FILE *outfile, DLLSPEC *spec ) " if (reason == %d && __wine_spec_init_state == 1)\n" " _init( __wine_main_argc, __wine_main_argv, __wine_main_environ );\n" " ret = %s ? %s( inst, reason, reserved ) : 1;\n" - " if (reason == %d && __wine_spec_init_state == 1) _fini();\n" - " return ret;\n" - "}\n", + " if (reason == %d && __wine_spec_init_state == 1)\n", DLL_PROCESS_ATTACH, init_func, init_func, DLL_PROCESS_DETACH ); + if (!nr_delayed) + fprintf( outfile, " _fini();\n" ); + else + fprintf( outfile, + " {\n" + " extern int __stdcall FreeLibrary(void *);\n" + " unsigned int i;\n" + " _fini();\n" + " for (i = 0; i < sizeof(__wine_delay_imp_hmod)/sizeof(__wine_delay_imp_hmod[0]); i++)\n" + " if (__wine_delay_imp_hmod[i]) FreeLibrary( __wine_delay_imp_hmod[i] );\n" + " }\n" ); + fprintf( outfile, " return ret;\n}\n" ); init_func = "__wine_dll_main"; } else switch(spec->subsystem) diff --git a/reactos/tools/winebuild/utils.c b/reactos/tools/winebuild/utils.c index 79b3899d97e..1fe09aa30f8 100644 --- a/reactos/tools/winebuild/utils.c +++ b/reactos/tools/winebuild/utils.c @@ -74,6 +74,13 @@ char *strupper(char *s) return s; } +int strendswith(const char* str, const char* end) +{ + int l = strlen(str); + int m = strlen(end); + return l >= m && strcmp(str + l - m, end) == 0; +} + void fatal_error( const char *msg, ... ) { va_list valist; diff --git a/reactos/tools/winebuild/winebuild.man.in b/reactos/tools/winebuild/winebuild.man.in index 4f47749fc9e..5371b0a141b 100644 --- a/reactos/tools/winebuild/winebuild.man.in +++ b/reactos/tools/winebuild/winebuild.man.in @@ -68,6 +68,12 @@ Change to the specified directory before reading source files. Only meaningful in .BR \--debug\ mode. .TP +.BI \-d,\ --delay-lib= name +Set the delayed import mode for the specified library, which must be +one of the libraries imported with the \fB-l\fR option. Delayed mode +means that the library won't be loaded until a function imported from +it is actually called. +.TP .BI \-D\ symbol Ignored for compatibility with the C compiler. .TP @@ -132,11 +138,6 @@ Import the specified library, looking for a corresponding \fIlibname.def\fR file in the directories specified with the \fB-L\fR option. .TP -.BI \-d,\ --delay-lib= name -Same as the \fB-l\fR option, but import the specified library in -delayed mode (i.e. the library won't be loaded until a function -imported from it is actually called). -.TP .BI \-M,\ --main-module= module Specify that we are building a 16-bit dll, that will ultimately be linked together with the 32-bit dll specified in \fImodule\fR. Only @@ -243,7 +244,7 @@ The function returns a 64-bit value (Win32 only). The entry point is only available on i386 platforms. .TP .B -register -The function uses CPU register to pass arguments. +The function uses CPU register to pass arguments (Win16 only). .TP .B -private The function cannot be imported from other dlls, it can only be diff --git a/reactos/tools/wrc/wrctypes.h b/reactos/tools/wrc/wrctypes.h index e7eb9a4b283..d776d268879 100644 --- a/reactos/tools/wrc/wrctypes.h +++ b/reactos/tools/wrc/wrctypes.h @@ -535,13 +535,13 @@ typedef struct versioninfo { int filetype; int filesubtype; struct { - int fv:1; - int pv:1; - int fo:1; - int ff:1; - int ffm:1; - int ft:1; - int fst:1; + unsigned fv:1; + unsigned pv:1; + unsigned fo:1; + unsigned ff:1; + unsigned ffm:1; + unsigned ft:1; + unsigned fst:1; } gotit; ver_block_t *blocks; lvc_t lvc; diff --git a/reactos/w32api/include/ddk/winddk.h b/reactos/w32api/include/ddk/winddk.h index 81af7cf255b..01a17c7c207 100644 --- a/reactos/w32api/include/ddk/winddk.h +++ b/reactos/w32api/include/ddk/winddk.h @@ -8510,6 +8510,15 @@ typedef NTSTATUS PSECURITY_DESCRIPTOR SecurityDescriptor, PULONG BufferLength); +typedef struct _OBJECT_HEADER_NAME_INFO +{ + struct _DIRECTORY_OBJECT *Directory; + UNICODE_STRING Name; + ULONG QueryReferences; + ULONG Reserved2; + ULONG DbgReferenceCount; +} OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO; + typedef struct _OBJECT_CREATE_INFORMATION { ULONG Attributes; diff --git a/reactos/w32api/include/winuser.h b/reactos/w32api/include/winuser.h index 99d7e16b0c2..e5e57061f78 100644 --- a/reactos/w32api/include/winuser.h +++ b/reactos/w32api/include/winuser.h @@ -153,6 +153,7 @@ extern "C" { #define CDS_FULLSCREEN 4 #define CDS_GLOBAL 8 #define CDS_SET_PRIMARY 16 +#define CDS_VIDEOPARAMETERS 20 #define CDS_RESET 0x40000000 #define CDS_SETRECT 0x20000000 #define CDS_NORESET 0x10000000