static status_t GetEdidFromBIOS(edid1_raw& edidRaw) { // Get the EDID info from the video BIOS, and return B_OK if successful. #define ADDRESS_SEGMENT(address) ((addr_t)(address) >> 4) #define ADDRESS_OFFSET(address) ((addr_t)(address) & 0xf) vm86_state vmState; status_t status = vm86_prepare(&vmState, 0x2000); if (status != B_OK) { TRACE("GetEdidFromBIOS(); vm86_prepare() failed, status: 0x%lx\n", status); return status; } vmState.regs.eax = 0x4f15; vmState.regs.ebx = 0; // 0 = report DDC service vmState.regs.ecx = 0; vmState.regs.es = 0; vmState.regs.edi = 0; status = vm86_do_int(&vmState, 0x10); if (status == B_OK) { // AH contains the error code, and AL determines wether or not the // function is supported. if (vmState.regs.eax != 0x4f) status = B_NOT_SUPPORTED; // Test if DDC is supported by the monitor. if ((vmState.regs.ebx & 3) == 0) status = B_NOT_SUPPORTED; } if (status == B_OK) { // According to the author of the vm86 functions, the address of any // object to receive data must be >= 0x1000 and within the ram size // specified in the second argument of the vm86_prepare() call above. // Thus, the address of the struct to receive the EDID info is set to // 0x1000. edid1_raw* edid = (edid1_raw*)0x1000; vmState.regs.eax = 0x4f15; vmState.regs.ebx = 1; // 1 = read EDID vmState.regs.ecx = 0; vmState.regs.edx = 0; vmState.regs.es = ADDRESS_SEGMENT(edid); vmState.regs.edi = ADDRESS_OFFSET(edid); status = vm86_do_int(&vmState, 0x10); if (status == B_OK) { if (vmState.regs.eax != 0x4f) { status = B_NOT_SUPPORTED; } else { // Copy the EDID info to the caller's location, and compute the // checksum of the EDID info while copying. uint8 sum = 0; uint8 allOr = 0; uint8* dest = (uint8*)&edidRaw; uint8* src = (uint8*)edid; for (uint32 j = 0; j < sizeof(edidRaw); j++) { sum += *src; allOr |= *src; *dest++ = *src++; } if (allOr == 0) { TRACE("GetEdidFromBIOS(); EDID info contains only zeros\n"); status = B_ERROR; } else if (sum != 0) { TRACE("GetEdidFromBIOS(); Checksum error in EDID info\n"); status = B_ERROR; } } } } vm86_cleanup(&vmState); return status; }
static status_t GetEdidFromBIOS(edid1_raw& edidRaw) { // Get the EDID info from the video BIOS, and return B_OK if successful. #define ADDRESS_SEGMENT(address) ((addr_t)(address) >> 4) #define ADDRESS_OFFSET(address) ((addr_t)(address) & 0xf) bios_module_info* biosModule; status_t status = get_module(B_BIOS_MODULE_NAME, (module_info**)&biosModule); if (status != B_OK) { TRACE("GetEdidFromBIOS(): failed to get BIOS module: 0x%" B_PRIx32 "\n", status); return status; } bios_state* state; status = biosModule->prepare(&state); if (status != B_OK) { TRACE("GetEdidFromBIOS(): bios_prepare() failed: 0x%" B_PRIx32 "\n", status); put_module(B_BIOS_MODULE_NAME); return status; } bios_regs regs = {}; regs.eax = 0x4f15; regs.ebx = 0; // 0 = report DDC service regs.ecx = 0; regs.es = 0; regs.edi = 0; status = biosModule->interrupt(state, 0x10, ®s); if (status == B_OK) { // AH contains the error code, and AL determines whether or not the // function is supported. if (regs.eax != 0x4f) status = B_NOT_SUPPORTED; // Test if DDC is supported by the monitor. if ((regs.ebx & 3) == 0) status = B_NOT_SUPPORTED; } if (status == B_OK) { edid1_raw* edid = (edid1_raw*)biosModule->allocate_mem(state, sizeof(edid1_raw)); if (edid == NULL) { status = B_NO_MEMORY; goto out; } regs.eax = 0x4f15; regs.ebx = 1; // 1 = read EDID regs.ecx = 0; regs.edx = 0; regs.es = ADDRESS_SEGMENT(edid); regs.edi = ADDRESS_OFFSET(edid); status = biosModule->interrupt(state, 0x10, ®s); if (status == B_OK) { if (regs.eax != 0x4f) { status = B_NOT_SUPPORTED; } else { // Copy the EDID info to the caller's location, and compute the // checksum of the EDID info while copying. uint8 sum = 0; uint8 allOr = 0; uint8* dest = (uint8*)&edidRaw; uint8* src = (uint8*)edid; for (uint32 j = 0; j < sizeof(edidRaw); j++) { sum += *src; allOr |= *src; *dest++ = *src++; } if (allOr == 0) { TRACE("GetEdidFromBIOS(); EDID info contains only zeros\n"); status = B_ERROR; } else if (sum != 0) { TRACE("GetEdidFromBIOS(); Checksum error in EDID info\n"); status = B_ERROR; } } } } out: biosModule->finish(state); put_module(B_BIOS_MODULE_NAME); TRACE("GetEdidFromBIOS() status: 0x%" B_PRIx32 "\n", status); return status; }