This looks like a rewrite of BTH_LE_GATT_CHARACTERISTIC. Why not use that struct directly?
There are a [bunch of additional flags ](https://github.com/bluez/bluez/blob/master/doc/org.bluez.GattCharacteristic.... `org.bluez.GattCharacteristic` objects that `BTH_LE_GATT_CHARACTERISTIC` does not support. The driver doesn't use them ATM, but they are utilized in the WinRT APIs, so I'll likely add them in the future.
Maybe embed BTH_LE_GATT_CHARACTERISTIC inside struct winebluetooth_watcher_event_gatt_characteristic_added, then, and just add the extra parts alongside it later.
In this patch series this is only ever taken under props_cs. Is there a point to having this separate CS? Even if there will be a case where it can be taken by itself, will it really make a measurable performance difference?
(The same can be asked of the four other mutexes already used in this file. Those at least are already used by themselves, but do we really need all of them?)
So, `chars_cs` does not get used by itself in this series, but is meant for future MRs, where the driver creates and exposes PDOs for individual GATT services on every LE device (which is needed for [`BluetoothGATTGetCharacteristicValue`](https://learn.microsoft.com/en-us/windows/win32/api/bluetoothleapis/nf-bluet...) as it operates on HANDLEs to _services_, not devices).
And how about the latter question? Do we really get a performance difference from separating all these locks?
You don't actually use this later, but instead check ->count directly in the caller. Since this is a private ioctl you might as well get rid of everything you're not using.
Doesn't IoStatus.Information need to be set so that ntoskrnl knows how many bytes to transfer in the reply?
Oh right, it's buffered, my mistake.
Why the loop? The API function only asks for the first N and the total count; you can just allocate a buffer large enough to hold the first N and then return it, can't you?
It's the same idea as `IOCTL_BTH_GET_DEVICE_INFO` in bluetoothapis/main.c. This allows for the number of GATT services/characteristics to change between two successive IOCTL calls, which might happen if the system is discovering a LE device that hasn't finished exposing all of its available services/characteristics.
I understand the loop pattern, but why do you need to make more than *one* ioctl? Unlike in BluetoothFindFirstDevice(), you don't need to retrieve every characteristic here, only as many as the caller allocated space for.
Do we want a FIXME for the flags?
For both BluetoothGetGATTServices and BluetoothGATTGetCharacteristics, the MSDN documentation lists `BLUETOOTH_GATT_FLAG_NONE` as the only flag option, which is 0.
Sure, but MSDN isn't always accurate, and it might change in the future without us really knowing about it. I always advocate for a FIXME for any parameter we ignore, even if it's documented as being reserved. Especially if we aren't going to check for it and return an error.