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