Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
June 2021
- 82 participants
- 1899 messages
Re: [PATCH] include: add AV1 support to dxva.h
by Jan Ekström
> > On 11/20/20 3:37 PM, Steve Lhomme wrote:
> > Based on the DXVA AV1 specs
> > https://www.microsoft.com/en-us/download/details.aspx?id=101577
> >
> > The structures and the associated define are available in Windows SDK
> > since at least 10.0.20231.0.
>
> Is this something pre-released? Latest one I see is 10.0.19041.0,
> corresponding to Windows 10 2004.
> It does not have the types.
Hi,
Sorry for the out-of-the-blue outsider comment onto an old thread (hopefully the In-Reply-To header will work from the archive URL), but as various OSS multimedia projects would like these definitions to be in wine/mingw-w64, I can inform you that:
1. Since mid-May the structures have been officially defined in what was previously called MSDN: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/dxva/ns-dxva-…
2. MS seemingly today (?) released a stable SDK 10.0.20348.0 which finally is a non-insider SDK that defines these structures. It is not currently available in the VS installer, but it is available as a "server" SDK at https://developer.microsoft.com/en-US/windows/downloads/windows-10-sdk/ .
I hope this should enable these structures to be verified, and pulled in.
Best regards,
Jan
June 30, 2021
Re: [PATCH v3] dinput: Introduce new HID joystick backend.
by Arkadiusz Hiler
On Wed, Jun 30, 2021 at 10:54:19AM +0200, Rémi Bernon wrote:
> This adds a new joystick backend, implemented on top of HID and without
> any host dependencies. This will be progressively implementated, and
> it's not going to be usable until at least a few more patches.
>
> Because of that, and because it may also introduce regressions compared
> to the existing backends, it is disabled by default and is optionally
> enabled using the following global registry key:
>
> [HKCU\\Software\\Wine\\DirectInput\\Joysticks]
> "HID"="enabled"
>
> Or using the corresponding AppDefaults registry key:
>
> [HKCU\\Software\\Wine\\AppDefaults\\<app.exe>\\DirectInput\\Joysticks]
> "HID"="enabled"
>
> This setting will be removed later, when it becomes usable enough, to
> use the individual device disable mechanism available in joy.cpl.
>
> Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
> ---
>
> v3: Use setupapi directly, as user32 api usage was confusing. This also
> now matches device on either their index, HID handle or vid_pid,
> depending on what's been provided.
>
> The instance GUID now includes the HID handle, which will be more
> stable than the device index in setupapi device list.
>
> Matching the vid_pid assumes that setupapi device path is upper
> case, which I think is the case. We could make sure otherwise but
> I don't think we have to and it's not very convenient without wcsupr.
Yes, setupapi seems to be always uppercasing thing.
> +static HRESULT hid_joystick_device_open( DWORD index, UINT32 handle, UINT32 vid_pid, WCHAR *device_path,
> + HANDLE *device, DWORD version, PHIDP_PREPARSED_DATA *preparsed,
> + HIDD_ATTRIBUTES *attrs, HIDP_CAPS *caps, DIDEVICEINSTANCEW *instance )
> +{
> + static const WCHAR vid_pid_fmt_w[] = {'V','I','D','_','%','0','4','X','&','P','I','D','_','%','0','4','X',0};
> + char buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR)];
> + SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (void *)buffer;
> + SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)};
> + SP_DEVINFO_DATA devinfo = {sizeof(devinfo)};
> + WCHAR vid_pid_w[18] = {0};
> + UINT32 i = 0, hid_handle;
> + HDEVINFO set;
> + DWORD type;
> + GUID hid;
> +
> + TRACE( "index %u, handle %u, vid_pid %d\n", index, handle, vid_pid );
> +
> + HidD_GetHidGuid( &hid );
> + snprintfW( vid_pid_w, ARRAY_SIZE(vid_pid_w), vid_pid_fmt_w, vid_pid & 0xffff, vid_pid >> 16 );
> +
> + set = SetupDiGetClassDevsW( &hid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT );
> + if (set == INVALID_HANDLE_VALUE) return DIERR_DEVICENOTREG;
> +
> + *device = NULL;
> + *preparsed = NULL;
> + while (SetupDiEnumDeviceInterfaces( set, NULL, &hid, i++, &iface ))
> + {
> + detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
> + if (!SetupDiGetDeviceInterfaceDetailW( set, &iface, detail, sizeof(buffer), NULL, &devinfo ))
> + continue;
This should never fail because MAX_PATH, so how about a FIXME / WARN in
addition to that continue?
> + if (!SetupDiGetDevicePropertyW( set, &devinfo, &DEVPROPKEY_HID_HANDLE, &type,
> + (BYTE *)&hid_handle, sizeof(hid_handle), NULL, 0 ) ||
> + type != DEVPROP_TYPE_UINT32)
> + continue;
I was thinking about sticking to RawInput enumeration and using the
handles that you get from there instead of the indexes. This way you
would need to do GetRawInputDeviceInfo() only in
hid_joystick_enum_device() or maybe another helper that would try to map
vidpid from product GUID to a handle.
With that you would be able to make hid_joystick_device_open() take the
RawInput handle as the only parameter identifying the device.
This would also work on Windows (after the PE conversion), but I don't
think it's our goal, so I believe that setupapi may be a better choice
here.
> + if (!hid_joystick_device_try_open( detail->DevicePath, device, preparsed, attrs, caps, instance ))
> + continue;
> +
> + if (!handle && !vid_pid && !index--) break;
> + if (handle && handle == hid_handle) break;
> + if (vid_pid && strstrW( detail->DevicePath, vid_pid_w )) break;
You have the device handle here, so why not just use HidD_GetAttibutes()?
Another option would be to use GetRawInputDeviceInfo() with the
hid_handle.
> + CloseHandle( *device );
> + HidD_FreePreparsedData( *preparsed );
> + *device = NULL;
> + *preparsed = NULL;
> + }
> +
> + SetupDiDestroyDeviceInfoList( set );
> + if (!*device || !*preparsed) return DIERR_DEVICENOTREG;
> +
> + lstrcpynW( device_path, detail->DevicePath, MAX_PATH );
> + instance->guidInstance = hid_joystick_guid;
> + instance->guidInstance.Data3 = hid_handle;
> + instance->guidProduct = DInput_PIDVID_Product_GUID;
> + instance->guidProduct.Data1 = MAKELONG( attrs->VendorID, attrs->ProductID );
> + instance->dwDevType = get_device_type( version, caps->Usage != HID_USAGE_GENERIC_GAMEPAD ) | DIDEVTYPE_HID;
> + instance->guidFFDriver = GUID_NULL;
> + instance->wUsagePage = caps->UsagePage;
> + instance->wUsage = caps->Usage;
> + return DI_OK;
> +}
> +
> +static HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance,
> + DWORD version, int index )
> +{
> + HIDD_ATTRIBUTES attrs = {sizeof(attrs)};
> + PHIDP_PREPARSED_DATA preparsed;
> + WCHAR device_path[MAX_PATH];
> + HIDP_CAPS caps;
> + HANDLE device;
> + HRESULT hr;
> +
> + TRACE( "type %x, flags %#x, instance %p, version %04x, index %d\n", type, flags, instance, version, index );
> +
> + hr = hid_joystick_device_open( index, 0, 0, device_path, &device, version,
> + &preparsed, &attrs, &caps, instance );
hid_joystick_device_open() is getting a bit unwieldy with all the
possible parameter combinations. I don't think it needs the enumeration
/ vidpid lookup logic.
IMO it would read better if hid_joystick_device_open() would take the
path or RI handle and enum logic would be moved either here or to
a helper.
> + if (hr != DI_OK) return hr;
> +
> + HidD_FreePreparsedData( preparsed );
> + CloseHandle( device );
> +
> + if (instance->dwSize != sizeof(DIDEVICEINSTANCEW))
> + return S_FALSE;
> + if (version < 0x0800 && type != DIDEVTYPE_JOYSTICK)
> + return S_FALSE;
> + if (version >= 0x0800 && type != DI8DEVCLASS_ALL && type != DI8DEVCLASS_GAMECTRL)
> + return S_FALSE;
> +
> + if (device_disabled_registry( "HID", TRUE ))
> + return DIERR_DEVICENOTREG;
> +
> + TRACE( "Found device %s, usage %04x:%04x, product %s, instance %s, name %s\n", debugstr_w(device_path),
> + instance->wUsagePage, instance->wUsage, debugstr_guid( &instance->guidProduct ),
> + debugstr_guid( &instance->guidInstance ), debugstr_w(instance->tszInstanceName) );
> +
> + return DI_OK;
> +}
> +
> +static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, REFGUID guid, IDirectInputDevice8W **out )
> +{
> + DIDEVICEINSTANCEW instance = {sizeof(instance)};
> + GUID inst_guid = *guid, prod_guid = *guid;
> + DWORD size = sizeof(struct hid_joystick);
> + HIDD_ATTRIBUTES attrs = {sizeof(attrs)};
> + struct hid_joystick *impl = NULL;
> + PHIDP_PREPARSED_DATA preparsed;
> + UINT32 handle = 0, vid_pid = 0;
> + DIDATAFORMAT *format = NULL;
> + WCHAR device_path[MAX_PATH];
> + HIDP_CAPS caps;
> + HANDLE device;
> + HRESULT hr;
> +
> + TRACE( "dinput %p, guid %s, out %p\n", dinput, debugstr_guid( guid ), out );
> +
> + *out = NULL;
> +
> + inst_guid.Data3 = hid_joystick_guid.Data3;
> + prod_guid.Data1 = DInput_PIDVID_Product_GUID.Data1;
> + if (IsEqualGUID( &hid_joystick_guid, &inst_guid )) handle = guid->Data3;
Data3 is only a short. I think we should use 64 bits for our magic and
another 64 bits for the RawInput handle.
Or 32 if we go with our internal knowledge about how those handles are
implemented in Wine.
--
Cheers,
Arek
June 30, 2021
[PATCH 4/4] nsi: Implement NsiAllocateAndGetTable() and NsiFreeTable().
by Huw Davies
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/nsi/nsi.c | 53 +++++++++++++++++++++++++++++++++++++++++---
dlls/nsi/tests/nsi.c | 5 ++---
2 files changed, 52 insertions(+), 6 deletions(-)
diff --git a/dlls/nsi/nsi.c b/dlls/nsi/nsi.c
index 981fcdba954..37054dd0de6 100644
--- a/dlls/nsi/nsi.c
+++ b/dlls/nsi/nsi.c
@@ -39,9 +39,52 @@ DWORD WINAPI NsiAllocateAndGetTable( DWORD unk, const NPI_MODULEID *module, DWOR
void **rw_data, DWORD rw_size, void **dynamic_data, DWORD dynamic_size,
void **static_data, DWORD static_size, DWORD *count, DWORD unk2 )
{
- FIXME( "%d %p %d %p %d %p %d %p %d %p %d %p %d: stub\n", unk, module, table, key_data, key_size,
+ DWORD err, num = 0;
+ void *data[4] = { NULL };
+ DWORD sizes[4] = { key_size, rw_size, dynamic_size, static_size };
+ int i, attempt;
+
+ TRACE( "%d %p %d %p %d %p %d %p %d %p %d %p %d\n", unk, module, table, key_data, key_size,
rw_data, rw_size, dynamic_data, dynamic_size, static_data, static_size, count, unk2 );
- return ERROR_CALL_NOT_IMPLEMENTED;
+
+ for (attempt = 0; attempt < 5; attempt++)
+ {
+ err = NsiEnumerateObjectsAllParameters( unk, 0, module, table, NULL, 0, NULL, 0, NULL, 0, NULL, 0, &num );
+ if (err) return err;
+
+ for (i = 0; i < ARRAY_SIZE(data); i++)
+ {
+ if (sizes[i])
+ {
+ data[i] = heap_alloc( sizes[i] * num );
+ if (!data[i])
+ {
+ err = ERROR_OUTOFMEMORY;
+ goto err;
+ }
+ }
+ }
+
+ err = NsiEnumerateObjectsAllParameters( unk, 0, module, table, data[0], sizes[0], data[1], sizes[1],
+ data[2], sizes[2], data[3], sizes[3], &num );
+ if (err != ERROR_MORE_DATA) break;
+
+ NsiFreeTable( data[0], data[1], data[2], data[3] );
+ memset( data, 0, sizeof(data) );
+ }
+
+ if (!err)
+ {
+ if (sizes[0]) *key_data = data[0];
+ if (sizes[1]) *rw_data = data[1];
+ if (sizes[2]) *dynamic_data = data[2];
+ if (sizes[3]) *static_data = data[3];
+ *count = num;
+ }
+
+err:
+ if (err) NsiFreeTable( data[0], data[1], data[2], data[3] );
+ return err;
}
DWORD WINAPI NsiEnumerateObjectsAllParameters( DWORD unk, DWORD unk2, const NPI_MODULEID *module, DWORD table,
@@ -128,7 +171,11 @@ DWORD WINAPI NsiEnumerateObjectsAllParametersEx( struct nsi_enumerate_all_ex *pa
void WINAPI NsiFreeTable( void *key_data, void *rw_data, void *dynamic_data, void *static_data )
{
- FIXME( "%p %p %p %p: stub\n", key_data, rw_data, dynamic_data, static_data );
+ TRACE( "%p %p %p %p\n", key_data, rw_data, dynamic_data, static_data );
+ heap_free( key_data );
+ heap_free( rw_data );
+ heap_free( dynamic_data );
+ heap_free( static_data );
}
DWORD WINAPI NsiGetAllParameters( DWORD unk, const NPI_MODULEID *module, DWORD table, const void *key, DWORD key_size,
diff --git a/dlls/nsi/tests/nsi.c b/dlls/nsi/tests/nsi.c
index 51b149e9f65..35ca0bb07c9 100644
--- a/dlls/nsi/tests/nsi.c
+++ b/dlls/nsi/tests/nsi.c
@@ -54,9 +54,7 @@ static void test_nsi_api( void )
(void **)&stat_tbl, sizeof(*stat_tbl), &count, 0 );
if (!err) break;
}
-todo_wine
ok( !err, "got %d\n", err );
- if (err) return;
rw_size = rw_sizes[i];
for (i = 0; i < count; i++)
@@ -68,7 +66,9 @@ todo_wine
err = NsiGetAllParameters( 1, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid_tbl + i, sizeof(*luid_tbl),
&get_rw, rw_size, &get_dyn, sizeof(get_dyn), &get_stat, sizeof(get_stat) );
+todo_wine
ok( !err, "got %d\n", err );
+ if (err) break;
/* test a selection of members */
ok( IsEqualGUID( &get_rw.network_guid, &rw->network_guid ), "mismatch\n" );
ok( get_rw.alias.Length == rw->alias.Length, "mismatch\n" );
@@ -273,7 +273,6 @@ static void test_ndis_ifinfo( void )
(void **)&stat_tbl, sizeof(*stat_tbl), &count, 0 );
if (!err) break;
}
-todo_wine
ok( !err, "got %d\n", err );
if (err) return;
rw_size = rw_sizes[i];
--
2.23.0
June 30, 2021
[PATCH 3/4] nsiproxy: Implement NDIS ifinfo enumerate_all.
by Huw Davies
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/nsiproxy.sys/Makefile.in | 3 +-
dlls/nsiproxy.sys/ndis.c | 499 +++++++++++++++++++++++++++
dlls/nsiproxy.sys/nsi.c | 40 ++-
dlls/nsiproxy.sys/nsiproxy_private.h | 17 +
4 files changed, 557 insertions(+), 2 deletions(-)
create mode 100644 dlls/nsiproxy.sys/ndis.c
diff --git a/dlls/nsiproxy.sys/Makefile.in b/dlls/nsiproxy.sys/Makefile.in
index f382689d463..e44aacf5b54 100644
--- a/dlls/nsiproxy.sys/Makefile.in
+++ b/dlls/nsiproxy.sys/Makefile.in
@@ -1,7 +1,8 @@
MODULE = nsiproxy.sys
-IMPORTS = ntoskrnl
+IMPORTS = ntoskrnl uuid
EXTRADLLFLAGS = -Wl,--subsystem,native
C_SRCS = \
device.c \
+ ndis.c \
nsi.c
diff --git a/dlls/nsiproxy.sys/ndis.c b/dlls/nsiproxy.sys/ndis.c
new file mode 100644
index 00000000000..356a32635a3
--- /dev/null
+++ b/dlls/nsiproxy.sys/ndis.c
@@ -0,0 +1,499 @@
+/*
+ * nsiproxy.sys ndis module
+ *
+ * Copyright 2003, 2006, 2011 Juan Lang
+ * Copyright 2021 Huw Davies
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#include "config.h"
+
+#include <stdarg.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
+#ifdef HAVE_NET_IF_ARP_H
+#include <net/if_arp.h>
+#endif
+
+#ifdef HAVE_NETINET_IF_ETHER_H
+#include <netinet/if_ether.h>
+#endif
+
+#ifdef HAVE_NET_ROUTE_H
+#include <net/route.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+
+#ifdef HAVE_NET_IF_DL_H
+#include <net/if_dl.h>
+#endif
+
+#ifdef HAVE_NET_IF_TYPES_H
+#include <net/if_types.h>
+#endif
+
+#define NONAMELESSUNION
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "winternl.h"
+#include "winioctl.h"
+#define USE_WS_PREFIX
+#include "winsock2.h"
+#include "ws2ipdef.h"
+#include "nldef.h"
+#include "ifdef.h"
+#include "netiodef.h"
+#include "ddk/wdm.h"
+#include "wine/nsi.h"
+#include "wine/list.h"
+#include "wine/heap.h"
+#include "wine/debug.h"
+
+#include "nsiproxy_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(nsi);
+
+struct if_entry
+{
+ struct list entry;
+ GUID if_guid;
+ NET_LUID if_luid;
+ WCHAR *if_name;
+ char if_unix_name[IFNAMSIZ];
+ IF_PHYSICAL_ADDRESS if_phys_addr;
+ DWORD if_index;
+ DWORD if_type;
+};
+
+static struct list if_list = LIST_INIT( if_list );
+
+static CRITICAL_SECTION if_list_cs;
+static CRITICAL_SECTION_DEBUG if_list_cs_debug =
+{
+ 0, 0, &if_list_cs,
+ { &if_list_cs_debug.ProcessLocksList, &if_list_cs_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": if_list_cs") }
+};
+static CRITICAL_SECTION if_list_cs = { &if_list_cs_debug, -1, 0, 0, 0, 0 };
+
+static struct if_entry *find_entry_from_index( DWORD index )
+{
+ struct if_entry *entry;
+
+ LIST_FOR_EACH_ENTRY( entry, &if_list, struct if_entry, entry )
+ if (entry->if_index == index) return entry;
+
+ return NULL;
+}
+
+#if defined (SIOCGIFHWADDR) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR)
+static NTSTATUS if_get_physical( const char *name, DWORD *type, IF_PHYSICAL_ADDRESS *phys_addr )
+{
+ int fd, size, i;
+ struct ifreq ifr;
+ NTSTATUS ret = STATUS_SUCCESS;
+ static const struct type_lookup
+ {
+ unsigned short ifi_type;
+ IFTYPE mib_type;
+ DWORD addr_len;
+ } types[] =
+ {
+ { ARPHRD_LOOPBACK, MIB_IF_TYPE_LOOPBACK, 0 },
+ { ARPHRD_ETHER, MIB_IF_TYPE_ETHERNET, ETH_ALEN },
+ { ARPHRD_FDDI, MIB_IF_TYPE_FDDI, ETH_ALEN },
+ { ARPHRD_IEEE802, MIB_IF_TYPE_TOKENRING, ETH_ALEN },
+ { ARPHRD_IEEE802_TR, MIB_IF_TYPE_TOKENRING, ETH_ALEN },
+ { ARPHRD_SLIP, MIB_IF_TYPE_SLIP, 0 },
+ { ARPHRD_PPP, MIB_IF_TYPE_PPP, 0 }
+ };
+
+ *type = MIB_IF_TYPE_OTHER;
+ memset( phys_addr, 0, sizeof(*phys_addr) );
+
+ size = strlen( name ) + 1;
+ if (size > sizeof(ifr.ifr_name)) return STATUS_NAME_TOO_LONG;
+ memset( &ifr, 0, sizeof(ifr) );
+ memcpy( ifr.ifr_name, name, size );
+
+ fd = socket( PF_INET, SOCK_DGRAM, 0 );
+ if (fd == -1) return STATUS_TOO_MANY_OPENED_FILES;
+
+ if (ioctl( fd, SIOCGIFHWADDR, &ifr ))
+ {
+ ret = STATUS_DEVICE_DATA_ERROR;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(types); i++)
+ if (ifr.ifr_hwaddr.sa_family == types[i].ifi_type)
+ {
+ *type = types[i].mib_type;
+ phys_addr->Length = types[i].addr_len;
+ memcpy( phys_addr->Address, ifr.ifr_hwaddr.sa_data, phys_addr->Length );
+ break;
+ }
+
+err:
+ close( fd );
+ return ret;
+}
+
+#elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
+
+static NTSTATUS if_get_physical( const char *name, DWORD *type, IF_PHYSICAL_ADDRESS *phys_addr )
+{
+ struct if_msghdr *ifm;
+ struct sockaddr_dl *sdl;
+ u_char *p, *buf;
+ size_t mib_len;
+ int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 }, i;
+ static const struct type_lookup
+ {
+ u_char sdl_type;
+ IFTYPE mib_type;
+ } types[] =
+ {
+ { IFT_ETHER, MIB_IF_TYPE_ETHERNET },
+ { IFT_FDDI, MIB_IF_TYPE_FDDI },
+ { IFT_ISO88024, MIB_IF_TYPE_TOKENRING },
+ { IFT_ISO88025, MIB_IF_TYPE_TOKENRING },
+ { IFT_PPP, MIB_IF_TYPE_PPP },
+ { IFT_SLIP, MIB_IF_TYPE_SLIP },
+ { IFT_LOOP, MIB_IF_TYPE_LOOPBACK }
+ };
+
+ *type = MIB_IF_TYPE_OTHER;
+ memset( phys_addr, 0, sizeof(*phys_addr) );
+
+ if (sysctl( mib, 6, NULL, &mib_len, NULL, 0 ) < 0) return STATUS_TOO_MANY_OPENED_FILES;
+
+ buf = malloc( mib_len );
+ if (!buf) return STATUS_NO_MEMORY;
+
+ if (sysctl( mib, 6, buf, &mib_len, NULL, 0 ) < 0)
+ {
+ free( buf );
+ return STATUS_TOO_MANY_OPENED_FILES;
+ }
+
+ for (p = buf; p < buf + mib_len; p += ifm->ifm_msglen)
+ {
+ ifm = (struct if_msghdr *)p;
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+
+ if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0) continue;
+
+ if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
+ memcmp( sdl->sdl_data, name, max( sdl->sdl_nlen, strlen( name ) ) ))
+ continue;
+
+ for (i = 0; i < ARRAY_SIZE(types); i++)
+ if (sdl->sdl_type == types[i].sdl_type)
+ {
+ *type = types[i].mib_type;
+ break;
+ }
+
+ phys_addr->Length = sdl->sdl_alen;
+ if (phys_addr->Length > sizeof(phys_addr->Address)) phys_addr->Length = 0;
+ memcpy( phys_addr->Address, LLADDR(sdl), phys_addr->Length );
+ break;
+ }
+
+ free( buf );
+ return STATUS_SUCCESS;
+}
+#endif
+
+static WCHAR *strdupAtoW( const char *str )
+{
+ WCHAR *ret = NULL;
+ DWORD len;
+
+ if (!str) return ret;
+ len = MultiByteToWideChar( CP_UNIXCP, 0, str, -1, NULL, 0 );
+ ret = heap_alloc( len * sizeof(WCHAR) );
+ if (ret) MultiByteToWideChar( CP_UNIXCP, 0, str, -1, ret, len );
+ return ret;
+}
+
+static struct if_entry *add_entry( DWORD index, char *name )
+{
+ struct if_entry *entry;
+ int name_len = strlen( name );
+
+ if (name_len >= IFNAMSIZ - 1) return NULL;
+ entry = heap_alloc( sizeof(*entry) );
+ if (!entry) return NULL;
+
+ entry->if_index = index;
+ memcpy( entry->if_unix_name, name, name_len + 1 );
+ entry->if_name = strdupAtoW( name );
+ if (!entry->if_name)
+ {
+ heap_free( entry );
+ return NULL;
+ }
+
+ if_get_physical( name, &entry->if_type, &entry->if_phys_addr );
+
+ entry->if_luid.Info.Reserved = 0;
+ entry->if_luid.Info.NetLuidIndex = index;
+ entry->if_luid.Info.IfType = entry->if_type;
+
+ memset( &entry->if_guid, 0, sizeof(entry->if_guid) );
+ entry->if_guid.Data1 = index;
+ memcpy( entry->if_guid.Data4 + 2, "NetDev", 6 );
+
+ list_add_tail( &if_list, &entry->entry );
+ return entry;
+}
+
+static void update_if_table( void )
+{
+ struct if_nameindex *indices = if_nameindex(), *entry;
+
+ for (entry = indices; entry->if_index; entry++)
+ {
+ if (!find_entry_from_index( entry->if_index ))
+ add_entry( entry->if_index, entry->if_name );
+ }
+
+ if_freenameindex( indices );
+}
+
+static void if_counted_string_init( IF_COUNTED_STRING *str, const WCHAR *value )
+{
+ str->Length = value ? min( lstrlenW( value ), ARRAY_SIZE(str->String) - 1 ) * sizeof(WCHAR) : 0;
+ if (str->Length) memcpy( str->String, value, str->Length );
+ memset( (char *)str->String + str->Length, 0, sizeof(str->String) - str->Length );
+}
+
+static void ifinfo_fill_dynamic( struct if_entry *entry, struct nsi_ndis_ifinfo_dynamic *data )
+{
+ int fd, name_len = strlen( entry->if_unix_name );
+ struct ifreq req;
+
+ memset( data, 0, sizeof(*data) );
+
+ if (name_len >= sizeof(req.ifr_name)) return;
+ memcpy( req.ifr_name, entry->if_unix_name, name_len + 1 );
+
+ fd = socket( PF_INET, SOCK_DGRAM, 0 );
+ if (fd == -1) return;
+
+ if (!ioctl( fd, SIOCGIFFLAGS, &req ))
+ {
+ if (req.ifr_flags & IFF_UP) data->oper_status = IfOperStatusUp;
+#ifdef IFF_DORMANT
+ else if (req.ifr_flags & IFF_DORMANT) data->oper_status = IfOperStatusDormant;
+#endif
+ else data->oper_status = IfOperStatusDown;
+ } else data->oper_status = IfOperStatusUnknown;
+
+ data->flags.unk = 0;
+ data->flags.not_media_conn = 0;
+ data->flags.unk2 = 0;
+ data->media_conn_state = MediaConnectStateConnected;
+ data->unk = 0;
+
+ if (!ioctl( fd, SIOCGIFMTU, &req )) data->mtu = req.ifr_mtu;
+ else data->mtu = 0;
+
+ close( fd );
+
+#ifdef __linux__
+ {
+ FILE *fp;
+
+ if ((fp = fopen( "/proc/net/dev", "r" )))
+ {
+ char buf[512], *ptr;
+
+ while ((ptr = fgets( buf, sizeof(buf), fp )))
+ {
+ while (*ptr && isspace( *ptr )) ptr++;
+ if (!_strnicmp( ptr, entry->if_unix_name, name_len ) && ptr[name_len] == ':')
+ {
+ unsigned long long values[9];
+ ptr += name_len + 1;
+ sscanf( ptr, "%llu %llu %llu %llu %*u %*u %*u %llu %llu %llu %llu %llu",
+ values, values + 1, values + 2, values + 3, values + 4,
+ values + 5, values + 6, values + 7, values + 8 );
+ data->in_octets = values[0];
+ data->in_ucast_pkts = values[1];
+ data->in_errors = values[2];
+ data->in_discards = values[3];
+ data->in_mcast_pkts = values[4];
+ data->out_octets = values[5];
+ data->out_ucast_pkts = values[6];
+ data->out_errors = values[7];
+ data->out_discards = values[8];
+ break;
+ }
+ }
+ fclose( fp );
+ }
+ }
+#elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
+ {
+ int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, entry->if_index };
+ size_t needed;
+ char *buf = NULL, *end;
+ struct if_msghdr *ifm;
+ struct if_data ifdata;
+
+ if (sysctl( mib, ARRAY_SIZE(mib), NULL, &needed, NULL, 0 ) == -1) goto done;
+ buf = heap_alloc( needed );
+ if (!buf) goto done;
+ if (sysctl( mib, ARRAY_SIZE(mib), buf, &needed, NULL, 0 ) == -1) goto done;
+ for (end = buf + needed; buf < end; buf += ifm->ifm_msglen)
+ {
+ ifm = (struct if_msghdr *) buf;
+ if (ifm->ifm_type == RTM_IFINFO)
+ {
+ ifdata = ifm->ifm_data;
+ data->xmit_speed = data->rcv_speed = ifdata.ifi_baudrate;
+ data->in_octets = ifdata.ifi_ibytes;
+ data->in_errors = ifdata.ifi_ierrors;
+ data->in_discards = ifdata.ifi_iqdrops;
+ data->in_ucast_pkts = ifdata.ifi_ipackets;
+ data->in_mcast_pkts = ifdata.ifi_imcasts;
+ data->out_octets = ifdata.ifi_obytes;
+ data->out_ucast_pkts = ifdata.ifi_opackets;
+ data->out_mcast_pkts = ifdata.ifi_omcasts;
+ data->out_errors = ifdata.ifi_oerrors;
+ break;
+ }
+ }
+ done:
+ heap_free( buf );
+ }
+#endif
+}
+
+static void ifinfo_fill_entry( struct if_entry *entry, NET_LUID *key, struct nsi_ndis_ifinfo_rw *rw,
+ struct nsi_ndis_ifinfo_dynamic *dyn, struct nsi_ndis_ifinfo_static *stat )
+{
+ if (key) memcpy( key, &entry->if_luid, sizeof(entry->if_luid) );
+
+ if (rw)
+ {
+ memset( &rw->network_guid, 0, sizeof(entry->if_guid) );
+ rw->admin_status = MIB_IF_ADMIN_STATUS_UP;
+ if_counted_string_init( &rw->alias, entry->if_name );
+ memcpy( &rw->phys_addr, &entry->if_phys_addr, sizeof(entry->if_phys_addr) );
+ rw->pad = 0;
+ if_counted_string_init( &rw->name2, NULL );
+ rw->unk = 0;
+ }
+
+ if (dyn) ifinfo_fill_dynamic( entry, dyn );
+
+ if (stat)
+ {
+ stat->if_index = entry->if_index;
+ if_counted_string_init( &stat->descr, entry->if_name ); /* get a more descriptive name */
+ stat->type = entry->if_type;
+ stat->access_type = (entry->if_type == MIB_IF_TYPE_LOOPBACK) ? NET_IF_ACCESS_LOOPBACK : NET_IF_ACCESS_BROADCAST;
+ stat->unk = 0;
+ stat->conn_type = NET_IF_CONNECTION_DEDICATED;
+ memcpy( &stat->if_guid, &entry->if_guid, sizeof(entry->if_guid) );
+ stat->conn_present = entry->if_type != MIB_IF_TYPE_LOOPBACK;
+ memcpy( &stat->perm_phys_addr, &entry->if_phys_addr, sizeof(entry->if_phys_addr) );
+ stat->flags.hw = entry->if_type != MIB_IF_TYPE_LOOPBACK;
+ stat->flags.filter = 0;
+ stat->flags.unk = 0;
+ stat->media_type = 0;
+ stat->phys_medium_type = 0;
+ }
+}
+
+static NTSTATUS ifinfo_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
+ void *dynamic_data, DWORD dynamic_size,
+ void *static_data, DWORD static_size, DWORD_PTR *count )
+{
+ struct if_entry *entry;
+ DWORD num = 0;
+ NTSTATUS status = STATUS_SUCCESS;
+ BOOL want_data = key_size || rw_size || dynamic_size || static_size;
+
+ TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data, key_size, rw_data, rw_size,
+ dynamic_data, dynamic_size, static_data, static_size, count );
+
+ EnterCriticalSection( &if_list_cs );
+
+ update_if_table();
+
+ LIST_FOR_EACH_ENTRY( entry, &if_list, struct if_entry, entry )
+ {
+ if (num < *count)
+ {
+ ifinfo_fill_entry( entry, key_data, rw_data, dynamic_data, static_data );
+ key_data = (BYTE *)key_data + key_size;
+ rw_data = (BYTE *)rw_data + rw_size;
+ dynamic_data = (BYTE *)dynamic_data + dynamic_size;
+ static_data = (BYTE *)static_data + static_size;
+ }
+ num++;
+ }
+
+ LeaveCriticalSection( &if_list_cs );
+
+ if (!want_data || num <= *count) *count = num;
+ else status = STATUS_MORE_ENTRIES;
+
+ return status;
+}
+
+static const struct module_table tables[] =
+{
+ {
+ NSI_NDIS_IFINFO_TABLE,
+ {
+ sizeof(NET_LUID), sizeof(struct nsi_ndis_ifinfo_rw),
+ sizeof(struct nsi_ndis_ifinfo_dynamic), sizeof(struct nsi_ndis_ifinfo_static)
+ },
+ ifinfo_enumerate_all,
+ },
+ { ~0u }
+};
+
+const struct module ndis_module =
+{
+ &NPI_MS_NDIS_MODULEID,
+ tables
+};
diff --git a/dlls/nsiproxy.sys/nsi.c b/dlls/nsiproxy.sys/nsi.c
index 7ff36c093ba..85b9be1e587 100644
--- a/dlls/nsiproxy.sys/nsi.c
+++ b/dlls/nsiproxy.sys/nsi.c
@@ -30,9 +30,47 @@
#include "ifdef.h"
#include "netiodef.h"
#include "wine/nsi.h"
+#include "wine/debug.h"
#include "nsiproxy_private.h"
+WINE_DEFAULT_DEBUG_CHANNEL(nsi);
+
+static const struct module *modules[] =
+{
+ &ndis_module,
+};
+
+static const struct module_table *get_module_table( const NPI_MODULEID *id, DWORD table )
+{
+ const struct module_table *entry;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(modules); i++)
+ if (NmrIsEqualNpiModuleId( modules[i]->module, id ))
+ for (entry = modules[i]->tables; entry->table != ~0u; entry++)
+ if (entry->table == table) return entry;
+
+ return NULL;
+}
+
NTSTATUS nsi_enumerate_all_ex( struct nsi_enumerate_all_ex *params )
{
- return STATUS_NOT_IMPLEMENTED;
+ const struct module_table *entry = get_module_table( params->module, params->table );
+ DWORD sizes[4] = { params->key_size, params->rw_size, params->dynamic_size, params->static_size };
+ void *data[4] = { params->key_data, params->rw_data, params->dynamic_data, params->static_data };
+ int i;
+
+ if (!entry || !entry->enumerate_all)
+ {
+ WARN( "table not found\n" );
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sizes); i++)
+ {
+ if (!sizes[i]) data[i] = NULL;
+ else if (sizes[i] != entry->sizes[i]) return STATUS_INVALID_PARAMETER;
+ }
+
+ return entry->enumerate_all( data[0], sizes[0], data[1], sizes[1], data[2], sizes[2], data[3], sizes[3], ¶ms->count );
}
diff --git a/dlls/nsiproxy.sys/nsiproxy_private.h b/dlls/nsiproxy.sys/nsiproxy_private.h
index 19b520d17cc..6745dbc6b56 100644
--- a/dlls/nsiproxy.sys/nsiproxy_private.h
+++ b/dlls/nsiproxy.sys/nsiproxy_private.h
@@ -19,3 +19,20 @@
*/
NTSTATUS nsi_enumerate_all_ex( struct nsi_enumerate_all_ex *params ) DECLSPEC_HIDDEN;
+
+struct module_table
+{
+ DWORD table;
+ DWORD sizes[4];
+ NTSTATUS (*enumerate_all)( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
+ void *dynamic_data, DWORD dynamic_size,
+ void *static_data, DWORD static_size, DWORD_PTR *count );
+};
+
+struct module
+{
+ const NPI_MODULEID *module;
+ const struct module_table *tables;
+};
+
+extern const struct module ndis_module DECLSPEC_HIDDEN;
--
2.23.0
June 30, 2021
[PATCH 2/4] iphlpapi: For unknown interface types set the physical address length to zero.
by Huw Davies
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/iphlpapi/ifenum.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/iphlpapi/ifenum.c b/dlls/iphlpapi/ifenum.c
index 2e99ebe03fd..3b4ac775db7 100644
--- a/dlls/iphlpapi/ifenum.c
+++ b/dlls/iphlpapi/ifenum.c
@@ -498,7 +498,7 @@ static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr
break;
#endif
default:
- addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
+ addrLen = 0;
*type = MIB_IF_TYPE_OTHER;
}
if (addrLen > *len) {
--
2.23.0
June 30, 2021
[PATCH 1/4] iphlpapi: Fill out a few more MIB_IF_ROW2 entries.
by Huw Davies
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/iphlpapi/iphlpapi_main.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index 21edd9ee128..7b104330ba7 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -1781,7 +1781,7 @@ DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
*/
DWORD WINAPI GetIfEntry2( MIB_IF_ROW2 *row2 )
{
- DWORD ret, len = ARRAY_SIZE(row2->Description);
+ DWORD ret;
char buf[MAX_ADAPTER_NAME], *name;
MIB_IFROW row;
@@ -1803,14 +1803,19 @@ DWORD WINAPI GetIfEntry2( MIB_IF_ROW2 *row2 )
ConvertInterfaceLuidToGuid( &row2->InterfaceLuid, &row2->InterfaceGuid );
row2->Type = row.dwType;
row2->Mtu = row.dwMtu;
- MultiByteToWideChar( CP_UNIXCP, 0, (const char *)row.bDescr, -1, row2->Description, len );
+ MultiByteToWideChar( CP_UNIXCP, 0, (const char *)row.bDescr, -1, row2->Description, ARRAY_SIZE(row2->Description) );
+ MultiByteToWideChar( CP_UNIXCP, 0, (const char *)row.bDescr, -1, row2->Alias, ARRAY_SIZE(row2->Alias) );
row2->PhysicalAddressLength = row.dwPhysAddrLen;
memcpy( &row2->PhysicalAddress, &row.bPhysAddr, row.dwPhysAddrLen );
memcpy( &row2->PermanentPhysicalAddress, &row.bPhysAddr, row.dwPhysAddrLen );
- row2->OperStatus = IfOperStatusUp;
+ row2->OperStatus = row.dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL ? IfOperStatusUp : IfOperStatusDown;
row2->AdminStatus = NET_IF_ADMIN_STATUS_UP;
row2->MediaConnectState = MediaConnectStateConnected;
row2->ConnectionType = NET_IF_CONNECTION_DEDICATED;
+ row2->TransmitLinkSpeed = row2->ReceiveLinkSpeed = row.dwSpeed;
+ row2->AccessType = (row2->Type == MIB_IF_TYPE_LOOPBACK) ? NET_IF_ACCESS_LOOPBACK : NET_IF_ACCESS_BROADCAST;
+ row2->InterfaceAndOperStatusFlags.ConnectorPresent = row2->Type != MIB_IF_TYPE_LOOPBACK;
+ row2->InterfaceAndOperStatusFlags.HardwareInterface = row2->Type != MIB_IF_TYPE_LOOPBACK;
/* stats */
row2->InOctets = row.dwInOctets;
--
2.23.0
June 30, 2021
[PATCH v3] dinput: Introduce new HID joystick backend.
by Rémi Bernon
This adds a new joystick backend, implemented on top of HID and without
any host dependencies. This will be progressively implementated, and
it's not going to be usable until at least a few more patches.
Because of that, and because it may also introduce regressions compared
to the existing backends, it is disabled by default and is optionally
enabled using the following global registry key:
[HKCU\\Software\\Wine\\DirectInput\\Joysticks]
"HID"="enabled"
Or using the corresponding AppDefaults registry key:
[HKCU\\Software\\Wine\\AppDefaults\\<app.exe>\\DirectInput\\Joysticks]
"HID"="enabled"
This setting will be removed later, when it becomes usable enough, to
use the individual device disable mechanism available in joy.cpl.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
v3: Use setupapi directly, as user32 api usage was confusing. This also
now matches device on either their index, HID handle or vid_pid,
depending on what's been provided.
The instance GUID now includes the HID handle, which will be more
stable than the device index in setupapi device list.
Matching the vid_pid assumes that setupapi device path is upper
case, which I think is the case. We could make sure otherwise but
I don't think we have to and it's not very convenient without wcsupr.
dlls/dinput/Makefile.in | 3 +-
dlls/dinput/dinput_main.c | 3 +-
dlls/dinput/dinput_private.h | 1 +
dlls/dinput/joystick.c | 17 +-
dlls/dinput/joystick_hid.c | 491 ++++++++++++++++++++++++++++++
dlls/dinput/joystick_linux.c | 2 +-
dlls/dinput/joystick_linuxinput.c | 2 +-
dlls/dinput/joystick_private.h | 2 +-
dlls/dinput8/Makefile.in | 3 +-
9 files changed, 513 insertions(+), 11 deletions(-)
create mode 100644 dlls/dinput/joystick_hid.c
diff --git a/dlls/dinput/Makefile.in b/dlls/dinput/Makefile.in
index a22c8a72180..29d3e8ece65 100644
--- a/dlls/dinput/Makefile.in
+++ b/dlls/dinput/Makefile.in
@@ -1,6 +1,6 @@
MODULE = dinput.dll
IMPORTLIB = dinput
-IMPORTS = dinput dxguid uuid comctl32 ole32 user32 advapi32
+IMPORTS = dinput dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi
EXTRADEFS = -DDIRECTINPUT_VERSION=0x0700
EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS)
@@ -12,6 +12,7 @@ C_SRCS = \
dinput_main.c \
effect_linuxinput.c \
joystick.c \
+ joystick_hid.c \
joystick_linux.c \
joystick_linuxinput.c \
joystick_osx.c \
diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c
index c7b932aca44..88ee1855675 100644
--- a/dlls/dinput/dinput_main.c
+++ b/dlls/dinput/dinput_main.c
@@ -80,7 +80,8 @@ static const struct dinput_device *dinput_devices[] =
&keyboard_device,
&joystick_linuxinput_device,
&joystick_linux_device,
- &joystick_osx_device
+ &joystick_osx_device,
+ &joystick_hid_device,
};
HINSTANCE DINPUT_instance;
diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h
index 7e0f56c68df..c11b64585d9 100644
--- a/dlls/dinput/dinput_private.h
+++ b/dlls/dinput/dinput_private.h
@@ -67,6 +67,7 @@ struct DevicePlayer {
extern const struct dinput_device mouse_device DECLSPEC_HIDDEN;
extern const struct dinput_device keyboard_device DECLSPEC_HIDDEN;
+extern const struct dinput_device joystick_hid_device DECLSPEC_HIDDEN;
extern const struct dinput_device joystick_linux_device DECLSPEC_HIDDEN;
extern const struct dinput_device joystick_linuxinput_device DECLSPEC_HIDDEN;
extern const struct dinput_device joystick_osx_device DECLSPEC_HIDDEN;
diff --git a/dlls/dinput/joystick.c b/dlls/dinput/joystick.c
index 8ea7850621c..60153d0d0f3 100644
--- a/dlls/dinput/joystick.c
+++ b/dlls/dinput/joystick.c
@@ -271,13 +271,13 @@ void dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid, DWORD dwFlags)
}
}
-BOOL device_disabled_registry(const char* name)
+BOOL device_disabled_registry(const char* name, BOOL disable)
{
static const char disabled_str[] = "disabled";
+ static const char enabled_str[] = "enabled";
static const char joystick_key[] = "Joysticks";
char buffer[MAX_PATH];
HKEY hkey, appkey, temp;
- BOOL do_disable = FALSE;
get_app_key(&hkey, &appkey);
@@ -297,16 +297,23 @@ BOOL device_disabled_registry(const char* name)
/* Look for the "controllername"="disabled" key */
if (!get_config_key(hkey, appkey, name, buffer, sizeof(buffer)))
- if (!strcmp(disabled_str, buffer))
+ {
+ if (!disable && !strcmp(disabled_str, buffer))
{
TRACE("Disabling joystick '%s' based on registry key.\n", name);
- do_disable = TRUE;
+ disable = TRUE;
+ }
+ else if (disable && !strcmp(enabled_str, buffer))
+ {
+ TRACE("Enabling joystick '%s' based on registry key.\n", name);
+ disable = FALSE;
}
+ }
if (appkey) RegCloseKey(appkey);
if (hkey) RegCloseKey(hkey);
- return do_disable;
+ return disable;
}
BOOL is_xinput_device(const DIDEVCAPS *devcaps, WORD vid, WORD pid)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
new file mode 100644
index 00000000000..f29c806a51d
--- /dev/null
+++ b/dlls/dinput/joystick_hid.c
@@ -0,0 +1,491 @@
+/* DirectInput HID Joystick device
+ *
+ * Copyright 2021 Rémi Bernon 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winternl.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "winreg.h"
+
+#include "ddk/hidsdi.h"
+#include "setupapi.h"
+#include "devguid.h"
+#include "dinput.h"
+#include "setupapi.h"
+
+#include "wine/debug.h"
+
+#include "dinput_private.h"
+#include "device_private.h"
+#include "joystick_private.h"
+
+#include "initguid.h"
+#include "devpkey.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dinput);
+
+DEFINE_GUID( hid_joystick_guid, 0x9e573edb, 0x7734, 0x11d2, 0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7 );
+DEFINE_DEVPROPKEY( DEVPROPKEY_HID_HANDLE, 0xbc62e415, 0xf4fe, 0x405c, 0x8e, 0xda, 0x63, 0x6f, 0xb5, 0x9f, 0x08, 0x98, 2 );
+
+struct hid_joystick
+{
+ IDirectInputDeviceImpl base;
+
+ HANDLE device;
+ PHIDP_PREPARSED_DATA preparsed;
+};
+
+static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface )
+{
+ return CONTAINING_RECORD( CONTAINING_RECORD( iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface ),
+ struct hid_joystick, base );
+}
+
+static ULONG WINAPI hid_joystick_Release( IDirectInputDevice8W *iface )
+{
+ struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface );
+ struct hid_joystick tmp = *impl;
+ ULONG res;
+
+ if (!(res = IDirectInputDevice2WImpl_Release( iface )))
+ {
+ HidD_FreePreparsedData( tmp.preparsed );
+ CloseHandle( tmp.device );
+ }
+
+ return res;
+}
+
+static HRESULT WINAPI hid_joystick_GetCapabilities( IDirectInputDevice8W *iface, DIDEVCAPS *caps )
+{
+ FIXME( "iface %p, caps %p stub!\n", iface, caps );
+
+ if (!caps) return E_POINTER;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_EnumObjects( IDirectInputDevice8W *iface, LPDIENUMDEVICEOBJECTSCALLBACKW callback,
+ void *ref, DWORD flags )
+{
+ FIXME( "iface %p, callback %p, ref %p, flags %#x stub!\n", iface, callback, ref, flags );
+
+ if (!callback) return DIERR_INVALIDPARAM;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_GetProperty( IDirectInputDevice8W *iface, REFGUID guid, DIPROPHEADER *header )
+{
+ FIXME( "iface %p, guid %s, header %p stub!\n", iface, debugstr_guid( guid ), header );
+
+ if (!header) return DIERR_INVALIDPARAM;
+ if (!IS_DIPROP( guid )) return DI_OK;
+
+ switch (LOWORD( guid ))
+ {
+ default: return IDirectInputDevice2WImpl_GetProperty( iface, guid, header );
+ }
+}
+
+static HRESULT WINAPI hid_joystick_SetProperty( IDirectInputDevice8W *iface, REFGUID guid, const DIPROPHEADER *header )
+{
+ FIXME( "iface %p, guid %s, header %p stub!\n", iface, debugstr_guid( guid ), header );
+
+ if (!header) return DIERR_INVALIDPARAM;
+ if (!IS_DIPROP( guid )) return DI_OK;
+
+ switch (LOWORD( guid ))
+ {
+ default: return IDirectInputDevice2WImpl_SetProperty( iface, guid, header );
+ }
+}
+
+static HRESULT WINAPI hid_joystick_Acquire( IDirectInputDevice8W *iface )
+{
+ HRESULT hr;
+
+ TRACE( "iface %p.\n", iface );
+
+ if ((hr = IDirectInputDevice2WImpl_Acquire( iface )) != DI_OK) return hr;
+
+ return DI_OK;
+}
+
+static HRESULT WINAPI hid_joystick_Unacquire( IDirectInputDevice8W *iface )
+{
+ HRESULT hr;
+
+ TRACE( "iface %p.\n", iface );
+
+ if ((hr = IDirectInputDevice2WImpl_Unacquire( iface )) != DI_OK) return hr;
+
+ return DI_OK;
+}
+
+static HRESULT WINAPI hid_joystick_GetDeviceState( IDirectInputDevice8W *iface, DWORD len, void *ptr )
+{
+ FIXME( "iface %p, len %u, ptr %p stub!\n", iface, len, ptr );
+
+ if (!ptr) return DIERR_INVALIDPARAM;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_GetObjectInfo( IDirectInputDevice8W *iface, DIDEVICEOBJECTINSTANCEW *instance,
+ DWORD obj, DWORD how )
+{
+ FIXME( "iface %p, instance %p, obj %#x, how %#x stub!\n", iface, instance, obj, how );
+
+ if (!instance) return E_POINTER;
+ if (instance->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3W) &&
+ instance->dwSize != sizeof(DIDEVICEOBJECTINSTANCEW))
+ return DIERR_INVALIDPARAM;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_GetDeviceInfo( IDirectInputDevice8W *iface, DIDEVICEINSTANCEW *instance )
+{
+ FIXME( "iface %p, instance %p stub!\n", iface, instance );
+
+ if (!instance) return E_POINTER;
+ if (instance->dwSize != sizeof(DIDEVICEINSTANCE_DX3W) &&
+ instance->dwSize != sizeof(DIDEVICEINSTANCEW))
+ return DIERR_INVALIDPARAM;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_CreateEffect( IDirectInputDevice8W *iface, REFGUID rguid,
+ const DIEFFECT *effect, IDirectInputEffect **out,
+ IUnknown *outer )
+{
+ FIXME( "iface %p, rguid %s, effect %p, out %p, outer %p stub!\n", iface, debugstr_guid( rguid ),
+ effect, out, outer );
+
+ if (!out) return E_POINTER;
+ if (!rguid || !effect) return DI_NOEFFECT;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_EnumEffects( IDirectInputDevice8W *iface, LPDIENUMEFFECTSCALLBACKW callback,
+ void *ref, DWORD type )
+{
+ FIXME( "iface %p, callback %p, ref %p, type %#x stub!\n", iface, callback, ref, type );
+
+ if (!callback) return DIERR_INVALIDPARAM;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_GetEffectInfo( IDirectInputDevice8W *iface, DIEFFECTINFOW *info, REFGUID guid )
+{
+ FIXME( "iface %p, info %p, guid %s stub!\n", iface, info, debugstr_guid( guid ) );
+
+ if (!info) return E_POINTER;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_GetForceFeedbackState( IDirectInputDevice8W *iface, DWORD *out )
+{
+ FIXME( "iface %p, out %p stub!\n", iface, out );
+
+ if (!out) return E_POINTER;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_SendForceFeedbackCommand( IDirectInputDevice8W *iface, DWORD flags )
+{
+ FIXME( "iface %p, flags %x stub!\n", iface, flags );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_EnumCreatedEffectObjects( IDirectInputDevice8W *iface,
+ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK callback,
+ void *ref, DWORD flags )
+{
+ FIXME( "iface %p, callback %p, ref %p, flags %#x stub!\n", iface, callback, ref, flags );
+
+ if (!callback) return DIERR_INVALIDPARAM;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_BuildActionMap( IDirectInputDevice8W *iface, DIACTIONFORMATW *format,
+ const WCHAR *username, DWORD flags )
+{
+ FIXME( "iface %p, format %p, username %s, flags %#x stub!\n", iface, format, debugstr_w(username), flags );
+
+ if (!format) return DIERR_INVALIDPARAM;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_SetActionMap( IDirectInputDevice8W *iface, DIACTIONFORMATW *format,
+ const WCHAR *username, DWORD flags )
+{
+ struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface );
+
+ TRACE( "iface %p, format %p, username %s, flags %#x.\n", iface, format, debugstr_w(username), flags );
+
+ if (!format) return DIERR_INVALIDPARAM;
+
+ return _set_action_map( iface, format, username, flags, impl->base.data_format.wine_df );
+}
+
+static const IDirectInputDevice8WVtbl hid_joystick_vtbl =
+{
+ /*** IUnknown methods ***/
+ IDirectInputDevice2WImpl_QueryInterface,
+ IDirectInputDevice2WImpl_AddRef,
+ hid_joystick_Release,
+ /*** IDirectInputDevice methods ***/
+ hid_joystick_GetCapabilities,
+ hid_joystick_EnumObjects,
+ hid_joystick_GetProperty,
+ hid_joystick_SetProperty,
+ hid_joystick_Acquire,
+ hid_joystick_Unacquire,
+ hid_joystick_GetDeviceState,
+ IDirectInputDevice2WImpl_GetDeviceData,
+ IDirectInputDevice2WImpl_SetDataFormat,
+ IDirectInputDevice2WImpl_SetEventNotification,
+ IDirectInputDevice2WImpl_SetCooperativeLevel,
+ hid_joystick_GetObjectInfo,
+ hid_joystick_GetDeviceInfo,
+ IDirectInputDevice2WImpl_RunControlPanel,
+ IDirectInputDevice2WImpl_Initialize,
+ /*** IDirectInputDevice2 methods ***/
+ hid_joystick_CreateEffect,
+ hid_joystick_EnumEffects,
+ hid_joystick_GetEffectInfo,
+ hid_joystick_GetForceFeedbackState,
+ hid_joystick_SendForceFeedbackCommand,
+ hid_joystick_EnumCreatedEffectObjects,
+ IDirectInputDevice2WImpl_Escape,
+ IDirectInputDevice2WImpl_Poll,
+ IDirectInputDevice2WImpl_SendDeviceData,
+ /*** IDirectInputDevice7 methods ***/
+ IDirectInputDevice7WImpl_EnumEffectsInFile,
+ IDirectInputDevice7WImpl_WriteEffectToFile,
+ /*** IDirectInputDevice8 methods ***/
+ hid_joystick_BuildActionMap,
+ hid_joystick_SetActionMap,
+ IDirectInputDevice8WImpl_GetImageInfo,
+};
+
+static BOOL hid_joystick_device_try_open( const WCHAR *path, HANDLE *device, PHIDP_PREPARSED_DATA *preparsed,
+ HIDD_ATTRIBUTES *attrs, HIDP_CAPS *caps, DIDEVICEINSTANCEW *instance )
+{
+ PHIDP_PREPARSED_DATA preparsed_data = NULL;
+ HANDLE device_file;
+
+ device_file = CreateFileW( path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, 0 );
+ if (device_file == INVALID_HANDLE_VALUE) return FALSE;
+
+ if (!HidD_GetPreparsedData( device_file, &preparsed_data )) goto failed;
+ if (!HidD_GetAttributes( device_file, attrs )) goto failed;
+ if (HidP_GetCaps( preparsed_data, caps ) != HIDP_STATUS_SUCCESS) goto failed;
+
+ if (caps->UsagePage == HID_USAGE_PAGE_GAME) FIXME( "Unimplemented HID game usage page!\n" );
+ if (caps->UsagePage == HID_USAGE_PAGE_SIMULATION) FIXME( "Unimplemented HID simulation usage page!\n" );
+ if (caps->UsagePage != HID_USAGE_PAGE_GENERIC) goto failed;
+ if (caps->Usage != HID_USAGE_GENERIC_GAMEPAD && caps->Usage != HID_USAGE_GENERIC_JOYSTICK) goto failed;
+
+ if (!HidD_GetProductString( device_file, instance->tszInstanceName, MAX_PATH )) goto failed;
+ if (!HidD_GetProductString( device_file, instance->tszProductName, MAX_PATH )) goto failed;
+
+ *device = device_file;
+ *preparsed = preparsed_data;
+ return TRUE;
+
+failed:
+ CloseHandle( device_file );
+ HidD_FreePreparsedData( preparsed_data );
+ return FALSE;
+}
+
+static HRESULT hid_joystick_device_open( DWORD index, UINT32 handle, UINT32 vid_pid, WCHAR *device_path,
+ HANDLE *device, DWORD version, PHIDP_PREPARSED_DATA *preparsed,
+ HIDD_ATTRIBUTES *attrs, HIDP_CAPS *caps, DIDEVICEINSTANCEW *instance )
+{
+ static const WCHAR vid_pid_fmt_w[] = {'V','I','D','_','%','0','4','X','&','P','I','D','_','%','0','4','X',0};
+ char buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR)];
+ SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (void *)buffer;
+ SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)};
+ SP_DEVINFO_DATA devinfo = {sizeof(devinfo)};
+ WCHAR vid_pid_w[18] = {0};
+ UINT32 i = 0, hid_handle;
+ HDEVINFO set;
+ DWORD type;
+ GUID hid;
+
+ TRACE( "index %u, handle %u, vid_pid %d\n", index, handle, vid_pid );
+
+ HidD_GetHidGuid( &hid );
+ snprintfW( vid_pid_w, ARRAY_SIZE(vid_pid_w), vid_pid_fmt_w, vid_pid & 0xffff, vid_pid >> 16 );
+
+ set = SetupDiGetClassDevsW( &hid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT );
+ if (set == INVALID_HANDLE_VALUE) return DIERR_DEVICENOTREG;
+
+ *device = NULL;
+ *preparsed = NULL;
+ while (SetupDiEnumDeviceInterfaces( set, NULL, &hid, i++, &iface ))
+ {
+ detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
+ if (!SetupDiGetDeviceInterfaceDetailW( set, &iface, detail, sizeof(buffer), NULL, &devinfo ))
+ continue;
+ if (!SetupDiGetDevicePropertyW( set, &devinfo, &DEVPROPKEY_HID_HANDLE, &type,
+ (BYTE *)&hid_handle, sizeof(hid_handle), NULL, 0 ) ||
+ type != DEVPROP_TYPE_UINT32)
+ continue;
+ if (!hid_joystick_device_try_open( detail->DevicePath, device, preparsed, attrs, caps, instance ))
+ continue;
+
+ if (!handle && !vid_pid && !index--) break;
+ if (handle && handle == hid_handle) break;
+ if (vid_pid && strstrW( detail->DevicePath, vid_pid_w )) break;
+
+ CloseHandle( *device );
+ HidD_FreePreparsedData( *preparsed );
+ *device = NULL;
+ *preparsed = NULL;
+ }
+
+ SetupDiDestroyDeviceInfoList( set );
+ if (!*device || !*preparsed) return DIERR_DEVICENOTREG;
+
+ lstrcpynW( device_path, detail->DevicePath, MAX_PATH );
+ instance->guidInstance = hid_joystick_guid;
+ instance->guidInstance.Data3 = hid_handle;
+ instance->guidProduct = DInput_PIDVID_Product_GUID;
+ instance->guidProduct.Data1 = MAKELONG( attrs->VendorID, attrs->ProductID );
+ instance->dwDevType = get_device_type( version, caps->Usage != HID_USAGE_GENERIC_GAMEPAD ) | DIDEVTYPE_HID;
+ instance->guidFFDriver = GUID_NULL;
+ instance->wUsagePage = caps->UsagePage;
+ instance->wUsage = caps->Usage;
+ return DI_OK;
+}
+
+static HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance,
+ DWORD version, int index )
+{
+ HIDD_ATTRIBUTES attrs = {sizeof(attrs)};
+ PHIDP_PREPARSED_DATA preparsed;
+ WCHAR device_path[MAX_PATH];
+ HIDP_CAPS caps;
+ HANDLE device;
+ HRESULT hr;
+
+ TRACE( "type %x, flags %#x, instance %p, version %04x, index %d\n", type, flags, instance, version, index );
+
+ hr = hid_joystick_device_open( index, 0, 0, device_path, &device, version,
+ &preparsed, &attrs, &caps, instance );
+ if (hr != DI_OK) return hr;
+
+ HidD_FreePreparsedData( preparsed );
+ CloseHandle( device );
+
+ if (instance->dwSize != sizeof(DIDEVICEINSTANCEW))
+ return S_FALSE;
+ if (version < 0x0800 && type != DIDEVTYPE_JOYSTICK)
+ return S_FALSE;
+ if (version >= 0x0800 && type != DI8DEVCLASS_ALL && type != DI8DEVCLASS_GAMECTRL)
+ return S_FALSE;
+
+ if (device_disabled_registry( "HID", TRUE ))
+ return DIERR_DEVICENOTREG;
+
+ TRACE( "Found device %s, usage %04x:%04x, product %s, instance %s, name %s\n", debugstr_w(device_path),
+ instance->wUsagePage, instance->wUsage, debugstr_guid( &instance->guidProduct ),
+ debugstr_guid( &instance->guidInstance ), debugstr_w(instance->tszInstanceName) );
+
+ return DI_OK;
+}
+
+static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, REFGUID guid, IDirectInputDevice8W **out )
+{
+ DIDEVICEINSTANCEW instance = {sizeof(instance)};
+ GUID inst_guid = *guid, prod_guid = *guid;
+ DWORD size = sizeof(struct hid_joystick);
+ HIDD_ATTRIBUTES attrs = {sizeof(attrs)};
+ struct hid_joystick *impl = NULL;
+ PHIDP_PREPARSED_DATA preparsed;
+ UINT32 handle = 0, vid_pid = 0;
+ DIDATAFORMAT *format = NULL;
+ WCHAR device_path[MAX_PATH];
+ HIDP_CAPS caps;
+ HANDLE device;
+ HRESULT hr;
+
+ TRACE( "dinput %p, guid %s, out %p\n", dinput, debugstr_guid( guid ), out );
+
+ *out = NULL;
+
+ inst_guid.Data3 = hid_joystick_guid.Data3;
+ prod_guid.Data1 = DInput_PIDVID_Product_GUID.Data1;
+ if (IsEqualGUID( &hid_joystick_guid, &inst_guid )) handle = guid->Data3;
+ else if (IsEqualGUID( &DInput_PIDVID_Product_GUID, &prod_guid )) vid_pid = guid->Data1;
+ else return DIERR_DEVICENOTREG;
+
+ hr = hid_joystick_device_open( 0, handle, vid_pid, device_path, &device, dinput->dwVersion,
+ &preparsed, &attrs, &caps, &instance );
+ if (hr != DI_OK) return hr;
+
+ hr = direct_input_device_alloc( size, &hid_joystick_vtbl, guid, dinput, (void **)&impl );
+ if (FAILED(hr)) goto failed;
+
+ impl->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": hid_joystick.base.crit");
+ impl->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND;
+
+ impl->device = device;
+ impl->preparsed = preparsed;
+
+ if (!(format = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*format) ))) goto failed;
+ impl->base.data_format.wine_df = format;
+
+ TRACE( "Created %p\n", impl );
+
+ *out = &impl->base.IDirectInputDevice8W_iface;
+ return DI_OK;
+
+failed:
+ HeapFree( GetProcessHeap(), 0, format );
+ HeapFree( GetProcessHeap(), 0, impl );
+ HidD_FreePreparsedData( preparsed );
+ CloseHandle( device );
+ return hr;
+}
+
+const struct dinput_device joystick_hid_device =
+{
+ "Wine HID joystick driver",
+ hid_joystick_enum_device,
+ hid_joystick_create_device,
+};
diff --git a/dlls/dinput/joystick_linux.c b/dlls/dinput/joystick_linux.c
index 3215978c995..312ef3d9c42 100644
--- a/dlls/dinput/joystick_linux.c
+++ b/dlls/dinput/joystick_linux.c
@@ -175,7 +175,7 @@ static INT find_joystick_devices(void)
/* Append driver name */
strcat(joydev.name, JOYDEVDRIVER);
- if (device_disabled_registry(joydev.name)) {
+ if (device_disabled_registry(joydev.name, FALSE)) {
close(fd);
continue;
}
diff --git a/dlls/dinput/joystick_linuxinput.c b/dlls/dinput/joystick_linuxinput.c
index 2b970271ec3..558c8cc19e5 100644
--- a/dlls/dinput/joystick_linuxinput.c
+++ b/dlls/dinput/joystick_linuxinput.c
@@ -264,7 +264,7 @@ static void find_joydevs(void)
else
joydev.name = joydev.device;
- if (device_disabled_registry(joydev.name)) {
+ if (device_disabled_registry(joydev.name, FALSE)) {
close(fd);
HeapFree(GetProcessHeap(), 0, joydev.name);
if (joydev.name != joydev.device)
diff --git a/dlls/dinput/joystick_private.h b/dlls/dinput/joystick_private.h
index 874bf3e69a7..9cc30605234 100644
--- a/dlls/dinput/joystick_private.h
+++ b/dlls/dinput/joystick_private.h
@@ -57,7 +57,7 @@ HRESULT setup_dinput_options(JoystickGenericImpl *This, const int *default_axis_
DWORD joystick_map_pov(const POINTL *p) DECLSPEC_HIDDEN;
-BOOL device_disabled_registry(const char* name) DECLSPEC_HIDDEN;
+BOOL device_disabled_registry(const char* name, BOOL disable) DECLSPEC_HIDDEN;
ULONG WINAPI JoystickWGenericImpl_Release(LPDIRECTINPUTDEVICE8W iface);
diff --git a/dlls/dinput8/Makefile.in b/dlls/dinput8/Makefile.in
index 35b3bfb75f5..5032c7689bc 100644
--- a/dlls/dinput8/Makefile.in
+++ b/dlls/dinput8/Makefile.in
@@ -1,6 +1,6 @@
MODULE = dinput8.dll
IMPORTLIB = dinput8
-IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32
+IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi
EXTRADEFS = -DDIRECTINPUT_VERSION=0x0800
EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS)
PARENTSRC = ../dinput
@@ -13,6 +13,7 @@ C_SRCS = \
dinput_main.c \
effect_linuxinput.c \
joystick.c \
+ joystick_hid.c \
joystick_linux.c \
joystick_linuxinput.c \
joystick_osx.c \
--
2.32.0
June 30, 2021
Re: [PATCH v2 5/5] ntoskrnl.exe: Implement Ke(Initialize|Insert|Remove)DeviceQueue.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=93335
Your paranoid android.
=== debiant2 (32 bit Arabic:Morocco report) ===
ntoskrnl.exe:
ntoskrnl: Timeout
June 30, 2021
Re: [PATCH v10 [rebased] 2/4] vulkan-1/tests: Add tests for VK_KHR_external_memory_win32.
by Francois Gouget
On Fri, 25 Jun 2021, Derek Lesho wrote:
> Looks like Marvin didn't pick up my unorthodox naming scheme for this resend,
> and applied each patch individually, sorry about that.
Right: I think it's the early closing bracket that confused it. It
probably considered: "[PATCH v10 [rebased]" which does not include part
numbers.
--
Francois Gouget <fgouget(a)codeweavers.com>
June 30, 2021
[PATCH v2 5/5] ntoskrnl.exe: Implement Ke(Initialize|Insert|Remove)DeviceQueue.
by Rémi Bernon
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 6 +-
dlls/ntoskrnl.exe/sync.c | 47 ++++++++++
dlls/ntoskrnl.exe/tests/driver.c | 128 ++++++++++++++++++++++++++++
include/ddk/wdm.h | 4 +
4 files changed, 182 insertions(+), 3 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
index 9bea60817b3..ea6d9e9fc95 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
@@ -567,7 +567,7 @@
@ stub KeI386SetGdtSelector
@ stub KeIcacheFlushCount
@ stdcall KeInitializeApc(ptr ptr long ptr ptr ptr long ptr)
-@ stub KeInitializeDeviceQueue
+@ stdcall KeInitializeDeviceQueue(ptr)
@ stdcall KeInitializeDpc(ptr ptr ptr)
@ stdcall KeInitializeEvent(ptr long long)
@ stub KeInitializeInterrupt
@@ -579,7 +579,7 @@
@ stdcall KeInitializeTimer(ptr)
@ stdcall KeInitializeTimerEx(ptr long)
@ stub KeInsertByKeyDeviceQueue
-@ stub KeInsertDeviceQueue
+@ stdcall KeInsertDeviceQueue(ptr ptr)
@ stub KeInsertHeadQueue
@ stdcall KeInsertQueue(ptr ptr)
@ stub KeInsertQueueApc
@@ -617,7 +617,7 @@
@ stdcall KeReleaseSpinLockFromDpcLevel(ptr)
@ stub KeRemoveByKeyDeviceQueue
@ stub KeRemoveByKeyDeviceQueueIfBusy
-@ stub KeRemoveDeviceQueue
+@ stdcall KeRemoveDeviceQueue(ptr)
@ stub KeRemoveEntryDeviceQueue
@ stub KeRemoveQueue
@ stub KeRemoveQueueDpc
diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c
index 2751032f13d..13e2d3e7559 100644
--- a/dlls/ntoskrnl.exe/sync.c
+++ b/dlls/ntoskrnl.exe/sync.c
@@ -1362,3 +1362,50 @@ BOOLEAN WINAPI KeSetTimer(KTIMER *timer, LARGE_INTEGER duetime, KDPC *dpc)
return KeSetTimerEx(timer, duetime, 0, dpc);
}
+
+void WINAPI KeInitializeDeviceQueue( KDEVICE_QUEUE *queue )
+{
+ TRACE( "queue %p.\n", queue );
+
+ KeInitializeSpinLock( &queue->Lock );
+ InitializeListHead( &queue->DeviceListHead );
+ queue->Busy = FALSE;
+ queue->Type = IO_TYPE_DEVICE_QUEUE;
+ queue->Size = sizeof(*queue);
+}
+
+BOOLEAN WINAPI KeInsertDeviceQueue( KDEVICE_QUEUE *queue, KDEVICE_QUEUE_ENTRY *entry )
+{
+ BOOL insert;
+ KIRQL irql;
+
+ TRACE( "queue %p, entry %p.\n", queue, entry );
+
+ KeAcquireSpinLock( &queue->Lock, &irql );
+ insert = entry->Inserted = queue->Busy;
+ if (insert) InsertTailList( &queue->DeviceListHead, &entry->DeviceListEntry );
+ queue->Busy = TRUE;
+ KeReleaseSpinLock( &queue->Lock, irql );
+
+ return insert;
+}
+
+KDEVICE_QUEUE_ENTRY *WINAPI KeRemoveDeviceQueue( KDEVICE_QUEUE *queue )
+{
+ KDEVICE_QUEUE_ENTRY *entry = NULL;
+ KIRQL irql;
+
+ TRACE( "queue %p.\n", queue );
+
+ KeAcquireSpinLock( &queue->Lock, &irql );
+ if (IsListEmpty( &queue->DeviceListHead )) queue->Busy = FALSE;
+ else
+ {
+ entry = CONTAINING_RECORD( RemoveHeadList( &queue->DeviceListHead ),
+ KDEVICE_QUEUE_ENTRY, DeviceListEntry );
+ entry->Inserted = FALSE;
+ }
+ KeReleaseSpinLock( &queue->Lock, irql );
+
+ return entry;
+}
diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c
index 918b4632c40..94139b4b654 100644
--- a/dlls/ntoskrnl.exe/tests/driver.c
+++ b/dlls/ntoskrnl.exe/tests/driver.c
@@ -141,6 +141,133 @@ static void test_irp_struct(IRP *irp, DEVICE_OBJECT *device)
IoFreeIrp(irp);
}
+static int cancel_queue_cnt;
+
+static void WINAPI cancel_queued_irp(DEVICE_OBJECT *device, IRP *irp)
+{
+ IoReleaseCancelSpinLock(irp->CancelIrql);
+ ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
+ ok(!irp->CancelRoutine, "CancelRoutine = %p\n", irp->CancelRoutine);
+ irp->IoStatus.Status = STATUS_CANCELLED;
+ irp->IoStatus.Information = 0;
+ cancel_queue_cnt++;
+}
+
+static void test_queue(void)
+{
+ KDEVICE_QUEUE_ENTRY *entry;
+ KDEVICE_QUEUE queue;
+ BOOLEAN ret;
+ KIRQL irql;
+ IRP *irp;
+
+ irp = IoAllocateIrp(1, FALSE);
+
+ memset(&queue, 0xcd, sizeof(queue));
+ KeInitializeDeviceQueue(&queue);
+ ok(!queue.Busy, "unexpected Busy state\n");
+ ok(queue.Size == sizeof(queue), "unexpected Size %x\n", queue.Size);
+ ok(queue.Type == IO_TYPE_DEVICE_QUEUE, "unexpected Type %x\n", queue.Type);
+ ok(IsListEmpty(&queue.DeviceListHead), "expected empty queue list\n");
+
+ ret = KeInsertDeviceQueue(&queue, &irp->Tail.Overlay.DeviceQueueEntry);
+ ok(!ret, "expected KeInsertDeviceQueue to not insert IRP\n");
+ ok(queue.Busy, "expected Busy state\n");
+ ok(IsListEmpty(&queue.DeviceListHead), "expected empty queue list\n");
+ ok(!irp->Tail.Overlay.DeviceQueueEntry.Inserted, "expected not inserted\n");
+
+ entry = KeRemoveDeviceQueue(&queue);
+ ok(!entry, "expected KeRemoveDeviceQueue to return NULL\n");
+ ok(!queue.Busy, "unexpected Busy state\n");
+ ok(IsListEmpty(&queue.DeviceListHead), "expected empty queue list\n");
+ ok(!irp->Tail.Overlay.DeviceQueueEntry.Inserted, "expected not inserted\n");
+
+ ret = KeInsertDeviceQueue(&queue, &irp->Tail.Overlay.DeviceQueueEntry);
+ ok(!ret, "expected KeInsertDeviceQueue to not insert IRP\n");
+ ok(queue.Busy, "expected Busy state\n");
+ ok(IsListEmpty(&queue.DeviceListHead), "expected empty queue list\n");
+ ok(!irp->Tail.Overlay.DeviceQueueEntry.Inserted, "expected not inserted\n");
+
+ ret = KeInsertDeviceQueue(&queue, &irp->Tail.Overlay.DeviceQueueEntry);
+ ok(ret, "expected KeInsertDeviceQueue to insert IRP\n");
+ ok(queue.Busy, "expected Busy state\n");
+ ok(!IsListEmpty(&queue.DeviceListHead), "unexpected empty queue list\n");
+ ok(irp->Tail.Overlay.DeviceQueueEntry.Inserted, "expected inserted\n");
+ ok(queue.DeviceListHead.Flink == &irp->Tail.Overlay.DeviceQueueEntry.DeviceListEntry,
+ "unexpected queue list head\n");
+
+ entry = KeRemoveDeviceQueue(&queue);
+ ok(entry != NULL, "expected KeRemoveDeviceQueue to return non-NULL\n");
+ ok(CONTAINING_RECORD(entry, IRP, Tail.Overlay.DeviceQueueEntry) == irp,
+ "unexpected IRP returned\n");
+ ok(queue.Busy, "expected Busy state\n");
+ ok(IsListEmpty(&queue.DeviceListHead), "expected empty queue list\n");
+ ok(!irp->Tail.Overlay.DeviceQueueEntry.Inserted, "expected not inserted\n");
+
+ entry = KeRemoveDeviceQueue(&queue);
+ ok(entry == NULL, "expected KeRemoveDeviceQueue to return NULL\n");
+ ok(!queue.Busy, "unexpected Busy state\n");
+ ok(IsListEmpty(&queue.DeviceListHead), "expected empty queue list\n");
+ ok(!irp->Tail.Overlay.DeviceQueueEntry.Inserted, "expected not inserted\n");
+
+ IoCancelIrp(irp);
+ ok(irp->Cancel, "unexpected non-cancelled state\n");
+
+ ret = KeInsertDeviceQueue(&queue, &irp->Tail.Overlay.DeviceQueueEntry);
+ ok(!ret, "expected KeInsertDeviceQueue to not insert IRP\n");
+ ok(queue.Busy, "expected Busy state\n");
+ ok(IsListEmpty(&queue.DeviceListHead), "expected empty queue list\n");
+ ok(!irp->Tail.Overlay.DeviceQueueEntry.Inserted, "expected inserted\n");
+ ret = KeInsertDeviceQueue(&queue, &irp->Tail.Overlay.DeviceQueueEntry);
+ ok(ret, "expected KeInsertDeviceQueue to insert IRP\n");
+ ok(queue.Busy, "expected Busy state\n");
+ ok(!IsListEmpty(&queue.DeviceListHead), "unexpected empty queue list\n");
+ ok(irp->Tail.Overlay.DeviceQueueEntry.Inserted, "expected inserted\n");
+ ok(queue.DeviceListHead.Flink == &irp->Tail.Overlay.DeviceQueueEntry.DeviceListEntry,
+ "unexpected queue list head\n");
+
+ entry = KeRemoveDeviceQueue(&queue);
+ ok(entry != NULL, "expected KeRemoveDeviceQueue to return non-NULL\n");
+ ok(CONTAINING_RECORD(entry, IRP, Tail.Overlay.DeviceQueueEntry) == irp,
+ "unexpected IRP returned\n");
+ ok(queue.Busy, "expected Busy state\n");
+ ok(IsListEmpty(&queue.DeviceListHead), "expected empty queue list\n");
+ ok(!irp->Tail.Overlay.DeviceQueueEntry.Inserted, "expected inserted\n");
+ ok(irp->Cancel, "unexpected non-cancelled state\n");
+
+ IoFreeIrp(irp);
+
+ irp = IoAllocateIrp(1, FALSE);
+
+ IoAcquireCancelSpinLock(&irql);
+ IoSetCancelRoutine(irp, cancel_queued_irp);
+ IoReleaseCancelSpinLock(irql);
+
+ ret = KeInsertDeviceQueue(&queue, &irp->Tail.Overlay.DeviceQueueEntry);
+ ok(ret, "expected KeInsertDeviceQueue to insert IRP\n");
+ ok(queue.Busy, "expected Busy state\n");
+ ok(!IsListEmpty(&queue.DeviceListHead), "expected empty queue list\n");
+ ok(irp->Tail.Overlay.DeviceQueueEntry.Inserted, "expected inserted\n");
+ ok(queue.DeviceListHead.Flink == &irp->Tail.Overlay.DeviceQueueEntry.DeviceListEntry,
+ "unexpected queue list head\n");
+
+ IoCancelIrp(irp);
+ ok(irp->Cancel, "unexpected non-cancelled state\n");
+ ok(cancel_queue_cnt, "expected cancel routine to be called\n");
+
+ entry = KeRemoveDeviceQueue(&queue);
+ ok(entry != NULL, "expected KeRemoveDeviceQueue to return non-NULL\n");
+ ok(CONTAINING_RECORD(entry, IRP, Tail.Overlay.DeviceQueueEntry) == irp,
+ "unexpected IRP returned\n");
+ ok(irp->Cancel, "unexpected non-cancelled state\n");
+ ok(cancel_queue_cnt, "expected cancel routine to be called\n");
+ ok(queue.Busy, "expected Busy state\n");
+ ok(IsListEmpty(&queue.DeviceListHead), "expected empty queue list\n");
+ ok(!irp->Tail.Overlay.DeviceQueueEntry.Inserted, "expected inserted\n");
+
+ IoFreeIrp(irp);
+}
+
static void test_mdl_map(void)
{
char buffer[20] = "test buffer";
@@ -2128,6 +2255,7 @@ static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *st
test_init_funcs();
test_load_driver();
test_sync();
+ test_queue();
test_version();
test_stack_callout();
test_lookaside_list();
diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h
index ca369c22d09..2c2bbf44632 100644
--- a/include/ddk/wdm.h
+++ b/include/ddk/wdm.h
@@ -397,6 +397,7 @@ typedef struct _WAIT_CONTEXT_BLOCK {
#define IO_TYPE_ERROR_LOG 0x0b
#define IO_TYPE_ERROR_MESSAGE 0x0c
#define IO_TYPE_DEVICE_OBJECT_EXTENSION 0x0d
+#define IO_TYPE_DEVICE_QUEUE 0x14
typedef struct _DEVICE_OBJECT {
CSHORT Type;
@@ -1750,6 +1751,7 @@ void WINAPI KeEnterCriticalRegion(void);
void WINAPI KeGenericCallDpc(PKDEFERRED_ROUTINE,PVOID);
ULONG WINAPI KeGetCurrentProcessorNumber(void);
PKTHREAD WINAPI KeGetCurrentThread(void);
+void WINAPI KeInitializeDeviceQueue(KDEVICE_QUEUE*);
void WINAPI KeInitializeDpc(KDPC*,PKDEFERRED_ROUTINE,void*);
void WINAPI KeInitializeEvent(PRKEVENT,EVENT_TYPE,BOOLEAN);
void WINAPI KeInitializeMutex(PRKMUTEX,ULONG);
@@ -1760,6 +1762,7 @@ static FORCEINLINE void WINAPI KeInitializeSpinLock( KSPIN_LOCK *lock )
}
void WINAPI KeInitializeTimerEx(PKTIMER,TIMER_TYPE);
void WINAPI KeInitializeTimer(KTIMER*);
+BOOLEAN WINAPI KeInsertDeviceQueue(KDEVICE_QUEUE*,KDEVICE_QUEUE_ENTRY*);
void WINAPI KeLeaveCriticalRegion(void);
ULONG WINAPI KeQueryActiveProcessorCountEx(USHORT);
KAFFINITY WINAPI KeQueryActiveProcessors(void);
@@ -1772,6 +1775,7 @@ LONG WINAPI KeReleaseMutex(PRKMUTEX,BOOLEAN);
LONG WINAPI KeReleaseSemaphore(PRKSEMAPHORE,KPRIORITY,LONG,BOOLEAN);
void WINAPI KeReleaseSpinLock(KSPIN_LOCK*,KIRQL);
void WINAPI KeReleaseSpinLockFromDpcLevel(KSPIN_LOCK*);
+KDEVICE_QUEUE_ENTRY * WINAPI KeRemoveDeviceQueue(KDEVICE_QUEUE*);
LONG WINAPI KeResetEvent(PRKEVENT);
void WINAPI KeRevertToUserAffinityThread(void);
void WINAPI KeRevertToUserAffinityThreadEx(KAFFINITY affinity);
--
2.32.0
June 30, 2021