static status_t vbe_get_mode_info(struct vm86_state& vmState, uint16 mode, struct vbe_mode_info* modeInfo) { struct vbe_mode_info* vbeModeInfo = (struct vbe_mode_info*)0x1000; memset(vbeModeInfo, 0, sizeof(vbe_mode_info)); vmState.regs.eax = 0x4f01; vmState.regs.ecx = mode; vmState.regs.es = 0x1000 >> 4; vmState.regs.edi = 0x0000; status_t status = vm86_do_int(&vmState, 0x10); if (status != B_OK) { dprintf(DEVICE_NAME ": vbe_get_mode_info(%u): vm86 failed\n", mode); return status; } if ((vmState.regs.eax & 0xffff) != 0x4f) { dprintf(DEVICE_NAME ": vbe_get_mode_info(): BIOS returned 0x%04lx\n", vmState.regs.eax & 0xffff); return B_ENTRY_NOT_FOUND; } memcpy(modeInfo, vbeModeInfo, sizeof(struct vbe_mode_info)); return B_OK; }
static status_t SetVesaDisplayMode(uint16 mode) { // Set the VESA display mode, and return B_OK if successful. #define SET_MODE_MASK 0x01ff #define SET_MODE_LINEAR_BUFFER (1 << 14) vm86_state vmState; status_t status = vm86_prepare(&vmState, 0x2000); if (status != B_OK) { TRACE("SetVesaDisplayMode(); vm86_prepare() failed, status: 0x%lx\n", status); return status; } vmState.regs.eax = 0x4f02; vmState.regs.ebx = (mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER; status = vm86_do_int(&vmState, 0x10); if (status != B_OK) { TRACE("SetVesaDisplayMode(0x%x): vm86_do_int failed\n", mode); } if (status == B_OK && (vmState.regs.eax & 0xffff) != 0x4f) { TRACE("SetVesaDisplayMode(0x%x): BIOS returned 0x%04lx\n", mode, vmState.regs.eax & 0xffff); status = B_ERROR; } vm86_cleanup(&vmState); return status; }
status_t vesa_set_indexed_colors(vesa_info& info, uint8 first, uint8* colors, uint16 count) { if (first + count > 256) count = 256 - first; // Prepare vm86 mode environment struct vm86_state vmState; status_t status = vm86_prepare(&vmState, 0x20000); if (status != B_OK) { dprintf(DEVICE_NAME": vesa_set_indexed_colors(): vm86_prepare failed: " "%s\n", strerror(status)); return status; } uint8* palette = (uint8*)0x1000; uint32 shift = 8 - info.bits_per_gun; // convert colors to VESA palette for (int32 i = first; i < count; i++) { uint8 color[3]; if (user_memcpy(color, &colors[i * 3], 3) < B_OK) return B_BAD_ADDRESS; // order is BGR- palette[i * 4 + 0] = color[2] >> shift; palette[i * 4 + 1] = color[1] >> shift; palette[i * 4 + 2] = color[0] >> shift; palette[i * 4 + 3] = 0; } // set palette vmState.regs.eax = 0x4f09; vmState.regs.ebx = 0; vmState.regs.ecx = count; vmState.regs.edx = first; vmState.regs.es = 0x1000 >> 4; vmState.regs.edi = 0x0000; status = vm86_do_int(&vmState, 0x10); if (status != B_OK) { dprintf(DEVICE_NAME ": vesa_set_indexed_colors(): vm86 failed: %s\n", strerror(status)); goto out; } if ((vmState.regs.eax & 0xffff) != 0x4f) { dprintf(DEVICE_NAME ": vesa_set_indexed_colors(): BIOS returned " "0x%04lx\n", vmState.regs.eax & 0xffff); status = B_ERROR; } out: vm86_cleanup(&vmState); return status; }
status_t vesa_set_dpms_mode(vesa_info& info, uint32 mode) { // Only let supported modes through mode &= info.shared_info->dpms_capabilities; uint8 vbeMode = 0; if ((mode & B_DPMS_OFF) != 0) vbeMode |= DPMS_OFF | DPMS_REDUCED_ON; if ((mode & B_DPMS_STAND_BY) != 0) vbeMode |= DPMS_STANDBY; if ((mode & B_DPMS_SUSPEND) != 0) vbeMode |= DPMS_SUSPEND; vbeMode &= info.vbe_dpms_capabilities; // Prepare vm86 mode environment struct vm86_state vmState; status_t status = vm86_prepare(&vmState, 0x20000); if (status != B_OK) { dprintf(DEVICE_NAME": vesa_set_dpms_mode(): vm86_prepare failed: %s\n", strerror(status)); return status; } vmState.regs.eax = 0x4f10; vmState.regs.ebx = (vbeMode << 8) | 1; vmState.regs.esi = 0; vmState.regs.edi = 0; status = vm86_do_int(&vmState, 0x10); if (status != B_OK) { dprintf(DEVICE_NAME ": vesa_set_dpms_mode(): vm86 failed: %s\n", strerror(status)); goto out; } if ((vmState.regs.eax & 0xffff) != 0x4f) { dprintf(DEVICE_NAME ": vesa_set_dpms_mode(): BIOS returned 0x%04lx\n", vmState.regs.eax & 0xffff); status = B_ERROR; goto out; } out: vm86_cleanup(&vmState); return status; }
static status_t vbe_set_mode(struct vm86_state& vmState, uint16 mode) { vmState.regs.eax = 0x4f02; vmState.regs.ebx = (mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER; status_t status = vm86_do_int(&vmState, 0x10); if (status != B_OK) { dprintf(DEVICE_NAME ": vbe_set_mode(%u): vm86 failed\n", mode); return status; } if ((vmState.regs.eax & 0xffff) != 0x4f) { dprintf(DEVICE_NAME ": vbe_set_mode(): BIOS returned 0x%04lx\n", vmState.regs.eax & 0xffff); return B_ERROR; } return B_OK; }
static status_t vbe_get_dpms_capabilities(uint32& vbeMode, uint32& mode) { // we always return a valid mode vbeMode = 0; mode = B_DPMS_ON; // Prepare vm86 mode environment struct vm86_state vmState; status_t status = vm86_prepare(&vmState, 0x20000); if (status != B_OK) { dprintf(DEVICE_NAME": vbe_get_dpms_capabilities(): vm86_prepare " "failed: %s\n", strerror(status)); return status; } vmState.regs.eax = 0x4f10; vmState.regs.ebx = 0; vmState.regs.esi = 0; vmState.regs.edi = 0; status = vm86_do_int(&vmState, 0x10); if (status != B_OK) { dprintf(DEVICE_NAME ": vbe_get_dpms_capabilities(): vm86 failed\n"); goto out; } if ((vmState.regs.eax & 0xffff) != 0x4f) { dprintf(DEVICE_NAME ": vbe_get_dpms_capabilities(): BIOS returned " "0x%04lx\n", vmState.regs.eax & 0xffff); status = B_ERROR; goto out; } vbeMode = vmState.regs.ebx >> 8; mode = vbe_to_system_dpms(vbeMode); out: vm86_cleanup(&vmState); return status; }
status_t vesa_get_dpms_mode(vesa_info& info, uint32& mode) { mode = B_DPMS_ON; // we always return a valid mode // Prepare vm86 mode environment struct vm86_state vmState; status_t status = vm86_prepare(&vmState, 0x20000); if (status != B_OK) { dprintf(DEVICE_NAME": vesa_get_dpms_mode(): vm86_prepare failed: %s\n", strerror(status)); return status; } vmState.regs.eax = 0x4f10; vmState.regs.ebx = 2; vmState.regs.esi = 0; vmState.regs.edi = 0; status = vm86_do_int(&vmState, 0x10); if (status != B_OK) { dprintf(DEVICE_NAME ": vesa_get_dpms_mode(): vm86 failed: %s\n", strerror(status)); goto out; } if ((vmState.regs.eax & 0xffff) != 0x4f) { dprintf(DEVICE_NAME ": vesa_get_dpms_mode(): BIOS returned 0x%04lx\n", vmState.regs.eax & 0xffff); status = B_ERROR; goto out; } mode = vbe_to_system_dpms(vmState.regs.ebx >> 8); out: vm86_cleanup(&vmState); return status; }
static status_t vbe_set_bits_per_gun(vm86_state& vmState, vesa_info& info, uint8 bits) { info.bits_per_gun = 6; vmState.regs.eax = 0x4f08; vmState.regs.ebx = (bits << 8) | 1; status_t status = vm86_do_int(&vmState, 0x10); if (status != B_OK) { dprintf(DEVICE_NAME ": vbe_set_bits_per_gun(): vm86 failed: %s\n", strerror(status)); return status; } if ((vmState.regs.eax & 0xffff) != 0x4f) { dprintf(DEVICE_NAME ": vbe_set_bits_per_gun(): BIOS returned 0x%04lx\n", vmState.regs.eax & 0xffff); return B_ERROR; } info.bits_per_gun = vmState.regs.ebx >> 8; return B_OK; }
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; }