dlls/winebth.sys: Create radio PDOs from the list of org.bluez.Adapter1 objects on BlueZ.

Add a "bluetooth watcher", which builds a list of radio devices discovered from BlueZ and sends them to the
driver in the form of BLUETOOTH_WATCHER_RADIO_DEVICE_ADDED events. Initially, send a list of
org.bluez.Adapter1 objects discovered via GetManagedObjects.
This commit is contained in:
Vibhav Pant 2024-10-17 17:53:10 +05:30
parent 983ff4aabf
commit 30ba51e3fc
No known key found for this signature in database
GPG key ID: E3FB28CB6AB59598
7 changed files with 666 additions and 8 deletions

View file

@ -27,6 +27,8 @@
#include <stdlib.h>
#include <dlfcn.h>
#include <assert.h>
#include <pthread.h>
#ifdef SONAME_LIBDBUS_1
#include <dbus/dbus.h>
@ -37,9 +39,13 @@
#include <windef.h>
#include <winternl.h>
#include <winbase.h>
#include <bthsdpdef.h>
#include <bluetoothapis.h>
#include <wine/debug.h>
#include "winebth_priv.h"
#include "unixlib.h"
#include "unixlib_priv.h"
#include "dbus.h"
@ -51,6 +57,8 @@ WINE_DECLARE_DEBUG_CHANNEL( dbus );
const int bluez_timeout = -1;
#define DBUS_INTERFACE_OBJECTMANAGER "org.freedesktop.DBus.ObjectManager"
#define BLUEZ_DEST "org.bluez"
#define BLUEZ_INTERFACE_ADAPTER "org.bluez.Adapter1"
@ -79,12 +87,75 @@ failed:
return FALSE;
}
static const char *bluez_next_dict_entry( DBusMessageIter *iter, DBusMessageIter *variant )
{
DBusMessageIter sub;
const char *name;
if (p_dbus_message_iter_get_arg_type( iter ) != DBUS_TYPE_DICT_ENTRY)
return NULL;
p_dbus_message_iter_recurse( iter, &sub );
p_dbus_message_iter_next( iter );
p_dbus_message_iter_get_basic( &sub, &name );
p_dbus_message_iter_next( &sub );
p_dbus_message_iter_recurse( &sub, variant );
return name;
}
static inline const char *dbgstr_dbus_connection( DBusConnection *connection )
{
return wine_dbg_sprintf( "{%p connected=%d}", connection,
p_dbus_connection_get_is_connected( connection ) );
}
static NTSTATUS bluez_get_objects_async( DBusConnection *connection, DBusPendingCall **call )
{
DBusMessage *request;
dbus_bool_t success;
TRACE( "Getting managed objects under '/' at service '%s'\n", BLUEZ_DEST );
request = p_dbus_message_new_method_call(
BLUEZ_DEST, "/", DBUS_INTERFACE_OBJECTMANAGER, "GetManagedObjects" );
if (!request)
{
return STATUS_NO_MEMORY;
}
success = p_dbus_connection_send_with_reply( connection, request, call, -1 );
p_dbus_message_unref( request );
if (!success)
return STATUS_NO_MEMORY;
if (*call == NULL)
return STATUS_INVALID_PARAMETER;
return STATUS_SUCCESS;
}
#define DBUS_OBJECTMANAGER_METHOD_GETMANAGEDOBJECTS_RETURN_SIGNATURE \
DBUS_TYPE_ARRAY_AS_STRING \
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING \
DBUS_TYPE_OBJECT_PATH_AS_STRING \
DBUS_TYPE_ARRAY_AS_STRING \
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING \
DBUS_TYPE_STRING_AS_STRING \
DBUS_TYPE_ARRAY_AS_STRING \
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING \
DBUS_TYPE_STRING_AS_STRING \
DBUS_TYPE_VARIANT_AS_STRING \
DBUS_DICT_ENTRY_END_CHAR_AS_STRING \
DBUS_DICT_ENTRY_END_CHAR_AS_STRING \
DBUS_DICT_ENTRY_END_CHAR_AS_STRING
struct bluez_watcher_ctx
{
void *init_device_list_call;
/* struct bluez_init_entry */
struct list initial_radio_list;
};
void *bluez_dbus_init( void )
{
DBusError error;
@ -120,10 +191,177 @@ void bluez_dbus_free( void *connection )
p_dbus_connection_unref( connection );
}
struct bluez_watcher_event
{
struct list entry;
enum winebluetooth_watcher_event_type event_type;
union winebluetooth_watcher_event_data event;
};
NTSTATUS bluez_watcher_init( void *connection, void **ctx )
{
NTSTATUS status;
DBusPendingCall *call;
struct bluez_watcher_ctx *watcher_ctx =
calloc( 1, sizeof( struct bluez_watcher_ctx ) );
if (watcher_ctx == NULL) return STATUS_NO_MEMORY;
status = bluez_get_objects_async( connection, &call );
if (status != STATUS_SUCCESS)
{
free( watcher_ctx );
ERR( "could not create async GetManagedObjects call: %#x\n", (int)status);
return status;
}
watcher_ctx->init_device_list_call = call;
list_init( &watcher_ctx->initial_radio_list );
*ctx = watcher_ctx;
TRACE( "ctx=%p\n", ctx );
return STATUS_SUCCESS;
}
struct bluez_init_entry
{
union {
struct winebluetooth_watcher_event_radio_added radio;
} object;
struct list entry;
};
static NTSTATUS bluez_build_initial_device_lists( DBusMessage *reply, struct list *adapter_list )
{
DBusMessageIter dict, paths_iter, iface_iter, prop_iter;
const char *path;
NTSTATUS status = STATUS_SUCCESS;
if (!p_dbus_message_has_signature( reply,
DBUS_OBJECTMANAGER_METHOD_GETMANAGEDOBJECTS_RETURN_SIGNATURE ))
{
ERR( "Unexpected signature in GetManagedObjects reply: %s\n",
debugstr_a( p_dbus_message_get_signature( reply ) ) );
return STATUS_INTERNAL_ERROR;
}
p_dbus_message_iter_init( reply, &dict );
p_dbus_message_iter_recurse( &dict, &paths_iter );
while((path = bluez_next_dict_entry( &paths_iter, &iface_iter )))
{
const char *iface;
while ((iface = bluez_next_dict_entry ( &iface_iter, &prop_iter )))
{
if (!strcmp( iface, BLUEZ_INTERFACE_ADAPTER ))
{
struct bluez_init_entry *init_device = calloc( 1, sizeof( *init_device ) );
struct unix_name *radio_name;
if (!init_device)
{
status = STATUS_NO_MEMORY;
goto done;
}
radio_name = unix_name_get_or_create( path );
if (!radio_name)
{
free( init_device );
status = STATUS_NO_MEMORY;
goto done;
}
init_device->object.radio.radio.handle = (UINT_PTR)radio_name;
list_add_tail( adapter_list, &init_device->entry );
TRACE( "Found BlueZ org.bluez.Adapter1 object %s: %p\n",
debugstr_a( radio_name->str ), radio_name );
break;
}
}
}
TRACE( "Initial device list: radios: %d\n", list_count( adapter_list ) );
done:
return status;
}
static struct bluez_init_entry *bluez_init_entries_list_pop( struct list *list )
{
struct list *entry = list_head( list );
struct bluez_init_entry *device = LIST_ENTRY( entry, struct bluez_init_entry, entry );
list_remove( entry );
return device;
}
NTSTATUS bluez_dbus_loop( void *c, void *watcher,
struct winebluetooth_event *result )
{
DBusConnection *connection;
struct bluez_watcher_ctx *watcher_ctx = watcher;
TRACE( "(%p, %p, %p)\n", c, watcher, result );
connection = p_dbus_connection_ref( c );
while (TRUE)
{
if (!list_empty( &watcher_ctx->initial_radio_list ))
{
struct bluez_init_entry *radio =
bluez_init_entries_list_pop( &watcher_ctx->initial_radio_list );
struct winebluetooth_watcher_event *watcher_event = &result->data.watcher_event;
result->status = WINEBLUETOOTH_EVENT_WATCHER_EVENT;
watcher_event->event_type = BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_ADDED;
watcher_event->event_data.radio_added = radio->object.radio;
free( radio );
p_dbus_connection_unref( connection );
return STATUS_PENDING;
}
else if (!p_dbus_connection_read_write_dispatch( connection, 100 ))
{
p_dbus_connection_unref( connection );
TRACE( "Disconnected from DBus\n" );
return STATUS_SUCCESS;
}
if (watcher_ctx->init_device_list_call != NULL
&& p_dbus_pending_call_get_completed( watcher_ctx->init_device_list_call ))
{
DBusMessage *reply = p_dbus_pending_call_steal_reply( watcher_ctx->init_device_list_call );
DBusError error;
NTSTATUS status;
p_dbus_pending_call_unref( watcher_ctx->init_device_list_call );
watcher_ctx->init_device_list_call = NULL;
p_dbus_error_init( &error );
if (p_dbus_set_error_from_message( &error, reply ))
{
ERR( "Error getting object list from BlueZ: '%s': '%s'\n", error.name,
error.message );
p_dbus_error_free( &error );
p_dbus_message_unref( reply );
p_dbus_connection_unref( connection );
return STATUS_NO_MEMORY;
}
status = bluez_build_initial_device_lists( reply, &watcher_ctx->initial_radio_list );
p_dbus_message_unref( reply );
if (status != STATUS_SUCCESS)
{
ERR( "Error building initial bluetooth devices list: %#x\n", (int)status );
p_dbus_connection_unref( connection );
return status;
}
}
}
}
#else
void *bluez_dbus_init( void ) { return NULL; }
void bluez_dbus_close( void *connection ) {}
void bluez_dbus_free( void *connection ) {}
NTSTATUS bluez_watcher_init( void *connection, void **ctx ) { return STATUS_NOT_SUPPORTED; }
NTSTATUS bluez_dbus_loop( void *c, void *watcher, struct winebluetooth_event *result )
{
return STATUS_NOT_SUPPORTED;
}
#endif /* SONAME_LIBDBUS_1 */

View file

@ -24,10 +24,18 @@
#include <config.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <pthread.h>
#include <ntstatus.h>
#define WIN32_NO_STATUS
#include <winternl.h>
#include <winbase.h>
#include <windef.h>
#include <wine/list.h>
#include <wine/rbtree.h>
#include <wine/debug.h>
#include "unixlib.h"
@ -35,14 +43,70 @@
WINE_DEFAULT_DEBUG_CHANNEL( winebth );
static int compare_string( const void *key, const struct wine_rb_entry *entry )
{
struct unix_name *str = WINE_RB_ENTRY_VALUE( entry, struct unix_name, entry );
return strcmp( key, str->str );
}
static struct rb_tree names = { .compare = compare_string };
static pthread_mutex_t names_mutex = PTHREAD_MUTEX_INITIALIZER;
struct unix_name *unix_name_get_or_create( const char *str )
{
struct rb_entry *entry;
struct unix_name *s;
pthread_mutex_lock( &names_mutex );
entry = rb_get( &names, str );
if (!entry)
{
struct unix_name *s = malloc( sizeof( struct unix_name ) );
if (!s)
{
pthread_mutex_unlock( &names_mutex );
return NULL;
}
s->str = strdup( str );
s->refcnt = 0;
rb_put( &names, str, &s->entry );
entry = &s->entry;
}
s = RB_ENTRY_VALUE( entry, struct unix_name, entry );
s->refcnt++;
pthread_mutex_unlock( &names_mutex );
return s;
}
void unix_name_free( struct unix_name *name )
{
pthread_mutex_lock( &names_mutex );
name->refcnt--;
if (name->refcnt == 0)
{
rb_remove( &names, &name->entry );
free( name );
}
pthread_mutex_unlock( &names_mutex );
}
static void *dbus_connection;
static void *bluetooth_watcher;
static NTSTATUS bluetooth_init ( void *params )
{
dbus_connection = bluez_dbus_init();
TRACE("dbus_connection=%p\n", dbus_connection);
NTSTATUS status;
return dbus_connection ? STATUS_SUCCESS : STATUS_INTERNAL_ERROR;
dbus_connection = bluez_dbus_init();
if (!dbus_connection)
return STATUS_INTERNAL_ERROR;
status = bluez_watcher_init( dbus_connection, &bluetooth_watcher );
if (status)
bluez_dbus_close( dbus_connection );
else
TRACE( "dbus_connection=%p bluetooth_watcher=%p\n", dbus_connection, bluetooth_watcher );
return status;
}
static NTSTATUS bluetooth_shutdown( void *params )
@ -54,9 +118,29 @@ static NTSTATUS bluetooth_shutdown( void *params )
return STATUS_SUCCESS;
}
static NTSTATUS bluetooth_adapter_free( void *args )
{
struct bluetooth_adapter_free_params *params = args;
unix_name_free( params->adapter );
return STATUS_SUCCESS;
}
static NTSTATUS bluetooth_get_event( void *args )
{
struct bluetooth_get_event_params *params = args;
if (!dbus_connection) return STATUS_NOT_SUPPORTED;
memset( &params->result, 0, sizeof( params->result ) );
return bluez_dbus_loop( dbus_connection, bluetooth_watcher, &params->result );
}
const unixlib_entry_t __wine_unix_call_funcs[] = {
bluetooth_init,
bluetooth_shutdown,
bluetooth_adapter_free,
bluetooth_get_event,
};
C_ASSERT( ARRAYSIZE( __wine_unix_call_funcs ) == unix_funcs_count );

View file

@ -21,15 +21,47 @@
#ifndef __WINE_WINEBTH_UNIXLIB_H
#define __WINE_WINEBTH_UNIXLIB_H
#include <stdlib.h>
#include <stdarg.h>
#include <windef.h>
#include <winbase.h>
#include <bthsdpdef.h>
#include <bluetoothapis.h>
#include <wine/unixlib.h>
#include <wine/debug.h>
#include "winebth_priv.h"
#ifdef WINE_UNIX_LIB
typedef struct unix_name *unix_name_t;
typedef void *unix_handle_t;
#else
typedef UINT_PTR unix_name_t;
typedef UINT_PTR unix_handle_t;
#endif
struct bluetooth_adapter_free_params
{
unix_name_t adapter;
};
struct bluetooth_get_event_params
{
struct winebluetooth_event result;
};
enum bluetoothapis_funcs
{
unix_bluetooth_init,
unix_bluetooth_shutdown,
unix_bluetooth_adapter_free,
unix_bluetooth_get_event,
unix_funcs_count
};

View file

@ -32,7 +32,20 @@
#include "unixlib.h"
struct unix_name
{
char *str;
SIZE_T refcnt;
struct wine_rb_entry entry;
};
extern struct unix_name *unix_name_get_or_create( const char *str );
extern void unix_name_free( struct unix_name *name );
extern void *bluez_dbus_init( void );
extern void bluez_dbus_close( void *connection );
extern void bluez_dbus_free( void *connection );
extern NTSTATUS bluez_dbus_loop( void *connection, void *watcher_ctx, struct winebluetooth_event *result );
extern NTSTATUS bluez_watcher_init( void *connection, void **ctx );
#endif /* __WINE_WINEBTH_UNIXLIB_PRIV_H */

View file

@ -34,6 +34,29 @@
#include "winebth_priv.h"
#include "unixlib.h"
WINE_DEFAULT_DEBUG_CHANNEL( winebth );
void winebluetooth_radio_free( winebluetooth_radio_t radio )
{
struct bluetooth_adapter_free_params args = { 0 };
TRACE( "(%p)\n", (void *)radio.handle );
args.adapter = radio.handle;
UNIX_BLUETOOTH_CALL( bluetooth_adapter_free, &args );
}
NTSTATUS winebluetooth_get_event( struct winebluetooth_event *result )
{
struct bluetooth_get_event_params params = {0};
NTSTATUS status;
TRACE( "(%p)\n", result );
status = UNIX_BLUETOOTH_CALL( bluetooth_get_event, &params );
*result = params.result;
return status;
}
NTSTATUS winebluetooth_init( void )
{
NTSTATUS status;

View file

@ -43,6 +43,132 @@ static DRIVER_OBJECT *driver_obj;
static DEVICE_OBJECT *bus_fdo, *bus_pdo;
#define DECLARE_CRITICAL_SECTION( cs ) \
static CRITICAL_SECTION cs; \
static CRITICAL_SECTION_DEBUG cs##_debug = { \
0, \
0, \
&( cs ), \
{ &cs##_debug.ProcessLocksList, &cs##_debug.ProcessLocksList }, \
0, \
0, \
{ (DWORD_PTR)( __FILE__ ": " #cs ) } }; \
static CRITICAL_SECTION cs = { &cs##_debug, -1, 0, 0, 0, 0 };
DECLARE_CRITICAL_SECTION( device_list_cs );
static struct list device_list = LIST_INIT( device_list );
struct bluetooth_radio
{
struct list entry;
BOOL removed;
DEVICE_OBJECT *device_obj;
winebluetooth_radio_t radio;
};
void WINAPIV append_id( struct string_buffer *buffer, const WCHAR *format, ... )
{
va_list args;
WCHAR *string;
int len;
va_start( args, format );
len = _vsnwprintf( NULL, 0, format, args ) + 1;
if (!(string = ExAllocatePool( PagedPool, (buffer->len + len) * sizeof( WCHAR ) )))
{
if (buffer->string)
ExFreePool( buffer->string );
buffer->string = NULL;
return;
}
if (buffer->string)
{
memcpy( string, buffer->string, buffer->len * sizeof( WCHAR ) );
ExFreePool( buffer->string );
}
_vsnwprintf( string + buffer->len, len, format, args );
buffer->string = string;
buffer->len += len;
va_end( args );
}
static HANDLE event_loop_thread;
static void add_bluetooth_radio( struct winebluetooth_watcher_event_radio_added event )
{
struct bluetooth_radio *device;
DEVICE_OBJECT *device_obj;
UNICODE_STRING string;
NTSTATUS status;
WCHAR name[256];
static unsigned int radio_index;
swprintf( name, ARRAY_SIZE( name ), L"\\Device\\WINEBTH-RADIO-%d", radio_index++ );
TRACE( "Adding new bluetooth radio %p: %s\n", (void *)event.radio.handle, debugstr_w( name ) );
RtlInitUnicodeString( &string, name );
status = IoCreateDevice( driver_obj, sizeof( *device ), &string, FILE_DEVICE_BLUETOOTH, 0,
FALSE, &device_obj );
if (status)
{
ERR( "Failed to create device, status %#lx\n", status );
return;
}
device = device_obj->DeviceExtension;
device->device_obj = device_obj;
device->radio = event.radio;
device->removed = FALSE;
EnterCriticalSection( &device_list_cs );
list_add_tail( &device_list, &device->entry );
LeaveCriticalSection( &device_list_cs );
IoInvalidateDeviceRelations( bus_pdo, BusRelations );
}
static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg )
{
NTSTATUS status;
while (TRUE)
{
struct winebluetooth_event result = {0};
status = winebluetooth_get_event( &result );
if (status != STATUS_PENDING) break;
switch (result.status)
{
case WINEBLUETOOTH_EVENT_WATCHER_EVENT:
{
struct winebluetooth_watcher_event *event = &result.data.watcher_event;
switch (event->event_type)
{
case BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_ADDED:
add_bluetooth_radio( event->event_data.radio_added );
break;
default:
FIXME( "Unknown bluetooth watcher event code: %#x\n", event->event_type );
}
break;
}
default:
FIXME( "Unknown bluetooth event loop status code: %#x\n", result.status );
}
}
if (status != STATUS_SUCCESS)
ERR( "Bluetooth event loop terminated with %#lx", status );
else
TRACE( "Exiting bluetooth event loop\n" );
return 0;
}
static NTSTATUS WINAPI fdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp )
{
IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
@ -51,7 +177,44 @@ static NTSTATUS WINAPI fdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp )
switch (stack->MinorFunction)
{
case IRP_MN_QUERY_DEVICE_RELATIONS:
{
struct bluetooth_radio *radio;
DEVICE_RELATIONS *devices;
SIZE_T i = 0;
if (stack->Parameters.QueryDeviceRelations.Type != BusRelations)
{
FIXME( "Unhandled Device Relation %x\n",
stack->Parameters.QueryDeviceRelations.Type );
break;
}
EnterCriticalSection( &device_list_cs );
devices = ExAllocatePool(
PagedPool, offsetof( DEVICE_RELATIONS, Objects[list_count( &device_list )] ) );
if (devices == NULL)
{
LeaveCriticalSection( &device_list_cs );
irp->IoStatus.Status = STATUS_NO_MEMORY;
break;
}
LIST_FOR_EACH_ENTRY(radio, &device_list, struct bluetooth_radio, entry)
{
devices->Objects[i++] = radio->device_obj;
call_fastcall_func1( ObfReferenceObject, radio->device_obj );
}
LeaveCriticalSection( &device_list_cs );
devices->Count = i;
irp->IoStatus.Information = (ULONG_PTR)devices;
irp->IoStatus.Status = STATUS_SUCCESS;
break;
}
case IRP_MN_START_DEVICE:
event_loop_thread =
CreateThread( NULL, 0, bluetooth_event_loop_thread_proc, NULL, 0, NULL );
irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IRP_MN_SURPRISE_REMOVAL:
@ -59,8 +222,20 @@ static NTSTATUS WINAPI fdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp )
break;
case IRP_MN_REMOVE_DEVICE:
{
struct bluetooth_radio *device, *cur;
NTSTATUS ret;
winebluetooth_shutdown();
WaitForSingleObject( event_loop_thread, INFINITE );
CloseHandle( event_loop_thread );
EnterCriticalSection( &device_list_cs );
LIST_FOR_EACH_ENTRY_SAFE( device, cur, &device_list, struct bluetooth_radio, entry )
{
assert( !device->removed );
winebluetooth_radio_free( device->radio );
list_remove( &device->entry );
IoDeleteDevice( device->device_obj );
}
LeaveCriticalSection( &device_list_cs );
IoSkipCurrentIrpStackLocation( irp );
ret = IoCallDriver( bus_pdo, irp );
IoDetachDevice( bus_pdo );
@ -75,14 +250,39 @@ static NTSTATUS WINAPI fdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp )
return IoCallDriver( bus_pdo, irp );
}
static NTSTATUS query_id(const struct bluetooth_radio *ext, IRP *irp, BUS_QUERY_ID_TYPE type )
{
struct string_buffer buf = {0};
TRACE( "(%p, %p, %s)\n", ext, irp, debugstr_BUS_QUERY_ID_TYPE( type ) );
switch (type)
{
case BusQueryCompatibleIDs:
append_id( &buf, L"" );
break;
default:
return irp->IoStatus.Status;
}
if (!buf.string)
return STATUS_NO_MEMORY;
irp->IoStatus.Information = (ULONG_PTR)buf.string;
return STATUS_SUCCESS;
}
static NTSTATUS WINAPI pdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp )
{
IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
struct bluetooth_radio *device = device_obj->DeviceExtension;
NTSTATUS ret = irp->IoStatus.Status;
TRACE( "device_obj %p, irp %p, minor function %s\n", device_obj, irp, debugstr_minor_function_code( stack->MinorFunction ) );
switch (stack->MinorFunction)
{
case IRP_MN_QUERY_ID:
ret = query_id( device, irp, stack->Parameters.QueryId.IdType );
break;
case IRP_MN_QUERY_CAPABILITIES:
{
DEVICE_CAPABILITIES *caps = stack->Parameters.DeviceCapabilities.Capabilities;
@ -96,11 +296,21 @@ static NTSTATUS WINAPI pdo_pnp( DEVICE_OBJECT *device_obj, IRP *irp )
ret = STATUS_SUCCESS;
break;
case IRP_MN_REMOVE_DEVICE:
IoDeleteDevice( device_obj );
assert( device->removed );
winebluetooth_radio_free( device->radio );
IoDeleteDevice( device->device_obj );
ret = STATUS_SUCCESS;
break;
case IRP_MN_SURPRISE_REMOVAL:
irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest( irp, IO_NO_INCREMENT );
return STATUS_SUCCESS;
EnterCriticalSection( &device_list_cs );
if (!device->removed)
{
device->removed = TRUE;
list_remove( &device->entry );
}
LeaveCriticalSection( &device_list_cs );
ret = STATUS_SUCCESS;
break;
default:
FIXME( "Unhandled minor function %s.\n", debugstr_minor_function_code( stack->MinorFunction ) );
break;
@ -144,7 +354,7 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
TRACE( "(%p, %s)\n", driver, debugstr_w( path->Buffer ) );
status = winebluetooth_init();
if (status != STATUS_SUCCESS)
if (status)
return status;
driver_obj = driver;

View file

@ -21,6 +21,8 @@
#ifndef __WINE_WINEBTH_WINEBTH_H_
#define __WINE_WINEBTH_WINEBTH_H_
#include <bthsdpdef.h>
#include <bluetoothapis.h>
#include <ddk/wdm.h>
#include <wine/debug.h>
@ -44,6 +46,20 @@ struct string_buffer
#define XX(i) case (i): return #i
static inline const char *debugstr_BUS_QUERY_ID_TYPE( BUS_QUERY_ID_TYPE type )
{
switch (type)
{
XX(BusQueryDeviceID);
XX(BusQueryHardwareIDs);
XX(BusQueryCompatibleIDs);
XX(BusQueryInstanceID);
XX(BusQueryDeviceSerialNumber);
XX(BusQueryContainerID);
default:
return wine_dbg_sprintf( "(unknown %d)", type );
}
}
static inline const char *debugstr_minor_function_code( UCHAR code )
{
@ -79,6 +95,48 @@ static inline const char *debugstr_minor_function_code( UCHAR code )
}
#undef XX
typedef struct
{
UINT_PTR handle;
} winebluetooth_radio_t;
void winebluetooth_radio_free( winebluetooth_radio_t radio );
enum winebluetooth_watcher_event_type
{
BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_ADDED,
};
struct winebluetooth_watcher_event_radio_added
{
winebluetooth_radio_t radio;
};
union winebluetooth_watcher_event_data
{
struct winebluetooth_watcher_event_radio_added radio_added;
};
struct winebluetooth_watcher_event
{
enum winebluetooth_watcher_event_type event_type;
union winebluetooth_watcher_event_data event_data;
};
enum winebluetooth_event_type
{
WINEBLUETOOTH_EVENT_WATCHER_EVENT,
};
struct winebluetooth_event
{
enum winebluetooth_event_type status;
union {
struct winebluetooth_watcher_event watcher_event;
} data;
};
NTSTATUS winebluetooth_get_event( struct winebluetooth_event *result );
NTSTATUS winebluetooth_init( void );
NTSTATUS winebluetooth_shutdown( void );