1 /* 2 * Copyright 2022, 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 <condition_variable.h> 12 #include <dpc.h> 13 14 #include "random.h" 15 16 #include "ccp.h" 17 18 19 #define CCP_REG_TRNG 0xc 20 21 22 device_manager_info* gDeviceManager; 23 random_for_controller_interface *gRandom; 24 dpc_module_info *gDPC; 25 26 27 static void 28 handleDPC(void *arg) 29 { 30 CALLED(); 31 ccp_device_info* bus = reinterpret_cast<ccp_device_info*>(arg); 32 33 uint32 lowValue = read32(bus->registers + CCP_REG_TRNG); 34 uint32 highValue = read32(bus->registers + CCP_REG_TRNG); 35 if (lowValue == 0 || highValue == 0) 36 return; 37 gRandom->queue_randomness((uint64)lowValue | ((uint64)highValue << 32)); 38 } 39 40 41 static int32 42 handleTimerHook(struct timer* timer) 43 { 44 ccp_device_info* bus = reinterpret_cast<ccp_device_info*>(timer->user_data); 45 46 gDPC->queue_dpc(bus->dpcHandle, handleDPC, bus); 47 return B_HANDLED_INTERRUPT; 48 } 49 50 51 // #pragma mark - 52 53 54 static status_t 55 register_device(device_node* parent) 56 { 57 device_attr attrs[] = { 58 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "CCP device"}}, 59 {B_DEVICE_BUS, B_STRING_TYPE, {.string = "CCP"}}, 60 {} 61 }; 62 63 return gDeviceManager->register_node(parent, 64 CCP_DEVICE_MODULE_NAME, attrs, NULL, NULL); 65 } 66 67 68 static status_t 69 init_bus(device_node* node, void** bus_cookie) 70 { 71 CALLED(); 72 73 driver_module_info* driver; 74 ccp_device_info* bus; 75 device_node* parent = gDeviceManager->get_parent_node(node); 76 gDeviceManager->get_driver(parent, &driver, (void**)&bus); 77 gDeviceManager->put_node(parent); 78 79 TRACE_ALWAYS("init_bus() addr 0x%" B_PRIxPHYSADDR " size 0x%" B_PRIx64 80 " \n", bus->base_addr, bus->map_size); 81 82 bus->registersArea = map_physical_memory("CCP memory mapped registers", 83 bus->base_addr, bus->map_size, B_ANY_KERNEL_ADDRESS, 84 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 85 (void **)&bus->registers); 86 if (bus->registersArea < 0) 87 return bus->registersArea; 88 89 status_t status = gDPC->new_dpc_queue(&bus->dpcHandle, "ccp timer", 90 B_LOW_PRIORITY); 91 if (status != B_OK) { 92 ERROR("dpc setup failed (%s)\n", strerror(status)); 93 return status; 94 } 95 96 bus->extractTimer.user_data = bus; 97 status = add_timer(&bus->extractTimer, &handleTimerHook, 1 * 1000 * 1000, B_PERIODIC_TIMER); 98 if (status != B_OK) { 99 ERROR("timer setup failed (%s)\n", strerror(status)); 100 return status; 101 } 102 103 // trigger also now 104 gDPC->queue_dpc(bus->dpcHandle, handleDPC, bus); 105 106 *bus_cookie = bus; 107 return B_OK; 108 109 } 110 111 112 static void 113 uninit_bus(void* bus_cookie) 114 { 115 ccp_device_info* bus = (ccp_device_info*)bus_cookie; 116 117 cancel_timer(&bus->extractTimer); 118 gDPC->delete_dpc_queue(&bus->dpcHandle); 119 120 if (bus->registersArea >= 0) 121 delete_area(bus->registersArea); 122 123 } 124 125 126 // #pragma mark - 127 128 129 module_dependency module_dependencies[] = { 130 { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager }, 131 { RANDOM_FOR_CONTROLLER_MODULE_NAME, (module_info**)&gRandom }, 132 { B_DPC_MODULE_NAME, (module_info **)&gDPC }, 133 {} 134 }; 135 136 137 static driver_module_info sCcpDeviceModule = { 138 { 139 CCP_DEVICE_MODULE_NAME, 140 0, 141 NULL 142 }, 143 144 NULL, // supports device 145 register_device, 146 init_bus, 147 uninit_bus, 148 NULL, // register child devices 149 NULL, // rescan 150 NULL, // device removed 151 }; 152 153 154 module_info* modules[] = { 155 (module_info* )&gCcpAcpiDevice, 156 (module_info* )&sCcpDeviceModule, 157 (module_info* )&gCcpPciDevice, 158 NULL 159 }; 160