mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-10 17:21:32 +00:00
[client] usbredir: gracefully disconnect USB devices
Wait for the usbredir disconnect acknowledgement before closing SPICE. Block replug while removal is pending and bound the shutdown wait.
This commit is contained in:
@@ -224,6 +224,7 @@ static bool tickTimerFn(void * unused)
|
|||||||
#define FRAME_TIMING_RECORD_COUNT 1024
|
#define FRAME_TIMING_RECORD_COUNT 1024
|
||||||
#define FRAME_TIMING_PUBLISH_BATCH_SIZE 32
|
#define FRAME_TIMING_PUBLISH_BATCH_SIZE 32
|
||||||
#define FRAME_TIMING_PRESENT_TIMEOUT_NS 500000000ULL
|
#define FRAME_TIMING_PRESENT_TIMEOUT_NS 500000000ULL
|
||||||
|
#define USB_REDIR_DISCONNECT_TIMEOUT_US 500000ULL
|
||||||
|
|
||||||
enum FrameTimingReady
|
enum FrameTimingReady
|
||||||
{
|
{
|
||||||
@@ -1811,6 +1812,7 @@ int spiceThread(void * arg)
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
|
PSStatus status = PS_STATUS_SHUTDOWN;
|
||||||
if (!purespice_connect(&config))
|
if (!purespice_connect(&config))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to connect to spice server");
|
DEBUG_ERROR("Failed to connect to spice server");
|
||||||
@@ -1818,6 +1820,7 @@ int spiceThread(void * arg)
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
connected = true;
|
connected = true;
|
||||||
|
status = PS_STATUS_RUN;
|
||||||
|
|
||||||
int processTimeout = 100;
|
int processTimeout = 100;
|
||||||
#if ENABLE_USB_AUDIO
|
#if ENABLE_USB_AUDIO
|
||||||
@@ -1837,7 +1840,6 @@ int spiceThread(void * arg)
|
|||||||
DEBUG_WARN("Failed to process USB audio redirection");
|
DEBUG_WARN("Failed to process USB audio redirection");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PSStatus status;
|
|
||||||
if ((status = purespice_process(processTimeout)) != PS_STATUS_RUN)
|
if ((status = purespice_process(processTimeout)) != PS_STATUS_RUN)
|
||||||
{
|
{
|
||||||
if (status != PS_STATUS_SHUTDOWN)
|
if (status != PS_STATUS_SHUTDOWN)
|
||||||
@@ -1856,8 +1858,27 @@ end:
|
|||||||
lgaSpice_setAvailable(false);
|
lgaSpice_setAvailable(false);
|
||||||
#endif
|
#endif
|
||||||
#if ENABLE_USB_AUDIO
|
#if ENABLE_USB_AUDIO
|
||||||
if (connected && usbRedir && !lgUsbRedir_process(usbRedir))
|
if (connected && status == PS_STATUS_RUN && usbRedir)
|
||||||
|
{
|
||||||
|
if (!lgUsbRedir_process(usbRedir))
|
||||||
DEBUG_WARN("Failed to disconnect USB audio device");
|
DEBUG_WARN("Failed to disconnect USB audio device");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const uint64_t deadline =
|
||||||
|
microtime() + USB_REDIR_DISCONNECT_TIMEOUT_US;
|
||||||
|
while (lgUsbRedir_disconnectPending(usbRedir) &&
|
||||||
|
microtime() < deadline)
|
||||||
|
{
|
||||||
|
status = purespice_process(10);
|
||||||
|
if (status != PS_STATUS_RUN)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == PS_STATUS_RUN &&
|
||||||
|
lgUsbRedir_disconnectPending(usbRedir))
|
||||||
|
DEBUG_WARN("Timed out disconnecting USB audio device");
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (connected)
|
if (connected)
|
||||||
purespice_disconnect();
|
purespice_disconnect();
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ struct LG_USBRedir
|
|||||||
atomic_bool desiredPlugged;
|
atomic_bool desiredPlugged;
|
||||||
atomic_bool available;
|
atomic_bool available;
|
||||||
bool plugged;
|
bool plugged;
|
||||||
|
bool disconnectPending;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void setAvailable(LG_USBRedir * usbredir, bool available)
|
static void setAvailable(LG_USBRedir * usbredir, bool available)
|
||||||
@@ -118,6 +119,12 @@ static void helloUSBRedir(void * opaque,
|
|||||||
setAvailable(usbredir, true);
|
setAvailable(usbredir, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void deviceDisconnectAck(void * opaque)
|
||||||
|
{
|
||||||
|
LG_USBRedir * usbredir = opaque;
|
||||||
|
usbredir->disconnectPending = false;
|
||||||
|
}
|
||||||
|
|
||||||
static void unplugDevice(LG_USBRedir * usbredir)
|
static void unplugDevice(LG_USBRedir * usbredir)
|
||||||
{
|
{
|
||||||
if (!usbredir->plugged)
|
if (!usbredir->plugged)
|
||||||
@@ -131,6 +138,7 @@ static void destroyParser(LG_USBRedir * usbredir)
|
|||||||
{
|
{
|
||||||
setAvailable(usbredir, false);
|
setAvailable(usbredir, false);
|
||||||
unplugDevice(usbredir);
|
unplugDevice(usbredir);
|
||||||
|
usbredir->disconnectPending = false;
|
||||||
|
|
||||||
if (!usbredir->parser)
|
if (!usbredir->parser)
|
||||||
return;
|
return;
|
||||||
@@ -192,8 +200,11 @@ static bool createParser(LG_USBRedir * usbredir)
|
|||||||
usbredir->parser->read_func = readUSBRedir;
|
usbredir->parser->read_func = readUSBRedir;
|
||||||
usbredir->parser->write_func = writeUSBRedir;
|
usbredir->parser->write_func = writeUSBRedir;
|
||||||
usbredir->parser->hello_func = helloUSBRedir;
|
usbredir->parser->hello_func = helloUSBRedir;
|
||||||
|
usbredir->parser->device_disconnect_ack_func = deviceDisconnectAck;
|
||||||
|
|
||||||
uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0 };
|
uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0 };
|
||||||
|
usbredirparser_caps_set_cap(caps,
|
||||||
|
usb_redir_cap_device_disconnect_ack);
|
||||||
usbredirparser_caps_set_cap(caps,
|
usbredirparser_caps_set_cap(caps,
|
||||||
usb_redir_cap_connect_device_version);
|
usb_redir_cap_connect_device_version);
|
||||||
usbredirparser_caps_set_cap(caps,
|
usbredirparser_caps_set_cap(caps,
|
||||||
@@ -252,12 +263,20 @@ bool lgUsbRedir_available(const LG_USBRedir * usbredir)
|
|||||||
return atomic_load_explicit(&usbredir->available, memory_order_acquire);
|
return atomic_load_explicit(&usbredir->available, memory_order_acquire);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool lgUsbRedir_disconnectPending(const LG_USBRedir * usbredir)
|
||||||
|
{
|
||||||
|
return usbredir->disconnectPending;
|
||||||
|
}
|
||||||
|
|
||||||
bool lgUsbRedir_process(LG_USBRedir * usbredir)
|
bool lgUsbRedir_process(LG_USBRedir * usbredir)
|
||||||
{
|
{
|
||||||
if (!usbredir->parser ||
|
if (!usbredir->parser ||
|
||||||
!atomic_load_explicit(&usbredir->available, memory_order_acquire))
|
!atomic_load_explicit(&usbredir->available, memory_order_acquire))
|
||||||
return flushUSBRedir(usbredir);
|
return flushUSBRedir(usbredir);
|
||||||
|
|
||||||
|
if (usbredir->disconnectPending)
|
||||||
|
return flushUSBRedir(usbredir);
|
||||||
|
|
||||||
const bool desired = atomic_load_explicit(&usbredir->desiredPlugged,
|
const bool desired = atomic_load_explicit(&usbredir->desiredPlugged,
|
||||||
memory_order_acquire);
|
memory_order_acquire);
|
||||||
if (desired != usbredir->plugged)
|
if (desired != usbredir->plugged)
|
||||||
@@ -271,6 +290,8 @@ bool lgUsbRedir_process(LG_USBRedir * usbredir)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
unplugDevice(usbredir);
|
unplugDevice(usbredir);
|
||||||
|
usbredir->disconnectPending = usbredirparser_peer_has_cap(
|
||||||
|
usbredir->parser, usb_redir_cap_device_disconnect_ack);
|
||||||
usbredirparser_send_device_disconnect(usbredir->parser);
|
usbredirparser_send_device_disconnect(usbredir->parser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ void lgUsbRedir_destroy(LG_USBRedir * usbredir);
|
|||||||
* lgUsbRedir_process on the PureSpice processing thread. */
|
* lgUsbRedir_process on the PureSpice processing thread. */
|
||||||
void lgUsbRedir_setPlugged(LG_USBRedir * usbredir, bool plugged);
|
void lgUsbRedir_setPlugged(LG_USBRedir * usbredir, bool plugged);
|
||||||
bool lgUsbRedir_available(const LG_USBRedir * usbredir);
|
bool lgUsbRedir_available(const LG_USBRedir * usbredir);
|
||||||
|
/* True after a device disconnect has been sent and until the guest has
|
||||||
|
* completed the detach. This must be queried on the processing thread. */
|
||||||
|
bool lgUsbRedir_disconnectPending(const LG_USBRedir * usbredir);
|
||||||
|
|
||||||
/* Apply pending device state and flush parser output. This must be called on
|
/* Apply pending device state and flush parser output. This must be called on
|
||||||
* the PureSpice processing thread. */
|
* the PureSpice processing thread. */
|
||||||
|
|||||||
Reference in New Issue
Block a user