From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/bthenum.c | 281 ++++++++++++++++++++++++++++++- dlls/winebth.sys/dbus.c | 67 +++++++- dlls/winebth.sys/unixlib.c | 18 ++ dlls/winebth.sys/unixlib.h | 16 ++ dlls/winebth.sys/winebluetooth.c | 20 +++ dlls/winebth.sys/winebluetooth.h | 13 +- dlls/winebth.sys/winebth.c | 2 +- dlls/winebth.sys/winebth_priv.h | 4 +- 8 files changed, 413 insertions(+), 8 deletions(-)
diff --git a/dlls/winebth.sys/bthenum.c b/dlls/winebth.sys/bthenum.c index 2de12b334ae..7e55cff1219 100644 --- a/dlls/winebth.sys/bthenum.c +++ b/dlls/winebth.sys/bthenum.c @@ -65,6 +65,7 @@ static DRIVER_OBJECT *driver_obj; enum bthenum_phys_device_kind { BTHENUM_PHYS_DEVICE_KIND_REMOTE_RADIO, + BTHENUM_PHYS_DEVICE_KIND_DEVICE_SERVICE, };
struct device_ext @@ -78,6 +79,7 @@ struct bthenum_func_local_radio_ext struct device_ext base; DEVICE_OBJECT *parent_radio_pdo; DEVICE_OBJECT *device_obj; + UINT16 localmfg;
RTL_CRITICAL_SECTION cs; /* Remote bluetooth radios associated with this radio (struct bthenum_phys_remote_radio) */ @@ -92,6 +94,18 @@ struct phys_device_ext struct bthenum_func_local_radio_ext *parent_fdo; };
+struct bthenum_phys_service_ext +{ + struct phys_device_ext base; + /* The remote device that this service instance belongs to */ + struct bthenum_phys_remote_radio_ext *remote_device; + DEVICE_OBJECT *device_obj; + struct list entry; + + GUID service_guid; + UNICODE_STRING service_link_name; +}; + /* Child PDO under a bluetooth radio FDO bus */ struct bthenum_phys_remote_radio_ext { @@ -104,6 +118,9 @@ struct bthenum_phys_remote_radio_ext struct winebluetooth_device_properties props;
UNICODE_STRING device_link_name; + + RTL_CRITICAL_SECTION cs; + struct list services; };
static struct bthenum_func_local_radio_ext *fdo_from_DEVICE_OBJECT( DEVICE_OBJECT *device ) @@ -144,10 +161,16 @@ NTSTATUS WINAPI bthenum_device_added( DEVICE_OBJECT *fdo_bus, child_device->known_props = event.known_props_mask; child_device->device_obj = child_pdo;
+ list_init( &child_device->services ); + RtlEnterCriticalSection( &fdo->cs ); list_add_tail(&fdo->devices, &child_device->entry); RtlLeaveCriticalSection( &fdo->cs );
+ RtlInitializeCriticalSectionEx( &child_device->cs, 0, + RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO ); + child_device->cs.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": bthenum_phys_remote_radio.cs" ); + IoInvalidateDeviceRelations( fdo_bus, BusRelations );
return STATUS_SUCCESS; @@ -167,8 +190,21 @@ NTSTATUS WINAPI bthenum_device_removed( DEVICE_OBJECT *fdo_bus, if (winebluetooth_device_equal( device_handle, remote_device->remote_radio_handle ) && !remote_device->base.base.removed) { + struct bthenum_phys_service_ext *service; remote_device->base.base.removed = TRUE; list_remove( &remote_device->entry ); + + RtlEnterCriticalSection( &remote_device->cs ); + LIST_FOR_EACH_ENTRY( service, &remote_device->services, struct bthenum_phys_service_ext, + entry ) + { + if (!service->base.base.removed) + { + service->base.base.removed = TRUE; + list_remove( &service->entry ); + } + } + RtlLeaveCriticalSection( &remote_device->cs ); break; } } @@ -220,7 +256,7 @@ bthenum_device_props_changed( DEVICE_OBJECT *fdo_bus, }
/* Called once for every Bluetooth Radio discovered. */ -NTSTATUS WINAPI bthenum_create_fdo_bus( DEVICE_OBJECT *pdo, DEVICE_OBJECT **fdo_bus ) +NTSTATUS bthenum_create_fdo_bus( DEVICE_OBJECT *pdo, DEVICE_OBJECT **fdo_bus, UINT16 localmfg ) { struct bthenum_func_local_radio_ext *fdo; NTSTATUS status; @@ -240,6 +276,7 @@ NTSTATUS WINAPI bthenum_create_fdo_bus( DEVICE_OBJECT *pdo, DEVICE_OBJECT **fdo_ fdo->base.removed = FALSE; fdo->parent_radio_pdo = pdo; fdo->device_obj = *fdo_bus; + fdo->localmfg = localmfg; list_init( &fdo->devices );
RtlInitializeCriticalSectionEx( &fdo->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO ); @@ -446,7 +483,7 @@ static NTSTATUS WINAPI fdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp ) struct bthenum_phys_remote_radio_ext *remote; DEVICE_RELATIONS *devices; SIZE_T i = 0; - SIZE_T objects_count; + SIZE_T objects_count = 0;
if (stack->Parameters.QueryDeviceRelations.Type != BusRelations) { @@ -454,7 +491,12 @@ static NTSTATUS WINAPI fdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp ) }
RtlEnterCriticalSection( &device->cs ); - objects_count = list_count( &device->devices ); + LIST_FOR_EACH_ENTRY( remote, &device->devices, struct bthenum_phys_remote_radio_ext, entry ) + { + objects_count++; + objects_count += list_count(&remote->services); + } + devices = ExAllocatePool( PagedPool, offsetof( DEVICE_RELATIONS, Objects[objects_count] ) ); if (devices == NULL) @@ -466,8 +508,16 @@ static NTSTATUS WINAPI fdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp )
LIST_FOR_EACH_ENTRY( remote, &device->devices, struct bthenum_phys_remote_radio_ext, entry ) { + struct bthenum_phys_service_ext *service; devices->Objects[i++] = remote->device_obj; call_fastcall_func1( ObfReferenceObject, remote->device_obj ); + + LIST_FOR_EACH_ENTRY( service, &remote->services, struct bthenum_phys_service_ext, + entry ) + { + devices->Objects[i++] = service->device_obj; + call_fastcall_func1(ObfReferenceObject, service->device_obj); + } } RtlLeaveCriticalSection( &device->cs ); assert( objects_count == i ); @@ -554,6 +604,108 @@ static NTSTATUS pdo_device_query_id( const struct bthenum_phys_remote_radio_ext return irp->IoStatus.Status; }
+struct guid_entry +{ + GUID guid; + struct rb_entry entry; +}; + +static int guid_entry_compare( const void *key, const struct rb_entry *entry ) +{ + return memcmp( key, RB_ENTRY_VALUE( entry, struct guid_entry, entry ), sizeof( GUID ) ); +} + +#define GUID_FORMAT "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}" +#define GUID_FORMAT_ARGS(guid) \ + (guid).Data1, (guid).Data2, (guid).Data3, (guid).Data4[0], (guid).Data4[1], \ + (guid).Data4[2], (guid).Data4[3], (guid).Data4[4], (guid).Data4[5], \ + (guid).Data4[6], (guid).Data4[7] + +static NTSTATUS WINAPI remote_device_refresh_services( struct bthenum_phys_remote_radio_ext *device, + GUID *arr, SIZE_T len ) +{ + struct rb_tree guid_tree; + struct guid_entry *new_guid; + struct bthenum_phys_service_ext *service; + struct bthenum_func_local_radio_ext *fdo_bus_ext = device->base.parent_fdo; + struct guid_entry *guid_entries; + NTSTATUS ret = STATUS_SUCCESS; + BOOL invalidate_bus_relations = FALSE; + SIZE_T i; + + TRACE("(%p, %p, %ld)\n", device, arr, len); + + guid_entries = calloc( len, sizeof( struct guid_entry ) ); + if (!guid_entries) + { + return STATUS_NO_MEMORY; + } + + rb_init( &guid_tree, guid_entry_compare ); + for ( i = 0; i < len; i++ ) + { + guid_entries[i].guid = arr[i]; + rb_put(&guid_tree, &arr[i], &guid_entries[i].entry); + } + + RtlEnterCriticalSection(&fdo_bus_ext->cs); + /* Go through all existing services for this device, and remove them the device's service list + * if they are not in guid_tree. Otherwise, remove them from guid_tree. */ + LIST_FOR_EACH_ENTRY( service, &device->services, struct bthenum_phys_service_ext, entry ) + { + struct rb_entry *guid_entry = rb_get( &guid_tree, &service->service_guid ); + + if (guid_entry != NULL) + { + /* The service already exists under this device, remove it from guid_tree. */ + rb_remove( &guid_tree, guid_entry ); + } + else + { + /* The service is no longer offered by the device, mark it as removed. */ + invalidate_bus_relations = TRUE; + service->base.base.removed = TRUE; + list_remove( &service->entry ); + } + } + /* Any entries remaining in guid_tree now need to be created under this device. */ + RB_FOR_EACH_ENTRY( new_guid, &guid_tree, struct guid_entry, entry ) + { + struct bthenum_phys_service_ext *service_device; + DEVICE_OBJECT *service_device_obj; + NTSTATUS status; + + if (IsEqualGUID(&new_guid->guid, &GUID_NULL)) continue; + + status = IoCreateDevice( fdo_bus_ext->device_obj->DriverObject, sizeof( *service_device ), + NULL, FILE_DEVICE_BLUETOOTH, 0, FALSE, &service_device_obj ); + if ( status != STATUS_SUCCESS ) + { + ERR( "failed to create sevice device: %#lx\n", status ); + ret = status; + goto done; + } + service_device = service_device_obj->DeviceExtension; + service_device->base.base.is_fdo = FALSE; + service_device->base.base.removed = FALSE; + service_device->base.kind = BTHENUM_PHYS_DEVICE_KIND_DEVICE_SERVICE; + service_device->base.parent_fdo = fdo_bus_ext; + + service_device->remote_device = device; + list_add_tail( &device->services, &service_device->entry ); + service_device->device_obj = service_device_obj; + service_device->service_guid = new_guid->guid; + memset( &service_device->service_link_name, 0, + sizeof( service_device->service_link_name ) ); + } + done: + RtlLeaveCriticalSection(&fdo_bus_ext->cs); + free(guid_entries); + if (invalidate_bus_relations) + IoInvalidateDeviceRelations( fdo_bus_ext->device_obj, BusRelations ); + return ret; +} + static NTSTATUS WINAPI pdo_device_pnp( DEVICE_OBJECT *device_obj, IRP *irp ) { struct bthenum_phys_remote_radio_ext *device = @@ -568,6 +720,7 @@ static NTSTATUS WINAPI pdo_device_pnp( DEVICE_OBJECT *device_obj, IRP *irp ) case IRP_MN_START_DEVICE: { GUID g = GUID_NULL; + GUID *guids = NULL;
if ( IoRegisterDeviceInterface( device->device_obj, &GUID_BTH_DEVICE_INTERFACE, NULL, &device->device_link_name ) == STATUS_SUCCESS ) @@ -575,6 +728,19 @@ static NTSTATUS WINAPI pdo_device_pnp( DEVICE_OBJECT *device_obj, IRP *irp ) IoSetDevicePropertyData( device_obj, &DEVPKEY_Bluetooth_ServiceGUID, LOCALE_NEUTRAL, 0, DEVPROP_TYPE_GUID, sizeof( GUID_NULL ), &g ); device_set_properties( device_obj, NULL, device->known_props, device->props ); + if (device->props.uuids_len != 0) + { + guids = calloc( device->props.uuids_len, sizeof( GUID ) ); + if (!guids) + { + status = STATUS_NO_MEMORY; + break; + } + winebluetooth_guid_array_copy( device->props.guids, device->props.uuids_len, guids ); + winebluetooth_guid_array_free( device->props.guids ); + } + remote_device_refresh_services( device, guids, device->props.uuids_len ); + if (guids) free( guids ); break; } case IRP_MN_SURPRISE_REMOVAL: @@ -623,6 +789,113 @@ static NTSTATUS WINAPI pdo_device_pnp( DEVICE_OBJECT *device_obj, IRP *irp )
#define LOCALMFG_FORMAT "LOCALMFG&%04x"
+static NTSTATUS pdo_service_query_id( const struct bthenum_phys_service_ext *service, IRP *irp, + BUS_QUERY_ID_TYPE type, struct string_buffer *buf ) +{ + struct winebluetooth_device_pnpid pnpid = service->remote_device->props.pnpid; + + TRACE( "service=%p irp=%p type=%s buf=%p\n", service, irp, debugstr_BUS_QUERY_ID_TYPE( type ), buf ); + + switch(type) + { + case BusQueryInstanceID: + { + BYTE *addr = service->remote_device->props.address.rgBytes; + append_id( buf, L"%p&%02X%02X%02X%02X%02X%02X", + service->remote_device->remote_radio_handle, addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5] ); + break; + } + case BusQueryDeviceID: + append_id( buf, L"BTHENUM\" GUID_FORMAT "_" PNPID_FORMAT, + GUID_FORMAT_ARGS( service->service_guid ), PNPID_FORMAT_ARGS( pnpid ) ); + break; + case BusQueryHardwareIDs: + { + append_id( buf, L"BTHENUM\" GUID_FORMAT "_" PNPID_FORMAT, + GUID_FORMAT_ARGS( service->service_guid ), PNPID_FORMAT_ARGS( pnpid ) ); + append_id( buf, L"BTHENUM\" GUID_FORMAT "_" LOCALMFG_FORMAT, + GUID_FORMAT_ARGS( service->service_guid ), service->base.parent_fdo->localmfg ); + append_id( buf, L"" ); + break; + } + case BusQueryCompatibleIDs: + { + append_id( buf, L"BTHENUM\" GUID_FORMAT, GUID_FORMAT_ARGS( service->service_guid ) ); + append_id( buf, L"BTHENUM\" GUID_FORMAT "_GENERIC", + GUID_FORMAT_ARGS( service->service_guid ) ); + append_id( buf, L"" ); + break; + } + default: + FIXME( "Unhandled ID query type %s\n", debugstr_BUS_QUERY_ID_TYPE( type ) ); + return irp->IoStatus.Status; + } + + if ( buf->string == NULL ) irp->IoStatus.Status = STATUS_NO_MEMORY; + else + { + irp->IoStatus.Status = STATUS_SUCCESS; + irp->IoStatus.Information = (ULONG_PTR)buf->string; + } + + return irp->IoStatus.Status; +} + +static NTSTATUS WINAPI pdo_service_pnp( DEVICE_OBJECT *device, IRP *irp ) +{ + struct bthenum_phys_service_ext *service = (struct bthenum_phys_service_ext *)device->DeviceExtension; + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + UCHAR code = stack->MinorFunction; + NTSTATUS status = irp->IoStatus.Status; + + TRACE( "device %p, irp %p, code %s\n", device, irp, debugstr_minor_function_code( code ) ); + switch (code) + { + case IRP_MN_START_DEVICE: + status = IoRegisterDeviceInterface( device, &service->service_guid, NULL, + &service->service_link_name ); + if (status == STATUS_SUCCESS) + status = IoSetDeviceInterfaceState( &service->service_link_name, TRUE ); + break; + case IRP_MN_SURPRISE_REMOVAL: + if (!service->base.base.removed) + { + service->base.base.removed = TRUE; + list_remove( &service->entry ); + } + status = STATUS_SUCCESS; + break; + case IRP_MN_REMOVE_DEVICE: + assert( service->base.base.removed ); + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + IoDeleteDevice( device ); + return STATUS_SUCCESS; + case IRP_MN_QUERY_ID: + { + BUS_QUERY_ID_TYPE type = stack->Parameters.QueryId.IdType; + struct string_buffer buf = { 0 }; + + status = pdo_service_query_id( service, irp, type, &buf ); + break; + } + case IRP_MN_QUERY_CAPABILITIES: + { + DEVICE_CAPABILITIES *caps = stack->Parameters.DeviceCapabilities.Capabilities; + caps->Removable = TRUE; + caps->SurpriseRemovalOK = TRUE; + caps->RawDeviceOK = TRUE; + status = STATUS_SUCCESS; + break; + } + } + + irp->IoStatus.Status = status; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return status; +} + static NTSTATUS WINAPI pdo_pnp( DEVICE_OBJECT *device, IRP *irp ) { struct phys_device_ext *base = (struct phys_device_ext *)device->DeviceExtension; @@ -630,6 +903,8 @@ static NTSTATUS WINAPI pdo_pnp( DEVICE_OBJECT *device, IRP *irp ) { case BTHENUM_PHYS_DEVICE_KIND_REMOTE_RADIO: return pdo_device_pnp( device, irp ); + case BTHENUM_PHYS_DEVICE_KIND_DEVICE_SERVICE: + return pdo_service_pnp( device, irp ); DEFAULT_UNREACHABLE; } } diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index 1809cfc6cf5..c7b6b723050 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -119,6 +119,41 @@ static inline int starts_with( const char *str, const char *prefix ) return !strncmp( str, prefix, strlen( prefix ) ); }
+static BOOL parse_uuid( GUID *guid, const char *str ) +{ + /* standard uuid format */ + if (strlen(str) == 36 && str[8] == '-' && str[13] == '-' && str[18] == '-' && str[23] == '-') + { + int i; + unsigned char *out = guid->Data4; + + if (sscanf( str, "%x-%hx-%hx-", (int *)&guid->Data1, &guid->Data2, &guid->Data3 ) != 3) return FALSE; + for (i = 19; i < 36; i++) + { + unsigned char val; + + if (i == 23) continue; + + if (str[i] >= '0' && str[i] <= '9') val = str[i] - '0'; + else if (str[i] >= 'a' && str[i] <= 'f') val = str[i] - 'a' + 10; + else if (str[i] >= 'A' && str[i] <= 'F') val = str[i] - 'A' + 10; + else return FALSE; + val <<= 4; + i++; + + if (str[i] >= '0' && str[i] <= '9') val += str[i] - '0'; + else if (str[i] >= 'a' && str[i] <= 'f') val += str[i] - 'a' + 10; + else if (str[i] >= 'A' && str[i] <= 'F') val += str[i] - 'A' + 10; + else return FALSE; + *out++ = val; + } + return TRUE; + } + + + return FALSE; +} + static NTSTATUS bluez_dbus_error_to_ntstatus( const DBusError *error ) {
@@ -476,6 +511,34 @@ static void bluez_device_prop_from_dict_entry( const char *prop_name, DBusMessag &props->pnpid.product_version ); *props_mask |= WINEBLUETOOTH_DEVICE_PROPERTY_PNPID; } + else if ( wanted_props_mask & WINEBLUETOOTH_DEVICE_PROPERTY_UUIDS && + !strcmp( prop_name, "UUIDs" ) && + p_dbus_message_iter_get_arg_type( variant ) == DBUS_TYPE_ARRAY ) + { + DBusMessageIter array_iter; + props->uuids_len = p_dbus_message_iter_get_element_count( variant ); + *props_mask |= WINEBLUETOOTH_DEVICE_PROPERTY_UUIDS; + + if (props->uuids_len != 0) + { + SIZE_T i = 0; + props->guids = calloc( props->uuids_len, sizeof( GUID ) ); + if (!props->guids) + { + props->uuids_len = 0; + return; + } + p_dbus_message_iter_recurse( variant, &array_iter ); + while(p_dbus_message_iter_has_next( &array_iter )) + { + const char *uuid_str = NULL; + + p_dbus_message_iter_get_basic( &array_iter, &uuid_str ); + parse_uuid( &props->guids[i++], uuid_str ); + p_dbus_message_iter_next( &array_iter ); + } + } + } }
NTSTATUS @@ -501,7 +564,8 @@ bluez_device_props_get_all_reply_to_params(
bluez_device_prop_from_dict_entry( prop_name, &variant, params->get_device_reported_name, ¶ms->props, &prop, - WINEBLUETOOTH_DEVICE_ALL_PROPERTIES ); + WINEBLUETOOTH_DEVICE_ALL_PROPERTIES + & ~WINEBLUETOOTH_DEVICE_PROPERTY_UUIDS ); params->valid_props |= prop; }
@@ -985,6 +1049,7 @@ static DBusHandlerResult bluez_filter( DBusConnection *conn, DBusMessage *msg, v { "LegacyPairing", WINEBLUETOOTH_DEVICE_PROPERTY_LEGACY_PAIRING_HINT }, { "ServicesResolved", WINEBLUETOOTH_DEVICE_PROPERTY_SERVICES_RESOLVED }, { "Modalias", WINEBLUETOOTH_DEVICE_PROPERTY_PNPID }, + { "UUIDs", WINEBLUETOOTH_DEVICE_PROPERTY_UUIDS } }; const char *object_path = p_dbus_message_get_path( msg );
diff --git a/dlls/winebth.sys/unixlib.c b/dlls/winebth.sys/unixlib.c index 9deaa848975..79fdb101648 100644 --- a/dlls/winebth.sys/unixlib.c +++ b/dlls/winebth.sys/unixlib.c @@ -179,6 +179,21 @@ static NTSTATUS bluetooth_event_loop_once( void *args ) return bluez_dbus_loop( dbus_connection, params->unix_watcher_ctx, ¶ms->result ); }
+static NTSTATUS bluetooth_guid_array_copy( void *args ) +{ + struct bluetooth_guid_array_copy_params *params = args; + + memcpy( params->dst, (GUID *)params->src, params->src_len * sizeof( GUID ) ); + return STATUS_SUCCESS; +} + +static NTSTATUS bluetooth_guid_array_free( void *args ) +{ + struct bluetooth_guid_array_free_params *params = args; + free( (GUID *)params->arr ); + return STATUS_SUCCESS; +} + const unixlib_entry_t __wine_unix_call_funcs[] = { bluetooth_init, bluetooth_shutdown, @@ -192,6 +207,9 @@ const unixlib_entry_t __wine_unix_call_funcs[] = { bluetooth_watcher_close,
bluetooth_event_loop_once, + + bluetooth_guid_array_copy, + bluetooth_guid_array_free, };
C_ASSERT( ARRAYSIZE( __wine_unix_call_funcs ) == unix_funcs_count ); diff --git a/dlls/winebth.sys/unixlib.h b/dlls/winebth.sys/unixlib.h index e3e60411d3b..15fd76c1366 100644 --- a/dlls/winebth.sys/unixlib.h +++ b/dlls/winebth.sys/unixlib.h @@ -103,6 +103,19 @@ struct bluetooth_event_loop_once_params struct winebluetooth_event_loop_result result; };
+struct bluetooth_guid_array_copy_params +{ + UINT_PTR src; + SIZE_T src_len; + + GUID *dst; +}; + +struct bluetooth_guid_array_free_params +{ + UINT_PTR arr; +}; + enum bluetoothapis_funcs { unix_bluetooth_init, @@ -118,6 +131,9 @@ enum bluetoothapis_funcs
unix_bluetooth_event_loop_once,
+ unix_bluetooth_guid_array_copy, + unix_bluetooth_guid_array_free, + unix_funcs_count };
diff --git a/dlls/winebth.sys/winebluetooth.c b/dlls/winebth.sys/winebluetooth.c index fc4cad3115b..0cc499d7acb 100644 --- a/dlls/winebth.sys/winebluetooth.c +++ b/dlls/winebth.sys/winebluetooth.c @@ -73,6 +73,26 @@ void winebluetooth_device_free( winebluetooth_device_t device ) UNIX_BLUETOOTH_CALL( bluetooth_device_free, ¶ms ); }
+NTSTATUS winebluetooth_guid_array_copy( UINT_PTR src, SIZE_T len, GUID *dst ) +{ + struct bluetooth_guid_array_copy_params params = {0}; + + TRACE( "(%p, %ld, %p)\n", src, len, dst ); + params.src = src; + params.src_len = len; + params.dst = dst; + return UNIX_BLUETOOTH_CALL( bluetooth_guid_array_copy, ¶ms ); +} + +NTSTATUS winebluetooth_guid_array_free( UINT_PTR src ) +{ + struct bluetooth_guid_array_free_params params = {0}; + + TRACE( "(%p)\n", src ); + params.arr = src; + return UNIX_BLUETOOTH_CALL( bluetooth_guid_array_free, ¶ms ); +} + NTSTATUS winebluetooth_watcher_init( winebluetooth_watcher_t *watcher ) { struct bluetooth_watcher_init_params args = { 0 }; diff --git a/dlls/winebth.sys/winebluetooth.h b/dlls/winebth.sys/winebluetooth.h index 97d978b9e0c..ff471855edb 100644 --- a/dlls/winebth.sys/winebluetooth.h +++ b/dlls/winebth.sys/winebluetooth.h @@ -108,6 +108,12 @@ struct winebluetooth_device_properties BOOL legacy_pairing_hint; BOOL services_resolved; struct winebluetooth_device_pnpid pnpid; + SIZE_T uuids_len; +#ifdef WINE_UNIX_LIB + GUID *guids; +#else + UINT_PTR guids; +#endif };
enum winebluetooth_discovery_transport @@ -142,6 +148,9 @@ static inline BOOL winebluetooth_device_equal( winebluetooth_device_t d1, return d1.handle == d2.handle; }
+NTSTATUS winebluetooth_guid_array_copy( UINT_PTR src, SIZE_T uuids, GUID *arr ); +NTSTATUS winebluetooth_guid_array_free( UINT_PTR src ); + typedef struct { #ifdef WINE_UNIX_LIB @@ -172,6 +181,7 @@ enum winebluetooth_watcher_event_type #define WINEBLUETOOTH_DEVICE_PROPERTY_LEGACY_PAIRING_HINT (1 << 9) #define WINEBLUETOOTH_DEVICE_PROPERTY_SERVICES_RESOLVED (1 << 10) #define WINEBLUETOOTH_DEVICE_PROPERTY_PNPID (1 << 11) +#define WINEBLUETOOTH_DEVICE_PROPERTY_UUIDS (1 << 12)
#define WINEBLUETOOTH_DEVICE_ALL_PROPERTIES \ ( WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS | WINEBLUETOOTH_DEVICE_PROPERTY_ADDRESS_TYPE | \ @@ -179,7 +189,8 @@ enum winebluetooth_watcher_event_type WINEBLUETOOTH_DEVICE_PROPERTY_TRUSTED | WINEBLUETOOTH_DEVICE_PROPERTY_PAIRED | \ WINEBLUETOOTH_DEVICE_PROPERTY_BONDED | WINEBLUETOOTH_DEVICE_PROPERTY_NAME | \ WINEBLUETOOTH_DEVICE_PROPERTY_LEGACY_PAIRING_HINT | \ - WINEBLUETOOTH_DEVICE_PROPERTY_SERVICES_RESOLVED | WINEBLUETOOTH_DEVICE_PROPERTY_PNPID ) + WINEBLUETOOTH_DEVICE_PROPERTY_SERVICES_RESOLVED | WINEBLUETOOTH_DEVICE_PROPERTY_PNPID | \ + WINEBLUETOOTH_DEVICE_PROPERTY_UUIDS )
enum winebluetooth_device_connection_type { diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 637d4933752..144bf546ba7 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -211,7 +211,7 @@ static void add_bluetooth_radio( struct winebluetooth_watcher_event_radio_added list_add_tail( &device_list, &device->entry ); LeaveCriticalSection( &device_list_cs );
- bthenum_create_fdo_bus( device_obj, &device->device_fdo_bus ); + bthenum_create_fdo_bus( device_obj, &device->device_fdo_bus, event.props.manufacturer ); IoInvalidateDeviceRelations( bus_pdo, BusRelations ); }
diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h index 7ea7f03108d..32d0d2ad95b 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -40,8 +40,8 @@ extern NTSTATUS WINAPI bthenum_device_removed( DEVICE_OBJECT *fdo_bus, const winebluetooth_device_t device_handle ); extern NTSTATUS WINAPI bthenum_device_props_changed( DEVICE_OBJECT *fdo_bus, struct winebluetooth_watcher_event_device_props_changed event ); -extern NTSTATUS WINAPI - bthenum_create_fdo_bus( DEVICE_OBJECT *pdo, DEVICE_OBJECT **fdo_bus ); +extern NTSTATUS WINAPI bthenum_create_fdo_bus( DEVICE_OBJECT *pdo, DEVICE_OBJECT **fdo_bus, + UINT16 localmfg ); extern NTSTATUS WINAPI bthenum_entry_point( DRIVER_OBJECT *driver, UNICODE_STRING *path );
struct string_buffer