From: Vibhav Pant <vibhavp@gmail.com> --- dlls/winebth.sys/dbus.c | 160 ++++++++++++++++++++++++++++--- dlls/winebth.sys/dbus.h | 1 + dlls/winebth.sys/unixlib.c | 17 ++++ dlls/winebth.sys/unixlib.h | 14 +++ dlls/winebth.sys/unixlib_priv.h | 2 + dlls/winebth.sys/winebluetooth.c | 20 ++++ dlls/winebth.sys/winebth.c | 118 ++++++++++++++++++++++- dlls/winebth.sys/winebth_priv.h | 11 +++ include/wine/winebth.h | 12 +++ 9 files changed, 340 insertions(+), 15 deletions(-) diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c index efc264e41ef..4bc9c2b0340 100644 --- a/dlls/winebth.sys/dbus.c +++ b/dlls/winebth.sys/dbus.c @@ -1033,6 +1033,104 @@ void bluez_gatt_characteristic_value_move( struct winebluetooth_gatt_characteris bluez_gatt_characteristic_value_free( dbus_val ); } +static NTSTATUS bluez_gatt_error_to_status( const DBusError *error ) +{ + if (p_dbus_error_has_name( error, "org.bluez.Error.NotPermitted" )) + { + if (!strcmp( error->message, "Read not permitted" )) + return STATUS_BTH_ATT_READ_NOT_PERMITTED; + else if (!strcmp( error->message, "Write not permitted" )) + return STATUS_BTH_ATT_WRITE_NOT_PERMITTED; + else + return STATUS_BTH_ATT_INSUFFICIENT_AUTHENTICATION; + } + else if (p_dbus_error_has_name( error, "org.bluez.Error.NotAuthorized" )) + return STATUS_BTH_ATT_INSUFFICIENT_AUTHORIZATION; + else if (p_dbus_error_has_name( error, "org.bluez.Error.NotSupported" )) + return STATUS_BTH_ATT_REQUEST_NOT_SUPPORTED; + else if (p_dbus_error_has_name( error, "org.bluez.Error.InvalidArguments" )) + { + if (!strcmp( error->message, "Invalid offset" )) + return STATUS_BTH_ATT_INVALID_OFFSET; + else if (!strcmp( error->message, "Invalid Length" )) + return STATUS_BTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH; + return STATUS_BTH_ATT_UNKNOWN_ERROR; + } + else if (p_dbus_error_has_name( error, "org.bluez.Error.Failed" )) + return STATUS_BTH_ATT_UNKNOWN_ERROR; + return bluez_dbus_error_to_ntstatus( error ); +} + +struct bluez_async_req_data +{ + IRP *irp; + struct bluez_watcher_ctx *watcher_ctx; +}; + +static void bluez_gatt_characteristic_read_callback( DBusPendingCall *pending, void *param ); + +NTSTATUS bluez_gatt_characteristic_read( void *connection, void *watcher_ctx, struct unix_name *characteristic, IRP *irp ) +{ + DBusMessageIter args_iter, dict_iter = DBUS_MESSAGE_ITER_INIT_CLOSED; + struct bluez_async_req_data *data = NULL; + DBusPendingCall *pending_call = NULL; + DBusMessage *request; + NTSTATUS status; + dbus_bool_t success; + + TRACE( "(%s, %p)\n", debugstr_a( characteristic->str ), irp ); + + request = p_dbus_message_new_method_call( BLUEZ_DEST, characteristic->str, BLUEZ_INTERFACE_GATT_CHARACTERISTICS, + "ReadValue" ); + if (!request) + return STATUS_NO_MEMORY; + if (!(data = malloc( sizeof( *data ) ))) + { + status = STATUS_NO_MEMORY; + goto failed; + } + + data->irp = irp; + data->watcher_ctx = watcher_ctx; + p_dbus_message_iter_init_append( request, &args_iter ); + if (!p_dbus_message_iter_open_container( &args_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter )) + { + status = STATUS_NO_MEMORY; + goto failed; + } + if (!p_dbus_message_iter_close_container( &args_iter, &dict_iter )) + { + status = STATUS_NO_MEMORY; + goto failed; + } + success = p_dbus_connection_send_with_reply( connection, request, &pending_call, bluez_timeout ); + if (!success) + { + status = STATUS_NO_MEMORY; + goto failed; + } + if (!pending_call) + { + status = STATUS_INTERNAL_ERROR; + goto failed; + } + if (!p_dbus_pending_call_set_notify( pending_call, bluez_gatt_characteristic_read_callback, data, free )) + { + p_dbus_pending_call_cancel( pending_call ); + p_dbus_pending_call_unref( pending_call ); + status = STATUS_NO_MEMORY; + goto failed; + } + p_dbus_pending_call_unref( pending_call ); + p_dbus_message_unref( request ); + return STATUS_PENDING; +failed: + p_dbus_message_iter_abandon_container_if_open( &args_iter, &dict_iter ); + p_dbus_message_unref( request ); + free( data ); + return status; +} + struct bluez_watcher_ctx { void *init_device_list_call; @@ -1050,6 +1148,44 @@ struct bluez_watcher_ctx struct list event_list; }; +static BOOL bluez_event_list_queue_new_event( struct list *event_list, + enum winebluetooth_watcher_event_type event_type, + union winebluetooth_watcher_event_data event ); + +static void bluez_gatt_characteristic_read_callback( DBusPendingCall *pending, void *param ) +{ + struct winebluetooth_watcher_event_gatt_characteristic_value_read read = {0}; + union winebluetooth_watcher_event_data event; + struct bluez_async_req_data *data = param; + DBusMessage *reply; + DBusError error; + + read.irp = data->irp; + reply = p_dbus_pending_call_steal_reply( pending ); + p_dbus_error_init( &error ); + if (p_dbus_set_error_from_message( &error, reply )) + read.result = bluez_gatt_error_to_status( &error ); + else + { + DBusMessageIter iter, bytes_iter; + + p_dbus_message_iter_init( reply, &iter ); + p_dbus_message_iter_recurse( &iter, &bytes_iter ); + if (!bluez_gatt_characteristic_value_new_from_iter( reply, &bytes_iter, &read.value )) + read.result = STATUS_NO_MEMORY; + } + + event.gatt_characteristic_value_read = read; + if (!bluez_event_list_queue_new_event( &data->watcher_ctx->event_list, + BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_READ, event )) + { + if (!winebluetooth_gatt_characteristic_value_is_inline( &read.value )) + bluez_gatt_characteristic_value_free( (struct bluez_gatt_characteristic_value *)read.value.handle ); + } + p_dbus_error_free( &error ); + p_dbus_message_unref( reply ); +} + struct bluez_init_entry { union { @@ -1471,18 +1607,9 @@ NTSTATUS bluez_device_disconnect( void *connection, const char *device_path ) return STATUS_SUCCESS; } -static BOOL bluez_event_list_queue_new_event( struct list *event_list, - enum winebluetooth_watcher_event_type event_type, - union winebluetooth_watcher_event_data event ); -struct bluez_device_pair_data -{ - IRP *irp; - struct bluez_watcher_ctx *watcher_ctx; -}; - static void bluez_device_pair_callback( DBusPendingCall *pending, void *param ) { - struct bluez_device_pair_data *data = param; + struct bluez_async_req_data *data = param; DBusMessage *reply; DBusError error; union winebluetooth_watcher_event_data event = {0}; @@ -1506,7 +1633,7 @@ NTSTATUS bluez_device_start_pairing( void *connection, void *watcher_ctx, struct { DBusMessage *request; DBusPendingCall *pending_call = NULL; - struct bluez_device_pair_data *data; + struct bluez_async_req_data *data; dbus_bool_t success; TRACE( "(%p, %p, %s, %p)\n", connection, watcher_ctx, debugstr_a( device->str ), irp ); @@ -2296,6 +2423,11 @@ static void bluez_watcher_free( struct bluez_watcher_ctx *watcher ) bluez_gatt_characteristic_value_free( (struct bluez_gatt_characteristic_value *)event1->event.gatt_characteristic_added.value.handle ); break; + case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_READ: + if (!winebluetooth_gatt_characteristic_value_is_inline( &event1->event.gatt_characteristic_value_read.value )) + bluez_gatt_characteristic_value_free( (struct bluez_gatt_characteristic_value *) + event1->event.gatt_characteristic_value_read.value.handle ); + break; } free( event1 ); } @@ -2552,6 +2684,7 @@ static NTSTATUS bluez_build_initial_device_lists( DBusMessage *reply, struct lis && 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( reply, &bytes_iter, &init_entry->object.characteristic.value )) @@ -2794,5 +2927,8 @@ void bluez_gatt_characteristic_value_move( struct winebluetooth_gatt_characteris return STATUS_NOT_SUPPORTED; } void bluez_gatt_characteristic_value_free( void *val ) { return STATUS_NOT_SUPPORTED; } - +void bluez_gatt_characteristic_read( void *connection, void *watcher, struct unix_name *characteristic, IRP *irp ) +{ + return STATUS_NOT_SUPPORTED; +} #endif /* SONAME_LIBDBUS_1 */ diff --git a/dlls/winebth.sys/dbus.h b/dlls/winebth.sys/dbus.h index 1232c87caf9..5b786524091 100644 --- a/dlls/winebth.sys/dbus.h +++ b/dlls/winebth.sys/dbus.h @@ -83,6 +83,7 @@ DO_FUNC(dbus_message_is_signal); \ DO_FUNC(dbus_message_iter_append_basic); \ DO_FUNC(dbus_message_iter_abandon_container); \ + DO_FUNC(dbus_message_iter_abandon_container_if_open); \ DO_FUNC(dbus_message_iter_close_container); \ DO_FUNC(dbus_message_iter_get_arg_type); \ DO_FUNC(dbus_message_iter_get_element_type); \ diff --git a/dlls/winebth.sys/unixlib.c b/dlls/winebth.sys/unixlib.c index c11000859bd..07aa6f8388d 100644 --- a/dlls/winebth.sys/unixlib.c +++ b/dlls/winebth.sys/unixlib.c @@ -269,6 +269,13 @@ static NTSTATUS bluetooth_gatt_service_free( void *args ) return STATUS_SUCCESS; } +static NTSTATUS bluetooth_gatt_characteristic_dup( void *args ) +{ + struct bluetooth_gatt_characteristic_dup_params *params = args; + unix_name_dup( params->characteristic ); + return STATUS_SUCCESS; +} + static NTSTATUS bluetooth_gatt_characteristic_free( void *args ) { struct bluetooth_gatt_characteristic_free_params *params = args; @@ -276,6 +283,13 @@ static NTSTATUS bluetooth_gatt_characteristic_free( void *args ) return STATUS_SUCCESS; } +static NTSTATUS bluetooth_gatt_characteristic_read( void *args ) +{ + struct bluetooth_gatt_characteristic_read_params *params = args; + if (!dbus_connection) return STATUS_NOT_SUPPORTED; + return bluez_gatt_characteristic_read( dbus_connection, bluetooth_watcher, params->chrc, params->irp ); +} + static NTSTATUS bluetooth_gatt_characteristic_value_move( void *args ) { struct bluetooth_gatt_characteristic_value_move_params *params = args; @@ -323,7 +337,10 @@ const unixlib_entry_t __wine_unix_call_funcs[] = { bluetooth_gatt_service_free, + bluetooth_gatt_characteristic_dup, bluetooth_gatt_characteristic_free, + bluetooth_gatt_characteristic_read, + bluetooth_gatt_characteristic_value_move, bluetooth_gatt_characteristic_value_free, diff --git a/dlls/winebth.sys/unixlib.h b/dlls/winebth.sys/unixlib.h index 2b2ecd919de..d76593609dc 100644 --- a/dlls/winebth.sys/unixlib.h +++ b/dlls/winebth.sys/unixlib.h @@ -69,6 +69,11 @@ struct bluetooth_gatt_service_free_params unix_name_t service; }; +struct bluetooth_gatt_characteristic_dup_params +{ + unix_name_t characteristic; +}; + struct bluetooth_gatt_characteristic_free_params { unix_name_t characteristic; @@ -137,6 +142,12 @@ struct bluetooth_device_start_pairing_params IRP *irp; }; +struct bluetooth_gatt_characteristic_read_params +{ + unix_name_t chrc; + IRP *irp; +}; + struct bluetooth_get_event_params { struct winebluetooth_event result; @@ -165,7 +176,10 @@ enum bluetoothapis_funcs unix_bluetooth_gatt_service_free, + unix_bluetooth_gatt_characteristic_dup, unix_bluetooth_gatt_characteristic_free, + unix_bluetooth_gatt_characteristic_read, + unix_bluetooth_gatt_characteristic_value_move, unix_bluetooth_gatt_characteristic_value_free, diff --git a/dlls/winebth.sys/unixlib_priv.h b/dlls/winebth.sys/unixlib_priv.h index d920e7fecbf..085da8c90c7 100644 --- a/dlls/winebth.sys/unixlib_priv.h +++ b/dlls/winebth.sys/unixlib_priv.h @@ -64,5 +64,7 @@ extern NTSTATUS bluez_device_start_pairing( void *dbus_connection, void *watcher extern NTSTATUS bluez_watcher_init( void *connection, void **ctx ); extern void bluez_gatt_characteristic_value_move( struct winebluetooth_gatt_characteristic_value *value, BYTE *buf ); extern void bluez_gatt_characteristic_value_free( void *val ); +extern NTSTATUS bluez_gatt_characteristic_read( void *connection, void *watcher_ctx, + struct unix_name *characteristic, IRP *irp ); extern void bluez_watcher_close( void *connection, void *ctx ); #endif /* __WINE_WINEBTH_UNIXLIB_PRIV_H */ diff --git a/dlls/winebth.sys/winebluetooth.c b/dlls/winebth.sys/winebluetooth.c index 4a89d871564..973a2053452 100644 --- a/dlls/winebth.sys/winebluetooth.c +++ b/dlls/winebth.sys/winebluetooth.c @@ -214,6 +214,16 @@ void winebluetooth_gatt_service_free( winebluetooth_gatt_service_t service ) UNIX_BLUETOOTH_CALL( bluetooth_gatt_service_free, &args ); } +void winebluetooth_gatt_characteristic_dup( winebluetooth_gatt_characteristic_t characteristic ) +{ + struct bluetooth_gatt_characteristic_dup_params args = {0}; + + TRACE( "(%p)\n", (void *)characteristic.handle ); + + args.characteristic = characteristic.handle; + UNIX_BLUETOOTH_CALL( bluetooth_gatt_characteristic_dup, &args ); +} + void winebluetooth_gatt_characteristic_free( winebluetooth_gatt_characteristic_t characteristic ) { struct bluetooth_gatt_characteristic_free_params args = {0}; @@ -224,6 +234,16 @@ void winebluetooth_gatt_characteristic_free( winebluetooth_gatt_characteristic_t UNIX_BLUETOOTH_CALL( bluetooth_gatt_characteristic_free, &args ); } +NTSTATUS winebluetooth_gatt_characteristic_read_async( winebluetooth_gatt_characteristic_t chrc, IRP *irp ) +{ + struct bluetooth_gatt_characteristic_read_params params = {0}; + + TRACE( "(%p, %p)\n", (void *)chrc.handle, irp ); + params.chrc = chrc.handle; + params.irp = irp; + return UNIX_BLUETOOTH_CALL( bluetooth_gatt_characteristic_read, ¶ms ); +} + static const char * debugstr_winebluetooth_gatt_characteristic_value( const struct winebluetooth_gatt_characteristic_value *val ) { diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c index 6fcc79a0753..60c7733cfd3 100644 --- a/dlls/winebth.sys/winebth.c +++ b/dlls/winebth.sys/winebth.c @@ -123,6 +123,8 @@ struct bluetooth_gatt_service CRITICAL_SECTION chars_cs; struct list characteristics; /* Guarded by chars_cs */ + + LIST_ENTRY irp_list; /* Guarded by device_list_cs */ }; struct bluetooth_gatt_characteristic @@ -196,6 +198,20 @@ static struct bluetooth_gatt_service *find_gatt_service( struct list *services, return NULL; } +/* Called should hold chars_cs */ +static struct bluetooth_gatt_characteristic *find_gatt_characteristic( struct list *chars, const BTH_LE_UUID *uuid, + UINT16 handle ) +{ + struct bluetooth_gatt_characteristic *chrc; + + LIST_FOR_EACH_ENTRY( chrc, chars, struct bluetooth_gatt_characteristic, entry ) + { + if (IsBthLEUuidMatch( chrc->props.CharacteristicUuid, *uuid ) && chrc->props.AttributeHandle == handle) + return chrc; + } + return NULL; +} + static NTSTATUS bluetooth_gatt_service_get_characteristics( struct bluetooth_gatt_service *service, IRP *irp ) { const SIZE_T min_size = offsetof( struct winebth_le_device_get_gatt_characteristics_params, characteristics[0] ); @@ -234,6 +250,7 @@ static NTSTATUS bluetooth_gatt_service_get_characteristics( struct bluetooth_gat static NTSTATUS bluetooth_gatt_service_dispatch( DEVICE_OBJECT *device, struct bluetooth_gatt_service *ext, IRP *irp ) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + ULONG outsize = stack->Parameters.DeviceIoControl.OutputBufferLength; ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; NTSTATUS status = irp->IoStatus.Status; @@ -253,12 +270,75 @@ static NTSTATUS bluetooth_gatt_service_dispatch( DEVICE_OBJECT *device, struct b status = bluetooth_gatt_service_get_characteristics( ext, irp ); break; } + case IOCTL_WINEBTH_GATT_SERVICE_READ_CHARACTERISITIC_VALUE: + { + struct winebth_gatt_service_read_characterisitic_value_params *params = irp->AssociatedIrp.SystemBuffer; + struct bluetooth_gatt_characteristic *chrc; + + if (!params || outsize < sizeof( *params )) + { + status = STATUS_INVALID_USER_BUFFER; + break; + } + + irp->IoStatus.Information = sizeof( *params ); + EnterCriticalSection( &ext->chars_cs ); + chrc = find_gatt_characteristic( &ext->characteristics, ¶ms->uuid, params->handle ); + if (!chrc) + { + status = STATUS_NOT_FOUND; + LeaveCriticalSection( &ext->chars_cs ); + break; + } + if (!chrc->props.IsReadable) + { + status = STATUS_PRIVILEGE_NOT_HELD; + LeaveCriticalSection( &ext->chars_cs ); + break; + } + if (params->from_device || !chrc->value) + { + winebluetooth_gatt_characteristic_t chrc2 = chrc->characteristic ; + + /* Avoids a deadlock if the event loop holds device_list_cs and is waiting on chars_cs. */ + winebluetooth_gatt_characteristic_dup( chrc2 ); + LeaveCriticalSection( &ext->chars_cs ); + + EnterCriticalSection( &device_list_cs ); + status = winebluetooth_gatt_characteristic_read_async( chrc2, irp ); + if (status == STATUS_PENDING) + { + IoMarkIrpPending( irp ); + InsertTailList( &ext->irp_list, &irp->Tail.Overlay.ListEntry ); + } + LeaveCriticalSection( &device_list_cs ); + + winebluetooth_gatt_characteristic_free( chrc2 ); + } + else + { + ULONG needed = offsetof( struct winebth_gatt_service_read_characterisitic_value_params, buf[params->size] ); + + params->size = chrc->value->DataSize; + status = STATUS_SUCCESS; + if (outsize >= needed) + { + memcpy( params->buf, chrc->value->Data, params->size ); + irp->IoStatus.Information = + offsetof( struct winebth_gatt_service_read_characterisitic_value_params, buf[params->size] ); + } + LeaveCriticalSection( &ext->chars_cs ); + } + break; + } default: FIXME( "Unimplemented IOCTL code: %#lx\n", code ); } - - irp->IoStatus.Status = status; - IoCompleteRequest( irp, IO_NO_INCREMENT ); + if (status != STATUS_PENDING) + { + irp->IoStatus.Status = status; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + } return status; } @@ -1241,6 +1321,7 @@ static void bluetooth_device_add_gatt_service( struct winebluetooth_watcher_even ext->gatt_service.primary = !!event.is_primary; ext->gatt_service.handle = event.attr_handle; ext->gatt_service.remote_device = device; + InitializeListHead( &ext->gatt_service.irp_list ); list_init( &ext->gatt_service.characteristics ); InitializeCriticalSectionEx( &ext->gatt_service.chars_cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO ); @@ -1482,6 +1563,33 @@ done: winebluetooth_gatt_characteristic_free( event.characteristic ); } +static void bluetooth_gatt_characteristic_value_read_complete_irp( + struct winebluetooth_watcher_event_gatt_characteristic_value_read read ) +{ + NTSTATUS status = read.result; + + if (!read.result) + { + ULONG needed = offsetof( struct winebth_gatt_service_read_characterisitic_value_params, buf[read.value.size] ); + struct winebth_gatt_service_read_characterisitic_value_params *params = read.irp->AssociatedIrp.SystemBuffer; + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( read.irp ); + ULONG outsize = stack->Parameters.DeviceIoControl.OutputBufferLength; + + params->size = read.value.size; + if (outsize >= needed) + { + read.irp->IoStatus.Information = needed; + winebluetooth_gatt_characteristic_value_move( &read.value, params->buf ); + } + else + { + read.irp->IoStatus.Information = sizeof( *params ); + winebluetooth_gatt_characteristic_value_free( &read.value ); + } + } + complete_irp( read.irp, status ); +} + static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg ) { NTSTATUS status; @@ -1536,6 +1644,10 @@ static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg ) case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_CHANGED: bluetooth_gatt_characteristic_value_update( event->event_data.gatt_characteristic_value_changed ); break; + case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_READ: + bluetooth_gatt_characteristic_value_read_complete_irp( + event->event_data.gatt_characteristic_value_read ); + 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 3e32ae9470b..cd33d3dd72b 100644 --- a/dlls/winebth.sys/winebth_priv.h +++ b/dlls/winebth.sys/winebth_priv.h @@ -255,6 +255,7 @@ static inline BOOL winebluetooth_gatt_service_equal( winebluetooth_gatt_service_ return s1.handle == s2.handle; } +void winebluetooth_gatt_characteristic_dup( winebluetooth_gatt_characteristic_t characteristic ); void winebluetooth_gatt_characteristic_free( winebluetooth_gatt_characteristic_t characteristic ); static inline BOOL winebluetooth_gatt_characteristic_equal( winebluetooth_gatt_characteristic_t c1, winebluetooth_gatt_characteristic_t c2) @@ -281,6 +282,7 @@ static inline BOOL winebluetooth_gatt_characteristic_value_is_inline( const stru { return val->size <= ARRAY_SIZE( val->buf ); } +NTSTATUS winebluetooth_gatt_characteristic_read_async( winebluetooth_gatt_characteristic_t chrc, IRP *irp ); enum winebluetooth_watcher_event_type { @@ -296,6 +298,7 @@ enum winebluetooth_watcher_event_type BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_ADDED, BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_REMOVED, BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_CHANGED, + BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_READ, }; struct winebluetooth_watcher_event_radio_added @@ -376,6 +379,13 @@ struct winebluetooth_watcher_event_gatt_characteristic_value_changed struct winebluetooth_gatt_characteristic_value value; }; +struct winebluetooth_watcher_event_gatt_characteristic_value_read +{ + IRP *irp; + struct winebluetooth_gatt_characteristic_value value; + NTSTATUS result; +}; + union winebluetooth_watcher_event_data { struct winebluetooth_watcher_event_radio_added radio_added; @@ -390,6 +400,7 @@ union winebluetooth_watcher_event_data 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_gatt_characteristic_value_read gatt_characteristic_value_read; }; struct winebluetooth_watcher_event diff --git a/include/wine/winebth.h b/include/wine/winebth.h index 572be91bb45..c41f0362f55 100644 --- a/include/wine/winebth.h +++ b/include/wine/winebth.h @@ -41,6 +41,9 @@ /* Get all characteristics for a GATT service */ #define IOCTL_WINEBTH_LE_DEVICE_GET_GATT_CHARACTERISTICS CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xc1, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* Read the associated value for a GATT characteristic */ +#define IOCTL_WINEBTH_GATT_SERVICE_READ_CHARACTERISITIC_VALUE CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xd0, METHOD_BUFFERED, FILE_ANY_ACCESS) + DEFINE_GUID( GUID_WINEBTH_AUTHENTICATION_REQUEST, 0xca67235f, 0xf621, 0x4c27, 0x85, 0x65, 0xa4, 0xd5, 0x5e, 0xa1, 0x26, 0xe8 ); @@ -93,6 +96,15 @@ struct winebth_le_device_get_gatt_characteristics_params BTH_LE_GATT_CHARACTERISTIC characteristics[0]; }; +struct winebth_gatt_service_read_characterisitic_value_params +{ + BTH_LE_UUID uuid; + UINT16 handle; + unsigned int from_device : 1; + ULONG size; + BYTE buf[1]; +}; + #pragma pack(pop) #endif /* __WINEBTH_H__ */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10208