This MR introduces an initial implementation for `IOCTL_BTH_GET_DEVICE_INFO` which returns a list of known/cached devices by BlueZ.
-- v2: winebth.sys: Remove the corresponding device entry for Bluetooth radios on receiving InterfacesRemoved for org.bluez.Device1 objects. winebth.sys: Queue a DEVICE_ADDED event on receiving InterfacesAdded for objects that implement org.bluez.Device1. winebth.sys: Add connection related properties for remote devices.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/dbus.c | 118 +++++++++++++++++++++++++++++-- dlls/winebth.sys/unixlib.c | 9 +++ dlls/winebth.sys/unixlib.h | 7 ++ dlls/winebth.sys/winebluetooth.c | 9 +++ dlls/winebth.sys/winebth.c | 51 +++++++++++++ dlls/winebth.sys/winebth_priv.h | 31 ++++++++ 6 files changed, 221 insertions(+), 4 deletions(-)
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index 1ab7ebaea74..d8a4247d453 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -115,6 +115,7 @@ const int bluez_timeout = -1;
#define BLUEZ_DEST "org.bluez" #define BLUEZ_INTERFACE_ADAPTER "org.bluez.Adapter1" +#define BLUEZ_INTERFACE_DEVICE "org.bluez.Device1"
#define DO_FUNC( f ) typeof( f ) (*p_##f) DBUS_FUNCS; @@ -491,6 +492,40 @@ static void bluez_radio_prop_from_dict_entry( const char *prop_name, DBusMessage } }
+static void bluez_device_prop_from_dict_entry( const char *prop_name, DBusMessageIter *variant, + struct winebluetooth_device_properties *props, + winebluetooth_device_props_mask_t *props_mask, + winebluetooth_device_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_DEVICE_PROPERTY_NAME && + !strcmp( prop_name, "Name" ) && + p_dbus_message_iter_get_arg_type( variant ) == DBUS_TYPE_STRING) + { + const char *name_str; + SIZE_T len; + + p_dbus_message_iter_get_basic( variant, &name_str ); + len = strlen( name_str ); + memcpy( props->name, name_str, min( len + 1, ARRAYSIZE( props->name ) ) ); + props->name[ARRAYSIZE( props->name ) - 1] = '\0'; + *props_mask |= WINEBLUETOOTH_DEVICE_PROPERTY_NAME; + } + else if (wanted_props_mask & WINEBLUETOOTH_DEVICE_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_DEVICE_PROPERTY_ADDRESS; + } +} + static NTSTATUS bluez_adapter_get_props_async( void *connection, const char *radio_object_path, DBusPendingCall **call ) { @@ -520,6 +555,8 @@ struct bluez_watcher_ctx
/* struct bluez_init_entry */ struct list initial_radio_list; + /* struct bluez_init_entry */ + struct list initial_device_list;
/* struct bluez_watcher_event */ struct list event_list; @@ -529,6 +566,7 @@ struct bluez_init_entry { union { struct winebluetooth_watcher_event_radio_added radio; + struct winebluetooth_watcher_event_device_added device; } object; struct list entry; }; @@ -929,6 +967,10 @@ static void bluez_watcher_free( struct bluez_watcher_ctx *watcher ) case BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_PROPERTIES_CHANGED: unix_name_free( (struct unix_name *)event1->event.radio_props_changed.radio.handle ); break; + case BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_ADDED: + unix_name_free( (struct unix_name *)event1->event.device_added.radio.handle ); + unix_name_free( (struct unix_name *)event1->event.device_added.device.handle ); + break; } free( event1 ); } @@ -955,7 +997,7 @@ NTSTATUS bluez_watcher_init( void *connection, void **ctx ) } watcher_ctx->init_device_list_call = call; list_init( &watcher_ctx->initial_radio_list ); - + list_init( &watcher_ctx->initial_device_list ); list_init( &watcher_ctx->event_list );
/* The bluez_dbus_loop thread will free up the watcher when the disconnect message is processed (i.e, @@ -1010,7 +1052,8 @@ void bluez_watcher_close( void *connection, void *ctx ) p_dbus_connection_remove_filter( connection, bluez_filter, ctx ); }
-static NTSTATUS bluez_build_initial_device_lists( DBusMessage *reply, struct list *adapter_list ) +static NTSTATUS bluez_build_initial_device_lists( DBusMessage *reply, struct list *adapter_list, + struct list *device_list ) { DBusMessageIter dict, paths_iter, iface_iter, prop_iter; const char *path; @@ -1062,10 +1105,65 @@ static NTSTATUS bluez_build_initial_device_lists( DBusMessage *reply, struct lis debugstr_a( radio_name->str ), radio_name ); break; } + else if (!strcmp( iface, BLUEZ_INTERFACE_DEVICE )) + { + const char *prop_name; + DBusMessageIter variant; + struct bluez_init_entry *init_device; + struct unix_name *device_name, *radio_name = NULL; + + init_device = calloc( 1, sizeof( *init_device ) ); + if (!init_device) + { + status = STATUS_NO_MEMORY; + goto done; + } + device_name = unix_name_get_or_create( path ); + if (!device_name) + { + free( init_device ); + status = STATUS_NO_MEMORY; + goto done; + } + init_device->object.device.device.handle = (UINT_PTR)device_name; + + while((prop_name = bluez_next_dict_entry( &prop_iter, &variant ))) + { + if (!strcmp( prop_name, "Adapter" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_OBJECT_PATH) + { + const char *path; + p_dbus_message_iter_get_basic( &variant, &path ); + radio_name = unix_name_get_or_create( path ); + if (!radio_name) + { + unix_name_free( device_name ); + free( init_device ); + status = STATUS_NO_MEMORY; + goto done; + } + init_device->object.device.radio.handle = (UINT_PTR)radio_name; + } + else + bluez_device_prop_from_dict_entry( prop_name, &variant, &init_device->object.device.props, + &init_device->object.device.known_props_mask, + WINEBLUETOOTH_DEVICE_ALL_PROPERTIES ); + } + if (!init_device->object.device.radio.handle) + { + unix_name_free( device_name ); + free( init_device ); + ERR( "Could not find the associated adapter for device %s\n", debugstr_a( path ) ); + break; + } + list_add_tail( device_list, &init_device->entry ); + TRACE( "Found BlueZ org.bluez.Device1 object %s: %p\n", debugstr_a( path ), device_name ); + break; + } } }
- TRACE( "Initial device list: radios: %d\n", list_count( adapter_list ) ); + TRACE( "Initial device list: radios: %d, devices: %d\n", list_count( adapter_list ), list_count( device_list ) ); done: return status; } @@ -1083,6 +1181,17 @@ static BOOL bluez_watcher_event_queue_ready( struct bluez_watcher_ctx *ctx, stru free( radio ); return TRUE; } + if (!list_empty( &ctx->initial_device_list )) + { + struct bluez_init_entry *device; + + device = LIST_ENTRY( list_head( &ctx->initial_device_list ), struct bluez_init_entry, entry ); + event->event_type = BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_ADDED; + event->event_data.device_added = device->object.device; + list_remove( &device->entry ); + free( device ); + return TRUE; + } if (!list_empty( &ctx->event_list )) { struct bluez_watcher_event *watcher_event = @@ -1147,7 +1256,8 @@ NTSTATUS bluez_dbus_loop( void *c, void *watcher, p_dbus_connection_unref( connection ); return STATUS_NO_MEMORY; } - status = bluez_build_initial_device_lists( reply, &watcher_ctx->initial_radio_list ); + status = bluez_build_initial_device_lists( reply, &watcher_ctx->initial_radio_list, + &watcher_ctx->initial_device_list ); p_dbus_message_unref( reply ); if (status != STATUS_SUCCESS) { diff --git a/dlls/winebth.sys/unixlib.c b/dlls/winebth.sys/unixlib.c index b7bf4012ce3..a80a51d9cf1 100644 --- a/dlls/winebth.sys/unixlib.c +++ b/dlls/winebth.sys/unixlib.c @@ -164,6 +164,13 @@ static NTSTATUS bluetooth_adapter_set_prop( void *arg ) return bluez_adapter_set_prop( dbus_connection, params ); }
+static NTSTATUS bluetooth_device_free( void *args ) +{ + struct bluetooth_device_free_params *params = args; + unix_name_free( params->device ); + return STATUS_SUCCESS; +} + static NTSTATUS bluetooth_get_event( void *args ) { struct bluetooth_get_event_params *params = args; @@ -181,6 +188,8 @@ const unixlib_entry_t __wine_unix_call_funcs[] = { bluetooth_adapter_get_unique_name, bluetooth_adapter_free,
+ bluetooth_device_free, + bluetooth_get_event, };
diff --git a/dlls/winebth.sys/unixlib.h b/dlls/winebth.sys/unixlib.h index f1530bcde19..002cc2cc3aa 100644 --- a/dlls/winebth.sys/unixlib.h +++ b/dlls/winebth.sys/unixlib.h @@ -49,6 +49,11 @@ struct bluetooth_adapter_free_params unix_name_t adapter; };
+struct bluetooth_device_free_params +{ + unix_name_t device; +}; + struct bluetooth_adapter_get_unique_name_params { unix_name_t adapter; @@ -79,6 +84,8 @@ enum bluetoothapis_funcs unix_bluetooth_adapter_get_unique_name, unix_bluetooth_adapter_free,
+ unix_bluetooth_device_free, + unix_bluetooth_get_event,
unix_funcs_count diff --git a/dlls/winebth.sys/winebluetooth.c b/dlls/winebth.sys/winebluetooth.c index a477e00fc08..6ebfe55ac28 100644 --- a/dlls/winebth.sys/winebluetooth.c +++ b/dlls/winebth.sys/winebluetooth.c @@ -77,6 +77,15 @@ void winebluetooth_radio_free( winebluetooth_radio_t radio ) UNIX_BLUETOOTH_CALL( bluetooth_adapter_free, &args ); }
+void winebluetooth_device_free( winebluetooth_device_t device ) +{ + struct bluetooth_device_free_params args = {0}; + TRACE( "(%p)\n", (void *)device.handle ); + + args.device = device.handle; + UNIX_BLUETOOTH_CALL( bluetooth_device_free, &args ); +} + NTSTATUS winebluetooth_get_event( struct winebluetooth_event *result ) { struct bluetooth_get_event_params params = {0}; diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 5bdea771d6f..43631e02967 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -78,6 +78,19 @@ struct bluetooth_radio WCHAR *hw_name; UNICODE_STRING bthport_symlink_name; UNICODE_STRING bthradio_symlink_name; + + CRITICAL_SECTION remote_devices_cs; + struct list remote_devices; /* Guarded by remote_devices_cs */ +}; + +struct bluetooth_remote_device +{ + struct list entry; + + winebluetooth_device_t device; + CRITICAL_SECTION props_cs; + winebluetooth_device_props_mask_t props_mask; /* Guarded by props_cs */ + struct winebluetooth_device_properties props; /* Guarded by props_cs */ };
static NTSTATUS WINAPI dispatch_bluetooth( DEVICE_OBJECT *device, IRP *irp ) @@ -270,8 +283,10 @@ static void add_bluetooth_radio( struct winebluetooth_watcher_event_radio_added device->hw_name = hw_name; device->props = event.props; device->props_mask = event.props_mask; + list_init( &device->remote_devices );
InitializeCriticalSection( &device->props_cs ); + InitializeCriticalSection( &device->remote_devices_cs );
EnterCriticalSection( &device_list_cs ); list_add_tail( &device_list, &device->entry ); @@ -330,6 +345,39 @@ static void update_bluetooth_radio_properties( struct winebluetooth_watcher_even LeaveCriticalSection( &device_list_cs ); }
+static void bluetooth_radio_add_remote_device( struct winebluetooth_watcher_event_device_added event ) +{ + struct bluetooth_radio *radio; + + EnterCriticalSection( &device_list_cs ); + LIST_FOR_EACH_ENTRY( radio, &device_list, struct bluetooth_radio, entry ) + { + if (winebluetooth_radio_equal( event.radio, radio->radio )) + { + struct bluetooth_remote_device *remote_device; + + remote_device = calloc( 1, sizeof( *remote_device ) ); + if (!remote_device) + { + winebluetooth_device_free( event.device ); + break; + } + + InitializeCriticalSection( &remote_device->props_cs ); + remote_device->device = event.device; + remote_device->props_mask = event.known_props_mask; + remote_device->props = event.props; + + EnterCriticalSection( &radio->remote_devices_cs ); + list_add_tail( &radio->remote_devices, &remote_device->entry ); + LeaveCriticalSection( &radio->remote_devices_cs ); + break; + } + } + LeaveCriticalSection( &device_list_cs ); + winebluetooth_radio_free( event.radio ); +} + static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg ) { NTSTATUS status; @@ -356,6 +404,9 @@ static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg ) case BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_PROPERTIES_CHANGED: update_bluetooth_radio_properties( event->event_data.radio_props_changed ); break; + case BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_ADDED: + bluetooth_radio_add_remote_device( event->event_data.device_added ); + break; default: FIXME( "Unknown bluetooth watcher event code: %#x\n", event->event_type ); } diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index 79ef0bd457a..cdedea7bab1 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -133,6 +133,19 @@ typedef UINT16 winebluetooth_radio_props_mask_t; WINEBLUETOOTH_RADIO_PROPERTY_VERSION | WINEBLUETOOTH_RADIO_PROPERTY_DISCOVERING | \ WINEBLUETOOTH_RADIO_PROPERTY_PAIRABLE)
+typedef struct +{ + UINT_PTR handle; +} winebluetooth_device_t; + +typedef UINT16 winebluetooth_device_props_mask_t; + +#define WINEBLUETOOTH_DEVICE_PROPERTY_NAME (1) +#define WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS (1 << 1) + +#define WINEBLUETOOTH_DEVICE_ALL_PROPERTIES \ + (WINEBLUETOOTH_DEVICE_PROPERTY_NAME | WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS) + union winebluetooth_property { BOOL boolean; @@ -154,6 +167,12 @@ struct winebluetooth_radio_properties BYTE version; };
+struct winebluetooth_device_properties +{ + BLUETOOTH_ADDRESS address; + CHAR name[BLUETOOTH_MAX_NAME_SIZE]; +}; + NTSTATUS winebluetooth_radio_get_unique_name( winebluetooth_radio_t radio, char *name, SIZE_T *size ); void winebluetooth_radio_free( winebluetooth_radio_t radio ); @@ -165,11 +184,14 @@ NTSTATUS winebluetooth_radio_set_property( winebluetooth_radio_t radio, ULONG prop_flag, union winebluetooth_property *property );
+void winebluetooth_device_free( winebluetooth_device_t device ); + enum winebluetooth_watcher_event_type { BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_ADDED, BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_REMOVED, BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_PROPERTIES_CHANGED, + BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_ADDED, };
struct winebluetooth_watcher_event_radio_added @@ -188,11 +210,20 @@ struct winebluetooth_watcher_event_radio_props_changed winebluetooth_radio_t radio; };
+struct winebluetooth_watcher_event_device_added +{ + winebluetooth_device_props_mask_t known_props_mask; + struct winebluetooth_device_properties props; + winebluetooth_device_t device; + winebluetooth_radio_t radio; +}; + union winebluetooth_watcher_event_data { struct winebluetooth_watcher_event_radio_added radio_added; winebluetooth_radio_t radio_removed; struct winebluetooth_watcher_event_radio_props_changed radio_props_changed; + struct winebluetooth_watcher_event_device_added device_added; };
struct winebluetooth_watcher_event
From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/winebth.c | 62 ++++++++++++++++++++++++++++++++++++++ include/bthioctl.h | 7 +++++ 2 files changed, 69 insertions(+)
diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 43631e02967..5d1f128c491 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -148,6 +148,68 @@ static NTSTATUS WINAPI dispatch_bluetooth( DEVICE_OBJECT *device, IRP *irp ) status = STATUS_SUCCESS; break; } + case IOCTL_BTH_GET_DEVICE_INFO: + { + BTH_DEVICE_INFO_LIST *list = irp->AssociatedIrp.SystemBuffer; + struct bluetooth_remote_device *device; + SIZE_T rem_devices; + + FIXME("IOCTL_BTH_GET_DEVICE_INFO: semi-stub!\n"); + + if (!list) + { + status = STATUS_INVALID_PARAMETER; + break; + } + if (outsize < sizeof( *list )) + { + status = STATUS_INVALID_BUFFER_SIZE; + break; + } + + rem_devices = (outsize - sizeof( *list ))/sizeof(BTH_DEVICE_INFO) + 1; + status = STATUS_SUCCESS; + irp->IoStatus.Information = 0; + + EnterCriticalSection( &ext->remote_devices_cs ); + LIST_FOR_EACH_ENTRY( device, &ext->remote_devices, struct bluetooth_remote_device, entry ) + { + list->numOfDevices++; + if (rem_devices > 0) + { + BTH_DEVICE_INFO *info; + + info = &list->deviceList[list->numOfDevices - 1]; + memset( info, 0, sizeof( *info ) ); + + EnterCriticalSection( &device->props_cs ); + if (device->props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_NAME) + { + info->flags |= BDIF_NAME; + memcpy( info->name, device->props.name, sizeof( info->name ) ); + } + if (device->props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS) + { + info->flags |= BDIF_ADDRESS; + info->address = RtlUlonglongByteSwap( device->props.address.ullLong ); + } + LeaveCriticalSection( &device->props_cs ); + + irp->IoStatus.Information += sizeof( *info ); + rem_devices--; + } + } + LeaveCriticalSection( &ext->remote_devices_cs ); + + irp->IoStatus.Information += sizeof( *list ); + if (list->numOfDevices) + irp->IoStatus.Information -= sizeof( BTH_DEVICE_INFO ); + + /* The output buffer needs to be exactly sized. */ + if (rem_devices) + status = STATUS_INVALID_BUFFER_SIZE; + break; + } case IOCTL_WINEBTH_RADIO_SET_FLAG: { const struct winebth_radio_set_flag_params *params = irp->AssociatedIrp.SystemBuffer; diff --git a/include/bthioctl.h b/include/bthioctl.h index a822c054f6c..56a665e9f41 100644 --- a/include/bthioctl.h +++ b/include/bthioctl.h @@ -23,6 +23,7 @@ #define __BTHIOCTL_H__
#define IOCTL_BTH_GET_LOCAL_INFO CTL_CODE(FILE_DEVICE_BLUETOOTH, 0x00, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_BTH_GET_DEVICE_INFO CTL_CODE(FILE_DEVICE_BLUETOOTH, 0x02, METHOD_BUFFERED, FILE_ANY_ACCESS)
#include <pshpack1.h>
@@ -43,6 +44,12 @@ typedef struct _BTH_LOCAL_RADIO_INFO BTH_RADIO_INFO radioInfo; } BTH_LOCAL_RADIO_INFO, *PBTH_LOCAL_RADIO_INFO;
+typedef struct _BTH_DEVICE_INFO_LIST +{ + ULONG numOfDevices; + BTH_DEVICE_INFO deviceList[1]; +} BTH_DEVICE_INFO_LIST, *PBTH_DEVICE_INFO_LIST; + #include <poppack.h>
#endif /* __BTHIOCTL_H__ */
From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/dbus.c | 20 ++++++++++++++++++++ dlls/winebth.sys/winebth.c | 8 ++++++-- dlls/winebth.sys/winebth_priv.h | 13 +++++++++---- 3 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index d8a4247d453..bebe11e4f2b 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -524,6 +524,26 @@ static void bluez_device_prop_from_dict_entry( const char *prop_name, DBusMessag parse_mac_address( addr_str, props->address.rgBytes ); *props_mask |= WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS; } + else if (wanted_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_CONNECTED && + !strcmp( prop_name, "Connected" ) && + p_dbus_message_iter_get_arg_type( variant ) == DBUS_TYPE_BOOLEAN) + { + dbus_bool_t connected; + + p_dbus_message_iter_get_basic( variant, &connected ); + props->connected = !!connected; + *props_mask |= WINEBLUETOOTH_DEVICE_PROPERTY_CONNECTED; + } + else if (wanted_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_PAIRED && + !strcmp( prop_name, "Paired" ) && + p_dbus_message_iter_get_arg_type( variant ) == DBUS_TYPE_BOOLEAN) + { + dbus_bool_t paired; + + p_dbus_message_iter_get_basic( variant, &paired ); + props->paired = !!paired; + *props_mask |= WINEBLUETOOTH_DEVICE_PROPERTY_PAIRED; + } }
static NTSTATUS bluez_adapter_get_props_async( void *connection, const char *radio_object_path, diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 5d1f128c491..69f8f48c614 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -154,8 +154,6 @@ static NTSTATUS WINAPI dispatch_bluetooth( DEVICE_OBJECT *device, IRP *irp ) struct bluetooth_remote_device *device; SIZE_T rem_devices;
- FIXME("IOCTL_BTH_GET_DEVICE_INFO: semi-stub!\n"); - if (!list) { status = STATUS_INVALID_PARAMETER; @@ -193,6 +191,12 @@ static NTSTATUS WINAPI dispatch_bluetooth( DEVICE_OBJECT *device, IRP *irp ) info->flags |= BDIF_ADDRESS; info->address = RtlUlonglongByteSwap( device->props.address.ullLong ); } + if (device->props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_CONNECTED && + device->props.connected) + info->flags |= BDIF_CONNECTED; + if (device->props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_PAIRED && + device->props.paired) + info->flags |= (BDIF_PAIRED | BDIF_PERSONAL); LeaveCriticalSection( &device->props_cs );
irp->IoStatus.Information += sizeof( *info ); diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index cdedea7bab1..0646a18409f 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -140,11 +140,14 @@ typedef struct
typedef UINT16 winebluetooth_device_props_mask_t;
-#define WINEBLUETOOTH_DEVICE_PROPERTY_NAME (1) -#define WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS (1 << 1) +#define WINEBLUETOOTH_DEVICE_PROPERTY_NAME (1) +#define WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS (1 << 1) +#define WINEBLUETOOTH_DEVICE_PROPERTY_CONNECTED (1 << 2) +#define WINEBLUETOOTH_DEVICE_PROPERTY_PAIRED (1 << 3)
-#define WINEBLUETOOTH_DEVICE_ALL_PROPERTIES \ - (WINEBLUETOOTH_DEVICE_PROPERTY_NAME | WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS) +#define WINEBLUETOOTH_DEVICE_ALL_PROPERTIES \ + (WINEBLUETOOTH_DEVICE_PROPERTY_NAME | WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS | \ + WINEBLUETOOTH_DEVICE_PROPERTY_CONNECTED | WINEBLUETOOTH_DEVICE_PROPERTY_PAIRED)
union winebluetooth_property { @@ -171,6 +174,8 @@ struct winebluetooth_device_properties { BLUETOOTH_ADDRESS address; CHAR name[BLUETOOTH_MAX_NAME_SIZE]; + BOOL connected; + BOOL paired; };
NTSTATUS winebluetooth_radio_get_unique_name( winebluetooth_radio_t radio, char *name,
From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/dbus.c | 58 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+)
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index bebe11e4f2b..b3bd366370f 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -796,6 +796,64 @@ static DBusHandlerResult bluez_filter( DBusConnection *conn, DBusMessage *msg, v unix_name_free( radio ); } } + else if (!strcmp( iface_name, BLUEZ_INTERFACE_DEVICE )) + { + struct winebluetooth_watcher_event_device_added device_added = {0}; + struct unix_name *device_name, *radio_name = NULL; + DBusMessageIter props_iter, variant; + const char *prop_name; + + device_name = unix_name_get_or_create( object_path ); + device_added.device.handle = (UINT_PTR)device_name; + if (!device_name) + { + ERR("Failed to allocate memory for device path %s\n", debugstr_a( object_path )); + break; + } + p_dbus_message_iter_next( &iface_entry ); + p_dbus_message_iter_recurse( &iface_entry, &props_iter ); + + while((prop_name = bluez_next_dict_entry( &props_iter, &variant ))) + { + if (!strcmp( prop_name, "Adapter" ) && + p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_OBJECT_PATH) + { + const char *path; + + p_dbus_message_iter_get_basic( &variant, &path ); + radio_name = unix_name_get_or_create( path ); + if (!radio_name) + { + unix_name_free( device_name ); + ERR("Failed to allocate memory for radio path %s\n", debugstr_a( path )); + break; + } + device_added.radio.handle = (UINT_PTR)radio_name; + } + else + bluez_device_prop_from_dict_entry( prop_name, &variant, &device_added.props, + &device_added.known_props_mask, + WINEBLUETOOTH_DEVICE_ALL_PROPERTIES ); + } + + if (!radio_name) + { + unix_name_free( device_name ); + ERR( "Could not find the associated adapter for device %s\n", debugstr_a( object_path ) ); + break; + } + else + { + union winebluetooth_watcher_event_data event = { .device_added = device_added }; + TRACE( "New BlueZ org.bluez.Device1 object added at %s: %p\n", debugstr_a( object_path ), + device_name ); + if (!bluez_event_list_queue_new_event( event_list, BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_ADDED, event )) + { + unix_name_free( device_name ); + unix_name_free( radio_name ); + } + } + } p_dbus_message_iter_next( &ifaces_iter ); } }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/dbus.c | 19 +++++++++++++++++++ dlls/winebth.sys/winebth.c | 27 +++++++++++++++++++++++++++ dlls/winebth.sys/winebth_priv.h | 7 +++++++ 3 files changed, 53 insertions(+)
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index b3bd366370f..4ce43116944 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -899,6 +899,22 @@ static DBusHandlerResult bluez_filter( DBusConnection *conn, DBusMessage *msg, v event_list, BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_REMOVED, event )) unix_name_free( radio_name ); } + else if (!strcmp( interfaces[i], BLUEZ_INTERFACE_DEVICE )) + { + struct unix_name *device; + union winebluetooth_watcher_event_data event; + + device = unix_name_get_or_create( object_path ); + if (!device) + { + ERR( "Failed to allocate memory for adapter path %s\n", object_path ); + continue; + } + event.device_removed.device.handle = (UINT_PTR)device; + if (!bluez_event_list_queue_new_event( event_list, BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_REMOVED, + event )) + unix_name_free( device ); + } } p_dbus_free_string_array( interfaces ); } @@ -1049,6 +1065,9 @@ static void bluez_watcher_free( struct bluez_watcher_ctx *watcher ) unix_name_free( (struct unix_name *)event1->event.device_added.radio.handle ); unix_name_free( (struct unix_name *)event1->event.device_added.device.handle ); break; + case BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_REMOVED: + unix_name_free( (struct unix_name *)event1->event.device_removed.device.handle ); + break; } free( event1 ); } diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 69f8f48c614..bce67f0ffe0 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -444,6 +444,30 @@ static void bluetooth_radio_add_remote_device( struct winebluetooth_watcher_even winebluetooth_radio_free( event.radio ); }
+static void bluetooth_radio_remove_remote_device( struct winebluetooth_watcher_event_device_removed event ) +{ + struct bluetooth_radio *radio; + + EnterCriticalSection( &device_list_cs ); + LIST_FOR_EACH_ENTRY( radio, &device_list, struct bluetooth_radio, entry ) + { + struct bluetooth_remote_device *device, *next; + + EnterCriticalSection( &radio->remote_devices_cs ); + LIST_FOR_EACH_ENTRY_SAFE( device, next, &radio->remote_devices, struct bluetooth_remote_device, entry ) + { + list_remove( &device->entry ); + winebluetooth_device_free( device->device ); + DeleteCriticalSection( &device->props_cs ); + free( device ); + break; + } + LeaveCriticalSection( &radio->remote_devices_cs ); + } + LeaveCriticalSection( &device_list_cs ); + winebluetooth_device_free( event.device ); +} + static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg ) { NTSTATUS status; @@ -473,6 +497,9 @@ static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg ) case BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_ADDED: bluetooth_radio_add_remote_device( event->event_data.device_added ); break; + case BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_REMOVED: + bluetooth_radio_remove_remote_device( event->event_data.device_removed ); + break; default: FIXME( "Unknown bluetooth watcher event code: %#x\n", event->event_type ); } diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index 0646a18409f..b5ee1bc0908 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -197,6 +197,7 @@ enum winebluetooth_watcher_event_type BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_REMOVED, BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_PROPERTIES_CHANGED, BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_ADDED, + BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_REMOVED };
struct winebluetooth_watcher_event_radio_added @@ -223,12 +224,18 @@ struct winebluetooth_watcher_event_device_added winebluetooth_radio_t radio; };
+struct winebluetooth_watcher_event_device_removed +{ + winebluetooth_device_t device; +}; + union winebluetooth_watcher_event_data { struct winebluetooth_watcher_event_radio_added radio_added; winebluetooth_radio_t radio_removed; struct winebluetooth_watcher_event_radio_props_changed radio_props_changed; struct winebluetooth_watcher_event_device_added device_added; + struct winebluetooth_watcher_event_device_removed device_removed; };
struct winebluetooth_watcher_event
As usual I'm trusting that the bluez/dbus logic makes sense, the other side of the glue seems broadly sensible.
I guess the library doesn't actually provide us with any way to just query the total number of devices at any given time? It would avoid having to keep track of devices in the first place...
This merge request was approved by Elizabeth Figura.
On Fri Feb 21 10:01:24 2025 +0000, Elizabeth Figura wrote:
As usual I'm trusting that the bluez/dbus logic makes sense, the other side of the glue seems broadly sensible. I guess the library doesn't actually provide us with any way to just query the total number of devices at any given time? It would avoid having to keep track of devices in the first place...
Thanks.
I guess the library doesn't actually provide us with any way to just query the total number of devices at any given time? It would avoid having to keep track of devices in the first place...
There is one to get all BlueZ objects, `GetManagedObjects`, it's how we build the list of initially known devices and local radios. However, we'll also need to create device PDOs under the `BTHENUM` enumerator minidriver for every remote device in the future (which requires using signals from DBus to track them), as the [BLE API](https://learn.microsoft.com/en-us/windows/win32/api/bluetoothleapis/) is implemented as IOCTLs to the device HANDLE (while the regular methods in bluetoothapis call the radio itself).
In such a case, using `GetManagedObjects` here can be potentially racy if a new device has been discovered, but BlueZ hasn't gotten around to emitting an `InterfacesAdded` signal for it yet, but `GetManagedObjects` does include it.