Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,9 @@
#
# Makefile for the usb common parts.
#
obj-$(CONFIG_USB_COMMON) += usb-common.o
usb-common-y += common.o
usb-common-$(CONFIG_USB_LED_TRIG) += led.o
obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o

179
drivers/usb/common/common.c Normal file
View file

@ -0,0 +1,179 @@
/*
* Provides code common for host and device side USB.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
* If either host side (ie. CONFIG_USB=y) or device side USB stack
* (ie. CONFIG_USB_GADGET=y) is compiled in the kernel, this module is
* compiled-in as well. Otherwise, if either of the two stacks is
* compiled as module, this file is compiled as module as well.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/usb/ch9.h>
#include <linux/usb/of.h>
#include <linux/usb/otg.h>
const char *usb_otg_state_string(enum usb_otg_state state)
{
static const char *const names[] = {
[OTG_STATE_A_IDLE] = "a_idle",
[OTG_STATE_A_WAIT_VRISE] = "a_wait_vrise",
[OTG_STATE_A_WAIT_BCON] = "a_wait_bcon",
[OTG_STATE_A_HOST] = "a_host",
[OTG_STATE_A_SUSPEND] = "a_suspend",
[OTG_STATE_A_PERIPHERAL] = "a_peripheral",
[OTG_STATE_A_WAIT_VFALL] = "a_wait_vfall",
[OTG_STATE_A_VBUS_ERR] = "a_vbus_err",
[OTG_STATE_B_IDLE] = "b_idle",
[OTG_STATE_B_SRP_INIT] = "b_srp_init",
[OTG_STATE_B_PERIPHERAL] = "b_peripheral",
[OTG_STATE_B_WAIT_ACON] = "b_wait_acon",
[OTG_STATE_B_HOST] = "b_host",
};
if (state < 0 || state >= ARRAY_SIZE(names))
return "UNDEFINED";
return names[state];
}
EXPORT_SYMBOL_GPL(usb_otg_state_string);
static const char *const speed_names[] = {
[USB_SPEED_UNKNOWN] = "UNKNOWN",
[USB_SPEED_LOW] = "low-speed",
[USB_SPEED_FULL] = "full-speed",
[USB_SPEED_HIGH] = "high-speed",
[USB_SPEED_WIRELESS] = "wireless",
[USB_SPEED_SUPER] = "super-speed",
};
const char *usb_speed_string(enum usb_device_speed speed)
{
if (speed < 0 || speed >= ARRAY_SIZE(speed_names))
speed = USB_SPEED_UNKNOWN;
return speed_names[speed];
}
EXPORT_SYMBOL_GPL(usb_speed_string);
const char *usb_state_string(enum usb_device_state state)
{
static const char *const names[] = {
[USB_STATE_NOTATTACHED] = "not attached",
[USB_STATE_ATTACHED] = "attached",
[USB_STATE_POWERED] = "powered",
[USB_STATE_RECONNECTING] = "reconnecting",
[USB_STATE_UNAUTHENTICATED] = "unauthenticated",
[USB_STATE_DEFAULT] = "default",
[USB_STATE_ADDRESS] = "addressed",
[USB_STATE_CONFIGURED] = "configured",
[USB_STATE_SUSPENDED] = "suspended",
};
if (state < 0 || state >= ARRAY_SIZE(names))
return "UNKNOWN";
return names[state];
}
EXPORT_SYMBOL_GPL(usb_state_string);
#ifdef CONFIG_OF
static const char *const usb_dr_modes[] = {
[USB_DR_MODE_UNKNOWN] = "",
[USB_DR_MODE_HOST] = "host",
[USB_DR_MODE_PERIPHERAL] = "peripheral",
[USB_DR_MODE_OTG] = "otg",
};
/**
* of_usb_get_suspend_clk_freq - Get suspend clock frequency
*
* USB3 core needs 16KHz clock for a small part that operates
* when the SS PHY is in its lowest power (P3) state.
* USB3 core receives suspend clock and divides it to make 16KHz clock.
*/
unsigned int of_usb_get_suspend_clk_freq(struct device_node *np)
{
unsigned int freq;
int err;
err = of_property_read_u32(np, "suspend_clk_freq", &freq);
if (err < 0)
return 0;
return freq;
}
EXPORT_SYMBOL_GPL(of_usb_get_suspend_clk_freq);
/**
* of_usb_get_dr_mode - Get dual role mode for given device_node
* @np: Pointer to the given device_node
*
* The function gets phy interface string from property 'dr_mode',
* and returns the correspondig enum usb_dr_mode
*/
enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np)
{
const char *dr_mode;
int err, i;
err = of_property_read_string(np, "dr_mode", &dr_mode);
if (err < 0)
return USB_DR_MODE_UNKNOWN;
for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++)
if (!strcmp(dr_mode, usb_dr_modes[i]))
return i;
return USB_DR_MODE_UNKNOWN;
}
EXPORT_SYMBOL_GPL(of_usb_get_dr_mode);
/**
* of_usb_get_maximum_speed - Get maximum requested speed for a given USB
* controller.
* @np: Pointer to the given device_node
*
* The function gets the maximum speed string from property "maximum-speed",
* and returns the corresponding enum usb_device_speed.
*/
enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np)
{
const char *maximum_speed;
int err;
int i;
err = of_property_read_string(np, "maximum-speed", &maximum_speed);
if (err < 0)
return USB_SPEED_UNKNOWN;
for (i = 0; i < ARRAY_SIZE(speed_names); i++)
if (strcmp(maximum_speed, speed_names[i]) == 0)
return i;
return USB_SPEED_UNKNOWN;
}
EXPORT_SYMBOL_GPL(of_usb_get_maximum_speed);
/**
* of_usb_host_tpl_support - to get if Targeted Peripheral List is supported
* for given targeted hosts (non-PC hosts)
* @np: Pointer to the given device_node
*
* The function gets if the targeted hosts support TPL or not
*/
bool of_usb_host_tpl_support(struct device_node *np)
{
if (of_find_property(np, "tpl-support", NULL))
return true;
return false;
}
EXPORT_SYMBOL_GPL(of_usb_host_tpl_support);
#endif
MODULE_LICENSE("GPL");

57
drivers/usb/common/led.c Normal file
View file

@ -0,0 +1,57 @@
/*
* LED Triggers for USB Activity
*
* Copyright 2014 Michal Sojka <sojka@merica.cz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/leds.h>
#include <linux/usb.h>
#define BLINK_DELAY 30
static unsigned long usb_blink_delay = BLINK_DELAY;
DEFINE_LED_TRIGGER(ledtrig_usb_gadget);
DEFINE_LED_TRIGGER(ledtrig_usb_host);
void usb_led_activity(enum usb_led_event ev)
{
struct led_trigger *trig = NULL;
switch (ev) {
case USB_LED_EVENT_GADGET:
trig = ledtrig_usb_gadget;
break;
case USB_LED_EVENT_HOST:
trig = ledtrig_usb_host;
break;
}
/* led_trigger_blink_oneshot() handles trig == NULL gracefully */
led_trigger_blink_oneshot(trig, &usb_blink_delay, &usb_blink_delay, 0);
}
EXPORT_SYMBOL_GPL(usb_led_activity);
static int __init ledtrig_usb_init(void)
{
led_trigger_register_simple("usb-gadget", &ledtrig_usb_gadget);
led_trigger_register_simple("usb-host", &ledtrig_usb_host);
return 0;
}
static void __exit ledtrig_usb_exit(void)
{
led_trigger_unregister_simple(ledtrig_usb_gadget);
led_trigger_unregister_simple(ledtrig_usb_host);
}
module_init(ledtrig_usb_init);
module_exit(ledtrig_usb_exit);

View file

@ -0,0 +1,367 @@
/*
* OTG Finite State Machine from OTG spec
*
* Copyright (C) 2007,2008 Freescale Semiconductor, Inc.
*
* Author: Li Yang <LeoLi@freescale.com>
* Jerry Huang <Chang-Ming.Huang@freescale.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/usb.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/usb/otg-fsm.h>
/* Change USB protocol when there is a protocol change */
static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
{
int ret = 0;
if (fsm->protocol != protocol) {
VDBG("Changing role fsm->protocol= %d; new protocol= %d\n",
fsm->protocol, protocol);
/* stop old protocol */
if (fsm->protocol == PROTO_HOST)
ret = otg_start_host(fsm, 0);
else if (fsm->protocol == PROTO_GADGET)
ret = otg_start_gadget(fsm, 0);
if (ret)
return ret;
/* start new protocol */
if (protocol == PROTO_HOST)
ret = otg_start_host(fsm, 1);
else if (protocol == PROTO_GADGET)
ret = otg_start_gadget(fsm, 1);
if (ret)
return ret;
fsm->protocol = protocol;
return 0;
}
return 0;
}
static int state_changed;
/* Called when leaving a state. Do state clean up jobs here */
static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
{
switch (old_state) {
case OTG_STATE_B_IDLE:
otg_del_timer(fsm, B_SE0_SRP);
fsm->b_se0_srp = 0;
fsm->adp_sns = 0;
fsm->adp_prb = 0;
break;
case OTG_STATE_B_SRP_INIT:
fsm->data_pulse = 0;
fsm->b_srp_done = 0;
break;
case OTG_STATE_B_PERIPHERAL:
break;
case OTG_STATE_B_WAIT_ACON:
otg_del_timer(fsm, B_ASE0_BRST);
fsm->b_ase0_brst_tmout = 0;
break;
case OTG_STATE_B_HOST:
break;
case OTG_STATE_A_IDLE:
fsm->adp_prb = 0;
break;
case OTG_STATE_A_WAIT_VRISE:
otg_del_timer(fsm, A_WAIT_VRISE);
fsm->a_wait_vrise_tmout = 0;
break;
case OTG_STATE_A_WAIT_BCON:
otg_del_timer(fsm, A_WAIT_BCON);
fsm->a_wait_bcon_tmout = 0;
break;
case OTG_STATE_A_HOST:
otg_del_timer(fsm, A_WAIT_ENUM);
break;
case OTG_STATE_A_SUSPEND:
otg_del_timer(fsm, A_AIDL_BDIS);
fsm->a_aidl_bdis_tmout = 0;
fsm->a_suspend_req_inf = 0;
break;
case OTG_STATE_A_PERIPHERAL:
otg_del_timer(fsm, A_BIDL_ADIS);
fsm->a_bidl_adis_tmout = 0;
break;
case OTG_STATE_A_WAIT_VFALL:
otg_del_timer(fsm, A_WAIT_VFALL);
fsm->a_wait_vfall_tmout = 0;
otg_del_timer(fsm, A_WAIT_VRISE);
break;
case OTG_STATE_A_VBUS_ERR:
break;
default:
break;
}
}
/* Called when entering a state */
static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
{
state_changed = 1;
if (fsm->otg->phy->state == new_state)
return 0;
VDBG("Set state: %s\n", usb_otg_state_string(new_state));
otg_leave_state(fsm, fsm->otg->phy->state);
switch (new_state) {
case OTG_STATE_B_IDLE:
otg_drv_vbus(fsm, 0);
otg_chrg_vbus(fsm, 0);
otg_loc_conn(fsm, 0);
otg_loc_sof(fsm, 0);
/*
* Driver is responsible for starting ADP probing
* if ADP sensing times out.
*/
otg_start_adp_sns(fsm);
otg_set_protocol(fsm, PROTO_UNDEF);
otg_add_timer(fsm, B_SE0_SRP);
break;
case OTG_STATE_B_SRP_INIT:
otg_start_pulse(fsm);
otg_loc_sof(fsm, 0);
otg_set_protocol(fsm, PROTO_UNDEF);
otg_add_timer(fsm, B_SRP_FAIL);
break;
case OTG_STATE_B_PERIPHERAL:
otg_chrg_vbus(fsm, 0);
otg_loc_sof(fsm, 0);
otg_set_protocol(fsm, PROTO_GADGET);
otg_loc_conn(fsm, 1);
break;
case OTG_STATE_B_WAIT_ACON:
otg_chrg_vbus(fsm, 0);
otg_loc_conn(fsm, 0);
otg_loc_sof(fsm, 0);
otg_set_protocol(fsm, PROTO_HOST);
otg_add_timer(fsm, B_ASE0_BRST);
fsm->a_bus_suspend = 0;
break;
case OTG_STATE_B_HOST:
otg_chrg_vbus(fsm, 0);
otg_loc_conn(fsm, 0);
otg_loc_sof(fsm, 1);
otg_set_protocol(fsm, PROTO_HOST);
usb_bus_start_enum(fsm->otg->host,
fsm->otg->host->otg_port);
break;
case OTG_STATE_A_IDLE:
otg_drv_vbus(fsm, 0);
otg_chrg_vbus(fsm, 0);
otg_loc_conn(fsm, 0);
otg_loc_sof(fsm, 0);
otg_start_adp_prb(fsm);
otg_set_protocol(fsm, PROTO_HOST);
break;
case OTG_STATE_A_WAIT_VRISE:
otg_drv_vbus(fsm, 1);
otg_loc_conn(fsm, 0);
otg_loc_sof(fsm, 0);
otg_set_protocol(fsm, PROTO_HOST);
otg_add_timer(fsm, A_WAIT_VRISE);
break;
case OTG_STATE_A_WAIT_BCON:
otg_drv_vbus(fsm, 1);
otg_loc_conn(fsm, 0);
otg_loc_sof(fsm, 0);
otg_set_protocol(fsm, PROTO_HOST);
otg_add_timer(fsm, A_WAIT_BCON);
break;
case OTG_STATE_A_HOST:
otg_drv_vbus(fsm, 1);
otg_loc_conn(fsm, 0);
otg_loc_sof(fsm, 1);
otg_set_protocol(fsm, PROTO_HOST);
/*
* When HNP is triggered while a_bus_req = 0, a_host will
* suspend too fast to complete a_set_b_hnp_en
*/
if (!fsm->a_bus_req || fsm->a_suspend_req_inf)
otg_add_timer(fsm, A_WAIT_ENUM);
break;
case OTG_STATE_A_SUSPEND:
otg_drv_vbus(fsm, 1);
otg_loc_conn(fsm, 0);
otg_loc_sof(fsm, 0);
otg_set_protocol(fsm, PROTO_HOST);
otg_add_timer(fsm, A_AIDL_BDIS);
break;
case OTG_STATE_A_PERIPHERAL:
otg_loc_sof(fsm, 0);
otg_set_protocol(fsm, PROTO_GADGET);
otg_drv_vbus(fsm, 1);
otg_loc_conn(fsm, 1);
otg_add_timer(fsm, A_BIDL_ADIS);
break;
case OTG_STATE_A_WAIT_VFALL:
otg_drv_vbus(fsm, 0);
otg_loc_conn(fsm, 0);
otg_loc_sof(fsm, 0);
otg_set_protocol(fsm, PROTO_HOST);
otg_add_timer(fsm, A_WAIT_VFALL);
break;
case OTG_STATE_A_VBUS_ERR:
otg_drv_vbus(fsm, 0);
otg_loc_conn(fsm, 0);
otg_loc_sof(fsm, 0);
otg_set_protocol(fsm, PROTO_UNDEF);
break;
default:
break;
}
fsm->otg->phy->state = new_state;
return 0;
}
/* State change judgement */
int otg_statemachine(struct otg_fsm *fsm)
{
enum usb_otg_state state;
mutex_lock(&fsm->lock);
state = fsm->otg->phy->state;
state_changed = 0;
/* State machine state change judgement */
switch (state) {
case OTG_STATE_UNDEFINED:
VDBG("fsm->id = %d\n", fsm->id);
if (fsm->id)
otg_set_state(fsm, OTG_STATE_B_IDLE);
else
otg_set_state(fsm, OTG_STATE_A_IDLE);
break;
case OTG_STATE_B_IDLE:
if (!fsm->id)
otg_set_state(fsm, OTG_STATE_A_IDLE);
else if (fsm->b_sess_vld && fsm->otg->gadget)
otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
else if ((fsm->b_bus_req || fsm->adp_change || fsm->power_up) &&
fsm->b_ssend_srp && fsm->b_se0_srp)
otg_set_state(fsm, OTG_STATE_B_SRP_INIT);
break;
case OTG_STATE_B_SRP_INIT:
if (!fsm->id || fsm->b_srp_done)
otg_set_state(fsm, OTG_STATE_B_IDLE);
break;
case OTG_STATE_B_PERIPHERAL:
if (!fsm->id || !fsm->b_sess_vld)
otg_set_state(fsm, OTG_STATE_B_IDLE);
else if (fsm->b_bus_req && fsm->otg->
gadget->b_hnp_enable && fsm->a_bus_suspend)
otg_set_state(fsm, OTG_STATE_B_WAIT_ACON);
break;
case OTG_STATE_B_WAIT_ACON:
if (fsm->a_conn)
otg_set_state(fsm, OTG_STATE_B_HOST);
else if (!fsm->id || !fsm->b_sess_vld)
otg_set_state(fsm, OTG_STATE_B_IDLE);
else if (fsm->a_bus_resume || fsm->b_ase0_brst_tmout) {
fsm->b_ase0_brst_tmout = 0;
otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
}
break;
case OTG_STATE_B_HOST:
if (!fsm->id || !fsm->b_sess_vld)
otg_set_state(fsm, OTG_STATE_B_IDLE);
else if (!fsm->b_bus_req || !fsm->a_conn || fsm->test_device)
otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
break;
case OTG_STATE_A_IDLE:
if (fsm->id)
otg_set_state(fsm, OTG_STATE_B_IDLE);
else if (!fsm->a_bus_drop && (fsm->a_bus_req ||
fsm->a_srp_det || fsm->adp_change || fsm->power_up))
otg_set_state(fsm, OTG_STATE_A_WAIT_VRISE);
break;
case OTG_STATE_A_WAIT_VRISE:
if (fsm->a_vbus_vld)
otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
else if (fsm->id || fsm->a_bus_drop ||
fsm->a_wait_vrise_tmout)
otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
break;
case OTG_STATE_A_WAIT_BCON:
if (!fsm->a_vbus_vld)
otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
else if (fsm->b_conn)
otg_set_state(fsm, OTG_STATE_A_HOST);
else if (fsm->id || fsm->a_bus_drop || fsm->a_wait_bcon_tmout)
otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
break;
case OTG_STATE_A_HOST:
if (fsm->id || fsm->a_bus_drop)
otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
else if ((!fsm->a_bus_req || fsm->a_suspend_req_inf) &&
fsm->otg->host->b_hnp_enable)
otg_set_state(fsm, OTG_STATE_A_SUSPEND);
else if (!fsm->b_conn)
otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
else if (!fsm->a_vbus_vld)
otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
break;
case OTG_STATE_A_SUSPEND:
if (!fsm->b_conn && fsm->otg->host->b_hnp_enable)
otg_set_state(fsm, OTG_STATE_A_PERIPHERAL);
else if (!fsm->b_conn && !fsm->otg->host->b_hnp_enable)
otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
else if (fsm->a_bus_req || fsm->b_bus_resume)
otg_set_state(fsm, OTG_STATE_A_HOST);
else if (fsm->id || fsm->a_bus_drop || fsm->a_aidl_bdis_tmout)
otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
else if (!fsm->a_vbus_vld)
otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
break;
case OTG_STATE_A_PERIPHERAL:
if (fsm->id || fsm->a_bus_drop)
otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
else if (fsm->a_bidl_adis_tmout || fsm->b_bus_suspend)
otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
else if (!fsm->a_vbus_vld)
otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
break;
case OTG_STATE_A_WAIT_VFALL:
if (fsm->a_wait_vfall_tmout)
otg_set_state(fsm, OTG_STATE_A_IDLE);
break;
case OTG_STATE_A_VBUS_ERR:
if (fsm->id || fsm->a_bus_drop || fsm->a_clr_err)
otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
break;
default:
break;
}
mutex_unlock(&fsm->lock);
VDBG("quit statemachine, changed = %d\n", state_changed);
return state_changed;
}
EXPORT_SYMBOL_GPL(otg_statemachine);