summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitaly Kuzmichev <vkuzmichev@mvista.com>2011-02-11 18:18:35 +0300
committerRemy Bohmer <linux@bohmer.net>2011-02-19 20:32:38 +0100
commite4ae66608bbf8b7be9162e5933a98905dcf52d6b (patch)
tree8f07caef2a6be9ceef8a560aabd4795ec2ef61aa
parent7612a43d0803ebd70071894658291300d4acc615 (diff)
downloadu-boot-e4ae66608bbf8b7be9162e5933a98905dcf52d6b.tar.gz
USB-RNDIS: Send RNDIS state on disconnecting
Add waiting for receiving Ethernet gadget state on the Windows host side before dropping pullup, but keep it for debug. Signed-off-by: Vitaly Kuzmichev <vkuzmichev@mvista.com>
-rw-r--r--drivers/usb/gadget/ether.c23
-rw-r--r--drivers/usb/gadget/rndis.c5
-rw-r--r--drivers/usb/gadget/rndis.h8
3 files changed, 36 insertions, 0 deletions
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index f909267f65..9fb0e80ad1 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -1921,10 +1921,22 @@ static void eth_start(struct eth_dev *dev, gfp_t gfp_flags)
static int eth_stop(struct eth_dev *dev)
{
+#ifdef RNDIS_COMPLETE_SIGNAL_DISCONNECT
+ unsigned long ts;
+ unsigned long timeout = CONFIG_SYS_HZ; /* 1 sec to stop RNDIS */
+#endif
+
if (rndis_active(dev)) {
rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0);
rndis_signal_disconnect(dev->rndis_config);
+#ifdef RNDIS_COMPLETE_SIGNAL_DISCONNECT
+ /* Wait until host receives OID_GEN_MEDIA_CONNECT_STATUS */
+ ts = get_timer(0);
+ while (get_timer(ts) < timeout)
+ usb_gadget_handle_interrupts();
+#endif
+
rndis_uninit(dev->rndis_config);
dev->rndis = 0;
}
@@ -2486,6 +2498,17 @@ void usb_eth_halt(struct eth_device *netdev)
if (!dev->gadget)
return;
+ /*
+ * Some USB controllers may need additional deinitialization here
+ * before dropping pull-up (also due to hardware issues).
+ * For example: unhandled interrupt with status stage started may
+ * bring the controller to fully broken state (until board reset).
+ * There are some variants to debug and fix such cases:
+ * 1) In the case of RNDIS connection eth_stop can perform additional
+ * interrupt handling. See RNDIS_COMPLETE_SIGNAL_DISCONNECT definition.
+ * 2) 'pullup' callback in your UDC driver can be improved to perform
+ * this deinitialization.
+ */
eth_stop(dev);
usb_gadget_disconnect(dev->gadget);
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 3e3f740ea5..886c0936e6 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -995,7 +995,12 @@ int rndis_signal_disconnect(int configNr)
rndis_per_dev_params[configNr].media_state
= NDIS_MEDIA_STATE_DISCONNECTED;
+#ifdef RNDIS_COMPLETE_SIGNAL_DISCONNECT
+ return rndis_indicate_status_msg(configNr,
+ RNDIS_STATUS_MEDIA_DISCONNECT);
+#else
return 0;
+#endif
}
void rndis_uninit(int configNr)
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
index 73a1204a03..d9e3a75287 100644
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -17,6 +17,14 @@
#include "ndis.h"
+/*
+ * By default rndis_signal_disconnect does not send status message about
+ * RNDIS disconnection to USB host (indicated as cable disconnected).
+ * Define RNDIS_COMPLETE_SIGNAL_DISCONNECT to send it.
+ * However, this will cause 1 sec delay on Ethernet device halt.
+ * Usually you do not need to define it. Mostly usable for debugging.
+ */
+
#define RNDIS_MAXIMUM_FRAME_SIZE 1518
#define RNDIS_MAX_TOTAL_SIZE 1558