summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorChristian Gromm <christian.gromm@microchip.com>2017-11-21 15:05:15 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-11-27 09:20:36 +0100
commit8f20f2dca8b390b4fe9e40ed6196c805a3f07b66 (patch)
treec497b6f4de948b5d86577f4baeca5f6d9f6fedca /drivers
parent7e0d35423350d118982096d151140616bbad147d (diff)
staging: most: usb: clear functional stall on OUT endpoint
For the MOST packet channel there are two dedicated USB endpoints. But internally the hardware has actually one channel for data forwarding from and to MOST. To have the hardware clean up its state machine correctly in case of an error, both USB pipes need to be reset. This patch triggers the host to also clear the OUT endpoint's halt condition in case an IN endpoint has signaled to be stalled. Signed-off-by: Christian Gromm <christian.gromm@microchip.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/staging/most/usb/usb.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/drivers/staging/most/usb/usb.c b/drivers/staging/most/usb/usb.c
index 87e7fec2af8a..1169635454f3 100644
--- a/drivers/staging/most/usb/usb.c
+++ b/drivers/staging/most/usb/usb.c
@@ -809,6 +809,21 @@ static void wq_clear_halt(struct work_struct *wq_obj)
if (usb_clear_halt(mdev->usb_device, pipe))
dev_warn(&mdev->usb_device->dev, "Failed to reset endpoint.\n");
+ /* If the functional Stall condition has been set on an
+ * asynchronous rx channel, we need to clear the tx channel
+ * too, since the hardware runs its clean-up sequence on both
+ * channels, as they are physically one on the network.
+ *
+ * The USB interface that exposes the asynchronous channels
+ * contains always two endpoints, and two only.
+ */
+ if (mdev->conf[channel].data_type == MOST_CH_ASYNC &&
+ mdev->conf[channel].direction == MOST_CH_RX) {
+ int peer = 1 - channel;
+ int snd_pipe = usb_sndbulkpipe(mdev->usb_device,
+ mdev->ep_address[peer]);
+ usb_clear_halt(mdev->usb_device, snd_pipe);
+ }
mdev->is_channel_healthy[channel] = true;
most_resume_enqueue(&mdev->iface, channel);
mutex_unlock(&mdev->io_mutex);