1 /* 2 * Copyright 2020, Jérôme Duval, jerome.duval@gmail.com. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <new> 8 #include <stdio.h> 9 #include <string.h> 10 11 #include <ACPI.h> 12 #include <ByteOrder.h> 13 #include <condition_variable.h> 14 15 #include "pch_i2c.h" 16 17 18 typedef struct { 19 pch_i2c_sim_info info; 20 acpi_device_module_info* acpi; 21 acpi_device device; 22 23 } pch_i2c_acpi_sim_info; 24 25 26 static status_t 27 pch_i2c_acpi_set_powerstate(pch_i2c_acpi_sim_info* info, uint8 power) 28 { 29 status_t status = info->acpi->evaluate_method(info->device, 30 power == 1 ? "_PS0" : "_PS3", NULL, NULL); 31 return status; 32 } 33 34 35 36 static acpi_status 37 pch_i2c_scan_parse_callback(ACPI_RESOURCE *res, void *context) 38 { 39 struct pch_i2c_crs* crs = (struct pch_i2c_crs*)context; 40 41 if (res->Type == ACPI_RESOURCE_TYPE_IRQ) { 42 crs->irq = res->Data.Irq.Interrupts[0]; 43 crs->irq_triggering = res->Data.Irq.Triggering; 44 crs->irq_polarity = res->Data.Irq.Polarity; 45 crs->irq_shareable = res->Data.Irq.Shareable; 46 } else if (res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { 47 crs->irq = res->Data.ExtendedIrq.Interrupts[0]; 48 crs->irq_triggering = res->Data.ExtendedIrq.Triggering; 49 crs->irq_polarity = res->Data.ExtendedIrq.Polarity; 50 crs->irq_shareable = res->Data.ExtendedIrq.Shareable; 51 } else if (res->Type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { 52 crs->addr_bas = res->Data.FixedMemory32.Address; 53 crs->addr_len = res->Data.FixedMemory32.AddressLength; 54 } 55 56 return B_OK; 57 } 58 59 60 // #pragma mark - 61 62 63 static status_t 64 acpi_scan_bus(i2c_bus_cookie cookie) 65 { 66 CALLED(); 67 pch_i2c_acpi_sim_info* bus = (pch_i2c_acpi_sim_info*)cookie; 68 69 bus->acpi->walk_namespace(bus->device, ACPI_TYPE_DEVICE, 1, 70 pch_i2c_scan_bus_callback, NULL, bus, NULL); 71 72 return B_OK; 73 } 74 75 76 static status_t 77 register_child_devices(void* cookie) 78 { 79 CALLED(); 80 81 pch_i2c_acpi_sim_info* bus = (pch_i2c_acpi_sim_info*)cookie; 82 device_node* node = bus->info.driver_node; 83 84 char prettyName[25]; 85 sprintf(prettyName, "PCH I2C Controller"); 86 87 device_attr attrs[] = { 88 // properties of this controller for i2c bus manager 89 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, 90 { string: prettyName }}, 91 { B_DEVICE_FIXED_CHILD, B_STRING_TYPE, 92 { string: I2C_FOR_CONTROLLER_MODULE_NAME }}, 93 94 // private data to identify the device 95 { NULL } 96 }; 97 98 return gDeviceManager->register_node(node, PCH_I2C_SIM_MODULE_NAME, 99 attrs, NULL, NULL); 100 } 101 102 103 static status_t 104 init_device(device_node* node, void** device_cookie) 105 { 106 CALLED(); 107 status_t status = B_OK; 108 109 pch_i2c_acpi_sim_info* bus = (pch_i2c_acpi_sim_info*)calloc(1, 110 sizeof(pch_i2c_acpi_sim_info)); 111 if (bus == NULL) 112 return B_NO_MEMORY; 113 114 acpi_device_module_info* acpi; 115 acpi_device device; 116 { 117 device_node* acpiParent = gDeviceManager->get_parent_node(node); 118 gDeviceManager->get_driver(acpiParent, (driver_module_info**)&acpi, 119 (void**)&device); 120 gDeviceManager->put_node(acpiParent); 121 } 122 123 bus->acpi = acpi; 124 bus->device = device; 125 bus->info.driver_node = node; 126 bus->info.scan_bus = acpi_scan_bus; 127 128 // Attach devices for I2C resources 129 struct pch_i2c_crs crs; 130 status = acpi->walk_resources(device, (ACPI_STRING)"_CRS", 131 pch_i2c_scan_parse_callback, &crs); 132 if (status != B_OK) { 133 ERROR("Error while getting I2C devices\n"); 134 free(bus); 135 return status; 136 } 137 if (crs.addr_bas == 0 || crs.addr_len == 0) { 138 TRACE("skipping non configured I2C devices\n"); 139 free(bus); 140 return B_BAD_VALUE; 141 } 142 143 bus->info.base_addr = crs.addr_bas; 144 bus->info.map_size = crs.addr_len; 145 bus->info.irq = crs.irq; 146 147 pch_i2c_acpi_set_powerstate(bus, 1); 148 149 *device_cookie = bus; 150 return B_OK; 151 } 152 153 154 static void 155 uninit_device(void* device_cookie) 156 { 157 pch_i2c_acpi_sim_info* bus = (pch_i2c_acpi_sim_info*)device_cookie; 158 free(bus); 159 } 160 161 162 static status_t 163 register_device(device_node* parent) 164 { 165 device_attr attrs[] = { 166 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "PCH I2C ACPI"}}, 167 {} 168 }; 169 170 return gDeviceManager->register_node(parent, 171 PCH_I2C_ACPI_DEVICE_MODULE_NAME, attrs, NULL, NULL); 172 } 173 174 175 static float 176 supports_device(device_node* parent) 177 { 178 CALLED(); 179 const char* bus; 180 181 // make sure parent is a PCH I2C ACPI device node 182 if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) 183 < B_OK) { 184 return -1; 185 } 186 187 if (strcmp(bus, "acpi") != 0) 188 return 0.0f; 189 190 TRACE("found an acpi node\n"); 191 192 // check whether it's really a device 193 uint32 device_type; 194 if (gDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, 195 &device_type, false) != B_OK 196 || device_type != ACPI_TYPE_DEVICE) { 197 return 0.0; 198 } 199 TRACE("found an acpi device\n"); 200 201 // check whether it's a PCH I2C device 202 const char *name; 203 if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &name, 204 false) != B_OK) { 205 return 0.0; 206 } 207 TRACE("found an acpi device hid %s\n", name); 208 209 if (strcmp(name, "INT33C2") == 0 210 || strcmp(name, "INT33C3") == 0 211 || strcmp(name, "INT3432") == 0 212 || strcmp(name, "INT3433") == 0 213 || strcmp(name, "INT3442") == 0 214 || strcmp(name, "INT3443") == 0 215 || strcmp(name, "INT3444") == 0 216 || strcmp(name, "INT3445") == 0 217 || strcmp(name, "INT3446") == 0 218 || strcmp(name, "INT3447") == 0 219 || strcmp(name, "80860AAC") == 0 220 || strcmp(name, "80865AAC") == 0 221 || strcmp(name, "80860F41") == 0 222 || strcmp(name, "808622C1") == 0) { 223 TRACE("PCH I2C device found! name %s\n", name); 224 return 0.6f; 225 } 226 227 return 0.0f; 228 } 229 230 231 // #pragma mark - 232 233 234 driver_module_info gPchI2cAcpiDevice = { 235 { 236 PCH_I2C_ACPI_DEVICE_MODULE_NAME, 237 0, 238 NULL 239 }, 240 241 supports_device, 242 register_device, 243 init_device, 244 uninit_device, 245 register_child_devices, 246 NULL, // rescan 247 NULL, // device removed 248 }; 249 250 251