[PATCH 3/7] usb: common: otg-fsm: add HNP polling implememtation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Li Jun <b47624@xxxxxxxxxxxxx>

OTG in host mode call this function to poll peripheral if it wants to be host
role.

Signed-off-by: Li Jun <jun.li@xxxxxxxxxxxxx>
---
 drivers/usb/common/usb-otg-fsm.c |   75 ++++++++++++++++++++++++++++++++++++++
 include/linux/usb/otg-fsm.h      |   10 +++++
 2 files changed, 85 insertions(+)

diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 862eb04..1cd8995 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -367,3 +367,78 @@ int otg_statemachine(struct otg_fsm *fsm)
 	return state_changed;
 }
 EXPORT_SYMBOL_GPL(otg_statemachine);
+
+/*
+ * Called by host to poll if peripheral wants to be host
+ * Return value:
+ * - host request flag(1) if the device wants to be host;
+ * - host request flag(0) if the device keeps peripheral role;
+ * - otherwise, error code.
+ */
+int otg_hnp_polling(struct otg_fsm *fsm)
+{
+	struct usb_device *udev;
+	u8 host_req_flag;
+	int retval;
+	enum usb_otg_state state = fsm->otg->state;
+
+	if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST)
+		return -EINVAL;
+
+	udev = usb_hub_find_child(fsm->otg->host->root_hub, 1);
+	if (!udev) {
+		dev_err(fsm->otg->host->controller,
+			"no usb dev connected, can't start HNP polling\n");
+		return -ENODEV;
+	}
+
+	/* Get host request flag from connected USB device */
+	retval = usb_control_msg(udev,
+				usb_rcvctrlpipe(udev, 0),
+				USB_REQ_GET_STATUS,
+				USB_DIR_IN | USB_RECIP_DEVICE,
+				0,
+				OTG_STS_SELECTOR,
+				&host_req_flag,
+				1,
+				USB_CTRL_GET_TIMEOUT);
+	if (retval != 1) {
+		dev_err(&udev->dev, "Get one byte OTG status failed\n");
+		return -EIO;
+	}
+
+	if (host_req_flag == 0) {
+		/* Continue HNP polling */
+		otg_add_timer(fsm, HNP_POLLING);
+		return 0;
+	} else if (host_req_flag != HOST_REQUEST_FLAG) {
+		dev_err(&udev->dev, "host request flag is invalid\n");
+		return -EINVAL;
+	}
+
+	/* Host request flag is set */
+	if (state == OTG_STATE_A_HOST) {
+		/* Set b_hnp_enable */
+		if (!fsm->otg->host->b_hnp_enable) {
+			retval = usb_control_msg(udev,
+					usb_sndctrlpipe(udev, 0),
+					USB_REQ_SET_FEATURE, 0,
+					USB_DEVICE_B_HNP_ENABLE,
+					0, NULL, 0,
+					USB_CTRL_SET_TIMEOUT);
+			if (retval < 0) {
+				dev_err(&udev->dev,
+					"can't enable HNP %d\n", retval);
+				return -EINVAL;
+			}
+			fsm->otg->host->b_hnp_enable = 1;
+		}
+
+		fsm->a_bus_req = 0;
+	} else if (state == OTG_STATE_B_HOST) {
+		fsm->b_bus_req = 0;
+	}
+
+	return HOST_REQUEST_FLAG;
+}
+EXPORT_SYMBOL_GPL(otg_hnp_polling);
diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h
index d1b3415..562f35b 100644
--- a/include/linux/usb/otg-fsm.h
+++ b/include/linux/usb/otg-fsm.h
@@ -40,6 +40,15 @@
 #define PROTO_HOST	(1)
 #define PROTO_GADGET	(2)
 
+#define OTG_STS_SELECTOR	0xF000	/* OTG status selector, according to
+					 * OTG and EH 2.0 Charpter 6.2.3
+					 * Table:6-4
+					 */
+#define HOST_REQUEST_FLAG	1	/* Host request flag, according to
+					 * OTG and EH 2.0 Charpter 6.2.3
+					 * Table:6-5
+					 */
+
 enum otg_fsm_timer {
 	/* Standard OTG timers */
 	A_WAIT_VRISE,
@@ -243,5 +252,6 @@ static inline int otg_start_gadget(struct otg_fsm *fsm, int on)
 }
 
 int otg_statemachine(struct otg_fsm *fsm);
+int otg_hnp_polling(struct otg_fsm *fsm);
 
 #endif /* __LINUX_USB_OTG_FSM_H */
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux