From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/dbus.c | 99 +++++++++++++++++++++++++++++++++ dlls/winebth.sys/winebth.c | 48 ++++++++++++++++ dlls/winebth.sys/winebth_priv.h | 33 +++++++++++ include/Makefile.in | 1 + include/ddk/bthguid.h | 37 ++++++++++++ 5 files changed, 218 insertions(+) create mode 100644 include/ddk/bthguid.h
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index 6c74c377d5c..2c7d7208b34 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -148,6 +148,97 @@ static NTSTATUS bluez_get_objects_async( DBusConnection *connection, DBusPending DBUS_DICT_ENTRY_END_CHAR_AS_STRING \ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ +static void parse_mac_address( const char *addr_str, BYTE dest[6] ) +{ + int addr[6], i; + + sscanf( addr_str, "%x:%x:%x:%x:%x:%x", &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], + &addr[5] ); + for (i = 0 ; i < 6; i++) + dest[i] = addr[i]; +} + +static void bluez_radio_prop_from_dict_entry( const char *prop_name, DBusMessageIter *variant, + struct winebluetooth_radio_properties *props, + winebluetooth_radio_props_mask_t *props_mask, + winebluetooth_radio_props_mask_t wanted_props_mask ) +{ + TRACE_(dbus)( "(%s, %p, %p, %p, %#x)\n", debugstr_a( prop_name ), variant, props, props_mask, + wanted_props_mask ); + + if (wanted_props_mask & WINEBLUETOOTH_RADIO_PROPERTY_ADDRESS && + !strcmp( prop_name, "Address" ) && + p_dbus_message_iter_get_arg_type( variant ) == DBUS_TYPE_STRING) + { + const char *addr_str; + p_dbus_message_iter_get_basic( variant, &addr_str ); + parse_mac_address( addr_str, props->address.rgBytes ); + *props_mask |= WINEBLUETOOTH_RADIO_PROPERTY_ADDRESS; + } + else if (wanted_props_mask & WINEBLUETOOTH_RADIO_PROPERTY_CLASS && + !strcmp( prop_name, "Class" ) && + p_dbus_message_iter_get_arg_type( variant ) == DBUS_TYPE_UINT32) + { + dbus_uint32_t class; + p_dbus_message_iter_get_basic( variant, &class ); + props->class = class; + *props_mask |= WINEBLUETOOTH_RADIO_PROPERTY_CLASS; + } + else if (wanted_props_mask & WINEBLUETOOTH_RADIO_PROPERTY_MANUFACTURER && + !strcmp( prop_name, "Manufacturer" ) && + p_dbus_message_iter_get_arg_type( variant ) == DBUS_TYPE_UINT16) + { + dbus_uint16_t manufacturer; + p_dbus_message_iter_get_basic( variant, &manufacturer ); + props->manufacturer = manufacturer; + *props_mask |= WINEBLUETOOTH_RADIO_PROPERTY_MANUFACTURER; + } + else if (wanted_props_mask & WINEBLUETOOTH_RADIO_PROPERTY_CONNECTABLE && + !strcmp( prop_name, "Connectable" ) && + p_dbus_message_iter_get_arg_type( variant ) == DBUS_TYPE_BOOLEAN) + { + dbus_bool_t connectable; + p_dbus_message_iter_get_basic( variant, &connectable ); + props->connectable = connectable != 0; + *props_mask |= WINEBLUETOOTH_RADIO_PROPERTY_CONNECTABLE; + } + else if (wanted_props_mask & WINEBLUETOOTH_RADIO_PROPERTY_DISCOVERABLE && + !strcmp( prop_name, "Discoverable" ) && + p_dbus_message_iter_get_arg_type( variant ) == DBUS_TYPE_BOOLEAN) + { + dbus_bool_t discoverable; + p_dbus_message_iter_get_basic( variant, &discoverable ); + props->discoverable = discoverable != 0; + *props_mask |= WINEBLUETOOTH_RADIO_PROPERTY_DISCOVERABLE; + } + else if (wanted_props_mask & WINEBLUETOOTH_RADIO_PROPERTY_DISCOVERING && + !strcmp( prop_name, "Discovering") && + p_dbus_message_iter_get_arg_type( variant ) == DBUS_TYPE_BOOLEAN) + { + dbus_bool_t discovering; + p_dbus_message_iter_get_basic( variant, &discovering ); + props->discovering = discovering != 0; + *props_mask |= WINEBLUETOOTH_RADIO_PROPERTY_DISCOVERING; + } + else if (wanted_props_mask & WINEBLUETOOTH_RADIO_PROPERTY_PAIRABLE && + !strcmp( prop_name, "Pairable" ) && + p_dbus_message_iter_get_arg_type( variant ) == DBUS_TYPE_BOOLEAN) + { + dbus_bool_t pairable; + p_dbus_message_iter_get_basic( variant, &pairable ); + props->pairable = pairable != 0; + *props_mask |= WINEBLUETOOTH_RADIO_PROPERTY_PAIRABLE; + } + else if (wanted_props_mask & WINEBLUETOOTH_RADIO_PROPERTY_VERSION && + !strcmp( prop_name, "Version" ) && + p_dbus_message_iter_get_arg_type( variant ) == DBUS_TYPE_BYTE) + { + p_dbus_message_iter_get_basic( variant, &props->version ); + *props_mask |= WINEBLUETOOTH_RADIO_PROPERTY_VERSION; + } +} + struct bluez_watcher_ctx { void *init_device_list_call; @@ -253,6 +344,8 @@ static NTSTATUS bluez_build_initial_device_lists( DBusMessage *reply, struct lis { if (!strcmp( iface, BLUEZ_INTERFACE_ADAPTER )) { + const char *prop_name; + DBusMessageIter variant; struct bluez_init_entry *init_device = calloc( 1, sizeof( *init_device ) ); struct unix_name *radio_name;
@@ -268,6 +361,12 @@ static NTSTATUS bluez_build_initial_device_lists( DBusMessage *reply, struct lis status = STATUS_NO_MEMORY; goto done; } + while ((prop_name = bluez_next_dict_entry( &prop_iter, &variant ))) + { + bluez_radio_prop_from_dict_entry( + prop_name, &variant, &init_device->object.radio.props, + &init_device->object.radio.props_mask, WINEBLUETOOTH_RADIO_ALL_PROPERTIES ); + } init_device->object.radio.radio.handle = (UINT_PTR)radio_name; list_add_tail( adapter_list, &init_device->entry ); TRACE( "Found BlueZ org.bluez.Adapter1 object %s: %p\n", diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index ca8b1b4dadb..e9c0ecdf870 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -27,11 +27,13 @@ #include <windef.h> #include <winbase.h> #include <winternl.h> +#include <winnls.h> #include <initguid.h> #include <devpkey.h> #include <bthdef.h> #include <winioctl.h> #include <ddk/wdm.h> +#include <ddk/bthguid.h>
#include <wine/debug.h> #include <wine/list.h> @@ -66,6 +68,9 @@ struct bluetooth_radio BOOL removed;
DEVICE_OBJECT *device_obj; + CRITICAL_SECTION props_cs; + winebluetooth_radio_props_mask_t props_mask; /* Guarded by props_cs */ + struct winebluetooth_radio_properties props; /* Guarded by props_cs */ winebluetooth_radio_t radio; WCHAR *hw_name; UNICODE_STRING bthport_symlink_name; @@ -175,6 +180,10 @@ static void add_bluetooth_radio( struct winebluetooth_watcher_event_radio_added device->radio = event.radio; device->removed = FALSE; device->hw_name = hw_name; + device->props = event.props; + device->props_mask = event.props_mask; + + InitializeCriticalSection( &device->props_cs );
EnterCriticalSection( &device_list_cs ); list_add_tail( &device_list, &device->entry ); @@ -329,6 +338,41 @@ static NTSTATUS query_id(const struct bluetooth_radio *ext, IRP *irp, BUS_QUERY_ return STATUS_SUCCESS; }
+/* Caller must hold props_cs */ +static void bluetooth_radio_set_properties( DEVICE_OBJECT *obj, + winebluetooth_radio_props_mask_t mask, + struct winebluetooth_radio_properties *props ) +{ + if (mask & WINEBLUETOOTH_RADIO_PROPERTY_ADDRESS) + { + union + { + UINT64 uint; + BYTE addr[8]; + } radio_addr = {0}; + memcpy( &radio_addr.addr[2], props->address.rgBytes, sizeof( props->address.rgBytes ) ); + IoSetDevicePropertyData( obj, &DEVPKEY_BluetoothRadio_Address, LOCALE_NEUTRAL, 0, + DEVPROP_TYPE_UINT64, sizeof( radio_addr ), &radio_addr ); + } + if (mask & WINEBLUETOOTH_RADIO_PROPERTY_MANUFACTURER) + { + UINT16 manufacturer = props->manufacturer; + IoSetDevicePropertyData( obj, &DEVPKEY_BluetoothRadio_Manufacturer, LOCALE_NEUTRAL, + 0, DEVPROP_TYPE_UINT16, sizeof( manufacturer ), &manufacturer ); + } + if (mask & WINEBLUETOOTH_RADIO_PROPERTY_NAME) + { + WCHAR buf[BLUETOOTH_MAX_NAME_SIZE * sizeof(WCHAR)]; + INT ret; + + if ((ret = MultiByteToWideChar( CP_ACP, 0, props->name, -1, buf, BLUETOOTH_MAX_NAME_SIZE))) + IoSetDevicePropertyData( obj, &DEVPKEY_NAME, LOCALE_NEUTRAL, 0, DEVPROP_TYPE_STRING, ret, buf ); + } + if (mask & WINEBLUETOOTH_RADIO_PROPERTY_VERSION) + IoSetDevicePropertyData( obj, &DEVPKEY_BluetoothRadio_LMPVersion, LOCALE_NEUTRAL, 0, DEVPROP_TYPE_BYTE, + sizeof( props->version ), &props->version ); +} + static NTSTATUS WINAPI pdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp ) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); @@ -351,6 +395,10 @@ static NTSTATUS WINAPI pdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp ) break; } case IRP_MN_START_DEVICE: + EnterCriticalSection( &device->props_cs ); + bluetooth_radio_set_properties( device_obj, device->props_mask, &device->props ); + LeaveCriticalSection( &device->props_cs ); + if (IoRegisterDeviceInterface( device_obj, &GUID_BTHPORT_DEVICE_INTERFACE, NULL, &device->bthport_symlink_name ) == STATUS_SUCCESS) IoSetDeviceInterfaceState( &device->bthport_symlink_name, TRUE ); diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index d047dcbc8e8..acb0db9532d 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -100,6 +100,37 @@ typedef struct UINT_PTR handle; } winebluetooth_radio_t;
+typedef UINT16 winebluetooth_radio_props_mask_t; + +#define WINEBLUETOOTH_RADIO_PROPERTY_NAME (1) +#define WINEBLUETOOTH_RADIO_PROPERTY_ADDRESS (1 << 2) +#define WINEBLUETOOTH_RADIO_PROPERTY_DISCOVERABLE (1 << 3) +#define WINEBLUETOOTH_RADIO_PROPERTY_CONNECTABLE (1 << 4) +#define WINEBLUETOOTH_RADIO_PROPERTY_CLASS (1 << 5) +#define WINEBLUETOOTH_RADIO_PROPERTY_MANUFACTURER (1 << 6) +#define WINEBLUETOOTH_RADIO_PROPERTY_VERSION (1 << 7) +#define WINEBLUETOOTH_RADIO_PROPERTY_DISCOVERING (1 << 8) +#define WINEBLUETOOTH_RADIO_PROPERTY_PAIRABLE (1 << 9) + +#define WINEBLUETOOTH_RADIO_ALL_PROPERTIES \ + (WINEBLUETOOTH_RADIO_PROPERTY_NAME | WINEBLUETOOTH_RADIO_PROPERTY_ADDRESS | \ + WINEBLUETOOTH_RADIO_PROPERTY_DISCOVERABLE | WINEBLUETOOTH_RADIO_PROPERTY_CONNECTABLE | \ + WINEBLUETOOTH_RADIO_PROPERTY_CLASS | WINEBLUETOOTH_RADIO_PROPERTY_MANUFACTURER | \ + WINEBLUETOOTH_RADIO_PROPERTY_VERSION | WINEBLUETOOTH_RADIO_PROPERTY_DISCOVERING | \ + WINEBLUETOOTH_RADIO_PROPERTY_PAIRABLE) + +struct winebluetooth_radio_properties +{ + BOOL discoverable; + BOOL connectable; + BOOL discovering; + BOOL pairable; + BLUETOOTH_ADDRESS address; + CHAR name[BLUETOOTH_MAX_NAME_SIZE]; + ULONG class; + USHORT manufacturer; + BYTE version; +};
NTSTATUS winebluetooth_radio_get_unique_name( winebluetooth_radio_t radio, char *name, SIZE_T *size ); @@ -112,6 +143,8 @@ enum winebluetooth_watcher_event_type
struct winebluetooth_watcher_event_radio_added { + winebluetooth_radio_props_mask_t props_mask; + struct winebluetooth_radio_properties props; winebluetooth_radio_t radio; };
diff --git a/include/Makefile.in b/include/Makefile.in index f3e915d3959..0712cfb2793 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -193,6 +193,7 @@ SOURCES = \ dde.h \ dde.rh \ ddeml.h \ + ddk/bthguid.h \ ddk/compstui.h \ ddk/csq.h \ ddk/d3dkmthk.h \ diff --git a/include/ddk/bthguid.h b/include/ddk/bthguid.h new file mode 100644 index 00000000000..0039076f92c --- /dev/null +++ b/include/ddk/bthguid.h @@ -0,0 +1,37 @@ +/* + * GUID definitions used by winebth.sys + * + * Copyright 2024 Vibhav Pant + * + * 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 + * + */ + +#ifndef __DDK_BTHGUID_H__ +#define __DDK_BTHGUID_H__ + +#define DEFINE_BTH_RADIO_DEVPROPKEY( d, i ) \ + DEFINE_DEVPROPKEY( DEVPKEY_BluetoothRadio_##d, 0xa92f26ca, 0xeda7, 0x4b1d, 0x9d, 0xb2, 0x27, \ + 0xb6, 0x8a, 0xa5, 0xa2, 0xeb, (i) ) + +DEFINE_BTH_RADIO_DEVPROPKEY( Address, 1 ); /* DEVPROP_TYPE_UINT64 */ +DEFINE_BTH_RADIO_DEVPROPKEY( Manufacturer, 2 ); /* DEVPROP_TYPE_UINT16 */ +DEFINE_BTH_RADIO_DEVPROPKEY( LMPSupportedFeatures, 3 ); /* DEVPROP_TYPE_UINT64 */ +DEFINE_BTH_RADIO_DEVPROPKEY( LMPVersion, 4 ); /* DEVPROP_TYPE_BYTE */ +DEFINE_BTH_RADIO_DEVPROPKEY( HCIVendorFeatures, 8 ); /* DEVPROP_TYPE_UINT64 */ +DEFINE_BTH_RADIO_DEVPROPKEY( MaximumAdvertisementDataLength, 17 ); /* DEVPROP_TYPE_UINT16 */ +DEFINE_BTH_RADIO_DEVPROPKEY( LELocalSupportedFeatures, 22 ); /* DEVPROP_TYPE_UINT64 */ + +#endif