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