diff --git a/lib/hal/video.c b/lib/hal/video.c index 30553d1cb..61da0cac2 100644 --- a/lib/hal/video.c +++ b/lib/hal/video.c @@ -54,7 +54,7 @@ static DWORD dwEncoderSettings = 0; static VIDEO_MODE vmCurrent = { 0, 0, 0, 0 }; static int flickerLevel = 5; static BOOL flickerSet = FALSE; -static BOOL softenFilter = TRUE; +static BOOL softenFilter = FALSE; static BOOL softenSet = FALSE; static GAMMA_RAMP_ENTRY gammaRampEntries[256]; @@ -381,7 +381,7 @@ void XVideoInit(DWORD dwMode, int width, int height, int bpp) _fb = framebufferMemory; XVideoSetFlickerFilter(5); - XVideoSetSoftenFilter(TRUE); + XVideoSetSoftenFilter(FALSE); for(i = 0; i < 256; i++) { defaultGammaRampEntries[i].red = i; diff --git a/lib/net/nvnetdrv/nvnetdrv.c b/lib/net/nvnetdrv/nvnetdrv.c index c05f55f6c..8ed21cdf8 100644 --- a/lib/net/nvnetdrv/nvnetdrv.c +++ b/lib/net/nvnetdrv/nvnetdrv.c @@ -264,6 +264,7 @@ static void nvnetdrv_handle_mii_irq (uint32_t miiStatus, bool init) if (miiStatus & NVREG_MIISTAT_LINKCHANGE) { nvnetdrv_start_txrx(); + nvnetdrv_link_state_change_callback(linkState & XNET_ETHERNET_LINK_ACTIVE); } INC_STAT(phy_interrupts, 1); @@ -654,3 +655,14 @@ void nvnetdrv_rx_release (void *buffer_virt) g_rxRing[index].flags = NV_RX_AVAIL; reg32(NvRegTxRxControl) = NVREG_TXRXCTL_GET; } + +bool nvnetdrv_is_link_up (void) +{ + uint32_t linkState = PhyGetLinkState(false); + return (linkState & XNET_ETHERNET_LINK_ACTIVE) != 0; +} + +__attribute__((weak)) void nvnetdrv_link_state_change_callback (bool link_active) +{ + (void)link_active; +} diff --git a/lib/net/nvnetdrv/nvnetdrv.h b/lib/net/nvnetdrv/nvnetdrv.h index 793ab8e37..e0f94ef9f 100644 --- a/lib/net/nvnetdrv/nvnetdrv.h +++ b/lib/net/nvnetdrv/nvnetdrv.h @@ -8,6 +8,7 @@ #include #include +#include #include // Must be greater than max ethernet frame size. A multiple of page size prevents page boundary crossing @@ -87,4 +88,15 @@ void nvnetdrv_submit_tx_descriptors (nvnetdrv_descriptor_t *buffers, size_t coun */ void nvnetdrv_rx_release (void *buffer_virt); +/** + * @brief Check if the link is up. + * @return true if link connected, false if link is down. + */ +bool nvnetdrv_is_link_up (void); + +/** + * Called by the ISR when the link state changes. + * @param link_up True if the link is up, false if it is down. + */ +void nvnetdrv_link_state_change_callback (bool link_up); #endif diff --git a/lib/net/nvnetdrv/nvnetdrv_lwip.c b/lib/net/nvnetdrv/nvnetdrv_lwip.c index 31457ae90..d5d979f9b 100644 --- a/lib/net/nvnetdrv/nvnetdrv_lwip.c +++ b/lib/net/nvnetdrv/nvnetdrv_lwip.c @@ -14,6 +14,7 @@ #include "lwip/snmp.h" #include "lwip/stats.h" #include "lwip/sys.h" +#include "lwip/tcpip.h" #include "netif/etharp.h" #include "netif/ppp/pppoe.h" #include "nvnetdrv.h" @@ -81,6 +82,17 @@ void rx_callback (void *buffer, uint16_t length) } } + +static void change_link_state(void *ctx) +{ + bool link_active = (bool)ctx; + if (link_active) { + netif_set_link_up(g_pnetif); + } else { + netif_set_link_down(g_pnetif); + } +} + /** * In this function, the hardware should be initialized. * Called from nforceif_init(). @@ -97,7 +109,7 @@ static err_t low_level_init (struct netif *netif) /* device capabilities */ /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ - netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; #if LWIP_IPV6 && LWIP_IPV6_MLD /* @@ -123,6 +135,10 @@ static err_t low_level_init (struct netif *netif) /* set MAC hardware address */ memcpy(netif->hwaddr, nvnetdrv_get_ethernet_addr(), 6); + // Let LWIP know if a ethernet cable is currently connected + bool link_up = nvnetdrv_is_link_up(); + change_link_state((void *)link_up); + return ERR_OK; } @@ -277,4 +293,11 @@ err_t nvnetif_init (struct netif *netif) /* initialize the hardware */ return low_level_init(netif); -} \ No newline at end of file +} + +void nvnetdrv_link_state_change_callback (bool link_active) +{ + // ISR safe mbox to tcpip thread. This is very unlikely to fail as the mbox is large and the messages + // are allocated from the kernel's pool allocator. + tcpip_try_callback(change_link_state, (void *)link_active); +} diff --git a/lib/pdclib b/lib/pdclib index 82bf35e9e..679081d47 160000 --- a/lib/pdclib +++ b/lib/pdclib @@ -1 +1 @@ -Subproject commit 82bf35e9ebe70ae3214d4426ff7d1ef6b648376e +Subproject commit 679081d4725ab893d0ef7822111b5c5d05a572f5 diff --git a/lib/usb/libusbohci_xbox/xid_driver.c b/lib/usb/libusbohci_xbox/xid_driver.c index f38ec4a45..c0158fcc6 100644 --- a/lib/usb/libusbohci_xbox/xid_driver.c +++ b/lib/usb/libusbohci_xbox/xid_driver.c @@ -372,6 +372,21 @@ int32_t usbh_xid_rumble(xid_dev_t *xid_dev, uint16_t l_value, uint16_t h_value){ return usbh_xid_write(xid_dev, 0, (uint8_t *)&command, sizeof(xid_gamepad_out), NULL); } +int32_t usbh_xid_sbc_lights(xid_dev_t *xid_dev, uint8_t lights[STEELBATTALION_LIGHT_BYTES]) { + if (xid_dev->xid_desc.bType != XID_TYPE_STEELBATTALION) + { + return USBH_ERR_NOT_SUPPORTED; + } + + xid_steelbattalion_out command = + { + .startByte = 0, + .bLength = sizeof(xid_steelbattalion_out), + }; + memcpy(command.lights, lights, STEELBATTALION_LIGHT_BYTES); + return usbh_xid_write(xid_dev, 0, (uint8_t *)&command, sizeof(xid_gamepad_out), NULL); +} + /** * @brief Returns the xid_type. * diff --git a/lib/usb/libusbohci_xbox/xid_driver.h b/lib/usb/libusbohci_xbox/xid_driver.h index 3d97cbee2..5f081313d 100644 --- a/lib/usb/libusbohci_xbox/xid_driver.h +++ b/lib/usb/libusbohci_xbox/xid_driver.h @@ -24,7 +24,7 @@ extern "C" struct xid_dev; typedef void(XID_CONN_FUNC)(struct xid_dev *hdev, int param); -typedef struct __attribute__((packed)) +typedef struct __attribute__((packed)) { uint8_t bLength; uint8_t bDescriptorType; @@ -36,7 +36,24 @@ typedef struct __attribute__((packed)) uint16_t wAlternateProductIds[4]; } xid_descriptor; -typedef struct __attribute__((packed)) +//XINPUT defines and struct format from +//https://docs.microsoft.com/en-us/windows/win32/api/xinput/ns-xinput-xinput_gamepad +#define XINPUT_GAMEPAD_DPAD_UP 0x0001 +#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002 +#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004 +#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008 +#define XINPUT_GAMEPAD_START 0x0010 +#define XINPUT_GAMEPAD_BACK 0x0020 +#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040 +#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080 +#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 +#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200 +#define XINPUT_GAMEPAD_A 0x1000 +#define XINPUT_GAMEPAD_B 0x2000 +#define XINPUT_GAMEPAD_X 0x4000 +#define XINPUT_GAMEPAD_Y 0x8000 + +typedef struct __attribute__((packed)) { uint8_t startByte; uint8_t bLength; @@ -47,8 +64,8 @@ typedef struct __attribute__((packed)) uint8_t y; uint8_t black; uint8_t white; - uint8_t l; - uint8_t r; + uint8_t leftTrigger; + uint8_t rightTrigger; int16_t leftStickX; int16_t leftStickY; int16_t rightStickX; @@ -63,6 +80,32 @@ typedef struct __attribute__((packed)) uint16_t hValue; } xid_gamepad_out; +typedef struct __attribute__((packed)) +{ + uint8_t startByte; + uint8_t bLength; + uint16_t buttons[3]; + uint16_t aimingLeverX; // 0 = Left, 0xFFFF = Right + uint16_t aimingLeverY; // 0 = Top, 0xFFFF = Bottom + int16_t turningLever; + int16_t sightChangeX; + int16_t sightChangeY; + uint16_t slidePedal; + uint16_t brakePedal; + uint16_t accelPedal; + uint8_t tuner; // 0-15 is from 9oclock, around clockwise + int8_t shifter; // -2 = R, -1 = N, 0 = Error, 1 = 1st, 2 = 2nd, 3 = 3rnd, 4 = 4th, 5 = 5th +} xid_steelbattalion_in; + +#define STEELBATTALION_LIGHT_COUNT 40 +#define STEELBATTALION_LIGHT_BYTES (STEELBATTALION_LIGHT_COUNT / 2) // Each nibble is 1 light +typedef struct __attribute__((packed)) +{ + uint8_t startByte; + uint8_t bLength; + uint8_t lights[STEELBATTALION_LIGHT_BYTES]; +} xid_steelbattalion_out; + //Ref https://xboxdevwiki.net/Xbox_DVD_Movie_Playback_Kit typedef struct __attribute__((packed)) { @@ -106,6 +149,7 @@ int32_t usbh_xid_read(xid_dev_t *xid_dev, uint8_t ep_addr, void *rx_complete_cal int32_t usbh_xid_write(xid_dev_t *xid_dev, uint8_t ep_addr, uint8_t *txbuff, uint32_t len, void *tx_complete_callback); xid_type usbh_xid_get_type(xid_dev_t *xid_dev); int32_t usbh_xid_rumble(xid_dev_t *xid_dev, uint16_t l_value, uint16_t h_value); +int32_t usbh_xid_sbc_lights(xid_dev_t *xid_dev, uint8_t lights[STEELBATTALION_LIGHT_BYTES]); #ifdef __cplusplus } diff --git a/lib/winapi/fileapi.h b/lib/winapi/fileapi.h index 64fc9d08a..6dfaaca30 100644 --- a/lib/winapi/fileapi.h +++ b/lib/winapi/fileapi.h @@ -18,6 +18,7 @@ DWORD GetFileAttributesA (LPCSTR lpFileName); BOOL GetFileAttributesExA (LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation); BOOL SetFileAttributesA (LPCSTR lpFileName, DWORD dwFileAttributes); +LONG CompareFileTime (const FILETIME *lpFileTime1, const FILETIME *lpFileTime2); BOOL GetFileTime (HANDLE hFile, LPFILETIME lpCreationTime, LPFILETIME lpLastAccessTime, LPFILETIME lpLastWriteTime); BOOL SetFileTime (HANDLE hFile, const FILETIME *lpCreationTime, const FILETIME *lpLastAccessTime, const FILETIME *lpLastWriteTime); diff --git a/lib/winapi/filemanip.c b/lib/winapi/filemanip.c index 6be700f0f..31140d264 100644 --- a/lib/winapi/filemanip.c +++ b/lib/winapi/filemanip.c @@ -106,6 +106,28 @@ BOOL SetFileAttributesA (LPCSTR lpFileName, DWORD dwFileAttributes) return TRUE; } +LONG CompareFileTime (const FILETIME *lpFileTime1, const FILETIME *lpFileTime2) +{ + ULARGE_INTEGER filetime1; + ULARGE_INTEGER filetime2; + + assert(lpFileTime1 != NULL); + assert(lpFileTime2 != NULL); + + filetime1.LowPart = lpFileTime1->dwLowDateTime; + filetime1.HighPart = lpFileTime1->dwHighDateTime; + filetime2.LowPart = lpFileTime2->dwLowDateTime; + filetime2.HighPart = lpFileTime2->dwHighDateTime; + + if (filetime1.QuadPart < filetime2.QuadPart) { + return -1; + } + if (filetime1.QuadPart > filetime2.QuadPart) { + return 1; + } + return 0; +} + BOOL GetFileTime (HANDLE hFile, LPFILETIME lpCreationTime, LPFILETIME lpLastAccessTime, LPFILETIME lpLastWriteTime) { NTSTATUS status; diff --git a/lib/winapi/sysinfo.c b/lib/winapi/sysinfo.c index 2479b6d60..ac93dd250 100644 --- a/lib/winapi/sysinfo.c +++ b/lib/winapi/sysinfo.c @@ -24,7 +24,7 @@ void GetSystemTime (LPSYSTEMTIME lpSystemTime) lpSystemTime->wHour = timeFields.Hour; lpSystemTime->wMinute = timeFields.Minute; lpSystemTime->wSecond = timeFields.Second; - lpSystemTime->wMilliseconds = timeFields.Millisecond; + lpSystemTime->wMilliseconds = timeFields.Milliseconds; lpSystemTime->wDayOfWeek = timeFields.Weekday; } @@ -92,6 +92,6 @@ void GetLocalTime (LPSYSTEMTIME lpSystemTime) lpSystemTime->wHour = timeFields.Hour; lpSystemTime->wMinute = timeFields.Minute; lpSystemTime->wSecond = timeFields.Second; - lpSystemTime->wMilliseconds = timeFields.Millisecond; + lpSystemTime->wMilliseconds = timeFields.Milliseconds; lpSystemTime->wDayOfWeek = timeFields.Weekday; } diff --git a/lib/winapi/timezoneapi.c b/lib/winapi/timezoneapi.c index e55c0f4d9..2dea55206 100644 --- a/lib/winapi/timezoneapi.c +++ b/lib/winapi/timezoneapi.c @@ -1,10 +1,12 @@ // SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Ryan Wendland +// SPDX-FileCopyrightText: 2025 Stefan Schmidt #include #include #include +#include #include #include @@ -210,3 +212,60 @@ DWORD GetTimeZoneInformation (LPTIME_ZONE_INFORMATION lpTimeZoneInformation) return TIME_ZONE_ID_STANDARD; } } + +BOOL FileTimeToSystemTime (const FILETIME *lpFileTime, LPSYSTEMTIME lpSystemTime) +{ + if (!lpFileTime || !lpSystemTime) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + LARGE_INTEGER filetime; + filetime.LowPart = lpFileTime->dwLowDateTime; + filetime.HighPart = lpFileTime->dwHighDateTime; + if (filetime.QuadPart < 0) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + TIME_FIELDS timefields; + RtlTimeToTimeFields(&filetime, &timefields); + + lpSystemTime->wYear = timefields.Year; + lpSystemTime->wMonth = timefields.Month; + lpSystemTime->wDay = timefields.Day; + lpSystemTime->wDayOfWeek = timefields.Weekday; + lpSystemTime->wHour = timefields.Hour; + lpSystemTime->wMinute = timefields.Minute; + lpSystemTime->wSecond = timefields.Second; + lpSystemTime->wMilliseconds = timefields.Milliseconds; + + return TRUE; +} + +BOOL SystemTimeToFileTime (const SYSTEMTIME *lpSystemTime, LPFILETIME lpFileTime) +{ + if (!lpSystemTime || !lpFileTime) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + TIME_FIELDS timefields; + timefields.Year = lpSystemTime->wYear; + timefields.Month = lpSystemTime->wMonth; + timefields.Day = lpSystemTime->wDay; + timefields.Hour = lpSystemTime->wHour; + timefields.Minute = lpSystemTime->wMinute; + timefields.Second = lpSystemTime->wSecond; + timefields.Milliseconds = lpSystemTime->wMilliseconds; + + LARGE_INTEGER filetime; + if (!RtlTimeFieldsToTime(&timefields, &filetime)) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + lpFileTime->dwLowDateTime = filetime.LowPart; + lpFileTime->dwHighDateTime = filetime.HighPart; + return TRUE; +} diff --git a/lib/winapi/timezoneapi.h b/lib/winapi/timezoneapi.h index 7dba20d54..09e2b1187 100644 --- a/lib/winapi/timezoneapi.h +++ b/lib/winapi/timezoneapi.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Ryan Wendland +// SPDX-FileCopyrightText: 2025 Stefan Schmidt #ifndef __TIMEZONEAPI_H__ #define __TIMEZONEAPI_H__ @@ -29,6 +30,9 @@ typedef struct _TIME_ZONE_INFORMATION DWORD GetTimeZoneInformation (LPTIME_ZONE_INFORMATION lpTimeZoneInformation); +BOOL FileTimeToSystemTime (const FILETIME *lpFileTime, LPSYSTEMTIME lpSystemTime); +BOOL SystemTimeToFileTime (const SYSTEMTIME *lpSystemTime, LPFILETIME lpFileTime); + #ifdef __cplusplus } #endif diff --git a/lib/winapi/winbase.h b/lib/winapi/winbase.h index a2d17921d..6945f4a46 100644 --- a/lib/winapi/winbase.h +++ b/lib/winapi/winbase.h @@ -25,7 +25,7 @@ extern "C" { #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000 #define THREAD_PRIORITY_ABOVE_NORMAL 1 -#define THREAD_PRIOIRTY_BELOW_NORMAL (-1) +#define THREAD_PRIORITY_BELOW_NORMAL (-1) #define THREAD_PRIORITY_HIGHEST 2 #define THREAD_PRIORITY_IDLE (-15) #define THREAD_PRIORITY_LOWEST (-2) diff --git a/lib/xboxkrnl/xboxkrnl.h b/lib/xboxkrnl/xboxkrnl.h index 6eab27374..01662fd36 100644 --- a/lib/xboxkrnl/xboxkrnl.h +++ b/lib/xboxkrnl/xboxkrnl.h @@ -184,7 +184,7 @@ typedef struct _TIME_FIELDS SHORT Hour; /**< Specifies a value from 0 to 23 */ SHORT Minute; /**< Specifies a value from 0 to 59 */ SHORT Second; /**< Specifies a value from 0 to 59 */ - SHORT Millisecond; /**< Specifies a value from 0 to 999 */ + SHORT Milliseconds; /**< Specifies a value from 0 to 999 */ SHORT Weekday; /**< Specifies a value from 0 to 6 (Sunday to Saturday) */ } TIME_FIELDS, *PTIME_FIELDS;