18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * usb hub driver head file
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 1999 Linus Torvalds
68c2ecf20Sopenharmony_ci * Copyright (C) 1999 Johannes Erdfelt
78c2ecf20Sopenharmony_ci * Copyright (C) 1999 Gregory P. Smith
88c2ecf20Sopenharmony_ci * Copyright (C) 2001 Brad Hards (bhards@bigpond.net.au)
98c2ecf20Sopenharmony_ci * Copyright (C) 2012 Intel Corp (tianyu.lan@intel.com)
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *  move struct usb_hub to this file.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/usb.h>
158c2ecf20Sopenharmony_ci#include <linux/usb/ch11.h>
168c2ecf20Sopenharmony_ci#include <linux/usb/hcd.h>
178c2ecf20Sopenharmony_ci#include "usb.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistruct usb_hub {
208c2ecf20Sopenharmony_ci	struct device		*intfdev;	/* the "interface" device */
218c2ecf20Sopenharmony_ci	struct usb_device	*hdev;
228c2ecf20Sopenharmony_ci	struct kref		kref;
238c2ecf20Sopenharmony_ci	struct urb		*urb;		/* for interrupt polling pipe */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	/* buffer for urb ... with extra space in case of babble */
268c2ecf20Sopenharmony_ci	u8			(*buffer)[8];
278c2ecf20Sopenharmony_ci	union {
288c2ecf20Sopenharmony_ci		struct usb_hub_status	hub;
298c2ecf20Sopenharmony_ci		struct usb_port_status	port;
308c2ecf20Sopenharmony_ci	}			*status;	/* buffer for status reports */
318c2ecf20Sopenharmony_ci	struct mutex		status_mutex;	/* for the status buffer */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	int			error;		/* last reported error */
348c2ecf20Sopenharmony_ci	int			nerrors;	/* track consecutive errors */
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	unsigned long		event_bits[1];	/* status change bitmask */
378c2ecf20Sopenharmony_ci	unsigned long		change_bits[1];	/* ports with logical connect
388c2ecf20Sopenharmony_ci							status change */
398c2ecf20Sopenharmony_ci	unsigned long		removed_bits[1]; /* ports with a "removed"
408c2ecf20Sopenharmony_ci							device present */
418c2ecf20Sopenharmony_ci	unsigned long		wakeup_bits[1];	/* ports that have signaled
428c2ecf20Sopenharmony_ci							remote wakeup */
438c2ecf20Sopenharmony_ci	unsigned long		power_bits[1]; /* ports that are powered */
448c2ecf20Sopenharmony_ci	unsigned long		child_usage_bits[1]; /* ports powered on for
458c2ecf20Sopenharmony_ci							children */
468c2ecf20Sopenharmony_ci	unsigned long		warm_reset_bits[1]; /* ports requesting warm
478c2ecf20Sopenharmony_ci							reset recovery */
488c2ecf20Sopenharmony_ci#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
498c2ecf20Sopenharmony_ci#error event_bits[] is too short!
508c2ecf20Sopenharmony_ci#endif
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	struct usb_hub_descriptor *descriptor;	/* class descriptor */
538c2ecf20Sopenharmony_ci	struct usb_tt		tt;		/* Transaction Translator */
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	unsigned		mA_per_port;	/* current for each child */
568c2ecf20Sopenharmony_ci#ifdef	CONFIG_PM
578c2ecf20Sopenharmony_ci	unsigned		wakeup_enabled_descendants;
588c2ecf20Sopenharmony_ci#endif
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	unsigned		limited_power:1;
618c2ecf20Sopenharmony_ci	unsigned		quiescing:1;
628c2ecf20Sopenharmony_ci	unsigned		disconnected:1;
638c2ecf20Sopenharmony_ci	unsigned		in_reset:1;
648c2ecf20Sopenharmony_ci	unsigned		quirk_disable_autosuspend:1;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	unsigned		quirk_check_port_auto_suspend:1;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	unsigned		has_indicators:1;
698c2ecf20Sopenharmony_ci	u8			indicator[USB_MAXCHILDREN];
708c2ecf20Sopenharmony_ci	struct delayed_work	leds;
718c2ecf20Sopenharmony_ci	struct delayed_work	init_work;
728c2ecf20Sopenharmony_ci	struct work_struct      events;
738c2ecf20Sopenharmony_ci	spinlock_t		irq_urb_lock;
748c2ecf20Sopenharmony_ci	struct timer_list	irq_urb_retry;
758c2ecf20Sopenharmony_ci	struct usb_port		**ports;
768c2ecf20Sopenharmony_ci};
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/**
798c2ecf20Sopenharmony_ci * struct usb port - kernel's representation of a usb port
808c2ecf20Sopenharmony_ci * @child: usb device attached to the port
818c2ecf20Sopenharmony_ci * @dev: generic device interface
828c2ecf20Sopenharmony_ci * @port_owner: port's owner
838c2ecf20Sopenharmony_ci * @peer: related usb2 and usb3 ports (share the same connector)
848c2ecf20Sopenharmony_ci * @req: default pm qos request for hubs without port power control
858c2ecf20Sopenharmony_ci * @connect_type: port's connect type
868c2ecf20Sopenharmony_ci * @location: opaque representation of platform connector location
878c2ecf20Sopenharmony_ci * @status_lock: synchronize port_event() vs usb_port_{suspend|resume}
888c2ecf20Sopenharmony_ci * @portnum: port index num based one
898c2ecf20Sopenharmony_ci * @is_superspeed cache super-speed status
908c2ecf20Sopenharmony_ci * @usb3_lpm_u1_permit: whether USB3 U1 LPM is permitted.
918c2ecf20Sopenharmony_ci * @usb3_lpm_u2_permit: whether USB3 U2 LPM is permitted.
928c2ecf20Sopenharmony_ci */
938c2ecf20Sopenharmony_cistruct usb_port {
948c2ecf20Sopenharmony_ci	struct usb_device *child;
958c2ecf20Sopenharmony_ci	struct device dev;
968c2ecf20Sopenharmony_ci	struct usb_dev_state *port_owner;
978c2ecf20Sopenharmony_ci	struct usb_port *peer;
988c2ecf20Sopenharmony_ci	struct dev_pm_qos_request *req;
998c2ecf20Sopenharmony_ci	enum usb_port_connect_type connect_type;
1008c2ecf20Sopenharmony_ci	usb_port_location_t location;
1018c2ecf20Sopenharmony_ci	struct mutex status_lock;
1028c2ecf20Sopenharmony_ci	u32 over_current_count;
1038c2ecf20Sopenharmony_ci	u8 portnum;
1048c2ecf20Sopenharmony_ci	u32 quirks;
1058c2ecf20Sopenharmony_ci	unsigned int is_superspeed:1;
1068c2ecf20Sopenharmony_ci	unsigned int usb3_lpm_u1_permit:1;
1078c2ecf20Sopenharmony_ci	unsigned int usb3_lpm_u2_permit:1;
1088c2ecf20Sopenharmony_ci};
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci#define to_usb_port(_dev) \
1118c2ecf20Sopenharmony_ci	container_of(_dev, struct usb_port, dev)
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ciextern int usb_hub_create_port_device(struct usb_hub *hub,
1148c2ecf20Sopenharmony_ci		int port1);
1158c2ecf20Sopenharmony_ciextern void usb_hub_remove_port_device(struct usb_hub *hub,
1168c2ecf20Sopenharmony_ci		int port1);
1178c2ecf20Sopenharmony_ciextern int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
1188c2ecf20Sopenharmony_ci		int port1, bool set);
1198c2ecf20Sopenharmony_ciextern struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev);
1208c2ecf20Sopenharmony_ciextern int hub_port_debounce(struct usb_hub *hub, int port1,
1218c2ecf20Sopenharmony_ci		bool must_be_connected);
1228c2ecf20Sopenharmony_ciextern int usb_clear_port_feature(struct usb_device *hdev,
1238c2ecf20Sopenharmony_ci		int port1, int feature);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic inline bool hub_is_port_power_switchable(struct usb_hub *hub)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	__le16 hcs;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	if (!hub)
1308c2ecf20Sopenharmony_ci		return false;
1318c2ecf20Sopenharmony_ci	hcs = hub->descriptor->wHubCharacteristics;
1328c2ecf20Sopenharmony_ci	return (le16_to_cpu(hcs) & HUB_CHAR_LPSM) < HUB_CHAR_NO_LPSM;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic inline int hub_is_superspeed(struct usb_device *hdev)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	return hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic inline int hub_is_superspeedplus(struct usb_device *hdev)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS &&
1438c2ecf20Sopenharmony_ci		le16_to_cpu(hdev->descriptor.bcdUSB) >= 0x0310 &&
1448c2ecf20Sopenharmony_ci		hdev->bos && hdev->bos->ssp_cap);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic inline unsigned hub_power_on_good_delay(struct usb_hub *hub)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	unsigned delay = hub->descriptor->bPwrOn2PwrGood * 2;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (!hub->hdev->parent)	/* root hub */
1528c2ecf20Sopenharmony_ci		return delay;
1538c2ecf20Sopenharmony_ci	else /* Wait at least 100 msec for power to become stable */
1548c2ecf20Sopenharmony_ci		return max(delay, 100U);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic inline int hub_port_debounce_be_connected(struct usb_hub *hub,
1588c2ecf20Sopenharmony_ci		int port1)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	return hub_port_debounce(hub, port1, true);
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic inline int hub_port_debounce_be_stable(struct usb_hub *hub,
1648c2ecf20Sopenharmony_ci		int port1)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	return hub_port_debounce(hub, port1, false);
1678c2ecf20Sopenharmony_ci}
168