Broadcast `GUID_BLUETOOTH_RADIO_IN_RANGE` and `GUID_BLUETOOTH_RADIO_OUT_OF_RANGE` events (documented [here](https://learn.microsoft.com/en-us/windows/win32/bluetooth/bluetooth-and-wm-d...)) when remote devices are discovered and lost, respectively. For new devices, `RADIO_IN_RANGE` is only broadcasted if the device was not an initial entry enumerated during driver initialization.
-- v2: winebth.sys: Broadcast GUID_BLUETOOTH_RADIO_IN_RANGE events for newly discovered remote devices as well. winebth.sys: Broadcast PnP event when remote devices are removed/lost.
From: Vibhav Pant vibhavp@gmail.com
On receiving a BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_PROPERTIES_CHANGED event from Unix, broadcast a GUID_BLUETOOTH_RADIO_IN_RANGE PnP event, containing the old and newly updated properties for the remote device. --- dlls/winebth.sys/winebth.c | 46 +++++++++++++++++++++++++++++++++++++- include/bthdef.h | 10 +++++++++ 2 files changed, 55 insertions(+), 1 deletion(-)
diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 44d8c3f90d4..c4923902691 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -557,7 +557,10 @@ static void bluetooth_radio_remove_remote_device( struct winebluetooth_watcher_e
static void bluetooth_radio_update_device_props( struct winebluetooth_watcher_event_device_props_changed event ) { + BTH_DEVICE_INFO device_new_info = {0}; + DEVICE_OBJECT *radio_obj = NULL; /* The radio PDO the remote device exists on. */ struct bluetooth_radio *radio; + ULONG device_old_flags = 0;
EnterCriticalSection( &device_list_cs ); LIST_FOR_EACH_ENTRY( radio, &device_list, struct bluetooth_radio, entry ) @@ -569,7 +572,13 @@ static void bluetooth_radio_update_device_props( struct winebluetooth_watcher_ev { if (winebluetooth_device_equal( event.device, device->device )) { + BTH_DEVICE_INFO old_info = {0}; + + radio_obj = radio->device_obj; + EnterCriticalSection( &device->props_cs ); + winebluetooth_device_properties_to_info( device->props_mask, &device->props, &old_info ); + device->props_mask |= event.changed_props_mask; device->props_mask &= ~event.invalid_props_mask; if (event.changed_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_NAME) @@ -586,16 +595,51 @@ static void bluetooth_radio_update_device_props( struct winebluetooth_watcher_ev device->props.trusted = event.props.trusted; if (event.changed_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_CLASS) device->props.class = event.props.class; + winebluetooth_device_properties_to_info( device->props_mask, &device->props, &device_new_info ); LeaveCriticalSection( &device->props_cs ); LeaveCriticalSection( &radio->remote_devices_cs ); + + device_old_flags = old_info.flags; goto done; } } LeaveCriticalSection( &radio->remote_devices_cs ); } done: - LeaveCriticalSection( &device_list_cs ); winebluetooth_device_free( event.device ); + + if (radio_obj) + { + TARGET_DEVICE_CUSTOM_NOTIFICATION *notification; + BTH_RADIO_IN_RANGE *device; + SIZE_T notif_size; + NTSTATUS ret; + + notif_size = offsetof( TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer[sizeof( *device )]); + notification = ExAllocatePool( PagedPool, notif_size ); + if (!notification) + { + LeaveCriticalSection( &device_list_cs ); + return; + } + + notification->Version = 1; + notification->Size = notif_size; + notification->Event = GUID_BLUETOOTH_RADIO_IN_RANGE; + notification->FileObject = NULL; + notification->NameBufferOffset = -1; + device = (BTH_RADIO_IN_RANGE *)notification->CustomDataBuffer; + memset( device, 0, sizeof( *device ) ); + device->previousDeviceFlags = device_old_flags; + device->deviceInfo = device_new_info; + + ret = IoReportTargetDeviceChange( radio_obj, notification ); + if (ret) + ERR("IoReportTargetDeviceChange failed: %#lx\n", ret ); + ExFreePool( notification ); + } + + LeaveCriticalSection( &device_list_cs ); }
static void bluetooth_radio_report_auth_event( struct winebluetooth_auth_event event ) diff --git a/include/bthdef.h b/include/bthdef.h index d71b2e005e7..d3b9387f8cc 100644 --- a/include/bthdef.h +++ b/include/bthdef.h @@ -29,6 +29,9 @@ DEFINE_GUID( GUID_BTHPORT_DEVICE_INTERFACE, 0x850302a, 0xb344, 0x4fda, 0x9b, 0xe DEFINE_GUID( GUID_BLUETOOTH_RADIO_INTERFACE, 0x92383b0e, 0xf90e, 0x4ac9, 0x8d, 0x44, 0x8c, 0x2d, 0x0d, 0x0e, 0xbd, 0xa2 );
+DEFINE_GUID( GUID_BLUETOOTH_RADIO_IN_RANGE, 0xea3b5b82, 0x26ee, 0x450e, 0xb0, 0xd8, 0xd2, 0x6f, + 0xe3, 0x0a, 0x38, 0x69 ); + typedef ULONG BTH_COD;
#define BTH_MAX_NAME_SIZE (248) @@ -52,6 +55,13 @@ typedef struct _BTH_DEVICE_INFO CHAR name[BTH_MAX_NAME_SIZE]; } BTH_DEVICE_INFO, *PBTH_DEVICE_INFO;
+/* Buffer for GUID_BLUETOOTH_RADIO_IN_RANGE events. */ +typedef struct _BTH_RADIO_IN_RANGE +{ + BTH_DEVICE_INFO deviceInfo; + ULONG previousDeviceFlags; +} BTH_RADIO_IN_RANGE, *PBTH_RADIO_IN_RANGE; + #ifdef __cplusplus } #endif
From: Vibhav Pant vibhavp@gmail.com
On receiving a BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_REMOVED event from Unix, broadcast a GUID_BLUETOOTH_RADIO_OUT_OF_RANGE PnP event for the device address that was removed. --- dlls/winebth.sys/winebth.c | 24 ++++++++++++++++++++++++ include/bthdef.h | 3 +++ 2 files changed, 27 insertions(+)
diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index c4923902691..dc680dcca3a 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -539,6 +539,30 @@ static void bluetooth_radio_remove_remote_device( struct winebluetooth_watcher_e if (winebluetooth_device_equal( event.device, device->device )) { list_remove( &device->entry ); + if (device->props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS) + { + TARGET_DEVICE_CUSTOM_NOTIFICATION *notification; + BLUETOOTH_ADDRESS *addr; + SIZE_T notif_size; + NTSTATUS ret; + + notif_size = offsetof( TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer[sizeof( *addr )] ); + if ((notification = ExAllocatePool( PagedPool, notif_size ))) + { + notification->Version = 1; + notification->Size = notif_size; + notification->Event = GUID_BLUETOOTH_RADIO_OUT_OF_RANGE; + notification->FileObject = NULL; + notification->NameBufferOffset = -1; + addr = (BLUETOOTH_ADDRESS *)notification->CustomDataBuffer; + addr->ullLong = RtlUlonglongByteSwap( device->props.address.ullLong ) >> 16; + + ret = IoReportTargetDeviceChange( radio->device_obj, notification ); + if (ret) + ERR( "IoReportTargetDeviceChange failed: %#lx\n", ret ); + ExFreePool( notification ); + } + } winebluetooth_device_free( device->device ); DeleteCriticalSection( &device->props_cs ); free( device ); diff --git a/include/bthdef.h b/include/bthdef.h index d3b9387f8cc..3686cbb6862 100644 --- a/include/bthdef.h +++ b/include/bthdef.h @@ -32,6 +32,9 @@ DEFINE_GUID( GUID_BLUETOOTH_RADIO_INTERFACE, 0x92383b0e, 0xf90e, 0x4ac9, 0x8d, 0 DEFINE_GUID( GUID_BLUETOOTH_RADIO_IN_RANGE, 0xea3b5b82, 0x26ee, 0x450e, 0xb0, 0xd8, 0xd2, 0x6f, 0xe3, 0x0a, 0x38, 0x69 );
+DEFINE_GUID( GUID_BLUETOOTH_RADIO_OUT_OF_RANGE, 0xe28867c9, 0xc2aa, 0x4ced, 0xb9, 0x69, 0x45, 0x70, + 0x86, 0x60, 0x37, 0xc4); + typedef ULONG BTH_COD;
#define BTH_MAX_NAME_SIZE (248)
From: Vibhav Pant vibhavp@gmail.com
Only broadcast the event when the remote device is not already known by the Unix Bluetooth service. --- dlls/winebth.sys/dbus.c | 1 + dlls/winebth.sys/winebth.c | 66 ++++++++++++++++++--------------- dlls/winebth.sys/winebth_priv.h | 1 + 3 files changed, 39 insertions(+), 29 deletions(-)
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index 25352d5e271..b390828d231 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -1908,6 +1908,7 @@ static NTSTATUS bluez_build_initial_device_lists( DBusMessage *reply, struct lis goto done; } init_device->object.device.device.handle = (UINT_PTR)device_name; + init_device->object.device.init_entry = TRUE;
while((prop_name = bluez_next_dict_entry( &prop_iter, &variant ))) { diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index dc680dcca3a..f4c342d9ef3 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -491,6 +491,35 @@ static void update_bluetooth_radio_properties( struct winebluetooth_watcher_even winebluetooth_radio_free( radio ); }
+static void bluetooth_radio_report_radio_in_range_event( DEVICE_OBJECT *radio_obj, ULONG remote_device_old_flags, + const BTH_DEVICE_INFO *new_device_info ) +{ + TARGET_DEVICE_CUSTOM_NOTIFICATION *notification; + BTH_RADIO_IN_RANGE *buffer; + SIZE_T notif_size; + NTSTATUS ret; + + notif_size = offsetof( TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer[sizeof( *buffer )]); + notification = ExAllocatePool( PagedPool, notif_size ); + if (!notification) + return; + + notification->Version = 1; + notification->Size = notif_size; + notification->Event = GUID_BLUETOOTH_RADIO_IN_RANGE; + notification->FileObject = NULL; + notification->NameBufferOffset = -1; + buffer = (BTH_RADIO_IN_RANGE *)notification->CustomDataBuffer; + memset( buffer, 0, sizeof( *buffer ) ); + buffer->previousDeviceFlags = remote_device_old_flags; + buffer->deviceInfo = *new_device_info; + + ret = IoReportTargetDeviceChange( radio_obj, notification ); + if (ret) + ERR("IoReportTargetDeviceChange failed: %#lx\n", ret ); + ExFreePool( notification ); +} + static void bluetooth_radio_add_remote_device( struct winebluetooth_watcher_event_device_added event ) { struct bluetooth_radio *radio; @@ -514,6 +543,13 @@ static void bluetooth_radio_add_remote_device( struct winebluetooth_watcher_even remote_device->props_mask = event.known_props_mask; remote_device->props = event.props;
+ if (!event.init_entry) + { + BTH_DEVICE_INFO device_info = {0}; + winebluetooth_device_properties_to_info( remote_device->props_mask, &remote_device->props, &device_info ); + bluetooth_radio_report_radio_in_range_event( radio->device_obj, 0, &device_info ); + } + EnterCriticalSection( &radio->remote_devices_cs ); list_add_tail( &radio->remote_devices, &remote_device->entry ); LeaveCriticalSection( &radio->remote_devices_cs ); @@ -633,35 +669,7 @@ done: winebluetooth_device_free( event.device );
if (radio_obj) - { - TARGET_DEVICE_CUSTOM_NOTIFICATION *notification; - BTH_RADIO_IN_RANGE *device; - SIZE_T notif_size; - NTSTATUS ret; - - notif_size = offsetof( TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer[sizeof( *device )]); - notification = ExAllocatePool( PagedPool, notif_size ); - if (!notification) - { - LeaveCriticalSection( &device_list_cs ); - return; - } - - notification->Version = 1; - notification->Size = notif_size; - notification->Event = GUID_BLUETOOTH_RADIO_IN_RANGE; - notification->FileObject = NULL; - notification->NameBufferOffset = -1; - device = (BTH_RADIO_IN_RANGE *)notification->CustomDataBuffer; - memset( device, 0, sizeof( *device ) ); - device->previousDeviceFlags = device_old_flags; - device->deviceInfo = device_new_info; - - ret = IoReportTargetDeviceChange( radio_obj, notification ); - if (ret) - ERR("IoReportTargetDeviceChange failed: %#lx\n", ret ); - ExFreePool( notification ); - } + bluetooth_radio_report_radio_in_range_event( radio_obj, device_old_flags, &device_new_info );
LeaveCriticalSection( &device_list_cs ); } diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index 13e234a0da8..e47491b6956 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -245,6 +245,7 @@ struct winebluetooth_watcher_event_device_added struct winebluetooth_device_properties props; winebluetooth_device_t device; winebluetooth_radio_t radio; + BOOL init_entry; };
struct winebluetooth_watcher_event_device_props_changed
This merge request was approved by Elizabeth Figura.