mirror of
https://review.haiku-os.org/haiku
synced 2024-11-23 15:28:58 +01:00
intel_extreme: reduce use of display_mode where display_timing is enough
In most cases we don't need to use the complete display_mode struct and we just need the timings. This will avoid future confusion between the virtual width/height and the actual display timings, if we implement scrolling someday. Change-Id: I6c4430b84130b956a47ea0a01afb0843f5a34fd2 Reviewed-on: https://review.haiku-os.org/c/haiku/+/4665 Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
parent
0cabd8891f
commit
4492fde7bf
@ -249,7 +249,7 @@ struct intel_shared_info {
|
||||
uint32 mode_count;
|
||||
|
||||
display_mode current_mode; // pretty much a hack until per-display modes
|
||||
display_mode panel_mode; // VBIOS VBT panel mode
|
||||
display_timing panel_timing; // Hardware timings of the LVDS panel, extracted from BIOS
|
||||
uint32 bytes_per_row;
|
||||
uint32 bits_per_pixel;
|
||||
uint32 dpms_mode;
|
||||
|
@ -250,7 +250,7 @@ FDILink::FDILink(pipe_index pipeIndex)
|
||||
|
||||
|
||||
status_t
|
||||
FDILink::Train(display_mode* target)
|
||||
FDILink::Train(display_timing* target)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
@ -284,7 +284,7 @@ FDILink::Train(display_mode* target)
|
||||
// Khz / 10. ( each output octet encoded as 10 bits.
|
||||
uint32 linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10;
|
||||
//Reserving 5% bandwidth for possible spread spectrum clock use
|
||||
uint32 bps = target->timing.pixel_clock * bitsPerPixel * 21 / 20;
|
||||
uint32 bps = target->pixel_clock * bitsPerPixel * 21 / 20;
|
||||
|
||||
//use DIV_ROUND_UP:
|
||||
uint32 lanes = (bps + (linkBandwidth * 8) - 1) / (linkBandwidth * 8);
|
||||
@ -338,7 +338,7 @@ FDILink::Train(display_mode* target)
|
||||
if (ret_n > 0x800000) {
|
||||
ret_n = 0x800000;
|
||||
}
|
||||
uint64 ret_m = target->timing.pixel_clock * ret_n * bitsPerPixel / linkspeed;
|
||||
uint64 ret_m = target->pixel_clock * ret_n * bitsPerPixel / linkspeed;
|
||||
while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) {
|
||||
ret_m >>= 1;
|
||||
ret_n >>= 1;
|
||||
@ -356,7 +356,7 @@ FDILink::Train(display_mode* target)
|
||||
if (ret_n > 0x800000) {
|
||||
ret_n = 0x800000;
|
||||
}
|
||||
ret_m = target->timing.pixel_clock * ret_n / linkspeed;
|
||||
ret_m = target->pixel_clock * ret_n / linkspeed;
|
||||
while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) {
|
||||
ret_m >>= 1;
|
||||
ret_n >>= 1;
|
||||
|
@ -65,7 +65,7 @@ public:
|
||||
FDIReceiver& Receiver()
|
||||
{ return fReceiver; };
|
||||
|
||||
status_t Train(display_mode* target);
|
||||
status_t Train(display_timing* target);
|
||||
|
||||
private:
|
||||
status_t _NormalTrain(uint32 lanes);
|
||||
|
@ -59,7 +59,7 @@ PanelFitter::IsEnabled()
|
||||
|
||||
|
||||
void
|
||||
PanelFitter::Enable(const display_mode& mode)
|
||||
PanelFitter::Enable(const display_timing& timing)
|
||||
{
|
||||
_Enable(true);
|
||||
|
||||
@ -69,7 +69,7 @@ PanelFitter::Enable(const display_mode& mode)
|
||||
TRACE("%s: PCH_PANEL_FITTER_WINDOW_POS, 0x%" B_PRIx32 "\n", __func__, read32(fRegisterBase + PCH_PANEL_FITTER_WINDOW_POS));
|
||||
|
||||
// Window size _must_ be the last register programmed as it 'arms'/unlocks all the other ones..
|
||||
write32(fRegisterBase + PCH_PANEL_FITTER_WINDOW_SIZE, (mode.timing.h_display << 16) | mode.timing.v_display);
|
||||
write32(fRegisterBase + PCH_PANEL_FITTER_WINDOW_SIZE, (timing.h_display << 16) | timing.v_display);
|
||||
}
|
||||
|
||||
|
||||
|
@ -17,7 +17,7 @@ public:
|
||||
virtual ~PanelFitter();
|
||||
|
||||
bool IsEnabled();
|
||||
void Enable(const display_mode& mode);
|
||||
void Enable(const display_timing& timing);
|
||||
void Disable();
|
||||
|
||||
private:
|
||||
|
@ -363,13 +363,13 @@ AnalogPort::SetDisplayMode(display_mode* target, uint32 colorMode)
|
||||
// Setup PanelFitter and Train FDI if it exists
|
||||
PanelFitter* fitter = fPipe->PFT();
|
||||
if (fitter != NULL)
|
||||
fitter->Enable(*target);
|
||||
fitter->Enable(target->timing);
|
||||
FDILink* link = fPipe->FDI();
|
||||
if (link != NULL)
|
||||
link->Train(target);
|
||||
link->Train(&target->timing);
|
||||
|
||||
pll_divisors divisors;
|
||||
compute_pll_divisors(target, &divisors, false);
|
||||
compute_pll_divisors(&target->timing, &divisors, false);
|
||||
|
||||
uint32 extraPLLFlags = 0;
|
||||
if (gInfo->shared_info->device_type.Generation() >= 3)
|
||||
@ -561,7 +561,7 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
|
||||
// For LVDS panels, we may need to set the timings according to the panel
|
||||
// native video mode, and let the panel fitter do the scaling. But the
|
||||
// place where the scaling happens varies accross generations of devices.
|
||||
display_mode hardwareTarget;
|
||||
display_timing hardwareTarget;
|
||||
bool needsScaling = false;
|
||||
|
||||
// TODO figure out how it's done (or if we need to configure something at
|
||||
@ -570,25 +570,20 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
|
||||
&& gInfo->shared_info->device_type.Generation() >= 3
|
||||
&& gInfo->shared_info->got_vbt) {
|
||||
// Set vbios hardware panel mode as base
|
||||
hardwareTarget = gInfo->shared_info->panel_mode;
|
||||
hardwareTarget = gInfo->shared_info->panel_timing;
|
||||
|
||||
if (hardwareTarget.timing.h_display == target->timing.h_display
|
||||
&& hardwareTarget.timing.v_display == target->timing.v_display) {
|
||||
if (hardwareTarget.h_display == target->timing.h_display
|
||||
&& hardwareTarget.v_display == target->timing.v_display) {
|
||||
// We are setting the native video mode, nothing special to do
|
||||
TRACE("Setting LVDS to native mode\n");
|
||||
hardwareTarget = *target;
|
||||
hardwareTarget = target->timing;
|
||||
} else {
|
||||
// We need to enable the panel fitter
|
||||
TRACE("%s: hardware mode will actually be %dx%d\n", __func__,
|
||||
hardwareTarget.timing.h_display, hardwareTarget.timing.v_display);
|
||||
hardwareTarget.h_display, hardwareTarget.v_display);
|
||||
|
||||
hardwareTarget.space = target->space;
|
||||
// retain requested virtual size
|
||||
hardwareTarget.virtual_width = target->virtual_width;
|
||||
hardwareTarget.virtual_height = target->virtual_height;
|
||||
// FIXME we should also get the refresh frequency from the target
|
||||
// mode, and then "sanitize" the resulting mode we made up.
|
||||
|
||||
needsScaling = true;
|
||||
}
|
||||
} else {
|
||||
@ -596,7 +591,7 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
|
||||
"generation, scaling may not work\n");
|
||||
// We don't have VBT data, try to set the requested mode directly
|
||||
// and hope for the best
|
||||
hardwareTarget = *target;
|
||||
hardwareTarget = target->timing;
|
||||
}
|
||||
|
||||
// Setup PanelFitter and Train FDI if it exists
|
||||
@ -664,7 +659,7 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
|
||||
|
||||
// Program pipe PLL's (using the hardware mode timings, since that's what
|
||||
// the PLL is used for)
|
||||
fPipe->ConfigureClocks(divisors, hardwareTarget.timing.pixel_clock,
|
||||
fPipe->ConfigureClocks(divisors, hardwareTarget.pixel_clock,
|
||||
extraPLLFlags);
|
||||
|
||||
if (gInfo->shared_info->device_type.Generation() != 4) {
|
||||
@ -799,13 +794,13 @@ DigitalPort::SetDisplayMode(display_mode* target, uint32 colorMode)
|
||||
// Setup PanelFitter and Train FDI if it exists
|
||||
PanelFitter* fitter = fPipe->PFT();
|
||||
if (fitter != NULL)
|
||||
fitter->Enable(*target);
|
||||
fitter->Enable(target->timing);
|
||||
FDILink* link = fPipe->FDI();
|
||||
if (link != NULL)
|
||||
link->Train(target);
|
||||
link->Train(&target->timing);
|
||||
|
||||
pll_divisors divisors;
|
||||
compute_pll_divisors(target, &divisors, false);
|
||||
compute_pll_divisors(&target->timing, &divisors, false);
|
||||
|
||||
uint32 extraPLLFlags = 0;
|
||||
if (gInfo->shared_info->device_type.Generation() >= 3)
|
||||
@ -1345,16 +1340,16 @@ DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode)
|
||||
// Setup PanelFitter and Train FDI if it exists
|
||||
PanelFitter* fitter = fPipe->PFT();
|
||||
if (fitter != NULL)
|
||||
fitter->Enable(*target);
|
||||
fitter->Enable(target->timing);
|
||||
// Skip FDI if we have a CPU connected display
|
||||
if (PortIndex() != INTEL_PORT_A) {
|
||||
FDILink* link = fPipe->FDI();
|
||||
if (link != NULL)
|
||||
link->Train(target);
|
||||
link->Train(&target->timing);
|
||||
}
|
||||
|
||||
pll_divisors divisors;
|
||||
compute_pll_divisors(target, &divisors, false);
|
||||
compute_pll_divisors(&target->timing, &divisors, false);
|
||||
|
||||
uint32 extraPLLFlags = 0;
|
||||
if (gInfo->shared_info->device_type.Generation() >= 3)
|
||||
|
@ -179,9 +179,9 @@ limit_modes_for_gen3_lvds(display_mode* mode)
|
||||
// display.
|
||||
// FIXME do this only for that display. The whole display mode logic
|
||||
// needs to be adjusted to know which display we're talking about.
|
||||
if (gInfo->shared_info->panel_mode.timing.h_display < mode->timing.h_display)
|
||||
if (gInfo->shared_info->panel_timing.h_display < mode->timing.h_display)
|
||||
return false;
|
||||
if (gInfo->shared_info->panel_mode.timing.v_display < mode->timing.v_display)
|
||||
if (gInfo->shared_info->panel_timing.v_display < mode->timing.v_display)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -230,9 +230,17 @@ create_mode_list(void)
|
||||
if (gInfo->shared_info->device_type.Generation() < 4)
|
||||
limitModes = limit_modes_for_gen3_lvds;
|
||||
|
||||
display_mode mode;
|
||||
mode.timing = gInfo->shared_info->panel_timing;
|
||||
mode.space = B_RGB32;
|
||||
mode.virtual_width = mode.timing.h_display;
|
||||
mode.virtual_height = mode.timing.v_display;
|
||||
mode.h_display_start = 0;
|
||||
mode.v_display_start = 0;
|
||||
mode.flags = 0;
|
||||
|
||||
// TODO: support lower modes via scaling and windowing
|
||||
gInfo->mode_list_area = create_display_modes("intel extreme modes",
|
||||
NULL, &gInfo->shared_info->panel_mode, 1,
|
||||
gInfo->mode_list_area = create_display_modes("intel extreme modes", NULL, &mode, 1,
|
||||
supportedSpaces, colorSpaceCount, limitModes, &list, &count);
|
||||
} else {
|
||||
// Otherwise return the 'real' list of modes
|
||||
|
@ -184,9 +184,9 @@ static pll_limits kLimitsPinLvds = {
|
||||
|
||||
|
||||
static bool
|
||||
lvds_dual_link(display_mode* current)
|
||||
lvds_dual_link(display_timing* current)
|
||||
{
|
||||
float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
|
||||
float requestedPixelClock = current->pixel_clock / 1000.0f;
|
||||
if (requestedPixelClock > 112.999)
|
||||
return true;
|
||||
|
||||
@ -215,7 +215,7 @@ valid_pll_divisors(pll_divisors* divisors, pll_limits* limits)
|
||||
|
||||
|
||||
static void
|
||||
compute_pll_p2(display_mode* current, pll_divisors* divisors,
|
||||
compute_pll_p2(display_timing* current, pll_divisors* divisors,
|
||||
pll_limits* limits, bool isLVDS)
|
||||
{
|
||||
if (isLVDS) {
|
||||
@ -227,7 +227,7 @@ compute_pll_p2(display_mode* current, pll_divisors* divisors,
|
||||
divisors->p2 = limits->max.p2;
|
||||
}
|
||||
} else {
|
||||
if (current->timing.pixel_clock < limits->dot_limit) {
|
||||
if (current->pixel_clock < limits->dot_limit) {
|
||||
// slow DAC timing
|
||||
divisors->p2 = limits->max.p2;
|
||||
} else {
|
||||
@ -269,9 +269,9 @@ compute_pll_p(pll_divisors* divisors)
|
||||
|
||||
|
||||
static void
|
||||
compute_dpll_g4x(display_mode* current, pll_divisors* divisors, bool isLVDS)
|
||||
compute_dpll_g4x(display_timing* current, pll_divisors* divisors, bool isLVDS)
|
||||
{
|
||||
float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
|
||||
float requestedPixelClock = current->pixel_clock / 1000.0f;
|
||||
float referenceClock
|
||||
= gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
|
||||
|
||||
@ -363,9 +363,9 @@ compute_dpll_g4x(display_mode* current, pll_divisors* divisors, bool isLVDS)
|
||||
|
||||
|
||||
static void
|
||||
compute_dpll_9xx(display_mode* current, pll_divisors* divisors, bool isLVDS)
|
||||
compute_dpll_9xx(display_timing* current, pll_divisors* divisors, bool isLVDS)
|
||||
{
|
||||
float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
|
||||
float requestedPixelClock = current->pixel_clock / 1000.0f;
|
||||
float referenceClock
|
||||
= gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
|
||||
|
||||
@ -447,7 +447,7 @@ compute_dpll_9xx(display_mode* current, pll_divisors* divisors, bool isLVDS)
|
||||
|
||||
|
||||
void
|
||||
compute_pll_divisors(display_mode* current, pll_divisors* divisors, bool isLVDS)
|
||||
compute_pll_divisors(display_timing* current, pll_divisors* divisors, bool isLVDS)
|
||||
{
|
||||
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)
|
||||
|| (gInfo->shared_info->pch_info != INTEL_PCH_NONE)) {
|
||||
|
@ -33,7 +33,7 @@ struct pll_limits {
|
||||
|
||||
|
||||
bool valid_pll_divisors(pll_divisors* divisors, pll_limits* limits);
|
||||
void compute_pll_divisors(display_mode* current, pll_divisors* divisors,
|
||||
void compute_pll_divisors(display_timing* current, pll_divisors* divisors,
|
||||
bool isLVDS);
|
||||
|
||||
void refclk_activate_ilk(bool hasPanel);
|
||||
|
@ -102,16 +102,6 @@ struct lvds_bdb2_lfp_info {
|
||||
static struct vbios {
|
||||
area_id area;
|
||||
uint8* memory;
|
||||
display_mode* shared_info;
|
||||
struct {
|
||||
uint16 hsync_start;
|
||||
uint16 hsync_end;
|
||||
uint16 hsync_total;
|
||||
uint16 vsync_start;
|
||||
uint16 vsync_end;
|
||||
uint16 vsync_total;
|
||||
} timings_common;
|
||||
|
||||
uint16_t ReadWord(off_t address)
|
||||
{
|
||||
return memory[address] | memory[address + 1] << 8;
|
||||
@ -160,57 +150,37 @@ get_bios(void)
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
feed_shared_info(uint8* data)
|
||||
static void
|
||||
sanitize_panel_timing(display_timing& timing)
|
||||
{
|
||||
bool bogus = false;
|
||||
|
||||
/* handle bogus h/vtotal values, if got such */
|
||||
if (vbios.timings_common.hsync_end > vbios.timings_common.hsync_total) {
|
||||
vbios.timings_common.hsync_total = vbios.timings_common.hsync_end + 1;
|
||||
if (timing.h_sync_end > timing.h_total) {
|
||||
timing.h_total = timing.h_sync_end + 1;
|
||||
bogus = true;
|
||||
TRACE((DEVICE_NAME": got bogus htotal. Fixing\n"));
|
||||
}
|
||||
if (vbios.timings_common.vsync_end > vbios.timings_common.vsync_total) {
|
||||
vbios.timings_common.vsync_total = vbios.timings_common.vsync_end + 1;
|
||||
if (timing.v_sync_end > timing.v_total) {
|
||||
timing.v_total = timing.v_sync_end + 1;
|
||||
bogus = true;
|
||||
TRACE((DEVICE_NAME": got bogus vtotal. Fixing\n"));
|
||||
}
|
||||
|
||||
if (bogus) {
|
||||
TRACE((DEVICE_NAME": adjusted LFP modeline: x%d Hz,\t"
|
||||
TRACE((DEVICE_NAME": adjusted LFP modeline: %" B_PRIu32 " KHz,\t"
|
||||
"%d %d %d %d %d %d %d %d\n",
|
||||
_PIXEL_CLOCK(data) / ((_H_ACTIVE(data) + _H_BLANK(data))
|
||||
* (_V_ACTIVE(data) + _V_BLANK(data))),
|
||||
_H_ACTIVE(data), vbios.timings_common.hsync_start,
|
||||
vbios.timings_common.hsync_end, vbios.timings_common.hsync_total,
|
||||
_V_ACTIVE(data), vbios.timings_common.vsync_start,
|
||||
vbios.timings_common.vsync_end, vbios.timings_common.vsync_total));
|
||||
timing.pixel_clock / (timing.h_total * timing.v_total),
|
||||
timing.h_display, timing.h_sync_start,
|
||||
timing.h_sync_end, timing.h_total,
|
||||
timing.v_display, timing.v_sync_start,
|
||||
timing.v_sync_end, timing.v_total));
|
||||
}
|
||||
|
||||
/* TODO: add retrieved info to edid info struct, not fixed mode struct */
|
||||
|
||||
/* struct display_timing is not packed, so we have to set elements
|
||||
individually */
|
||||
vbios.shared_info->timing.pixel_clock = _PIXEL_CLOCK(data) / 1000;
|
||||
vbios.shared_info->timing.h_display = vbios.shared_info->virtual_width
|
||||
= _H_ACTIVE(data);
|
||||
vbios.shared_info->timing.h_sync_start = vbios.timings_common.hsync_start;
|
||||
vbios.shared_info->timing.h_sync_end = vbios.timings_common.hsync_end;
|
||||
vbios.shared_info->timing.h_total = vbios.timings_common.hsync_total;
|
||||
vbios.shared_info->timing.v_display = vbios.shared_info->virtual_height
|
||||
= _V_ACTIVE(data);
|
||||
vbios.shared_info->timing.v_sync_start = vbios.timings_common.vsync_start;
|
||||
vbios.shared_info->timing.v_sync_end = vbios.timings_common.vsync_end;
|
||||
vbios.shared_info->timing.v_total = vbios.timings_common.vsync_total;
|
||||
|
||||
delete_area(vbios.area);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
get_lvds_mode_from_bios(display_mode* sharedInfo)
|
||||
get_lvds_mode_from_bios(display_timing* panelTiming)
|
||||
{
|
||||
if (!get_bios())
|
||||
return false;
|
||||
@ -276,27 +246,24 @@ get_lvds_mode_from_bios(display_mode* sharedInfo)
|
||||
"in BIOS VBT tables\n",
|
||||
lvds2_lfp_info->x_res, lvds2_lfp_info->y_res));
|
||||
|
||||
vbios.timings_common.hsync_start = _H_ACTIVE(timing_data)
|
||||
+ _H_SYNC_OFF(timing_data);
|
||||
vbios.timings_common.hsync_end
|
||||
= vbios.timings_common.hsync_start
|
||||
+ _H_SYNC_WIDTH(timing_data);
|
||||
vbios.timings_common.hsync_total = _H_ACTIVE(timing_data)
|
||||
+ _H_BLANK(timing_data);
|
||||
vbios.timings_common.vsync_start = _V_ACTIVE(timing_data)
|
||||
+ _V_SYNC_OFF(timing_data);
|
||||
vbios.timings_common.vsync_end
|
||||
= vbios.timings_common.vsync_start
|
||||
+ _V_SYNC_WIDTH(timing_data);
|
||||
vbios.timings_common.vsync_total = _V_ACTIVE(timing_data)
|
||||
+ _V_BLANK(timing_data);
|
||||
panelTiming->pixel_clock = _PIXEL_CLOCK(timing_data) / 1000;
|
||||
panelTiming->h_sync_start = _H_ACTIVE(timing_data) + _H_SYNC_OFF(timing_data);
|
||||
panelTiming->h_sync_end = panelTiming->h_sync_start + _H_SYNC_WIDTH(timing_data);
|
||||
panelTiming->h_total = _H_ACTIVE(timing_data) + _H_BLANK(timing_data);
|
||||
panelTiming->h_display = _H_ACTIVE(timing_data);
|
||||
panelTiming->v_sync_start = _V_ACTIVE(timing_data) + _V_SYNC_OFF(timing_data);
|
||||
panelTiming->v_sync_end = panelTiming->v_sync_start + _V_SYNC_WIDTH(timing_data);
|
||||
panelTiming->v_total = _V_ACTIVE(timing_data) + _V_BLANK(timing_data);
|
||||
panelTiming->v_display = _V_ACTIVE(timing_data);
|
||||
panelTiming->flags = 0;
|
||||
|
||||
vbios.shared_info = sharedInfo;
|
||||
return feed_shared_info(timing_data);
|
||||
sanitize_panel_timing(*panelTiming);
|
||||
delete_area(vbios.area);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete_area(vbios.area);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -446,7 +446,7 @@ intel_extreme_init(intel_info &info)
|
||||
|
||||
// Pull VBIOS panel mode for later use
|
||||
info.shared_info->got_vbt = get_lvds_mode_from_bios(
|
||||
&info.shared_info->panel_mode);
|
||||
&info.shared_info->panel_timing);
|
||||
|
||||
/* at least 855gm can't drive more than one head at time */
|
||||
if (info.device_type.InFamily(INTEL_FAMILY_8xx))
|
||||
|
@ -72,7 +72,7 @@ find_reg(const intel_info& info, uint32 target)
|
||||
}
|
||||
|
||||
|
||||
extern bool get_lvds_mode_from_bios(display_mode *mode);
|
||||
extern bool get_lvds_mode_from_bios(display_timing *timing);
|
||||
extern status_t intel_free_memory(intel_info& info, addr_t offset);
|
||||
extern status_t intel_allocate_memory(intel_info& info, size_t size,
|
||||
size_t alignment, uint32 flags, addr_t* _offset,
|
||||
|
Loading…
Reference in New Issue
Block a user