mirror of
https://gitlab.freedesktop.org/emersion/libdisplay-info.git
synced 2024-11-16 19:48:30 +01:00
displayid: add support for type III timings
Signed-off-by: Simon Ser <contact@emersion.fr>
This commit is contained in:
parent
245207e5ef
commit
7067ab6ad1
4 changed files with 200 additions and 1 deletions
|
@ -3,6 +3,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libdisplay-info/cvt.h>
|
||||
#include <libdisplay-info/displayid.h>
|
||||
|
||||
#include "di-edid-decode.h"
|
||||
|
@ -253,6 +254,59 @@ print_displayid_tiled_topo(const struct di_displayid_tiled_topo *tiled_topo)
|
|||
tiled_topo->serial_number);
|
||||
}
|
||||
|
||||
static void
|
||||
print_displayid_type_iii_timing(const struct di_displayid_type_iii_timing *t)
|
||||
{
|
||||
struct di_cvt_options cvt_options = {0};
|
||||
struct di_cvt_timing cvt_timing = {0};
|
||||
int hratio, vratio;
|
||||
double hbl, htotal;
|
||||
|
||||
switch (t->algo) {
|
||||
case DI_DISPLAYID_TYPE_III_TIMING_CVT_STANDARD_BLANKING:
|
||||
cvt_options.red_blank_ver = DI_CVT_REDUCED_BLANKING_NONE;
|
||||
break;
|
||||
case DI_DISPLAYID_TYPE_III_TIMING_CVT_REDUCED_BLANKING:
|
||||
cvt_options.red_blank_ver = DI_CVT_REDUCED_BLANKING_V1;
|
||||
break;
|
||||
}
|
||||
|
||||
cvt_options.h_pixels = t->horiz_active;
|
||||
|
||||
get_displayid_timing_aspect_ratio(t->aspect_ratio, &hratio, &vratio);
|
||||
if (t->aspect_ratio == DI_DISPLAYID_TIMING_ASPECT_RATIO_UNDEFINED)
|
||||
return;
|
||||
|
||||
cvt_options.v_lines = (cvt_options.h_pixels * vratio) / hratio;
|
||||
cvt_options.ip_freq_rqd = t->refresh_rate_hz;
|
||||
cvt_options.int_rqd = t->interlaced;
|
||||
|
||||
di_cvt_compute(&cvt_timing, &cvt_options);
|
||||
|
||||
hbl = cvt_timing.h_front_porch + cvt_timing.h_sync + cvt_timing.h_back_porch;
|
||||
htotal = cvt_timing.total_active_pixels + hbl;
|
||||
|
||||
printf(" CVT: %5dx%-5d", (int)cvt_options.h_pixels, (int)cvt_options.v_lines);
|
||||
printf(" %10.6f Hz", cvt_timing.act_frame_rate);
|
||||
printf(" %3u:%-3u", hratio, vratio);
|
||||
printf(" %8.3f kHz %13.6f MHz", cvt_timing.act_pixel_freq * 1000 / htotal,
|
||||
(double) cvt_timing.act_pixel_freq);
|
||||
printf(" (aspect %d:%d%s)", hratio, vratio,
|
||||
t->preferred ? ", preferred" : "");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
print_displayid_type_iii_timing_block(const struct di_displayid_data_block *data_block)
|
||||
{
|
||||
size_t i;
|
||||
const struct di_displayid_type_iii_timing *const *timings;
|
||||
|
||||
timings = di_displayid_data_block_get_type_iii_timings(data_block);
|
||||
for (i = 0; timings[i] != NULL; i++)
|
||||
print_displayid_type_iii_timing(timings[i]);
|
||||
}
|
||||
|
||||
static const char *
|
||||
displayid_product_type_name(enum di_displayid_product_type type)
|
||||
{
|
||||
|
@ -361,6 +415,9 @@ print_displayid(const struct di_displayid *displayid)
|
|||
case DI_DISPLAYID_DATA_BLOCK_TYPE_II_TIMING:
|
||||
print_displayid_type_ii_timing_block(data_block);
|
||||
break;
|
||||
case DI_DISPLAYID_DATA_BLOCK_TYPE_III_TIMING:
|
||||
print_displayid_type_iii_timing_block(data_block);
|
||||
break;
|
||||
default:
|
||||
break; /* Ignore */
|
||||
}
|
||||
|
|
98
displayid.c
98
displayid.c
|
@ -28,6 +28,10 @@
|
|||
* The size of a DisplayID type II timing.
|
||||
*/
|
||||
#define DISPLAYID_TYPE_II_TIMING_SIZE 11
|
||||
/**
|
||||
* The size of a DisplayID type III timing.
|
||||
*/
|
||||
#define DISPLAYID_TYPE_III_TIMING_SIZE 3
|
||||
|
||||
static bool
|
||||
is_all_zeroes(const uint8_t *data, size_t size)
|
||||
|
@ -436,6 +440,82 @@ parse_tiled_topo_block(struct di_displayid *displayid,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_type_iii_timing(struct di_displayid *displayid,
|
||||
struct di_displayid_data_block *data_block,
|
||||
const uint8_t data[static DISPLAYID_TYPE_III_TIMING_SIZE])
|
||||
{
|
||||
struct di_displayid_type_iii_timing *t;
|
||||
uint8_t algo, aspect_ratio;
|
||||
|
||||
t = calloc(1, sizeof(*t));
|
||||
if (t == NULL)
|
||||
return false;
|
||||
|
||||
t->preferred = has_bit(data[0], 7);
|
||||
|
||||
algo = get_bit_range(data[0], 6, 4);
|
||||
switch (algo) {
|
||||
case DI_DISPLAYID_TYPE_III_TIMING_CVT_STANDARD_BLANKING:
|
||||
case DI_DISPLAYID_TYPE_III_TIMING_CVT_REDUCED_BLANKING:
|
||||
t->algo = algo;
|
||||
break;
|
||||
default:
|
||||
add_failure(displayid,
|
||||
"Video Timing Modes Type 3 - Short Timings Data Block: Reserved algorithm 0x%02x.",
|
||||
algo);
|
||||
goto error_reserved;
|
||||
}
|
||||
|
||||
aspect_ratio = get_bit_range(data[0], 3, 0);
|
||||
if (timing_aspect_ratio_is_valid(aspect_ratio)) {
|
||||
t->aspect_ratio = aspect_ratio;
|
||||
} else {
|
||||
add_failure(displayid,
|
||||
"Video Timing Modes Type 3 - Short Timings Data Block: Reserved aspect ratio 0x%02x.",
|
||||
aspect_ratio);
|
||||
goto error_reserved;
|
||||
}
|
||||
|
||||
t->horiz_active = ((int32_t)data[1] + 1) * 8;
|
||||
|
||||
t->interlaced = has_bit(data[2], 7);
|
||||
t->refresh_rate_hz = (int32_t)get_bit_range(data[2], 6, 0) + 1;
|
||||
|
||||
assert(data_block->type_iii_timings_len < DISPLAYID_MAX_TYPE_III_TIMINGS);
|
||||
data_block->type_iii_timings[data_block->type_iii_timings_len++] = t;
|
||||
return true;
|
||||
|
||||
error_reserved:
|
||||
free(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_type_iii_timing_block(struct di_displayid *displayid,
|
||||
struct di_displayid_data_block *data_block,
|
||||
const uint8_t *data, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
check_data_block_revision(displayid, data,
|
||||
"Video Timing Modes Type 3 - Short Timings Data Block",
|
||||
1);
|
||||
|
||||
if ((size - DISPLAYID_DATA_BLOCK_HEADER_SIZE) % DISPLAYID_TYPE_III_TIMING_SIZE != 0)
|
||||
add_failure(displayid,
|
||||
"Video Timing Modes Type 3 - Short Timings Data Block: payload size not divisible by element size.");
|
||||
|
||||
for (i = DISPLAYID_DATA_BLOCK_HEADER_SIZE;
|
||||
i + DISPLAYID_TYPE_III_TIMING_SIZE <= size;
|
||||
i += DISPLAYID_TYPE_III_TIMING_SIZE) {
|
||||
if (!parse_type_iii_timing(displayid, data_block, &data[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
parse_data_block(struct di_displayid *displayid, const uint8_t *data,
|
||||
size_t size)
|
||||
|
@ -479,9 +559,12 @@ parse_data_block(struct di_displayid *displayid, const uint8_t *data,
|
|||
if (!parse_type_ii_timing_block(displayid, data_block, data, data_block_size))
|
||||
goto error;
|
||||
break;
|
||||
case DI_DISPLAYID_DATA_BLOCK_TYPE_III_TIMING:
|
||||
if (!parse_type_iii_timing_block(displayid, data_block, data, data_block_size))
|
||||
goto error;
|
||||
break;
|
||||
case DI_DISPLAYID_DATA_BLOCK_PRODUCT_ID:
|
||||
case DI_DISPLAYID_DATA_BLOCK_COLOR_CHARACT:
|
||||
case DI_DISPLAYID_DATA_BLOCK_TYPE_III_TIMING:
|
||||
case DI_DISPLAYID_DATA_BLOCK_TYPE_IV_TIMING:
|
||||
case DI_DISPLAYID_DATA_BLOCK_VESA_TIMING:
|
||||
case DI_DISPLAYID_DATA_BLOCK_CEA_TIMING:
|
||||
|
@ -630,6 +713,10 @@ destroy_data_block(struct di_displayid_data_block *data_block)
|
|||
for (i = 0; i < data_block->type_ii_timings_len; i++)
|
||||
free(data_block->type_ii_timings[i]);
|
||||
break;
|
||||
case DI_DISPLAYID_DATA_BLOCK_TYPE_III_TIMING:
|
||||
for (i = 0; i < data_block->type_iii_timings_len; i++)
|
||||
free(data_block->type_iii_timings[i]);
|
||||
break;
|
||||
default:
|
||||
break; /* Nothing to do */
|
||||
}
|
||||
|
@ -706,6 +793,15 @@ di_displayid_data_block_get_tiled_topo(const struct di_displayid_data_block *dat
|
|||
return &data_block->tiled_topo.base;
|
||||
}
|
||||
|
||||
const struct di_displayid_type_iii_timing *const *
|
||||
di_displayid_data_block_get_type_iii_timings(const struct di_displayid_data_block *data_block)
|
||||
{
|
||||
if (data_block->tag != DI_DISPLAYID_DATA_BLOCK_TYPE_III_TIMING) {
|
||||
return NULL;
|
||||
}
|
||||
return (const struct di_displayid_type_iii_timing *const *) data_block->type_iii_timings;
|
||||
}
|
||||
|
||||
const struct di_displayid_data_block *const *
|
||||
di_displayid_get_data_blocks(const struct di_displayid *displayid)
|
||||
{
|
||||
|
|
|
@ -34,6 +34,13 @@
|
|||
* I timing takes up 11 bytes.
|
||||
*/
|
||||
#define DISPLAYID_MAX_TYPE_II_TIMINGS 22
|
||||
/**
|
||||
* The maxiumum number of type III timings in a data block.
|
||||
*
|
||||
* A DisplayID data block has a maximum payload size of 248 bytes, and each type
|
||||
* III timing takes up 3 bytes.
|
||||
*/
|
||||
#define DISPLAYID_MAX_TYPE_III_TIMINGS 82
|
||||
|
||||
struct di_displayid {
|
||||
int version, revision;
|
||||
|
@ -67,6 +74,10 @@ struct di_displayid_data_block {
|
|||
struct di_displayid_type_i_ii_vii_timing *type_ii_timings[DISPLAYID_MAX_TYPE_II_TIMINGS + 1];
|
||||
size_t type_ii_timings_len;
|
||||
|
||||
/* Used for TYPE_III_TIMING, NULL-terminated */
|
||||
struct di_displayid_type_iii_timing *type_iii_timings[DISPLAYID_MAX_TYPE_III_TIMINGS + 1];
|
||||
size_t type_iii_timings_len;
|
||||
|
||||
/* Used for DISPLAY_PARAMS */
|
||||
struct di_displayid_display_params_priv display_params;
|
||||
|
||||
|
|
|
@ -310,6 +310,41 @@ struct di_displayid_tiled_topo {
|
|||
const struct di_displayid_tiled_topo *
|
||||
di_displayid_data_block_get_tiled_topo(const struct di_displayid_data_block *data_block);
|
||||
|
||||
/**
|
||||
* Formula/algorithm for type III timings.
|
||||
*/
|
||||
enum di_displayid_type_iii_timing_algo {
|
||||
/* VESA CVT, standard blanking */
|
||||
DI_DISPLAYID_TYPE_III_TIMING_CVT_STANDARD_BLANKING = 0,
|
||||
/* VESA CVT, reduced blanking */
|
||||
DI_DISPLAYID_TYPE_III_TIMING_CVT_REDUCED_BLANKING = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* Type III timing, defined in section 4.4.3.
|
||||
*/
|
||||
struct di_displayid_type_iii_timing {
|
||||
bool preferred;
|
||||
enum di_displayid_type_iii_timing_algo algo;
|
||||
enum di_displayid_timing_aspect_ratio aspect_ratio;
|
||||
/* Horizontal Active Image (in pixels) */
|
||||
int32_t horiz_active;
|
||||
bool interlaced;
|
||||
/* Frame/Field Refresh Rate (in Hz) */
|
||||
int32_t refresh_rate_hz;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get type III timings from a DisplayID data block.
|
||||
*
|
||||
* The returned array is NULL-terminated.
|
||||
*
|
||||
* Returns NULL if the data block tag isn't
|
||||
* DI_DISPLAYID_DATA_BLOCK_TYPE_III_TIMING.
|
||||
*/
|
||||
const struct di_displayid_type_iii_timing *const *
|
||||
di_displayid_data_block_get_type_iii_timings(const struct di_displayid_data_block *data_block);
|
||||
|
||||
/**
|
||||
* Get DisplayID data blocks.
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue