From: Vibhav Pant <vibhavp@gmail.com> --- dlls/winebth.sys/dbus.c | 55 +++++++++++++++++++++++++++ dlls/winebth.sys/winebth.c | 67 ++++++++++++++++++++++++++++++++- dlls/winebth.sys/winebth_priv.h | 8 ++++ 3 files changed, 129 insertions(+), 1 deletion(-) diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index 881621e8ca9..efc264e41ef 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -2148,6 +2148,55 @@ static void bluez_signal_handler( DBusConnection *conn, DBusMessage *msg, const return; } } + else if (!strcmp( iface, BLUEZ_INTERFACE_GATT_CHARACTERISTICS )) + { + struct winebluetooth_watcher_event_gatt_characteristic_value_changed changed_event = {0}; + union winebluetooth_watcher_event_data event; + DBusMessageIter changed_props_iter, variant; + const char *prop_name, *object_path; + struct unix_name *chrc_name; + BOOL val_changed = FALSE; + + p_dbus_message_iter_next( &iter ); + p_dbus_message_iter_recurse( &iter, &changed_props_iter ); + while ((prop_name = bluez_next_dict_entry( &changed_props_iter, &variant ))) + { + if (!strcmp( prop_name, "Value" ) + && p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_ARRAY + && p_dbus_message_iter_get_element_type( &variant ) == DBUS_TYPE_BYTE) + { + DBusMessageIter bytes_iter; + + p_dbus_message_iter_recurse( &variant, &bytes_iter ); + if (!bluez_gatt_characteristic_value_new_from_iter( msg, &bytes_iter, &changed_event.value )) + return; + val_changed = TRUE; + } + } + if (!val_changed) + return; + + object_path = p_dbus_message_get_path( msg ); + TRACE( "Value changed for GATT characteristic %s\n", debugstr_a( object_path ) ); + if (!(chrc_name = unix_name_get_or_create( object_path ))) + { + ERR( "Failed to allocate memory for GATT characteristic path %s\n", debugstr_a( object_path ) ); + if (!winebluetooth_gatt_characteristic_value_is_inline( &changed_event.value )) + bluez_gatt_characteristic_value_free( (struct bluez_gatt_characteristic_value *)changed_event.value.handle ); + return; + } + + changed_event.characteristic.handle = (UINT_PTR)chrc_name; + event.gatt_characteristic_value_changed = changed_event; + if (!bluez_event_list_queue_new_event( event_list, BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_CHANGED, + event )) + { + unix_name_free( chrc_name ); + if (!winebluetooth_gatt_characteristic_value_is_inline( &changed_event.value )) + bluez_gatt_characteristic_value_free( (struct bluez_gatt_characteristic_value *)changed_event.value.handle ); + return; + } + } } } @@ -2241,6 +2290,12 @@ static void bluez_watcher_free( struct bluez_watcher_ctx *watcher ) case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_REMOVED: unix_name_free( (struct unix_name *)event1->event.gatt_characterisic_removed.handle ); break; + case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_CHANGED: + unix_name_free( (struct unix_name *)event1->event.gatt_characteristic_value_changed.characteristic.handle ); + if (!winebluetooth_gatt_characteristic_value_is_inline( &event1->event.gatt_characteristic_added.value )) + bluez_gatt_characteristic_value_free( + (struct bluez_gatt_characteristic_value *)event1->event.gatt_characteristic_added.value.handle ); + break; } free( event1 ); } diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 84ed2b91256..6fcc79a0753 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -1,7 +1,7 @@ /* * Bluetooth bus driver * - * Copyright 2024-2025 Vibhav Pant + * Copyright 2024-2026 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1420,6 +1420,68 @@ static void bluetooth_gatt_characteristic_remove( winebluetooth_gatt_characteris winebluetooth_gatt_characteristic_free( handle ); } +static void bluetooth_gatt_characteristic_value_update( struct winebluetooth_watcher_event_gatt_characteristic_value_changed event ) +{ + struct bluetooth_radio *radio; + BOOL free_chrc_val = TRUE; + + EnterCriticalSection( &device_list_cs ); + LIST_FOR_EACH_ENTRY( radio, &device_list, struct bluetooth_radio, entry ) + { + struct bluetooth_remote_device *device; + + LIST_FOR_EACH_ENTRY( device, &radio->remote_devices, struct bluetooth_remote_device, entry ) + { + struct bluetooth_gatt_service *svc; + + EnterCriticalSection( &device->props_cs ); + if (!device->le) + { + LeaveCriticalSection( &device->props_cs ); + continue; + } + LIST_FOR_EACH_ENTRY( svc, &device->gatt_services, struct bluetooth_gatt_service, entry ) + { + struct bluetooth_gatt_characteristic *chrc; + + EnterCriticalSection( &svc->chars_cs ); + LIST_FOR_EACH_ENTRY( chrc, &svc->characteristics, struct bluetooth_gatt_characteristic, entry ) + { + if (winebluetooth_gatt_characteristic_equal( chrc->characteristic, event.characteristic )) + { + if (!chrc->value || chrc->value->DataSize < event.value.size) + { + void *tmp; + + tmp = realloc( chrc->value, offsetof( BTH_LE_GATT_CHARACTERISTIC_VALUE, Data[event.value.size] ) ); + if (!tmp) + { + LeaveCriticalSection( &svc->chars_cs ); + LeaveCriticalSection( &device->props_cs ); + goto done; + } + chrc->value = tmp; + } + chrc->value->DataSize = event.value.size; + winebluetooth_gatt_characteristic_value_move( &event.value, chrc->value->Data ); + free_chrc_val = FALSE; + LeaveCriticalSection( &svc->chars_cs ); + LeaveCriticalSection( &device->props_cs ); + goto done; + } + } + LeaveCriticalSection( &svc->chars_cs ); + } + LeaveCriticalSection( &device->props_cs ); + } + } +done: + LeaveCriticalSection( &device_list_cs ); + if (free_chrc_val) + winebluetooth_gatt_characteristic_value_free( &event.value ); + winebluetooth_gatt_characteristic_free( event.characteristic ); +} + static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg ) { NTSTATUS status; @@ -1471,6 +1533,9 @@ static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg ) case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_REMOVED: bluetooth_gatt_characteristic_remove( event->event_data.gatt_characterisic_removed ); break; + case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_CHANGED: + bluetooth_gatt_characteristic_value_update( event->event_data.gatt_characteristic_value_changed ); + 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 5b13f78aa59..3e32ae9470b 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -295,6 +295,7 @@ enum winebluetooth_watcher_event_type BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_GATT_SERVICE_REMOVED, BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_ADDED, BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_REMOVED, + BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_CHANGED, }; struct winebluetooth_watcher_event_radio_added @@ -369,6 +370,12 @@ struct winebluetooth_watcher_event_gatt_characteristic_added struct winebluetooth_gatt_characteristic_value value; }; +struct winebluetooth_watcher_event_gatt_characteristic_value_changed +{ + winebluetooth_gatt_characteristic_t characteristic; + struct winebluetooth_gatt_characteristic_value value; +}; + union winebluetooth_watcher_event_data { struct winebluetooth_watcher_event_radio_added radio_added; @@ -382,6 +389,7 @@ union winebluetooth_watcher_event_data winebluetooth_gatt_service_t gatt_service_removed; struct winebluetooth_watcher_event_gatt_characteristic_added gatt_characteristic_added; winebluetooth_gatt_characteristic_t gatt_characterisic_removed; + struct winebluetooth_watcher_event_gatt_characteristic_value_changed gatt_characteristic_value_changed; }; struct winebluetooth_watcher_event -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10208