From: Vibhav Pant vibhavp@gmail.com
--- dlls/winebth.sys/dbus.c | 91 ++++++++++++++++++++++++++++++++ dlls/winebth.sys/winebluetooth.h | 34 ++++++++++++ dlls/winebth.sys/winebth.c | 27 ++++++++++ include/ddk/bthguid.h | 25 +++++++++ 4 files changed, 177 insertions(+)
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index f3ffcaffa1f..8ab84a7bd45 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -167,6 +167,89 @@ 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_DISCOVERABLE; + } + 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; + } +} + struct bluez_watcher_ctx { void *init_device_list_call; @@ -269,6 +352,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;
@@ -285,6 +370,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 ); + } list_add_tail( adapter_list, &init_device->entry ); TRACE( "Found BlueZ %s object '%s': %p\n", BLUEZ_INTERFACE_ADAPTER, radio_name->str, init_device->object.radio.radio.handle ); diff --git a/dlls/winebth.sys/winebluetooth.h b/dlls/winebth.sys/winebluetooth.h index aeb6438cf97..aa6491b625f 100644 --- a/dlls/winebth.sys/winebluetooth.h +++ b/dlls/winebth.sys/winebluetooth.h @@ -34,6 +34,25 @@ typedef struct #endif } 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) + union winebluetooth_property { BOOL boolean; @@ -48,6 +67,19 @@ struct winebluetooth_bluetooth_version UCHAR minor; };
+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; + struct winebluetooth_bluetooth_version version; +}; + NTSTATUS winebluetooth_radio_get_unique_name( winebluetooth_radio_t radio, char *name, SIZE_T *size ); void winebluetooth_radio_free( winebluetooth_radio_t radio ); @@ -73,6 +105,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/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index c0959ab781f..51a4e29d3ca 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -70,6 +70,8 @@ struct bluetooth_radio
DEVICE_OBJECT *device_obj; DEVICE_OBJECT *device_fdo_bus; + winebluetooth_radio_props_mask_t props_mask; + struct winebluetooth_radio_properties props; winebluetooth_radio_t radio; WCHAR *hw_name; UNICODE_STRING bthport_symlink_name; @@ -183,6 +185,8 @@ static void add_bluetooth_radio( struct winebluetooth_watcher_event_radio_added device->removed = FALSE; device->hw_name = hw_name; device->device_fdo_bus = NULL; + device->props = event.props; + device->props_mask = event.props_mask; InitializeListHead(&device->irp_list);
EnterCriticalSection( &device_list_cs ); @@ -403,6 +407,29 @@ static NTSTATUS WINAPI pdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp ) } case IRP_MN_START_DEVICE: { + union + { + UINT64 uint; + BYTE addr[8]; + } radio_addr; + + if (device->props_mask & WINEBLUETOOTH_RADIO_PROPERTY_ADDRESS) + { + memset( &radio_addr, 0, sizeof( radio_addr ) ); + memcpy( &radio_addr.addr[2], device->props.address.rgBytes, + sizeof( device->props.address.rgBytes ) ); + IoSetDevicePropertyData( device_obj, &DEVPKEY_BluetoothRadio_Address, + LOCALE_NEUTRAL, 0, DEVPROP_TYPE_UINT64, + sizeof( radio_addr ), &radio_addr ); + } + if (device->props_mask & WINEBLUETOOTH_RADIO_PROPERTY_MANUFACTURER) + { + UINT16 manufacturer = device->props.manufacturer; + IoSetDevicePropertyData( device_obj, &DEVPKEY_BluetoothRadio_Manufacturer, + LOCALE_NEUTRAL, 0, DEVPROP_TYPE_UINT16, + sizeof( manufacturer ), &manufacturer ); + } + if (IoRegisterDeviceInterface( device_obj, &GUID_BTHPORT_DEVICE_INTERFACE, NULL, &device->bthport_symlink_name ) == STATUS_SUCCESS) IoSetDeviceInterfaceState( &device->bthport_symlink_name, TRUE ); diff --git a/include/ddk/bthguid.h b/include/ddk/bthguid.h index f565fc177d5..ce0f4adfad5 100644 --- a/include/ddk/bthguid.h +++ b/include/ddk/bthguid.h @@ -27,4 +27,29 @@ DEFINE_GUID( GUID_BLUETOOTH_RADIO_INTERFACE, 0x92383b0e, 0xf90e, 0x4ac9, 0x8d, 0x44, 0x8c, 0x2d, 0x0d, 0x0e, 0xbd, 0xa2 );
+#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 */ + + +#ifdef WINE_BTH_EXTENSIONS +#define DEFINE_WINEBTH_RADIO_DEVPROPKEY( d, i ) \ + DEFINE_DEVPROPKEY( DEVPKEY_WineBluetooth_Radio_##d, 0x9ccd2c1a, 0x4b06, 0x4ecf, 0xb1, 0xd5, \ + 0x35, 0x62, 0xd6, 0xb0, 0xda, 0xac, (i) ) + +/* Authentication I/O capability as currently advertised by the radio. DEVPROP_TYPE_BYTE */ +DEFINE_WINEBTH_RADIO_DEVPROPKEY( Capability, 1 ); + +#undef DEFINE_BTH_RADIO_DEVPROPKEY +#endif /* WINE_BTH_EXTENSIONS */ + + #endif