usb: host: pehci: Add USB core changes needed by PEHCI
A user can initiate host compliance tests or suspend/resume requests over the ISP1763A USB Host controller by issuing IOCTLs on the pehci device. Add necessary changes in USB core to support these requests. These changes are taken from the 1.0.6.0 version of ST-E pehci driver present at: http://www.box.net/shared/static/o5esh7r14q.zip along with the fixes for checkpatch errors and removal of unused variables. Change-Id: Ic6b175bcd3104730bac90278456e3bfbcd507801 Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
This commit is contained in:
committed by
Stephen Boyd
parent
e3c0e555c3
commit
05ea6076b8
@@ -30,6 +30,31 @@
|
||||
|
||||
#include "usb.h"
|
||||
|
||||
#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/usb/ch11.h>
|
||||
|
||||
int portno;
|
||||
int No_Data_Phase;
|
||||
EXPORT_SYMBOL(No_Data_Phase);
|
||||
int No_Status_Phase;
|
||||
EXPORT_SYMBOL(No_Status_Phase);
|
||||
unsigned char hub_tier;
|
||||
|
||||
#define PDC_HOST_NOTIFY 0x8001 /*completion from core */
|
||||
#define UNSUPPORTED_DEVICE 0x8099
|
||||
#define UNWANTED_SUSPEND 0x8098
|
||||
#define PDC_POWERMANAGEMENT 0x8097
|
||||
|
||||
int Unwanted_SecondReset;
|
||||
EXPORT_SYMBOL(Unwanted_SecondReset);
|
||||
int HostComplianceTest;
|
||||
EXPORT_SYMBOL(HostComplianceTest);
|
||||
int HostTest;
|
||||
EXPORT_SYMBOL(HostTest);
|
||||
#endif
|
||||
|
||||
|
||||
/* if we are in debug mode, always announce new devices */
|
||||
#ifdef DEBUG
|
||||
#ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES
|
||||
@@ -3366,6 +3391,9 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||
(portchange & USB_PORT_STAT_C_CONNECTION))
|
||||
clear_bit(port1, hub->removed_bits);
|
||||
|
||||
#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
|
||||
if (Unwanted_SecondReset == 0) /*stericsson*/
|
||||
#endif
|
||||
if (portchange & (USB_PORT_STAT_C_CONNECTION |
|
||||
USB_PORT_STAT_C_ENABLE)) {
|
||||
status = hub_port_debounce(hub, port1);
|
||||
@@ -3504,7 +3532,32 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||
status = hub_power_remaining(hub);
|
||||
if (status)
|
||||
dev_dbg(hub_dev, "%dmA power budget left\n", status);
|
||||
#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
|
||||
if (HostComplianceTest == 1 && udev->devnum > 1) {
|
||||
if (HostTest == 7) { /*SINGLE_STEP_GET_DEV_DESC */
|
||||
dev_info(hub_dev, "Testing "
|
||||
"SINGLE_STEP_GET_DEV_DESC\n");
|
||||
/* Test the Single Step Get Device Descriptor ,
|
||||
* take care it should not get status phase
|
||||
*/
|
||||
No_Data_Phase = 1;
|
||||
No_Status_Phase = 1;
|
||||
|
||||
usb_get_device_descriptor(udev, 8);
|
||||
No_Data_Phase = 0;
|
||||
No_Status_Phase = 0;
|
||||
}
|
||||
|
||||
if (HostTest == 8) {
|
||||
dev_info(hub_dev, "Testing "
|
||||
"SINGLE_STEP_SET_FEATURE\n");
|
||||
/* Test Single Step Set Feature */
|
||||
No_Status_Phase = 1;
|
||||
usb_get_device_descriptor(udev, 8);
|
||||
No_Status_Phase = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
|
||||
loop_disable:
|
||||
@@ -3581,6 +3634,11 @@ static void hub_events(void)
|
||||
u16 portstatus;
|
||||
u16 portchange;
|
||||
int i, ret;
|
||||
#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
|
||||
int j;
|
||||
int otgport = 0;
|
||||
struct usb_port_status port_status;
|
||||
#endif
|
||||
int connect_change, wakeup_change;
|
||||
|
||||
/*
|
||||
@@ -3657,6 +3715,171 @@ static void hub_events(void)
|
||||
|
||||
/* deal with port status changes */
|
||||
for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
|
||||
#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
|
||||
struct usb_port_status portsts;
|
||||
|
||||
/*if we have something to do on
|
||||
* otg port
|
||||
* */
|
||||
if ((hdev->otgstate & USB_OTG_SUSPEND) ||
|
||||
(hdev->otgstate & USB_OTG_ENUMERATE) ||
|
||||
(hdev->otgstate & USB_OTG_DISCONNECT) ||
|
||||
(hdev->otgstate & USB_OTG_RESUME)) {
|
||||
otgport = 1;
|
||||
}
|
||||
|
||||
|
||||
if (hdev->otgstate & USB_OTG_RESUME) {
|
||||
ret = clear_port_feature(hdev, i,
|
||||
USB_PORT_FEAT_SUSPEND);
|
||||
if (ret < 0) {
|
||||
dev_err(hub_dev, "usb otg port Resume"
|
||||
" fails, %d\n", ret);
|
||||
}
|
||||
hdev->otgstate &= ~USB_OTG_RESUME;
|
||||
}
|
||||
if ((hdev->otgstate & USB_OTG_SUSPEND)
|
||||
&& (hdev->children[0])) {
|
||||
hdev->otgstate &= ~USB_OTG_SUSPEND;
|
||||
|
||||
ret = set_port_feature(hdev, 1,
|
||||
USB_PORT_FEAT_SUSPEND);
|
||||
if (ret < 0) {
|
||||
dev_err(hub_dev, "usb otg port suspend"
|
||||
" fails, %d\n", ret);
|
||||
break;
|
||||
}
|
||||
msleep(1);
|
||||
ret = get_port_status(hdev, i, &portsts);
|
||||
if (ret < 0) {
|
||||
dev_err(hub_dev, "usb otg get port"
|
||||
" status fails, %d\n", ret);
|
||||
break;
|
||||
}
|
||||
portchange = le16_to_cpu(portsts.wPortChange);
|
||||
if (portchange & USB_PORT_STAT_C_SUSPEND) {
|
||||
clear_port_feature(hdev, i,
|
||||
USB_PORT_FEAT_C_SUSPEND);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (hdev->otgstate & USB_OTG_REMOTEWAKEUP) {
|
||||
|
||||
for (j = 1; j <= hub->descriptor->bNbrPorts;
|
||||
j++) {
|
||||
if (hdev->children[j - 1]) {
|
||||
dev_dbg(hub_dev, "child"
|
||||
" found at port %d\n", j);
|
||||
ret = usb_control_msg(hdev->
|
||||
children[j - 1],
|
||||
usb_sndctrlpipe(hdev->
|
||||
children[j - 1],
|
||||
0),
|
||||
USB_REQ_SET_FEATURE,
|
||||
USB_RECIP_DEVICE,
|
||||
USB_DEVICE_REMOTE_WAKEUP,
|
||||
0, NULL,
|
||||
0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
dev_err(hub_dev, "Port"
|
||||
" %d doesn't support"
|
||||
"remote wakeup\n", j);
|
||||
} else {
|
||||
dev_dbg(hub_dev, "Port"
|
||||
" %d supports"
|
||||
"remote wakeup\n", j);
|
||||
}
|
||||
ret = set_port_feature(hdev, j,
|
||||
USB_PORT_FEAT_SUSPEND);
|
||||
if (ret < 0) {
|
||||
dev_err(hub_dev, "Port"
|
||||
" %d NOT ABLE TO"
|
||||
" SUSPEND\n", j);
|
||||
} else {
|
||||
dev_dbg(hub_dev, "Port"
|
||||
" %d is ABLE TO"
|
||||
" SUSPEND\n", j);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = usb_control_msg(hdev,
|
||||
usb_sndctrlpipe(hdev, 0),
|
||||
USB_REQ_SET_FEATURE,
|
||||
USB_RECIP_DEVICE,
|
||||
USB_DEVICE_REMOTE_WAKEUP,
|
||||
0, NULL, 0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
dev_err(hub_dev, "HUB doesn't support"
|
||||
" REMOTE WAKEUP\n");
|
||||
} else {
|
||||
dev_dbg(hub_dev, "HUB supports"
|
||||
" REMOTE WAKEUP\n");
|
||||
}
|
||||
ret = 0;
|
||||
msleep(10);
|
||||
if (hdev->parent == hdev->bus->root_hub) {
|
||||
if (hdev->hcd_suspend &&
|
||||
hdev->hcd_priv) {
|
||||
dev_dbg(hub_dev, "calling"
|
||||
" suspend after remote wakeup"
|
||||
" command is issued\n");
|
||||
hdev->hcd_suspend(hdev->
|
||||
hcd_priv);
|
||||
}
|
||||
if (hdev->otg_notif)
|
||||
hdev->otg_notif(hdev->otgpriv,
|
||||
PDC_POWERMANAGEMENT, 10);
|
||||
}
|
||||
}
|
||||
|
||||
if (hdev->otgstate & USB_OTG_WAKEUP_ALL) {
|
||||
(void) usb_control_msg(hdev,
|
||||
usb_sndctrlpipe(hdev, 0),
|
||||
USB_REQ_CLEAR_FEATURE,
|
||||
USB_RECIP_DEVICE,
|
||||
USB_DEVICE_REMOTE_WAKEUP,
|
||||
0, NULL, 0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
dev_dbg(hub_dev, "Hub CLEARED REMOTE WAKEUP\n");
|
||||
for (j = 1; j <= hub->descriptor->bNbrPorts;
|
||||
j++) {
|
||||
if (hdev->children[j - 1]) {
|
||||
dev_dbg(hub_dev, "PORT %d"
|
||||
" SUSPEND IS CLEARD\n", j);
|
||||
clear_port_feature(hdev, j,
|
||||
USB_PORT_FEAT_C_SUSPEND);
|
||||
msleep(50);
|
||||
(void) usb_control_msg(hdev->
|
||||
children[j - 1],
|
||||
usb_sndctrlpipe(
|
||||
hdev->children[j - 1],
|
||||
0),
|
||||
USB_REQ_CLEAR_FEATURE,
|
||||
USB_RECIP_DEVICE,
|
||||
USB_DEVICE_REMOTE_WAKEUP,
|
||||
0, NULL,
|
||||
0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
dev_dbg(hub_dev, "PORT %d "
|
||||
"REMOTE WAKEUP IS "
|
||||
"CLEARD\n", j);
|
||||
msleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* reset the state of otg device,
|
||||
* regardless of otg device
|
||||
*/
|
||||
hdev->otgstate = 0;
|
||||
#endif
|
||||
if (test_bit(i, hub->busy_bits))
|
||||
continue;
|
||||
connect_change = test_bit(i, hub->change_bits);
|
||||
@@ -3761,9 +3984,19 @@ static void hub_events(void)
|
||||
HUB_BH_RESET_TIME, true);
|
||||
}
|
||||
|
||||
if (connect_change)
|
||||
if (connect_change) {
|
||||
#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
|
||||
if (hdev->parent == hdev->bus->root_hub)
|
||||
if (hdev->otg_notif
|
||||
&& (HostComplianceTest == 0))
|
||||
hdev->otg_notif(hdev->otgpriv,
|
||||
PDC_HOST_NOTIFY,
|
||||
5);
|
||||
portno = i;
|
||||
#endif
|
||||
hub_port_connect_change(hub, i,
|
||||
portstatus, portchange);
|
||||
}
|
||||
} /* end for i */
|
||||
|
||||
/* deal with hub status changes */
|
||||
@@ -3795,7 +4028,105 @@ static void hub_events(void)
|
||||
"condition\n");
|
||||
}
|
||||
}
|
||||
#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
|
||||
/* if we have something on otg */
|
||||
if (otgport) {
|
||||
otgport = 0;
|
||||
/* notify otg controller about it */
|
||||
if (hdev->parent == hdev->bus->root_hub)
|
||||
if (hdev->otg_notif)
|
||||
hdev->otg_notif(hdev->otgpriv,
|
||||
PDC_HOST_NOTIFY, 0);
|
||||
}
|
||||
|
||||
if (HostComplianceTest && hdev->devnum > 1) {
|
||||
/* TEST_SE0_NAK */
|
||||
if (HostTest == 1) {
|
||||
dev_info(hub_dev, "Testing for TEST_SE0_NAK\n");
|
||||
ret = clear_port_feature(hdev, portno,
|
||||
USB_PORT_FEAT_C_CONNECTION);
|
||||
ret = set_port_feature(hdev, portno,
|
||||
USB_PORT_FEAT_SUSPEND);
|
||||
ret = set_port_feature(hdev, portno | 0x300,
|
||||
USB_PORT_FEAT_TEST);
|
||||
ret = get_port_status(hdev, portno,
|
||||
&port_status);
|
||||
}
|
||||
/*TEST_J*/
|
||||
if (HostTest == 2) {
|
||||
dev_info(hub_dev, "Testing TEST_J\n");
|
||||
ret = clear_port_feature(hdev, portno,
|
||||
USB_PORT_FEAT_C_CONNECTION);
|
||||
ret = set_port_feature(hdev, portno,
|
||||
USB_PORT_FEAT_SUSPEND);
|
||||
ret = set_port_feature(hdev, portno | 0x100,
|
||||
USB_PORT_FEAT_TEST);
|
||||
ret = get_port_status(hdev, portno,
|
||||
&port_status);
|
||||
}
|
||||
if (HostTest == 3) {
|
||||
dev_info(hub_dev, "Testing TEST_K\n");
|
||||
ret = clear_port_feature(hdev, portno,
|
||||
USB_PORT_FEAT_C_CONNECTION);
|
||||
ret = set_port_feature(hdev, portno,
|
||||
USB_PORT_FEAT_SUSPEND);
|
||||
ret = set_port_feature(hdev, portno | 0x200,
|
||||
USB_PORT_FEAT_TEST);
|
||||
ret = get_port_status(hdev, portno,
|
||||
&port_status);
|
||||
}
|
||||
if (HostTest == 4) {
|
||||
dev_info(hub_dev, "Testing TEST_PACKET at Port"
|
||||
" %d\n", portno);
|
||||
ret = clear_port_feature(hdev, portno,
|
||||
USB_PORT_FEAT_C_CONNECTION);
|
||||
if (ret < 0)
|
||||
dev_err(hub_dev, "Clear port feature"
|
||||
" C_CONNECTION failed\n");
|
||||
|
||||
ret = set_port_feature(hdev, portno,
|
||||
USB_PORT_FEAT_SUSPEND);
|
||||
if (ret < 0)
|
||||
dev_err(hub_dev, "Clear port feature"
|
||||
" SUSPEND failed\n");
|
||||
|
||||
ret = set_port_feature(hdev, portno | 0x400,
|
||||
USB_PORT_FEAT_TEST);
|
||||
if (ret < 0)
|
||||
dev_err(hub_dev, "Clear port feature"
|
||||
" TEST failed\n");
|
||||
|
||||
ret = get_port_status(hdev, portno,
|
||||
&port_status);
|
||||
if (ret < 0)
|
||||
dev_err(hub_dev, "Get port status"
|
||||
" failed\n");
|
||||
}
|
||||
if (HostTest == 5) {
|
||||
dev_info(hub_dev, "Testing TEST_FORCE_ENBLE\n");
|
||||
ret = clear_port_feature(hdev, portno,
|
||||
USB_PORT_FEAT_C_CONNECTION);
|
||||
ret = set_port_feature(hdev, portno,
|
||||
USB_PORT_FEAT_SUSPEND);
|
||||
ret = set_port_feature(hdev, portno | 0x500,
|
||||
USB_PORT_FEAT_TEST);
|
||||
ret = get_port_status(hdev, portno,
|
||||
&port_status);
|
||||
}
|
||||
if (HostTest == 6) {
|
||||
dev_info(hub_dev, "Testing "
|
||||
"HS_HOST_PORT_SUSPEND_RESUME\n");
|
||||
ret = clear_port_feature(hdev, portno,
|
||||
USB_PORT_FEAT_C_CONNECTION);
|
||||
ret = set_port_feature(hdev, portno,
|
||||
USB_PORT_FEAT_SUSPEND);
|
||||
msleep(3000);
|
||||
ret = clear_port_feature(hdev, portno,
|
||||
USB_PORT_FEAT_SUSPEND);
|
||||
HostTest = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
loop_autopm:
|
||||
/* Balance the usb_autopm_get_interface() above */
|
||||
usb_autopm_put_interface_no_suspend(intf);
|
||||
|
||||
@@ -92,7 +92,30 @@ static int is_targeted(struct usb_device *dev)
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
|
||||
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
|
||||
continue;
|
||||
#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
|
||||
/*Hub is targeted device,so code execution should reach here */
|
||||
if (USB_CLASS_HUB == dev->descriptor.bDeviceClass) {
|
||||
/* count the tiers and if it is more than 6, return 0 */
|
||||
unsigned char tier = 0;
|
||||
struct usb_device *root_hub;
|
||||
|
||||
root_hub = dev->bus->root_hub;
|
||||
while ((dev->parent != NULL) && /* root hub not count */
|
||||
(dev->parent != root_hub) &&
|
||||
(tier != 6)) {/* interal hub not count */
|
||||
tier++;
|
||||
dev = dev->parent;
|
||||
}
|
||||
|
||||
if (tier == 6) {
|
||||
dev_err(&dev->dev, "5 tier of hubs reached,"
|
||||
" newly added hub will not be"
|
||||
" supported!\n");
|
||||
hub_tier = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -372,6 +372,16 @@ struct usb_bus {
|
||||
* limit. Because the arrays need to add a bit for hub status data, we
|
||||
* do 31, so plus one evens out to four bytes.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
|
||||
#define USB_OTG_SUSPEND 0x1
|
||||
#define USB_OTG_ENUMERATE 0x2
|
||||
#define USB_OTG_DISCONNECT 0x4
|
||||
#define USB_OTG_RESUME 0x8
|
||||
#define USB_OTG_REMOTEWAKEUP 0x10
|
||||
#define USB_OTG_WAKEUP_ALL 0x20
|
||||
#endif
|
||||
|
||||
#define USB_MAXCHILDREN (31)
|
||||
|
||||
struct usb_tt;
|
||||
@@ -500,6 +510,18 @@ struct usb_device {
|
||||
struct dentry *usbfs_dentry;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
|
||||
/*otg add ons */
|
||||
u8 otgdevice; /*device is otg type */
|
||||
|
||||
/*otg states from otg driver, suspend, enumerate, disconnect */
|
||||
u8 otgstate;
|
||||
void *otgpriv;
|
||||
void (*otg_notif) (void *otg_priv,
|
||||
unsigned long notif, unsigned long data);
|
||||
void *hcd_priv;
|
||||
void (*hcd_suspend) (void *hcd_priv);
|
||||
#endif
|
||||
int maxchild;
|
||||
struct usb_device **children;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user