blob: 347e25e5c309f1c54fd40c88c5bd71a55891e261 [file] [log] [blame]
Karthikeyan Ramasubramanian0bb5b1c2022-05-02 13:16:15 -06001/* SPDX-License-Identifier: GPL-2.0-or-later */
2
3#include <acpi/acpigen.h>
4#include <acpi/acpi_device.h>
5#include <stdlib.h>
6
7#include "chip.h"
8
9static const char *usb_hub_acpi_name(const struct device *dev)
10{
11 char *name;
12 const char *pattern;
13
14 /* USB ACPI driver does not have acpi_name operation defined. Hence return
15 the ACPI name for both the hub and any downstream facing ports. */
16 switch (dev->path.usb.port_type) {
17 case 0:
18 return "EHUB";
19 case 2:
20 pattern = "HS%02d";
21 break;
22 case 3:
23 pattern = "SS%02d";
24 break;
25 default:
26 return NULL;
27 }
28
29 name = malloc(ACPI_NAME_BUFFER_SIZE);
30 snprintf(name, ACPI_NAME_BUFFER_SIZE, pattern, dev->path.usb.port_id + 1);
31 name[4] = '\0';
32
33 return name;
34}
35
36static void usb_hub_add_ports(const struct device *dev)
37{
38 const struct drivers_usb_hub_config *config = config_of(dev);
39 struct device *port = NULL;
40 unsigned int child_count = 0;
41
42 while ((port = dev_bus_each_child(dev->link_list, port)) != NULL) {
43 if (child_count++ >= config->port_count) {
44 printk(BIOS_WARNING, "%s cannot be added. Port Count limit reached.\n",
45 dev_name(port));
46 continue;
47 }
48 acpigen_write_device(usb_hub_acpi_name(port));
49 acpigen_write_name_byte("_ADR", port->path.usb.port_id + 1);
50 acpigen_write_device_end();
51 }
52}
53
54static void usb_hub_acpi_fill_ssdt(const struct device *dev)
55{
56 const struct drivers_usb_hub_config *config = config_of(dev);
57 const char *scope = acpi_device_scope(dev);
58 const char *name = acpi_device_name(dev);
59
60 acpigen_write_scope(scope);
61 acpigen_write_device(name);
62 acpigen_write_ADR(0);
63 if (config->name)
64 acpigen_write_name_string("_DDN", config->name);
65 if (config->desc)
66 acpigen_write_name_unicode("_STR", config->desc);
67 usb_hub_add_ports(dev);
68 acpigen_write_device_end();
69 acpigen_write_scope_end();
70}
71
72static struct device_operations usb_hub_ops = {
73 .read_resources = noop_read_resources,
74 .set_resources = noop_set_resources,
75 .scan_bus = scan_static_bus,
76 .acpi_fill_ssdt = usb_hub_acpi_fill_ssdt,
77 .acpi_name = usb_hub_acpi_name
78};
79
80static void usb_hub_acpi_enable(struct device *dev)
81{
82 dev->ops = &usb_hub_ops;
83}
84
85struct chip_operations drivers_usb_hub_ops = {
86 CHIP_NAME("USB Hub")
87 .enable_dev = usb_hub_acpi_enable
88};