From b3cdcd979a30d4e0c73d5c18d66fee5056154536 Mon Sep 17 00:00:00 2001 From: Harald Hope Date: Thu, 24 Mar 2022 11:45:05 -0700 Subject: [PATCH] New version, man. Continuing development of EDID and monitor features, bug fixes, normal fixes. -------------------------------------------------------------------------------- KNOWN ISSUES: 1. Failed to handle case for monitor positions of array type: 2-2, 3-1, 1-3, 4-4. I'm not sure what structure those are really arranged in, but might be worth adding in the x+y pos values along with the row-col values. 2. For Monitors and graphics Device ports, if using non free nvidia driver and: nvidia-drm.modeset=1 not set in grub kernel boot parameters, there will be no /sys/class/drm data for the nvidia device, and thus no ports data, and no monitor data. 3. A class of high count DP or DVI port IDs are changed by Xorg drivers to for example: DP-6 > DP-2-3. This is very difficult to handle and will in general probably fail unfortunately because that level of port ID abstraction is just reazlly hard to deal with dynamically. 4. A to-do item: add bus ID children on --slots. This will probablby be in next inxi. -------------------------------------------------------------------------------- BUGS: 1. None outside of the various fixes. -------------------------------------------------------------------------------- FIXES: 1. In sensors, failed to pull out BAT sensor data. In most cases, this would not lead to any issues, but it could have. 2. This one just slipped my mind, I'd meant to do it, but in Montitor-x:, the primary ID should have been the 'real' kernel ID, not the mapped: ID, which is the X.org ID when different from the kernel ID. So mapped should be the Xorg version when they are different from the kernel version. 3. In Graphics, monitors can show > 1 ratio, failed to set all to :, resulting in: ratio: 3:2 or 16/10 modes:. Also fixed ParseEDID to output an array of ratios, which can then be processed as wanted. 4. Monitor map fixes: * Handle case in monitors where display ID: eDP and sys ID: eDP-1, this only works if 1 monitor in array. There's a variety of this type of failure, when X.org or its drivers decide to call the port ID XYZ with no number at all. All those possible cases are now handled, like eDP > eDP-1, VGA > VGA-1, and so on. * Added fallback, if no match, and if only 1 monitor, just map them to eachother if other mappings failed. Prompted by things like: s: DP-6 > d: DP-2-3; s: eDP-1 > d: DP-4, which are just impossible to create logic to map. 5. Removed 'ati' driver from xorg drivers list, it's simply a wrapper for r128, mach64, or radeon (and maybe amdgpu), and shows as failed, unloaded, or loaded, because of this. ati basically assigns the correct driver, that is, but is not itself a driver. Thanks mrmazda for spotting this issue. 6. Typo on QDI => Quantum Data. 7. Added fallback for monitor model, now using vendor code plus product code if nothing found for vendor nice name or model. This will show as 'model-id:' instead of model: to help differentiate the two. 8. Added Monitor product_code to manufacturer if no model name is found. 9. get_pci_vendor was trimming at ' / ' if the product string also contained ' / '. Fix is to ignore 1 character 'words' in the logic. 10. In Slots, failed to remove_duplicates in the slot info field, leading to redundant output strings. See Enhancement 3 and Code 4. 11. See Change 3, finally made -S section use full key: value pair, which makes stuff more explicit, like: System: Host: yawn Kernel: 5.16.0-11.1-liquorix-amd64 arch: x86_64 bits: 64 compiler: gcc v: 11.2.0 Desktop: Xfce v: 4.16.0 tk: Gtk v: 3.24.24 info: xfce4-panel wm: xfwm v: 4.16.1 vt: 7 dm: 1: LightDM v: 1.26.0 2: SDDM note: stopped Distro: Debian GNU/Linux bookworm/sid 12. Fix for mageia and lsb distro data, force use of os-release for mageia if detected. That overrides the forced use of lsb release for mandrake/mandriva, because for some reason mageia has decided to carry ALL the legacy distro files: '/etc/lsb-release', '/etc/lsb-release.d', '/etc/mageia-release', '/etc/mandrake-release', '/etc/mandrakelinux-release', '/etc/mandriva-release', '/etc/os-release', '/etc/redhat-release', '/etc/system-release' which is really not what this stuff is intended for, if it's an actual derived distro from a living base, then yes, include the base file, but all these have the same distro id data for mageia, none for the derived distros. Also, fixed an lsb release thing to avoid using codename if codename contains release number as well. Since lsb_release is totally legacy at this point, who cares if we might miss a specific codename here and there on legacy system. -------------------------------------------------------------------------------- ENHANCEMENTS: 1. Added Color Characteristics to EDID parser, for some reason that had been left out. 2. Added advanced EDID output option --edid, that allows for showing more advanced EDID data than is appropriate for most users cases. Ihcludes errors, color characteristics chroma: (chromacity), full modes, not just min/max. 3. In --slots, added bus-ID. Also extended report quality, made more granular, got rid of single blob from Type and Designation and now get more accurate and useful data. 4. In cases with > 1 DM, check to see if one or more are stopped or disabled, = and add (stopped) if it was detected in running service as stopped. -------------------------------------------------------------------------------- CHANGES: 1. Reversed monitor ID and mapped: ID values, that was a mistake, the mapped: item was supposed to contain the X.org mapped name, and the primary ID was supposed to be the actual real ID the kernel uses. Not a huge deal either way, but there it is. 2. Include disabled but connected Monitors. This works around nvidia bug showing monitors disabled when they are enabled, but also allows for showing connected monitors, though without as much data. 3. Made the last holdout -S > -Sa use strict full key: value pair output, like Desktop: XFCE v: 4.14.12 and so on. -------------------------------------------------------------------------------- DOCUMENTATION: 1. Added help/man for --edid info. -------------------------------------------------------------------------------- CODE: 1. In ParseEDID: made new key: edid_error, which contains an array ref of 1 or more edid errors. The previous version did a poor job and returned only the first error found, so there could have been > 1 error, and you'd never know it. This changes check_parsed_edid to _check_parsed_edid(). and adds a utility tool _edid_error, which grabs the message from main::message, giving better output integration. This also allows for future error handling expansion quite easily. 2. In map_monitor_ids() fixed matching pattern, made more robust and explicit, to catch things like s: eDP-1 d: eDP or eDP-1-1, both have been seen. Also added fallback for single monitor, just map them to eachother if mapping failed. 3. get_pci_vendor() added test for using anything that is 1 character length, to not break on 1 character length string matches. 4. Fully refactored --slots, that was originally written purely as a proof of concept in terms of adding a new feature during the original inxi 2.9 rewrite, and was never actually touched after that. --- inxi | 878 ++++++++++++++++++++++++++++++++++--------------- inxi.1 | 33 +- inxi.changelog | 190 +++++++++++ 3 files changed, 827 insertions(+), 274 deletions(-) diff --git a/inxi b/inxi index a2f0db5..1f983d1 100755 --- a/inxi +++ b/inxi @@ -48,8 +48,8 @@ use POSIX qw(ceil uname strftime ttyname); ## INXI INFO ## my $self_name='inxi'; -my $self_version='3.3.13'; -my $self_date='2022-02-22'; +my $self_version='3.3.14'; +my $self_date='2022-03-24'; my $self_patch='00'; ## END INXI INFO ## my ($b_pledge,@pledges); @@ -4653,6 +4653,12 @@ sub get { $show{'short'} = 0; $show{'bluetooth'} = 1; $show{'bluetooth-forced'} = 1;}, + 'edid' => sub { + $b_admin = 1; + $show{'short'} = 0; + $show{'edid'} = 1; + $show{'graphic'} = 1; + $show{'graphic-full'} = 1;}, 'f|flags|flag' => sub { $show{'short'} = 0; $show{'cpu'} = 1; @@ -4858,13 +4864,14 @@ sub get { } if ($arg >= 8){ $b_admin = 1; - $use{'downloader'} = 1; + # $use{'downloader'} = 1; # only if weather + $show{'edid'} = 1; $show{'process'} = 1; $show{'ps-cpu'} = 1; $show{'ps-mem'} = 1; $show{'repo'} = 1; $show{'slot'} = 1; - #$show{'weather'} = 1; + # $show{'weather'} = 1; } } else { @@ -5527,6 +5534,8 @@ sub show_options { size(s)."], ['1', '-E', '--bluetooth', "Show bluetooth device data and report, if available. Shows state, address, IDs, version info."], + ['1', '', '--edid', "Full graphics data, triggers -a, -G. Add monitor chroma, + full modelines (if > 2), EDID errors and warnings, if present."], ['1', '-f', '--flags', "All CPU $flags. Triggers -C. Not shown with -F to avoid spamming."], ['1', '-F', '--full', "Full output. Includes all Upper Case line letters @@ -5609,7 +5618,7 @@ sub show_options { full RAID; triggers -xx."], ['2', '7', '', "Network IP data (-i), bluetooth, logical (-L), RAID forced, full CPU $flags; triggers -xxx."], - ['2', '8', '', "Everything available, including repos (-r), + ['2', '8', '', "Everything available, including EDID (--edid), repos (-r), processes (-tcm), PCI slots (--slots); triggers admin (-a)."], ); # if distro maintainers don't want the weather feature disable it @@ -6659,6 +6668,9 @@ sub message { 'dmidecode-dev-mem' => 'dmidecode is not allowed to read /dev/mem', 'dmidecode-smbios' => 'No SMBIOS data for dmidecode to process', 'gl-console' => 'No advanced graphics data found on this system in console.', + 'edid-revision' => "invalid EDID revision: $id", + 'edid-sync' => "bad sync value: $id", + 'edid-version' => "invalid EDID version: $id", 'gl-empty' => 'Unset. Missing GL driver?', 'gl-null' => 'No GL data found on this system.', 'gl-root' => 'GL data unavailable in console for root.', @@ -6719,6 +6731,7 @@ sub message { 'smartctl-open' => 'Unable to open device. Wrong device ID given?', 'smartctl-udma-crc' => 'Bad cable/connection?', 'smartctl-usb' => 'Unknown USB bridge. Flash drive/Unsupported enclosure?', + 'stopped' => 'stopped', 'swap-admin' => 'No admin swap data available.', 'swap-data' => 'No swap data was found.', 'tool-missing-basic' => "", @@ -7848,7 +7861,9 @@ sub battery_data_sys { # Valid values: Unknown,Charging,Discharging,Not charging,Full # don't use clean_unset because Not charging is a valid value. elsif ($file eq 'status'){ - $value =~ s/unknown//i; + $value = lc($value); + $value =~ s/unknown//; + } } elsif ($b_root && -e $path && ! -r $path){ @@ -13506,7 +13521,6 @@ sub device_output { next if $row->[3] != 0; # print "$row->[0] $row->[3]\n"; $j = scalar @rows; - push(@{$graphics{'gpu-drivers'}},$row->[9]) if $row->[9]; my $device = main::trimmer($row->[4]); $device = ($device) ? main::clean_pci($device,'output') : 'N/A'; # have seen absurdly verbose card descriptions, with non related data etc @@ -13520,6 +13534,7 @@ sub device_output { my $item = main::get_pci_vendor($row->[4],$row->[12]); $rows[$j]->{main::key($num++,0,2,'vendor')} = $item if $item; } + push(@{$graphics{'gpu-drivers'}},$row->[9]) if $row->[9]; my $driver = ($row->[9]) ? $row->[9]:'N/A'; $rows[$j]->{main::key($num++,1,2,'driver')} = $driver; if ($row->[9] && !$bsd_type){ @@ -13649,9 +13664,9 @@ sub display_output(){ my ($num,$j) = (0,0); # note: these may not always be set, they won't be out of X, for example display_protocol(); - $graphics{'protocol'} = 'wayland' if $force{'wayland'}; # get rid of all inactive or disabled monitor port ids set_active_monitors() if $monitor_ids; + $graphics{'protocol'} = 'wayland' if $force{'wayland'}; # note, since the compositor is the server with wayland, always show it if ($extra > 1 || $graphics{'protocol'} eq 'wayland'){ set_compositor_data(); @@ -13777,7 +13792,7 @@ sub display_output(){ } my $gpu_drivers = gpu_drivers_sys('all'); my $drivers; - if ($gpu_drivers ){ + if ($gpu_drivers){ $drivers = join(',',@{$gpu_drivers}); } else { @@ -13924,24 +13939,31 @@ sub monitors_output_basic { } eval $end if $b_log; } -# row, num passed by ref +# $j, $row, $num passed by ref sub monitors_output_full { eval $start if $b_log; my ($type,$monitors,$j,$row,$num) = @_; my ($b_no_size,$resolution); - my ($m1,$m2,$m3) = ($type eq 'screen') ? (3,4,5) : (2,3,4); + my ($m1,$m2,$m3,$m4) = ($type eq 'screen') ? (3,4,5,6) : (2,3,4,5); + # note: in case where mapped id != sys id, the key will not match 'monitor' foreach my $key (sort keys %{$monitors}){ $j++; $$row[$j]->{main::key($$num++,1,$m1,'Monitor')} = $monitors->{$key}{'monitor'}; if ($monitors->{$key}{'monitor-mapped'}){ $$row[$j]->{main::key($$num++,0,$m2,'mapped')} = $monitors->{$key}{'monitor-mapped'}; } + if ($monitors->{$key}{'disabled'}){ + $$row[$j]->{main::key($$num++,0,$m2,'note')} = $monitors->{$key}{'disabled'}; + } if ($monitors->{$key}{'position'}){ $$row[$j]->{main::key($$num++,0,$m2,'pos')} = $monitors->{$key}{'position'}; } if ($monitors->{$key}{'model'}){ $$row[$j]->{main::key($$num++,0,$m2,'model')} = $monitors->{$key}{'model'}; } + elsif ($monitors->{$key}{'model-id'}){ + $$row[$j]->{main::key($$num++,0,$m2,'model-id')} = $monitors->{$key}{'model-id'}; + } if ($extra > 2 && $monitors->{$key}{'serial'}){ $$row[$j]->{main::key($$num++,0,$m2,'serial')} = main::filter($monitors->{$key}{'serial'}); } @@ -13976,6 +13998,21 @@ sub monitors_output_full { if ($b_admin && $monitors->{$key}{'gamma'}){ $$row[$j]->{main::key($$num++,0,$m2,'gamma')} = $monitors->{$key}{'gamma'}; } + if ($show{'edid'} && $monitors->{$key}{'colors'}){ + $$row[$j]->{main::key($$num++,1,$m2,'chroma')} = ''; + $$row[$j]->{main::key($$num++,1,$m3,'red')} = ''; + $$row[$j]->{main::key($$num++,0,$m4,'x')} = $monitors->{$key}{'colors'}{'red_x'}; + $$row[$j]->{main::key($$num++,0,$m4,'y')} = $monitors->{$key}{'colors'}{'red_y'}; + $$row[$j]->{main::key($$num++,1,$m3,'green')} = ''; + $$row[$j]->{main::key($$num++,0,$m4,'x')} = $monitors->{$key}{'colors'}{'green_x'}; + $$row[$j]->{main::key($$num++,0,$m4,'y')} = $monitors->{$key}{'colors'}{'green_y'}; + $$row[$j]->{main::key($$num++,1,$m3,'blue')} = ''; + $$row[$j]->{main::key($$num++,0,$m4,'x')} = $monitors->{$key}{'colors'}{'blue_x'}; + $$row[$j]->{main::key($$num++,0,$m4,'y')} = $monitors->{$key}{'colors'}{'blue_y'}; + $$row[$j]->{main::key($$num++,1,$m3,'white')} = ''; + $$row[$j]->{main::key($$num++,0,$m4,'x')} = $monitors->{$key}{'colors'}{'white_x'}; + $$row[$j]->{main::key($$num++,0,$m4,'y')} = $monitors->{$key}{'colors'}{'white_y'}; + } if ($extra > 2 && $monitors->{$key}{'scale'}){ $$row[$j]->{main::key($$num++,0,$m2,'scale')} = $monitors->{$key}{'scale'}; } @@ -13996,13 +14033,27 @@ sub monitors_output_full { $$row[$j]->{main::key($$num++,0,$m2,'ratio')} = $monitors->{$key}{'ratio'}; } if ($extra > 2){ - if ($monitors->{$key}{'modes-min-max'}){ - $$row[$j]->{main::key($$num++,0,$m2,'modes')} = $monitors->{$key}{'modes-min-max'}; + if (!$monitors->{$key}{'modes'} || !@{$monitors->{$key}{'modes'}}){ + $monitors->{$key}{'modes'} = ['N/A']; } - elsif ($monitors->{$key}{'modes-min'} && $monitors->{$key}{'modes-max'}){ + my $cnt = scalar @{$monitors->{$key}{'modes'}}; + if ($cnt == 1 || ($cnt > 2 && $show{'edid'})){ + $$row[$j]->{main::key($$num++,0,$m2,'modes')} = join(', ', @{$monitors->{$key}{'modes'}}); + } + else { $$row[$j]->{main::key($$num++,1,$m2,'modes')} = ''; - $$row[$j]->{main::key($$num++,0,$m3,'max')} = $monitors->{$key}{'modes-max'}; - $$row[$j]->{main::key($$num++,0,$m3,'min')} = $monitors->{$key}{'modes-min'}; + $$row[$j]->{main::key($$num++,0,$m3,'max')} = ${$monitors->{$key}{'modes'}}[0]; + $$row[$j]->{main::key($$num++,0,$m3,'min')} = ${$monitors->{$key}{'modes'}}[-1]; + } + } + if ($show{'edid'} && ($monitors->{$key}{'errors'} || $monitors->{$key}{'warnings'})){ + $j++; + $$row[$j]->{main::key($$num++,1,$m2,'EDID')} = ''; + if ($monitors->{$key}{'errors'}){ + $$row[$j]->{main::key($$num++,0,$m3,'errors')} = join('; ', @{$monitors->{$key}{'errors'}}); + } + if ($monitors->{$key}{'warnings'}){ + $$row[$j]->{main::key($$num++,0,$m3,'warnings')} = join('; ', @{$monitors->{$key}{'warnings'}}); } } } @@ -14308,9 +14359,9 @@ sub wayland_data_advanced { !$monitor_ids->{$key}{'dpi'} || !$monitor_ids->{$key}{'diagonal'})){ my $size_x = $monitor_ids->{$key}{'size-x'}; my $size_y = $monitor_ids->{$key}{'size-y'}; - $monitor_ids->{$key}{'size-x-i'} = sprintf("%.1f", ($size_x/25.4)); - $monitor_ids->{$key}{'size-y-i'} = sprintf("%.1f", ($size_y/25.4)); - $monitor_ids->{$key}{'diagonal'} = sprintf("%.1f", (sqrt($size_x**2 + $size_y**2)/25.4)) + 0; + $monitor_ids->{$key}{'size-x-i'} = sprintf("%.2f", ($size_x/25.4)) + 0; + $monitor_ids->{$key}{'size-y-i'} = sprintf("%.2f", ($size_y/25.4)) + 0; + $monitor_ids->{$key}{'diagonal'} = sprintf("%.2f", (sqrt($size_x**2 + $size_y**2)/25.4)) + 0; $monitor_ids->{$key}{'diagonal-m'} = sprintf("%.0f", (sqrt($size_x**2 + $size_y**2))); if ($monitor_ids->{$key}{'res-x'}){ my $res_x = $monitor_ids->{$key}{'res-x'}; @@ -14506,7 +14557,6 @@ sub swaymsg_data { $monitor_ids->{$id}{'model'} = main::clean($mon->{'make'}); if ($mon->{'model'}){ $monitor_ids->{$id}{'model'} .= ' ' . main::clean($mon->{'model'}); - } $monitor_ids->{$id}{'model'} = main::remove_duplicates($monitor_ids->{$id}{'model'}); } @@ -14765,11 +14815,10 @@ sub xdpyinfo_data { if ($size_x && $size_y && $res_y){ flip_size_x_y(\$size_x,\$size_y,\$res_x,\$res_y); } - $size_x_i = ($size_x) ? sprintf("%.1f", ($size_x/25.4)) : 0; - $size_y_i = ($size_y) ? sprintf("%.1f", ($size_y/25.4)) : 0; + $size_x_i = ($size_x) ? sprintf("%.2f", ($size_x/25.4)) : 0; + $size_y_i = ($size_y) ? sprintf("%.2f", ($size_y/25.4)) : 0; $dpi = ($res_x && $size_x) ? sprintf("%.0f", ($res_x*25.4/$size_x)) : ''; - $diagonal = ($size_x && $size_y) ? sprintf("%.1f", (sqrt($size_x**2 + $size_y**2)/25.4)) : ''; - $diagonal += 0 if $diagonal;# trick to get rid of decimal 0 + $diagonal = ($size_x && $size_y) ? sprintf("%.2f", (sqrt($size_x**2 + $size_y**2)/25.4)) + 0 : ''; $diagonal_m = ($size_x && $size_y) ? sprintf("%.0f", (sqrt($size_x**2 + $size_y**2))) : ''; } $screen = { @@ -14802,7 +14851,7 @@ sub xrandr_data { @xrandr = main::grabber("$program $display_opt 2>/dev/null",'','strip'); } else { - @xrandr = main::reader("$ENV{HOME}/bin/scripts/inxi/svn/branches/inxi-perl/xrandr.txt",'strip'); + @xrandr = main::reader("$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-test-1.txt",'strip'); } # $graphics{'dimensions'} = (\@dimensions); # we get a bit more info from xrandr than xdpyinfo, but xrandr fails to handle @@ -14842,25 +14891,30 @@ sub xrandr_data { # HDMI-2 connected 1920x1200+1080+0 (normal left inverted right x axis y axis) 519mm x 324mm # DP-1 connected primary 2560x1440+1080+1200 (normal left inverted right x axis y axis) 598mm x 336mm # HDMI-1 connected 1080x1920+0+0 left (normal left inverted right x axis y axis) 160mm x 90mm - elsif (/^([^\s]+)\s+connected\s(primary\s)?([0-9]+)\s*x\s*([0-9]+)\+([0-9]+)\+([0-9]+)(\s[^(]*\([^)]+\))?(\s([0-9]+)mm\sx\s([0-9]+)mm)?/){ + # disabled but connected: VGA-1 connected (normal left inverted right x axis y axis) + elsif (/^([^\s]+)\s+connected\s(primary\s)?/){ $monitor_id = $1; $set_as = $2; - $res_x = $3; - $res_y = $4; - $pos_x = $5; - $pos_y = $6; - $size_x = $9; - $size_y = $10; - # flip size x,y if don't roughly match res x/y ratio - if ($size_x && $size_y && $res_y){ - flip_size_x_y(\$size_x,\$size_y,\$res_x,\$res_y); + if (/^[^\s]+\s+connected\s(primary\s)?([0-9]+)\s*x\s*([0-9]+)\+([0-9]+)\+([0-9]+)(\s[^(]*\([^)]+\))?(\s([0-9]+)mm\sx\s([0-9]+)mm)?/){ + $res_x = $2; + $res_y = $3; + $pos_x = $4; + $pos_y = $5; + $size_x = $8; + $size_y = $9; + # flip size x,y if don't roughly match res x/y ratio + if ($size_x && $size_y && $res_y){ + flip_size_x_y(\$size_x,\$size_y,\$res_x,\$res_y); + } + $size_x_i = ($size_x) ? sprintf("%.2f", ($size_x/25.4)) + 0 : 0; + $size_y_i = ($size_y) ? sprintf("%.2f", ($size_y/25.4)) + 0 : 0; + $dpi = ($res_x && $size_x) ? sprintf("%.0f", $res_x * 25.4 / $size_x) : ''; + $diagonal = ($res_x && $size_x) ? sprintf("%.2f", (sqrt($size_x**2 + $size_y**2)/25.4)) + 0 : ''; + $diagonal_m = ($res_x && $size_x) ? sprintf("%.0f", (sqrt($size_x**2 + $size_y**2))) : ''; + } + else { + ($res_x,$res_y,$pos_x,$pos_y,$size_x,$size_x_i,$size_y,$size_y_i,$dpi,$diagonal,$diagonal_m) = () } - $size_x_i = ($size_x) ? sprintf("%.1f", ($size_x/25.4)) : 0; - $size_y_i = ($size_y) ? sprintf("%.1f", ($size_y/25.4)) : 0; - $dpi = ($res_x && $size_x) ? sprintf("%.0f", $res_x * 25.4 / $size_x) : ''; - $diagonal = ($res_x && $size_x) ? sprintf("%.1f", (sqrt($size_x**2 + $size_y**2)/25.4)) : ''; - $diagonal += 0 if $diagonal; # trick to get rid of decimal 0 - $diagonal_m = ($res_x && $size_x) ? sprintf("%.0f", (sqrt($size_x**2 + $size_y**2))) : ''; undef $primary; push(@ids,$monitor_id); if ($set_as){ @@ -15044,9 +15098,10 @@ sub display_drivers_x { # $log = "$ENV{HOME}/bin/scripts/inxi/data/xorg-logs/xorg-multi-driver-1.log"; } my @xorg = main::reader($log); - # list is from sgfxi plus non-free drivers, plus ARM drivers - my $list = join('|', qw(amdgpu apm ark armsoc atimisc ati - chips cirrus cyrix fbdev fbturbo fglrx geode glide glint + # list is from sgfxi plus non-free drivers, plus ARM drivers. + # Don't use ati. It's just a wrapper for: r128, mach64, radeon + my $list = join('|', qw(amdgpu apm ark armsoc atimisc + chips cirrus cyrix etnaviv fbdev fbturbo fglrx geode glide glint i128 i740 i810-dec100 i810e i810 i815 i830 i845 i855 i865 i915 i945 i965 iftv imstt intel ivtv mach64 mesa mga modesetting neomagic newport nouveau nsc nvidia nv openchrome r128 radeonhd radeon rendition @@ -15213,13 +15268,9 @@ sub set_monitors_sys { elsif ($item eq 'modes'){ @data = main::reader($file,'strip'); next if !@data; - if (scalar @data == 1 || $data[-1] eq $data[0]){ - $monitor_ids->{$port}{'modes-min-max'} = $data[0]; - } - else { - $monitor_ids->{$port}{'modes-min'} = $data[-1]; - $monitor_ids->{$port}{'modes-max'} = $data[0]; - } + # modes has repeat values, probably because kernel doesn't show hz + main::uniq(\@data); + $monitor_ids->{$port}{'modes'} = [@data]; } elsif ($item eq 'edid'){ next if -s $file; @@ -15227,7 +15278,7 @@ sub set_monitors_sys { } } main::log_data('dump','$ports ref',$monitor_ids) if $b_log; - print Data::Dumper::Dumper $monitor_ids if $dbg[44]; + print 'monitor_sys_data(): ', Data::Dumper::Dumper $monitor_ids if $dbg[44]; eval $end if $b_log; } sub monitor_edid_data { @@ -15239,9 +15290,12 @@ sub monitor_edid_data { return if !$edid_raw; my $edid = ParseEDID::parse_edid($edid_raw,$dbg[47]); main::log_data('dump','Parse::EDID',$edid) if $b_log; - print Data::Dumper::Dumper $edid if $dbg[44]; + print 'parse_edid(): ', Data::Dumper::Dumper $edid if $dbg[44]; return if !$edid || ref $edid ne 'HASH' || !%$edid; $monitor_ids->{$port}{'build-date'} = $edid->{'year'}; + if ($edid->{'color_characteristics'}){ + $monitor_ids->{$port}{'colors'} = $edid->{'color_characteristics'}; + } if ($edid->{'gamma'}){ $monitor_ids->{$port}{'gamma'} = ($edid->{'gamma'}/100 + 0); } @@ -15254,26 +15308,37 @@ sub monitor_edid_data { $model .= ' ' if $model; $model .= $edid->{'monitor_name'}; } + elsif ($model && $edid->{'product_code_h'}){ + $model .= ' ' . $edid->{'product_code_h'}; + } $monitor_ids->{$port}{'model'} = main::remove_duplicates(main::clean($model)); } + elsif ($edid->{'manufacturer_name'} && $edid->{'product_code_h'}){ + $monitor_ids->{$port}{'model-id'} = $edid->{'manufacturer_name'} . ' '; + $monitor_ids->{$port}{'model-id'} .= $edid->{'product_code_h'}; + } + # construct to match xorg values + if ($edid->{'manufacturer_name'} && $edid->{'product_code'}){ + my $id = $edid->{'manufacturer_name'} . sprintf('%x',$edid->{'product_code'}); + $monitor_ids->{$port}{$id} = ($edid->{'serial_number'}) ? $edid->{'serial_number'}: ''; + } if ($edid->{'diagonal_size'}){ $monitor_ids->{$port}{'diagonal-m'} = sprintf('%.0f',($edid->{'diagonal_size'}*25.4)) + 0; $monitor_ids->{$port}{'diagonal'} = sprintf('%.1f',$edid->{'diagonal_size'}) + 0; } - if ($edid->{'ratio_name'}){ - $edid->{'ratio_name'} =~ s|/|:|; # this should be changed in ParseEDID - $monitor_ids->{$port}{'ratio'} = $edid->{'ratio_name'}; + if ($edid->{'ratios'}){ + $monitor_ids->{$port}{'ratio'} = join(', ', @{$edid->{'ratios'}}); } if ($edid->{'detailed_timings'}){ $monitor_ids->{$port}{'res-x'} = $edid->{'detailed_timings'}[0]{'horizontal_active'}; $monitor_ids->{$port}{'res-y'} = $edid->{'detailed_timings'}[0]{'vertical_active'}; if ($edid->{'detailed_timings'}[0]{'horizontal_image_size'}){ $monitor_ids->{$port}{'size-x'} = $edid->{'detailed_timings'}[0]{'horizontal_image_size'}; - $monitor_ids->{$port}{'size-x-i'} = sprintf('%.1f',($edid->{'detailed_timings'}[0]{'horizontal_image_size'}/25.4)) + 0; + $monitor_ids->{$port}{'size-x-i'} = $edid->{'detailed_timings'}[0]{'horizontal_image_size_i'}; } if ($edid->{'detailed_timings'}[0]{'vertical_image_size'}){ $monitor_ids->{$port}{'size-y'} = $edid->{'detailed_timings'}[0]{'vertical_image_size'}; - $monitor_ids->{$port}{'size-y-i'} = sprintf('%.1f',($edid->{'detailed_timings'}[0]{'vertical_image_size'}/25.4)) + 0; + $monitor_ids->{$port}{'size-y-i'} = $edid->{'detailed_timings'}[0]{'vertical_image_size_i'}; } if ($edid->{'detailed_timings'}[0]{'horizontal_dpi'}){ $monitor_ids->{$port}{'dpi'} = sprintf('%.0f',$edid->{'detailed_timings'}[0]{'horizontal_dpi'}) + 0; @@ -15288,6 +15353,14 @@ sub monitor_edid_data { $monitor_ids->{$port}{'serial'} = main::clean_dmi($edid->{'serial_number'}); } } + # this will be an array reference of one or more edid errors + if ($edid->{'edid_errors'}){ + $monitor_ids->{$port}{'edid-errors'} = $edid->{'edid_errors'}; + } + # this will be an array reference of one or more edid warnings + if ($edid->{'edid_warnings'}){ + $monitor_ids->{$port}{'edid-warnings'} = $edid->{'edid_warnings'}; + } eval $end if $b_log; } sub advanced_monitor_data { @@ -15297,7 +15370,7 @@ sub advanced_monitor_data { my $position = ''; # then see if we can locate a default position primary monitor foreach my $key (keys %$monitors){ - next if !defined $monitors->{$key}{'pos-x'}; + next if !defined $monitors->{$key}{'pos-x'} || !defined $monitors->{$key}{'pos-y'}; # this is the only scenario we can guess at if no primary detected if (!$monitors->{$key}{'primary'} && $monitors->{$key}{'pos-x'} == 0 && $monitors->{$key}{'pos-y'} == 0){ @@ -15317,9 +15390,9 @@ sub advanced_monitor_data { # print Data::Dumper::Dumper \@horiz; # print Data::Dumper::Dumper \@vert; # print Data::Dumper::Dumper $layouts; - # print Data::Dumper::Dumper $monitor_map; + # print 'mon advanced monitor_map: ', Data::Dumper::Dumper $monitor_map; foreach my $key (keys %$monitors){ - if (@horiz && @vert){ + if (@horiz && @vert && (scalar @horiz > 1 || scalar @vert > 1)){ $monitors->{$key}{'position'} ||= ''; $position = ''; $position = get_monitor_position($monitors->{$key},\@horiz,\@vert); @@ -15333,18 +15406,44 @@ sub advanced_monitor_data { # note: xorg drivers can be different than gpu drivers $monitors->{$key}{'drivers'} = gpu_drivers_sys($mon_mapped); $monitors->{$key}{'build-date'} = $monitor_ids->{$mon_mapped}{'build-date'}; + $monitors->{$key}{'colors'} = $monitor_ids->{$mon_mapped}{'colors'}; $monitors->{$key}{'diagonal'} = $monitor_ids->{$mon_mapped}{'diagonal'}; $monitors->{$key}{'diagonal-m'} = $monitor_ids->{$mon_mapped}{'diagonal-m'}; $monitors->{$key}{'gamma'} = $monitor_ids->{$mon_mapped}{'gamma'}; - $monitors->{$key}{'modes-min-max'} = $monitor_ids->{$mon_mapped}{'modes-min-max'}; - $monitors->{$key}{'modes-max'} = $monitor_ids->{$mon_mapped}{'modes-max'}; - $monitors->{$key}{'modes-min'} = $monitor_ids->{$mon_mapped}{'modes-min'}; + $monitors->{$key}{'modes'} = $monitor_ids->{$mon_mapped}{'modes'}; $monitors->{$key}{'model'} = $monitor_ids->{$mon_mapped}{'model'}; + $monitors->{$key}{'color-characteristics'} = $monitor_ids->{$mon_mapped}{'color-characteristics'}; + if (!defined $monitors->{$key}{'size-x'} && $monitor_ids->{$mon_mapped}{'size-x'}){ + $monitors->{$key}{'size-x'} = $monitor_ids->{$mon_mapped}{'size-x'}; + $monitors->{$key}{'size-x-i'} = $monitor_ids->{$mon_mapped}{'size-x-i'}; + } + if (!defined $monitors->{$key}{'size-y'} && $monitor_ids->{$mon_mapped}{'size-y'}){ + $monitors->{$key}{'size-y'} = $monitor_ids->{$mon_mapped}{'size-y'}; + $monitors->{$key}{'size-y-i'} = $monitor_ids->{$mon_mapped}{'size-y-i'}; + } + if (!defined $monitors->{$key}{'dpi'} && $monitor_ids->{$mon_mapped}{'dpi'}){ + $monitors->{$key}{'dpi'} = $monitor_ids->{$mon_mapped}{'dpi'}; + } + if ($monitor_ids->{$mon_mapped}{'model-id'}){ + $monitors->{$key}{'model-id'} = $monitor_ids->{$mon_mapped}{'model-id'}; + } + if ($monitor_ids->{$mon_mapped}{'edid-errors'}){ + $monitors->{$key}{'edid-errors'} = $monitor_ids->{$mon_mapped}{'edid-errors'}; + } + if ($monitor_ids->{$mon_mapped}{'edid-warnings'}){ + $monitors->{$key}{'edid-warnings'} = $monitor_ids->{$mon_mapped}{'edid-warnings'}; + } + if ($monitor_ids->{$mon_mapped}{'enabled'} && + $monitor_ids->{$mon_mapped}{'enabled'} eq 'disabled'){ + $monitors->{$key}{'disabled'} = $monitor_ids->{$mon_mapped}{'enabled'}; + } $monitors->{$key}{'ratio'} = $monitor_ids->{$mon_mapped}{'ratio'}; $monitors->{$key}{'serial'} = $monitor_ids->{$mon_mapped}{'serial'}; - if ($mon_mapped ne $monitors->{$key}{'monitor'}){ - $monitors->{$key}{'monitor-mapped'} = $mon_mapped; - } + } + # now swap the drm id for the display server id if they don't match + if ($mon_mapped && $mon_mapped ne $monitors->{$key}{'monitor'}){ + $monitors->{$key}{'monitor-mapped'} = $monitors->{$key}{'monitor'}; + $monitors->{$key}{'monitor'} = $mon_mapped; } } # not printing out primary if Screen has only 1 Monitor @@ -15359,9 +15458,7 @@ sub advanced_monitor_data { sub set_active_monitors { eval $start if $b_log; foreach my $key (keys %$monitor_ids){ - if (!$monitor_ids->{$key}{'enabled'} || - $monitor_ids->{$key}{'enabled'} ne 'enabled' || - !$monitor_ids->{$key}{'status'} || + if (!$monitor_ids->{$key}{'status'} || $monitor_ids->{$key}{'status'} ne 'connected'){ delete $monitor_ids->{$key}; } @@ -15411,7 +15508,7 @@ sub set_monitor_layouts { '2-1' => 'middle-l','2-2' => 'middle-c','2-3' => 'middle-r', '3-1' => 'bottom-l','3-2' => 'bottom-c','3-3' => 'bottom-r'}; } -# this is required to resolve the insane situation where some xorg drivers change +# this is required to resolve the situation where some xorg drivers change # the kernel ID for the port to something slightly different, amdgpu in particular. sub map_monitor_ids { eval $start if $b_log; @@ -15420,13 +15517,12 @@ sub map_monitor_ids { @$display_ids = sort { lc($a) cmp lc($b) } @$display_ids; my @sys_ids; foreach my $key (keys %$monitor_ids){ - if ($monitor_ids->{$key}{'status'} eq 'connected' && - $monitor_ids->{$key}{'enabled'} eq 'enabled'){ + if ($monitor_ids->{$key}{'status'} eq 'connected'){ push(@sys_ids,$key); } } @sys_ids = sort { lc($a) cmp lc($b) } @sys_ids; - # @sys_ids = ('DP-1-1','DVI-I-1','VGA-1'); + # @sys_ids = ('DVI-I-1','eDP-1','VGA-1'); main::log_data('dump','@sys_ids',\@sys_ids) if $b_log; main::log_data('dump','$xrandr_ids ref',$display_ids) if $b_log; print 'sys: ', Data::Dumper::Dumper \@sys_ids if $dbg[45]; @@ -15435,31 +15531,37 @@ sub map_monitor_ids { $monitor_map = {}; # known patterns: s: DP-1, d: DisplayPort-0; s: HDMI-A-2, d: HDMI-A-1 # s: HDMI-A-2, d: HDMI-2; s: DVI-1 d: DVI1; s: HDMI-1, d: HDMI1 - # s: DVI-I-1, d: DVI0; s: VGA-1, d: VGA1; s: DP-1-1; d: DP-1-1 - my ($d_1,$d_2,$d_3,$d_4,$s_1,$s_2,$s_3,$s_4); + # s: DVI-I-1, d: DVI0; s: VGA-1, d: VGA1; s: DP-1-1; d: DP-1-1; + # s: eDP-1, d: eDP-1-1 (yes, reversed from normal deviation!); s: eDP-1, d: eDP + # worst: s: DP-6, d: DP-2-3 (2 banks of 3 according to X); s: eDP-1, d: DP-4; + my ($d_1,$d_2,$d_m,$s_1,$s_2,$s_m); + my $b_single = (scalar @sys_ids == 1) ? 1 : 0; + my $pattern = '([A-Z]+)(-[A-Z]-\d+-\d+|-[A-Z]-\d+|-\d+-\d+|-?\d+|)'; for (my $i=0; $i < scalar @$display_ids; $i++){ - print "s: $sys_ids[$i] x: $display_ids->[$i]\n" if $dbg[45]; - if ($display_ids->[$i] =~ /^([A-Z]+)(-[AB]|-[ADI]|-[ADI]-\d+?|-\d+?)?(-)?(\d+)$/i){ + print "s: $sys_ids[$i] d: $display_ids->[$i]\n" if $dbg[45]; + # try 1: /^([A-Z]+)(-[AB]|-[ADI]|-[ADI]-\d+?|-\d+?)?(-)?(\d+)$/i + if ($display_ids->[$i] =~ /^$pattern$/i){ $d_1 = $1; $d_2 = ($2) ? $2 : ''; - $d_3 = ($3) ? $3 : ''; - $d_4 = $4; + $d_2 =~ /(\d+)?$/; + $d_m = ($1) ? $1 : 0; $d_1 =~ s/^DisplayPort/DP/i; # amdgpu... - print " d1: $d_1 d2: $d_2 d3: $d_3 d4: $d_4\n" if $dbg[45]; - if ($sys_ids[$i] =~ /^([A-Z]+?)(-[AB]|-[ADI]|-[ADI]-\d+?|-\d+?)?(-)?(\d+)$/i){ + print " d1: $d_1 d2: $d_2 d3: $d_m\n" if $dbg[45]; + if ($sys_ids[$i] =~ /^$pattern$/i){ $s_1 = $1; $s_2 = ($2) ? $2 : ''; - $s_3 = ($3) ? $3 : ''; - $s_4 = $4; + $s_2 =~ /(\d+)?$/; + $s_m = ($1) ? $1 : 0; $d_1 = $s_1 if uc($d_1) eq 'XWAYLAND'; - print " d1: $d_1 s1: $s_1 s2: $s_2 s3: $s_3 s4: $s_4\n" if $dbg[45]; - if ($d_1 eq $s_1 && ($d_4 == $s_4 || $d_4 == ($s_4 - 1))){ + print " d1: $d_1 s1: $s_1 dm: $d_m sm: $s_m \n" if $dbg[45]; + if ($d_1 eq $s_1 && ($d_m == $s_m || $d_m == ($s_m - 1))){ $monitor_map->{$display_ids->[$i]} = $sys_ids[$i]; } } } if (!$monitor_map->{$display_ids->[$i]}){ - $monitor_map->{$display_ids->[$i]} = main::message('monitor-id'); + # we're not even going to try, if there's 1 sys and 1 display, just use it! + $monitor_map->{$display_ids->[$i]} = ($b_single) ? $sys_ids[$i] : main::message('monitor-id'); } } main::log_data('dump','$monitor_map ref',$monitor_map) if $b_log; @@ -22130,7 +22232,8 @@ sub process_lm_sensors { # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/sensors/sensors-zenpower-nvme-2.txt"; # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/sensors/sensors-pch-intel-1.txt"; # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/sensors/sensors-ppc-sr71.txt"; - # @sensors_data = main::reader($file); + my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/sensors/sensors-applesmc-1.txt"; + @sensors_data = main::reader($file); } else { # only way to get sensor array data? Unless using sensors -j, but can't assume json @@ -22151,6 +22254,9 @@ sub process_lm_sensors { if ($adapter =~ /^(drive|nvme)/){ $type = 'disk'; } + elsif ($adapter =~ /^(BAT)/){ + $type = 'bat'; + } # intel on die io controller, like southbridge/northbridge used to be elsif ($adapter =~ /^(pch[_-])/){ $type = 'pch'; @@ -22666,11 +22772,18 @@ sub gpu_data { package SlotItem; sub get { eval $start if $b_log; - my (@rows,$key1,$val1); + my ($data,@rows,$key1,$val1); my $num = 0; if ($fake{'dmidecode'} || ($alerts{'dmidecode'}->{'action'} eq 'use' && (!%risc || $use{'slot-tool'}))){ - @rows = slot_output(); + $data = slot_data_dmi(); + @rows = slot_output($data) if $data; + if (!@rows){ + my $key = 'Message'; + push(@rows, { + main::key($num++,0,1,$key) => main::message('pci-slot-data',''), + },); + } } elsif (%risc && !$use{'slot-tool'}){ $key1 = 'Message'; @@ -22688,63 +22801,162 @@ sub get { } sub slot_output { eval $start if $b_log; + my $data = $_[0]; my (@rows); - my $num = 0; - foreach my $entry (@dmi){ + my $num = 1; + foreach my $slot_data (@$data){ + next if !$slot_data || ref $slot_data ne 'HASH'; $num = 1; - if ($entry->[0] == 9){ - my ($designation,$id,$length,$type,$usage) = ('','','','',''); - # skip first two row, we don't need that data - my $j = scalar @rows; - foreach my $item (@$entry[2 .. $#$entry]){ - if ($item !~ /^~/){ # skip the indented rows - my @value = split(/:\s+/, $item); - if ($value[0] eq 'Type'){ - $type = $value[1]; - } - if ($value[0] eq 'Designation'){ - $designation = $value[1]; - } - if ($value[0] eq 'Current Usage'){ - $usage = $value[1]; - - } - if ($value[0] eq 'ID'){ - $id = $value[1]; - } - if ($extra > 1 && $value[0] eq 'Length'){ - $length = $value[1]; - } - } + my $j = scalar @rows; + $slot_data->{'id'} = 'N/A' if !defined $slot_data->{'id'}; # can be 0 + $slot_data->{'pci'} ||= 'N/A'; + push(@rows, { + main::key($num++,1,1,'Slot') => $slot_data->{'id'}, + main::key($num++,0,2,'type') => $slot_data->{'pci'}, + },); + # PCIe only + if ($extra > 1 && $slot_data->{'gen'}){ + $rows[$j]->{main::key($num++,0,2,'gen')} = $slot_data->{'gen'}; + } + if ($slot_data->{'lanes-phys'} && $slot_data->{'lanes-active'} && + $slot_data->{'lanes-phys'} ne $slot_data->{'lanes-active'}){ + $rows[$j]->{main::key($num++,1,2,'lanes')} = ''; + $rows[$j]->{main::key($num++,0,3,'phys')} = $slot_data->{'lanes-phys'}; + $rows[$j]->{main::key($num++,0,3,'active')} = $slot_data->{'lanes-active'}; + } + elsif ($slot_data->{'lanes-phys'}){ + $rows[$j]->{main::key($num++,0,2,'lanes')} = $slot_data->{'lanes-phys'}; + } + # Non PCIe only + if ($extra > 1 && $slot_data->{'bits'}){ + $rows[$j]->{main::key($num++,0,2,'bits')} = $slot_data->{'bits'}; + } + # PCI-X and PCI only + if ($extra > 1 && $slot_data->{'mhz'}){ + $rows[$j]->{main::key($num++,0,2,'MHz')} = $slot_data->{'mhz'}; + } + $rows[$j]->{main::key($num++,0,2,'status')} = $slot_data->{'usage'}; + if ($slot_data->{'j'} || $slot_data->{'m2'}){ + my $info = ($slot_data->{'m2'}) ? $slot_data->{'m2'} : ''; + if ($slot_data->{'j'}){ + $info .= ' ' if $info; + $info .= $slot_data->{'j'}; } - if ($type){ - $id = 'N/A' if ($id eq ''); - if ($type eq 'Other' && $designation){ - $type = $designation; - } - elsif ($type && $designation){ - $type = "$type $designation"; - } - push(@rows, { - main::key($num++,1,1,'Slot') => $id, - main::key($num++,0,2,'type') => $type, - main::key($num++,0,2,'status') => $usage, - },); - if ($extra > 1){ - $rows[$j]->{main::key($num++,0,2,'length')} = $length; - } + $rows[$j]->{main::key($num++,0,2,'info')} = $info; + } + if ($extra > 1){ + $slot_data->{'length'} ||= 'N/A'; + $rows[$j]->{main::key($num++,0,2,'length')} = $slot_data->{'length'}; + if ($slot_data->{'cpu'}){ + $rows[$j]->{main::key($num++,0,2,'cpu')} = $slot_data->{'cpu'}; } } - } - if (!@rows){ - my $key = 'Message'; - push(@rows, { - main::key($num++,0,1,$key) => main::message('pci-slot-data',''), - },); + if ($extra > 0){ + $slot_data->{'bus_address'} ||= 'N/A'; + $rows[$j]->{main::key($num++,0,2,'bus-ID')} =$slot_data->{'bus_address'}; + } } eval $end if $b_log; return @rows; } +sub slot_children { + eval $start if $b_log; + + eval $end if $b_log; +} +sub slot_data_dmi { + eval $start if $b_log; + my $i = 0; + my @slots; + foreach my $slot_data (@dmi){ + next if $slot_data->[0] != 9; + my %data; + # skip first two row, we don't need that data + foreach my $item (@$slot_data[2 .. $#$slot_data]){ + if ($item !~ /^~/){ # skip the indented rows + my @value = split(/:\s+/, $item, 2); + if ($value[0] eq 'Type'){ + $data{'type'} = $value[1]; + } + if ($value[0] eq 'Designation'){ + $data{'designation'} = $value[1]; + } + if ($value[0] eq 'Current Usage'){ + $data{'usage'} = lc($value[1]); + } + if ($value[0] eq 'ID'){ + $data{'id'} = $value[1]; + } + if ($extra > 1 && $value[0] eq 'Length'){ + $data{'length'} = lc($value[1]); + } + if ($extra > 1 && $value[0] eq 'Bus Address'){ + $value[1] =~ s/^0000://; + $data{'bus_address'} = $value[1]; + } + } + } + if ($data{'type'} eq 'Other' && $data{'designation'}){ + $data{'type'} = $data{'designation'}; + undef $data{'designation'}; + } + foreach my $string (($data{'type'},$data{'designation'})){ + next if !$string; + print "st: $string\n" if $dbg[48]; + $string =~ s/(PCI[\s_-]?Express|Pci[_-]?e)/PCIe /ig; + $string =~ s/PCI[\s_-]?X/PCIX /ig; + $string =~ s/Mini[\s_-]?PCI/MiniPCI /ig; + $string =~ s/PCMCIA/PCMCIA /ig; + if (!$data{'pci'} && $string =~ /(AGP|ISA|MiniPCI|PCIe|PCIX|PCMCIA|PCI)/){ + $data{'pci'} = $1; + # print "pci: $data{'pci'}\n"; + } + if ($string =~ /(MiniPCI|PCMCIA)/){ + $data{'pci'} = $1; + # print "pci: $data{'pci'}\n"; + } + # legacy format: PCIE#3-x8 + if (!$data{'lanes-phys'} && $string =~ /(^x|#\d+-x)(\d+)/){ + $data{'lanes-phys'} = $2; + } + if (!$data{'lanes-active'} && $string =~ /^x\d+ .*? x(\d+)/){ + $data{'lanes-active'} = $1; + } + if (!defined $data{'slot'} && $string =~ s/SLOT-?(\d+)?\b//){ + $data{'slot'} = $1 if defined $1; + } + # legacy format, seens with PCI-X/PCIe mobos: PCIX#2-100MHz, PCIE#3-x8 + if (!defined $data{'id'} && $string =~ /(#|PCI)(\d+)\b/){ + $data{'id'} = $2; + } + if (!$data{'j'} && $string =~ s/\bJ-?(\S+)\b//){ + $data{'j'} = 'J' . $1; + } + if (!$data{'m2'} && $string =~ s/\bM\.?2\b//){ + $data{'m2'} = 'M.2'; + } + if (!$data{'cpu'} && $string =~ s/CPU-?(\d+)\b//){ + $data{'cpu'} = $1; + } + if (!$data{'gen'} && $data{'pci'} && $data{'pci'} eq 'PCIe' && + $string =~ /PCIe[\s_-]*([\d.]+)/){ + $data{'gen'} = $1 + 0; + } + if (!$data{'mhz'} && $data{'pci'} && $string =~ /(\d+)[\s_-]?MHz/){ + $data{'mhz'} = $1; + } + if (!$data{'bits'} && $data{'pci'} && $string =~ /\b(\d+)[\s_-]?bit/){ + $data{'bits'} = $1; + } + $i++; + } + push(@slots,{%data}) if %data; + } + print '@slots: ', Data::Dumper::Dumper \@slots if $dbg[48]; + main::log_data('dump','@slots final',\@slots) if $b_log; + eval $end if $b_log; + return \@slots if @slots; +} } ## SwapItem @@ -25620,6 +25832,7 @@ sub pci_class { '11' => 'signal-processing', '12' => 'processing-accelerators', '13' => 'non-essential-instrumentation', + # 14 - fe reserved '40' => 'coprocessor', 'ff' => 'unassigned', ); @@ -25986,6 +26199,7 @@ sub get_display_manager { } } @dms = @temp; + my (@dm_info); # print Data::Dumper::Dumper \@dms; # we know the files or directories exist so no need for further checks here foreach my $dm (@dms){ @@ -25994,30 +26208,36 @@ sub get_display_manager { ($path = check_program($dm))){} else {$path = $dm} # print "$path $extra\n"; + @dm_info = (); @data = program_data($dm,$path,3); - $dm = $data[0]; - $dm .= ' ' . $data[1] if $data[1]; - push(@found,$dm); + $dm_info[0] = $data[0]; + $dm_info[1] = $data[1]; + if (scalar @dms > 1 && (my $temp = ServiceData::get('status',$dm))){ + $dm_info[2] = message('stopped') if $temp && $temp =~ /stopped|disabled/; + } + push(@found,[@dm_info]); } if (!@found){ # ly does not have a run/pid file if (grep {$_ eq 'ly'} @ps_gui){ @data = program_data('ly','ly',3); - $found[0] = $data[0]; - $found[0] .= ' ' . $data[1] if $data[1]; + $dm_info[0] = $data[0]; + $dm_info[1] = $data[1]; + $found[0] = [@dm_info]; } elsif (grep {/startx$/} @ps_gui){ - $found[0] = 'startx'; + $found[0] = ['startx']; } elsif (grep {$_ eq 'xinit'} @ps_gui){ - $found[0] = 'xinit'; + $found[0] = ['xinit']; } } # might add this in, but the rate of new dm's makes it more likely it's an # unknown dm, so we'll keep output to N/A + # print Data::Dumper::Dumper \@found; log_data('dump','display manager: @found',\@found) if $b_log; eval $end if $b_log; - return join(', ', @found) if @found; + return \@found if @found; } ## DistroData @@ -26102,12 +26322,12 @@ sub get_linux_distro { # note, pclinuxos has all these mandrake/mandriva files, careful! my $lsb_good_s = 'mandrake-release|mandriva-release|mandrakelinux-release|'; $lsb_good_s .= 'manjaro-release'; - my $os_release_good_s = 'altlinux-release|arch-release|pclinuxos-release|'; - $os_release_good_s .= 'rpi-issue|SuSE-release'; + my $os_release_good_s = 'altlinux-release|arch-release|mageia-release|'; + $os_release_good_s .= 'pclinuxos-release|rpi-issue|SuSE-release'; # we need these empirically verified one by one as they appear, but always remember # that stuff changes, legacy, deprecated, but these ideally are going to be right - my $osr_good = 'manjaro|antergos|chakra|guix|pclinuxos|raspberry pi os|slint|'; - $osr_good .= 'zorin'; + my $osr_good = 'manjaro|antergos|chakra|guix|mageia|pclinuxos|raspberry pi os|'; + $osr_good .= 'slint|zorin'; my ($b_issue,$b_lsb,$b_skip_issue,$b_skip_osr); my ($issue,$lsb_release) = ('/etc/issue','/etc/lsb-release'); $b_issue = 1 if -f $issue; @@ -26169,13 +26389,15 @@ sub get_linux_distro { @working = (@derived,@primary); foreach my $file (@working){ if ("/etc/$file" =~ /($distro_files_s)$/){ - # Now lets see if the distro file is in the known-good working-lsb-list - # if so, use lsb-release, if not, then just use the found file - # this is for only those distro's with self named release/version files + # These is for only those distro's with self named release/version files # because Mint does not use such, it must be done as below + # Force use of os-release file in cases where there might be conflict + # between lsb-release rules and os-release priorities. if (@osr && $file =~ /($os_release_good_s)$/){ $distro_file = $os_release; } + # Now lets see if the distro file is in the known-good working-lsb-list + # if so, use lsb-release, if not, then just use the found file elsif ($b_lsb && $file =~ /$lsb_good_s/){ $distro_file = $lsb_release; } @@ -26504,8 +26726,12 @@ sub get_lsb_release { else { # avoid duplicates $distro = $id; - $distro .= " $release" if $distro !~ /$release/; - $distro .= " $codename" if $distro !~ /$codename/; + $distro .= " $release" if $release && $distro !~ /$release/; + # eg: release: 9 codename: mga9 + if ($codename && $distro !~ /$codename/i && + (!$release || $codename !~ /$release/)){ + $distro .= " $codename"; + } $distro =~ s/^\s+|\s\s+|\s+$//g; # get rid of double and trailing spaces } eval $end if $b_log; @@ -26701,6 +26927,7 @@ sub generate_data { # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/ram/dmidecode-speed-configured-1.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/ram/dmidecode-speed-configured-2.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/ram/00srv-dmidecode-mushkin-1.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/dmidecode/dmidecode-slots-pcix-pcie-1.txt"; # open(my $fh, '<', $file) or die "can't open $file: $!"; # chomp(@data = <$fh>); } @@ -27161,24 +27388,26 @@ sub get_kernel_bits { sub get_kernel_data { eval $start if $b_log; - my ($kernel,$ksplice) = ('',''); + my ($ksplice) = (''); + my @kernel; # Linux; yawn; 4.9.0-3.1-liquorix-686-pae; #1 ZEN SMP PREEMPT liquorix 4.9-4 (2017-01-14); i686 # FreeBSD; siwi.pair.com; 8.2-STABLE; FreeBSD 8.2-STABLE #0: Tue May 31 14:36:14 EDT 2016 erik5@iddhi.pair.com:/usr/obj/usr/src/sys/82PAIRx-AMD64; amd64 if (@uname){ - $kernel = $uname[2]; - if ((my $program = check_program('uptrack-uname')) && $kernel){ + $kernel[0] = $uname[2]; + if ((my $program = check_program('uptrack-uname')) && $kernel[0]){ $ksplice = qx($program -rm); $ksplice = trimmer($ksplice); - $kernel = ($ksplice) ? $ksplice . ' (ksplice)' : $kernel; + $kernel[0] = $ksplice . ' (ksplice)' if $ksplice; } - $kernel .= ' ' . $uname[-1]; - $kernel = ($bsd_type) ? $uname[0] . ' ' . $kernel : $kernel; + $kernel[1] = $uname[-1]; } - $kernel ||= 'N/A'; - log_data('data',"kernel: $kernel ksplice: $ksplice") if $b_log; + # we want these to have values to save validation checks for output + $kernel[0] ||= 'N/A'; + $kernel[1] ||= 'N/A'; + log_data('data',"kernel: " . join('; ', @kernel) . " ksplice: $ksplice") if $b_log; log_data('dump','perl @uname', \@uname) if $b_log; eval $end if $b_log; - return $kernel; + return \@kernel; } ## KernelParameters @@ -27766,7 +27995,7 @@ my @edid_info = ( ['C', 'max_size_vertical'], # in cm, 0 on projectors ['C', 'gamma'], ['a', 'feature_support'], - ['a10', '_color_characteristics'], + ['a10', 'color_characteristics'], ['a3' , 'established_timings'], ['a16', 'standard_timings'], ['a72', 'monitor_details'], @@ -27895,6 +28124,21 @@ my %subfields = ( [1, 'native'], [7, 'mode'], ], + # Section 3.7 in VESA-EEDID-A2.pdf specs + color_characteristics => [ + # Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1 Gy0 + [8, 'white_point_red_green'], + # Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0 + [8, 'white_point_blue_white'], + [8, 'red_x'], + [8, 'red_y'], + [8, 'green_x'], + [8, 'green_y'], + [8, 'blue_x'], + [8, 'blue_y'], + [8, 'white_x'], + [8, 'white_y'], + ], ); my @cea_video_mode_to_detailed_timing = ( 'pixel_clock', @@ -27981,50 +28225,58 @@ my @cea_video_modes = ( [ 297.000, 1920, 1080, "16/9", 720, 528, 44, 45, 4, 10, 1, 1, 0 ], # 64: 1920x1080@100.00 ); # Exist but IDs Unknown: Pixio, AOpen (AON?), AORUS [probably GBT], Deco Gear, -# Eyoyo, GAEMS, GeChic, KOORUI, Lilliput, Mobile Pixels, Nexanic, -# SunFounder, TECNII, TPEKKA, V7/VSEVEN, -# Guesses: KYY=KYY, MSI=MSI, +# Eyoyo, GAEMS, GeChic, KOORUI, Lilliput, Mobile Pixels, Nexanic, SunFounder, +# TECNII, TPEKKA, V7/VSEVEN, +# Guesses: KYY=KYY, MSI=MSI, KOE=Kaohsiung Opto Electronics # PGS: Princeton Graphic Systems; SDC: Samsung Display Co; # SIS: Silicon Integrated Systems; STN: Samsung Electronics America; +# BDS: Barco Display Systems # TAI: Toshiba America +# HIQ: Hitachi ImageQuest or Kaohsiung Opto Electronics? or does Imagequest make hitachi: +# NVD: Nvidia or NewVisionDisplay? my %vendors = ( -'ACI' => 'Asus', 'ACR' => 'Acer', 'ACT' => 'Targa', 'ADI' => 'ADI', -'AMW' => 'AMW', 'ANX' => 'Acer Netxix', 'AOC' => 'AOC', 'API' => 'Acer', +'AAC' => 'AcerView', 'ACI' => 'Asus', 'ACR' => 'Acer', 'ACT' => 'Targa', 'ADI' => 'ADI', +'AIC' => 'AG Neovo', 'AMW' => 'AMW', 'ANX' => 'Acer Netxix', 'AOC' => 'AOC', 'API' => 'A Plus Info', 'APP' => 'Apple', 'ART' => 'ArtMedia', 'AST' => 'AST Research', 'AUO' => 'AU Optronics', -'BEL' => 'Beltronic', 'BMM' => 'BMM', 'BNQ' => 'BenQ', 'BOE' => 'BOE Display', -'CMN' => 'Chi Mei Innolux', 'CPL' => 'Compal/ALFA', 'CPQ' => 'Compaq', -'CPT' => 'Asus', 'CTX' => 'CTX (Chuntex)', 'CVT' => 'DGM', -'DEC' => 'DEC', 'DEL' => 'Dell', 'DPC' => 'Delta', 'DPL' => 'Digital Projection', 'DWE' => 'Daewoo', -'ECS' => 'Elitegroup', 'EIZ' => 'EIZO', 'EPI' => 'Envision', 'ETR' => 'Rotel', -'FCM' => 'Funai', 'FUS' => 'Fujitsu Siemens', -'GBT' => 'Gigabyte', 'GSM' => 'LG (GoldStar)', 'GWY' => 'Gateway 2000', +'BEL' => 'Beltronic', 'BMM' => 'BMM', 'BNQ' => 'BenQ', 'BOE' => 'BOE Display', 'BDS' => 'Barco', +'CHO' => 'Sichuang Changhong', 'CMN' => 'ChiMei InnoLux', 'CMO' => 'Chi Mei Optoelectronics', +'CPL' => 'Compal/ALFA', 'CPQ' => 'Compaq', 'CPT' => 'Chungwa Picture Tubes', 'CTX' => 'CTX (Chuntex)', 'CVT' => 'DGM', +'DEC' => 'DEC', 'DEL' => 'Dell', 'DON' => 'Denon', 'DPC' => 'Delta', 'DPL' => 'Digital Projection', 'DWE' => 'Daewoo', +'ECS' => 'Elitegroup', 'EIZ' => 'EIZO', 'ELS' => 'ELSA', 'ENC' => 'EIZO NANAO', 'EPI' => 'Envision', 'ETR' => 'Rotel', +'FCM' => 'Funai', 'FUJ' => 'Fujitsu', 'FUS' => 'Fujitsu Siemens', +'GBT' => 'Gigabyte', 'GFN' => 'Gefen', 'GSM' => 'LG (GoldStar)', 'GWY' => 'Gateway 2000', 'HEI' => 'Hyundai.', 'HIQ' => 'Hyundai ImageQuest', 'HIT' => 'Hitachi', 'HPN' => 'HP', -'HSD' => 'Hannspree', 'HSL' => 'Hansol', 'HTC' => 'Hitachi', 'HVR' => 'Hitache', 'HWP' => 'HP', -'IBM' => 'IBM', 'ICL' => 'Fujitsu ICL', 'IFS' => 'InFocus', 'IQT' => 'Hyundai', -'IVM' => 'Idek Iiyama', -'KDS' => 'KDS', 'KFC' => 'KFC Computek', 'KYY' => 'KYY', -'LEN' => 'Lenovo', 'LGD' => 'LG', 'LKM' => 'Adlas/Azalea', 'LNK' => 'LINK', -'LPL' => 'LG Philips', 'LTN' => 'Lite-On', -'MAG' => 'MAG InnoVision', 'MAX' => 'Maxdata', 'MED' => 'Medion', +'HSD' => 'HannSpree/HannStar', 'HSL' => 'Hansol', 'HTC' => 'Hitachi/Nissei', 'HVR' => 'Hitachi', +'HWP' => 'HP', 'HWV' => 'Huawei', +'IBM' => 'IBM', 'ICL' => 'Fujitsu ICL', 'IFS' => 'InFocus', 'INO' => 'Innolab Pte', 'IQT' => 'Hyundai', +'IVM' => 'Idek Iiyama', 'IVO' => 'InfoVision Optronics/Kunshan', +'KDS' => 'Korea Data Systems (KDS)', 'KFC' => 'KFC Computek', 'KOE' => 'Kaohsiung OptoElectronics', +'KTC' => 'Kingston', 'KYY' => 'KYY', +'LCD' => 'Toshiba Matsushita', 'LEN' => 'Lenovo', 'LGD' => 'LG Display', 'LKM' => 'Adlas/Azalea', +'LNK' => 'LINK', 'LPL' => 'LG Philips', 'LTN' => 'Lite-On', +'MAG' => 'MAG InnoVision', 'MAX' => 'Belinea/Maxdata', 'MED' => 'Medion', 'MEI' => 'Panasonic', 'MEL' => 'Mitsubishi', 'MIR' => 'Miro', 'MSI' => 'MSI', 'MTC' => 'MITAC', -'NAN' => 'NANAO', 'NEC' => 'NEC', 'NOK' => 'Nokia', 'NVD' => 'Nvidia', -'OQI' => 'ViewSonic Optiquest', 'ORN' => 'Orion', +'NAN' => 'NANAO/EIZO', 'NEX' => 'Nexgen Mediatech', 'NCP' => 'Najing CEC Panda', 'NEC' => 'NEC', +'NOK' => 'Nokia', 'NVD' => 'Nvidia', +'ONK' => 'Onkyo', 'OPT' => 'Optoma','OQI' => 'ViewSonic Optiquest', 'ORN' => 'Orion', 'PBN' => 'Packard Bell', 'PCK' => 'Daewoo', 'PDC' => 'Polaroid', 'PGS' => 'Princeton', 'PHL' => 'Philips', 'PIO' => 'Pioneer', 'PNR' => 'Planar', 'PRT' => 'Princeton', -'QDI' => 'Quahtum Data', 'QDS' => 'Quanta Display', 'REL' => 'Relisys', -'SAM' => 'Samsung', 'SAN' => 'Sanyo', 'SDC' => 'Samsung', 'SEC' => 'Seiko Epson', -'SEN' => 'Sensics', 'SHP' => 'Sharp', 'SII' => 'Silicon Image', 'SIS' => 'SIS', -'SMC' => 'Samtron', 'SMI' => 'Smile', 'SNI' => 'Siemens Nixdorf', 'SNY' => 'Sony', -'SPT' => 'Sceptre', 'SRC' => 'Shamrock', 'STN' => 'Samsung', 'STP' => 'Sceptre', +'QDI' => 'Quantum Data', 'QDS' => 'Quanta Display', 'REL' => 'Relisys', 'REN' => 'Renesas', +'SAM' => 'Samsung', 'SAN' => 'Sanyo', 'SBI' => 'Smarttech', 'SDC' => 'Samsung', 'SEC' => 'Seiko Epson', +'SEN' => 'Sensics', 'SHP' => 'Sharp', 'SGD' => 'Sigma Designs', 'SGI' => 'SGI', 'SHI' => 'Jiangsu Shinco', +'SII' => 'Silicon Image', 'SIS' => 'SIS', 'SKM' => 'Guangzhou Teclast', 'SMC' => 'Samtron', +'SMI' => 'Smile', 'SNI' => 'Siemens Nixdorf', 'SNY' => 'Sony', 'SPT' => 'Sceptre', +'SRC' => 'Shamrock', 'STN' => 'Samsung', 'STP' => 'Sceptre', 'SUN' => 'Sun Microsystems', 'SYN' => 'Synaptics', 'TAI' => 'Toshiba', 'TAT' => 'Tatung', 'TOS' => 'Toshiba', 'TRL' => 'Royal Information', 'TSB' => 'Toshiba', 'UEG' => 'EliteGroup', 'UNM' => 'Unisys', -'VIT' => 'Visitech', 'VLV' => 'Valve', 'VSC' => 'ViewSonic', 'VTK' => 'Viewteck', -'WTC' => 'Wen Technology', 'ZCM' => 'Zenith', +'VIT' => 'Visitech', 'VLV' => 'Valve', 'VSC' => 'ViewSonic', 'VTK' => 'Viewteck', 'VTS' => 'VTech', +'WTC' => 'Wen Technology', 'XLX' => 'Xilinx', 'YMH' => 'Yamaha', 'ZCM' => 'Zenith', ); sub _within_limit { my ($value, $type, $limit) = @_; $type eq 'min' ? $value >= $limit : $value <= $limit; } + sub _get_many_bits { my ($s, $field_name) = @_; my @bits = split('', unpack('B*', $s)); @@ -28032,24 +28284,16 @@ sub _get_many_bits { foreach (@{$subfields{$field_name}}) { my ($size, $field) = @$_; my @l = ('0' x (8 - $size), splice(@bits, 0, $size)); - $h{$field} = unpack("C", pack('B*', join('', @l))) if $field && $field !~ /^_/; + if ($field && $field !~ /^_/){ + $h{$field} = unpack("C", pack('B*', join('', @l))); + # spec: chromacity: 0.xyz: white_point see color_characteristics + if ($h{$field} && $field_name eq 'color_characteristics'){ + $h{$field} = ($field =~ /_[xy]$/) ? sprintf('%0.3f',$h{$field}/255) : [@l[1..8]]; + } + } } \%h; } -sub check_parsed_edid { - my ($edid) = @_; - $edid->{edid_version} >= 1 && $edid->{edid_version} <= 2 or return 'bad edid_version'; - $edid->{edid_revision} != 0xff or return 'bad edid_revision'; - if ($edid->{monitor_range}) { - $edid->{monitor_range}{horizontal_min} && - $edid->{monitor_range}{horizontal_min} <= $edid->{monitor_range}{horizontal_max} - or return 'bad HorizSync'; - $edid->{monitor_range}{vertical_min} && - $edid->{monitor_range}{vertical_min} <= $edid->{monitor_range}{vertical_max} - or return 'bad VertRefresh'; - } - ''; -} sub _build_detailed_timing { my ($pixel_clock, $vv) = @_; my $h = _get_many_bits($vv, 'detailed_timing'); @@ -28083,11 +28327,12 @@ sub _add_standard_timing_modes { $v; } sub parse_edid { + eval $start if $b_log; my ($raw_edid, $verbose) = @_; - my %edid; + my (%edid, @warnings); my ($main_edid, @eedid_blocks) = unpack("a128" x (length($raw_edid) / 128), $raw_edid); my @vals = unpack(join('', map { $_->[0] } @edid_info), $main_edid); - my $i; + my $i = 0; foreach (@edid_info) { my ($field, $v) = ($_->[1], $vals[$i++]); if ($field eq 'year') { @@ -28101,6 +28346,8 @@ sub parse_edid { $v = _get_many_bits($v, 'video_input_definition'); } elsif ($field eq 'feature_support') { $v = _get_many_bits($v, 'feature_support'); + } elsif ($field eq 'color_characteristics') { + $v = _get_many_bits($v, 'color_characteristics'); } elsif ($field eq 'established_timings') { my $h = _get_many_bits($v, 'established_timings'); $v = [ @@ -28164,9 +28411,9 @@ sub parse_edid { push @{$edid{monitor_text}}, unpack('A13', $vv); } elsif ($flag == 0xff) { push @{$edid{serial_number2}}, unpack('A13', $vv); - } else { - $verbose && $vv ne "\0" x 13 && $vv ne " " x 13 and - warn "parse_edid: unknown flag $flag\n"; + } elsif ($vv ne "\0" x 13 && $vv ne " " x 13) { + push(@warnings, "parse_edid: unknown flag $flag"); + warn "$warnings[-1]\n" if $verbose; } } } @@ -28182,7 +28429,8 @@ sub parse_edid { $dtd_offset -= 4; while ($dtd_offset > 0) { if (!$v) { - warn "parse_edid: DTD offset outside of available data\n" if $verbose; + push(@warnings, "parse_edid: DTD offset outside of available data"); + warn "$warnings[-1]\n" if $verbose; last; } my $h = _get_many_bits($v, 'cea_data_block_collection'); @@ -28195,7 +28443,8 @@ sub parse_edid { $h = _get_many_bits($vmode, 'cea_video_data_block'); my $cea_mode = $cea_video_modes[$h->{mode} - 1]; if (!$cea_mode) { - warn "parse_edid: unhandled CEA mode $h->{mode}\n" if $verbose; + push(@warnings, "parse_edid: unhandled CEA mode $h->{mode}"); + warn "$warnings[-1]\n" if $verbose; next; } my %det_mode = (source => 'cea_vdb'); @@ -28212,11 +28461,18 @@ sub parse_edid { if $h->{horizontal_active} > 1 && $h->{vertical_active} > 1; } } else { - $verbose && warn "parse_edid: unknown tag $tag\n"; + push(@warnings, "parse_edid: unknown tag $tag"); + warn "$warnings[-1]\n" if $verbose; } } $edid{max_size_precision} = 'cm'; - $edid{EISA_ID} = $edid{manufacturer_name} . sprintf('%04x', $edid{product_code}) if $edid{product_code} && $edid{manufacturer_name}; + if ($edid{product_code}){ + $edid{product_code_h} = sprintf('%04x', $edid{product_code}); + if ($edid{manufacturer_name}){ + $edid{EISA_ID} = $edid{manufacturer_name} . $edid{product_code_h}; + } + $edid{product_code_h} = '0x'. $edid{product_code_h}; + } if ($edid{monitor_range}) { $edid{HorizSync} = $edid{monitor_range}{horizontal_min} . '-' . $edid{monitor_range}{horizontal_max}; $edid{VertRefresh} = $edid{monitor_range}{vertical_min} . '-' . $edid{monitor_range}{vertical_max}; @@ -28260,16 +28516,27 @@ sub parse_edid { $edid{ratio_name} = _ratio_name($in_cm{horizontal}, $in_cm{vertical}, 'mm'); $edid{ratio_precision} = 'mm'; } - $h->{bad_ratio} = 1 if - $edid{ratio_precision} && - abs($edid{ratio} - $h->{horizontal_active} / $h->{vertical_active}) > ($edid{ratio_precision} eq 'mm' ? 0.02 : 0.2); - + if ($edid{ratio_precision} && + abs($edid{ratio} - $h->{horizontal_active} / $h->{vertical_active}) > ($edid{ratio_precision} eq 'mm' ? 0.02 : 0.2)) { + $h->{bad_ratio} = 1; + } + if ($edid{ratio_name}) { + $edid{ratios} = $edid{ratio_name}; + $edid{ratios} =~ s|/|:|g; + $edid{ratios} = [split(/ or /, $edid{ratios})]; # "3/2 or 16/10" + } if ($edid{max_size_vertical}) { $h->{vertical_dpi} = $h->{vertical_active} / $edid{max_size_vertical} * 2.54; } if ($edid{max_size_horizontal}) { $h->{horizontal_dpi} = $h->{horizontal_active} / $edid{max_size_horizontal} * 2.54; } + if ($h->{horizontal_image_size}) { + $h->{horizontal_image_size_i} = sprintf('%.2f',($h->{horizontal_image_size}/25.4)) + 0; + } + if ($h->{vertical_image_size}) { + $h->{vertical_image_size_i} = sprintf('%.2f',($h->{vertical_image_size}/25.4)) + 0; + } my $dpi_string = ''; if ($h->{vertical_dpi} && $h->{horizontal_dpi}) { $dpi_string = @@ -28280,36 +28547,78 @@ sub parse_edid { my $horizontal_total = $h->{horizontal_active} + $h->{horizontal_blanking}; my $vertical_total = $h->{vertical_active} + $h->{vertical_blanking}; no warnings 'uninitialized'; - $h->{ModeLine_comment} = sprintf qq(# Monitor %s%s modeline (%.1f Hz vsync, %.1f kHz hsync, %sratio %s%s)), - $h->{preferred} ? "preferred" : "supported", - $h->{source} eq 'cea_vdb' ? " CEA" : '', - $h->{pixel_clock} / $horizontal_total / $vertical_total * 1000 * 1000 * ($h->{interlaced} ? 2 : 1), - $h->{pixel_clock} / $horizontal_total * 1000, - $h->{interlaced} ? "interlaced, " : '', - _nearest_ratio($h->{horizontal_active} / $h->{vertical_active}, 0.01) || sprintf("%.2f", $h->{horizontal_active} / $h->{vertical_active}), - $dpi_string ? ", $dpi_string" : ''; - - $h->{ModeLine} = sprintf qq("%dx%d" $h->{pixel_clock} %d %d %d %d %d %d %d %d %shsync %svsync%s), - $h->{horizontal_active}, $h->{vertical_active}, + $h->{ModeLine_comment} = sprintf(qq(# Monitor %s%s modeline (%.1f Hz vsync, %.1f kHz hsync, %sratio %s%s)), + $h->{preferred} ? "preferred" : "supported", + $h->{source} eq 'cea_vdb' ? " CEA" : '', + $h->{pixel_clock} / $horizontal_total / $vertical_total * 1000 * 1000 * ($h->{interlaced} ? 2 : 1), + $h->{pixel_clock} / $horizontal_total * 1000, + $h->{interlaced} ? "interlaced, " : '', + _nearest_ratio($h->{horizontal_active} / $h->{vertical_active}, 0.01) || sprintf("%.2f", $h->{horizontal_active} / $h->{vertical_active}), + $dpi_string ? ", $dpi_string" : ''); + + $h->{ModeLine} = sprintf(qq("%dx%d" $h->{pixel_clock} %d %d %d %d %d %d %d %d %shsync %svsync%s), + $h->{horizontal_active}, $h->{vertical_active}, - $h->{horizontal_active}, - $h->{horizontal_active} + $h->{horizontal_sync_offset}, - $h->{horizontal_active} + $h->{horizontal_sync_offset} + $h->{horizontal_sync_pulse_width}, - $horizontal_total, + $h->{horizontal_active}, + $h->{horizontal_active} + $h->{horizontal_sync_offset}, + $h->{horizontal_active} + $h->{horizontal_sync_offset} + $h->{horizontal_sync_pulse_width}, + $horizontal_total, - $h->{vertical_active}, - $h->{vertical_active} + $h->{vertical_sync_offset}, - $h->{vertical_active} + $h->{vertical_sync_offset} + $h->{vertical_sync_pulse_width}, - $vertical_total, + $h->{vertical_active}, + $h->{vertical_active} + $h->{vertical_sync_offset}, + $h->{vertical_active} + $h->{vertical_sync_offset} + $h->{vertical_sync_pulse_width}, + $vertical_total, - $h->{horizontal_sync_positive} ? '+' : '-', - $h->{vertical_sync_positive} ? '+' : '-', - $h->{interlaced} ? ' Interlace' : ''; + $h->{horizontal_sync_positive} ? '+' : '-', + $h->{vertical_sync_positive} ? '+' : '-', + $h->{interlaced} ? ' Interlace' : ''); } $edid{diagonal_size} = sqrt(_sqr($edid{max_size_horizontal}) + _sqr($edid{max_size_vertical})) / 2.54; - + # we want to use null data found tests so only return errors/warnings if + # %edid or if verbose, since then we want to know no matter what. + if (%edid || $verbose){ + _edid_errors(\%edid); + $edid{edid_warnings} = \@warnings if @warnings; + } + eval $end if $b_log; \%edid; } +sub _edid_errors { + my $edid = shift @_; + if (!defined $edid->{edid_version}){ + _edid_error('edid-version','undefined'); + } + elsif ($edid->{edid_version} < 1 || $edid->{edid_version} > 2){ + _edid_error('edid-version',$edid->{edid_version}); + } + if (!defined $edid->{edid_revision}){ + _edid_error('edid-revision','undefined'); + } + elsif ($edid->{edid_revision} == 0xff){ + _edid_error('edid-revision',$edid->{edid_revision}); + } + if ($edid->{monitor_range}){ + if (!$edid->{monitor_range}{horizontal_min}){ + _edid_error('edid-sync','no horizontal'); + } + elsif ($edid->{monitor_range}{horizontal_min} > $edid->{monitor_range}{horizontal_max}){ + _edid_error('edid-sync', + "bad horizontal values: min: $edid->{monitor_range}{horizontal_min} max: $edid->{monitor_range}{horizontal_max}"); + } + if (!$edid->{monitor_range}{vertical_min}){ + _edid_error('edid-sync','no vertical'); + } + elsif ($edid->{monitor_range}{vertical_min} > $edid->{monitor_range}{vertical_max}){ + _edid_error('edid-sync', + "bad vertical values: min: $edid->{monitor_range}{vertical_min} max: $edid->{monitor_range}{vertical_max}"); + } + } +} +sub _edid_error { + my ($edid,$error,$data) = @_; + $edid->{edid_errors} = [] if !$edid->{edid_error}; + push(@{$edid->{edid_errors}},main::message($error,$data)); +} sub _nearest_ratio { my ($ratio, $max_error) = @_; my @sorted = @@ -28392,23 +28701,24 @@ sub get_pci_vendor { eval $start if $b_log; my ($device, $subsystem) = @_; return if !$subsystem; - my ($vendor,$sep,$temp) = ('','',''); + my ($vendor,$sep) = ('',''); # get rid of any [({ type characters that will make regex fail # and similar matches show as non-match - $subsystem = clean_regex($subsystem); - my @data = split(/\s+/, $subsystem); - # when using strings in patterns for regex have to escape them - foreach (@data){ - $temp = $_; - $temp =~ s/(\+|\$|\?|\^|\*)/\\$1/g; - if ($device !~ m|\b$temp\b|){ - $vendor .= $sep . $_; + my @data = split(/\s+/, clean_regex($subsystem)); + foreach my $word (@data){ + # AMD Tahiti PRO [Radeon HD 7950/8950 OEM / R9 280] + # PC Partner Limited / Sapphire Technology Tahiti PRO [Radeon HD 7950/8950 OEM / R9 280] + # $word =~ s/(\+|\$|\?|\^|\*)/\\$1/g; + if (length($word) == 1 || $device !~ m|\b\Q$word\E\b|i){ + $vendor .= $sep . $word; $sep = ' '; } else { last; } } + # just in case we had a standalone last character after done + $vendor =~ s| [/\(\[\{a\.,-]$|| if $vendor; eval $end if $b_log; return $vendor; } @@ -28462,7 +28772,7 @@ sub get_pcie_data { if ($b_admin && (($data{'max_link_speed'} && $data{'max_link_speed'} ne $data{'current_link_speed'}) || ($data{'max_link_width'} && - $data{'max_link_width'} > $data{'current_link_width'}))){ + $data{'max_link_width'} ne $data{'current_link_width'}))){ $$rows[$j]->{key($$num++,1,3,'link-max')} = ''; if ($data{'max_link_speed'} && $data{'max_link_speed'} ne $data{'current_link_speed'}){ @@ -28470,7 +28780,7 @@ sub get_pcie_data { $$rows[$j]->{key($$num++,0,4,'speed')} = $data{'max_link_speed'}; } if ($data{'max_link_width'} && - $data{'max_link_width'} > $data{'current_link_width'}){ + $data{'max_link_width'} ne $data{'current_link_width'}){ $$rows[$j]->{key($$num++,0,4,'lanes')} = $data{'max_link_width'}; } } @@ -28751,12 +29061,14 @@ sub process_status { my @working = split(/\s*:\s*/,$row); ($value) = (''); # print "$working[0]::$working[1]\n"; + # Loaded: masked (Reason: Unit sddm.service is masked.) if ($working[0] eq 'Loaded'){ # note: sshd shows ssh for ssh.service $working[1] =~ /^(.+?)\s*\(.*?\.service;\s+(\S+?);.*/; $result = lc($1) if $1; $result = lc($2) if $2; # this will be enabled/disabled } + # Active: inactive (dead) elsif ($working[0] eq 'Active'){ $working[1] =~ /^(.+?)\s*\((\S+?)\).*/; $value = lc($1) if $1 && (!$result || $result ne 'disabled'); @@ -30413,7 +30725,7 @@ sub short_output { my @data = ({ main::key($num++,0,0,'CPU') => $cpu_string, main::key($num++,0,0,$speed_key) => $speed, - main::key($num++,0,0,$kernel_os) => main::get_kernel_data(), + main::key($num++,0,0,$kernel_os) => join(' ', @{main::get_kernel_data()}), main::key($num++,0,0,'Up') => main::get_uptime(), main::key($num++,0,0,'Mem') => $memory, main::key($num++,0,0,'Storage') => $disk_string, @@ -30584,7 +30896,7 @@ sub system_item { my ($index); my $data_name = main::key($prefix++,1,0,'System'); my ($desktop,$desktop_info,$desktop_key,$dm_key,$toolkit,$wm) = ('','','Desktop','dm','',''); - my (@desktop_data,$desktop_version); + my (@desktop_data,$desktop_version,$tk_version,$wm_version); my %data = ( $data_name => [{}], ); @@ -30592,7 +30904,9 @@ sub system_item { if ($show{'host'}){ $data{$data_name}->[$index]{main::key($num++,0,1,'Host')} = main::get_hostname(); } - $data{$data_name}->[$index]{main::key($num++,1,1,'Kernel')} = main::get_kernel_data(); + my $kernel_data = main::get_kernel_data(); + $data{$data_name}->[$index]{main::key($num++,1,1,'Kernel')} = $kernel_data->[0]; + $data{$data_name}->[$index]{main::key($num++,0,2,'arch')} = $kernel_data->[1]; $data{$data_name}->[$index]{main::key($num++,0,2,'bits')} = main::get_kernel_bits(); if ($extra > 0){ my @compiler = CompilerVersion::get(); # get compiler data @@ -30624,11 +30938,9 @@ sub system_item { my @desktop_data = DesktopEnvironment::get(); $desktop = $desktop_data[0] if $desktop_data[0]; $desktop_version = $desktop_data[1] if $desktop_data[1]; - $desktop .= ' ' . $desktop_version if $desktop_version; if ($extra > 0 && $desktop_data[3]){ - # $desktop .= ' (' . $desktop_data[2]; - # $desktop .= ($desktop_data[3]) ? ' ' . $desktop_data[3] . ')' : ')'; - $toolkit = "$desktop_data[2] $desktop_data[3]"; + $toolkit = $desktop_data[2]; + $tk_version = $desktop_data[3]; } if ($extra > 2 && $desktop_data[4]){ $desktop_info = $desktop_data[4]; @@ -30638,7 +30950,7 @@ sub system_item { (!$desktop_data[0] || $desktop_data[5] =~ /^(deepin.+|gnome[\s_-]shell|budgie.+)$/i || index(lc($desktop_data[5]),lc($desktop_data[0])) == -1)){ $wm = $desktop_data[5]; - $wm .= ' ' . $desktop_data[6] if $extra > 2 && $desktop_data[6]; + $wm_version = $desktop_data[6] if $extra > 2 && $desktop_data[6]; } } if (!$b_display || (!$desktop && $b_root)){ @@ -30669,8 +30981,14 @@ sub system_item { } $desktop ||= 'N/A'; $data{$data_name}->[$index]{main::key($num++,$cont_desk,1,$desktop_key)} = $desktop; + if ($desktop_version){ + $data{$data_name}->[$index]{main::key($num++,0,2,'v')} = $desktop_version; + } if ($toolkit){ - $data{$data_name}->[$index]{main::key($num++,0,2,'tk')} = $toolkit; + $data{$data_name}->[$index]{main::key($num++,1,2,'tk')} = $toolkit; + } + if ($tk_version){ + $data{$data_name}->[$index]{main::key($num++,0,3,'v')} = $tk_version; } if ($extra > 2){ if ($desktop_info){ @@ -30678,14 +30996,40 @@ sub system_item { } } if ($extra > 1){ - $data{$data_name}->[$index]{main::key($num++,0,2,'wm')} = $wm if $wm; + if ($wm){ + $data{$data_name}->[$index]{main::key($num++,1,2,'wm')} = $wm; + if ($wm_version){ + $data{$data_name}->[$index]{main::key($num++,0,3,'v')} = $wm_version; + } + } if ($extra > 2 && $b_display && defined $ENV{'XDG_VTNR'}){ $data{$data_name}->[$index]{main::key($num++,0,2,'vt')} = $ENV{'XDG_VTNR'}; } my $dms = main::get_display_manager(); + # note: version only present if proper extra level so no need to test again if ($dms || $desktop_key ne 'Console'){ - $dms ||= 'N/A'; - $data{$data_name}->[$index]{main::key($num++,0,$ind_dm,$dm_key)} = $dms; + if ($dms && scalar @{$dms} > 1){ + my $i = 0; + $data{$data_name}->[$index]{main::key($num++,1,$ind_dm,$dm_key)} = ''; + foreach my $dm_data (@{$dms}){ + $i++; + $data{$data_name}->[$index]{main::key($num++,1,($ind_dm + 1),$i)} = $dm_data->[0]; + if ($dm_data->[1]){ + $data{$data_name}->[$index]{main::key($num++,0,($ind_dm + 2),'v')} = $dm_data->[1]; + } + if ($dm_data->[2]){ + $data{$data_name}->[$index]{main::key($num++,0,($ind_dm + 2),'note')} = $dm_data->[2]; + } + } + } + else { + my $dm = ($dms && $dms->[0][0]) ? $dms->[0][0] : 'N/A'; + $data{$data_name}->[$index]{main::key($num++,1,$ind_dm,$dm_key)} = $dm; + if ($dms->[0][1]){ + $data{$data_name}->[$index]{main::key($num++,0,($ind_dm + 1),'v')} = $dms->[0][1]; + } + } + } } # if ($extra > 2 && $desktop_key ne 'Console'){ diff --git a/inxi.1 b/inxi.1 index 356b2d3..7e37418 100644 --- a/inxi.1 +++ b/inxi.1 @@ -15,7 +15,7 @@ .\" with this program; if not, write to the Free Software Foundation, Inc., .\" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. .\" -.TH INXI 1 "2022\-02\-22" "inxi" "inxi manual" +.TH INXI 1 "2022\-03\-24" "inxi" "inxi manual" .SH NAME inxi \- Command line system information script for console and IRC @@ -31,8 +31,9 @@ inxi \- Command line system information script for console and IRC [\fB\-v NUMBER\fR] [\fB\-W LOCATION\fR] [\fB\-\-weather\-unit\fR {\fBm\fR|\fBi\fR|\fBmi\fR|\fBim\fR}] [\fB\-y WIDTH\fR] -\fBinxi\fR [\fB\-\-memory\-modules\fR] [\fB\-\-memory\-short\fR] -[\fB\-\-recommends\fR] [\fB\-\-sensors\-default\fR] [\fB\-\-slots\fR] +\fBinxi\fR [\fB\-\-edid\fR] [\fB\-\-memory\-modules\fR] +[\fB\-\-memory\-short\fR] [\fB\-\-recommends\fR] [\fB\-\-sensors\-default\fR] +[\fB\-\-slots\fR] \fBinxi\fB [\fB\-x\fR|\fB\-xx\fR|\fB\-xxx\fR|\fB\-a\fR] \fB\-OPTION(s)\fR @@ -253,6 +254,17 @@ or \fBrfkill unblock bluetooth\fR +.TP +.B \-\-edid\fR +.br +Triggers full \fBEDID\fR data in Graphics, activates \fB\-G\fR and \fB\-a\fR. + +\- Adds monitor chromacity (\fBchroma: red:..green:...blue:...white:\fR). + +\- Shows all available monitor modes if > 2 present, in comma separated list. + +\- Shows \fBEDID\fR errors and warnings if any present. + .TP .B \-\-filter\fR, \fB\-z\fR .br @@ -295,7 +307,8 @@ Xvesa); for Wayland: GBM/EGL data (not implemented). Compositor information will show if detected using \fB\-xx\fR option or always if detected and Wayland since the compositor is the server with Wayland. -\fB\-Gxx\fR shows monitor data as well, if detected. +\fB\-Gxx\fR shows monitor data as well, if detected. \fB\-\-edid\fR shows +advanced monitor data (full modes, chroma, etc.). .TP .B \-h \fR, \fB\-\-help\fR @@ -770,9 +783,10 @@ of optical drives. .TP .B \-v 8 -\- All system data available. Adds Repos (\fB\-r\fR), PCI slots -(\fB\-\-slots\fR), processes (\fB\-tcm\fR), admin (\fB\-\-admin\fR). Useful for -testing output and to see what data you can get from your system. +\- All system data available. Adds advanced EDID data (\fB\-\-edid\fR), Repos +(\fB\-r\fR), PCI slots (\fB\-\-slots\fR), processes (\fB\-tcm\fR), admin +(\fB\-\-admin\fR). Useful for testing output and to see what data you can get +from your system. .TP .B \-w \fR, \fB\-\-weather\fR @@ -1317,6 +1331,11 @@ distributions for this feature. Due to the complexity of distribution identification, these will only be added as relatively solid methods are found for each distribution system base detection. +.TP +.B \-x \-\-slots\fR +\- Adds \fBbus\-ID:\fR. Note that this bus ID does not unfortunately appear to +be readily detected as the source bus ID for any particular device bus ID. + .TP .B \-x \-t\fR (\fB\-\-processes\fR) \- Adds memory use output to CPU (\fB\-xt c\fR), and CPU use to memory diff --git a/inxi.changelog b/inxi.changelog index 57e3763..0dace8a 100644 --- a/inxi.changelog +++ b/inxi.changelog @@ -1,3 +1,193 @@ +================================================================================ +Version: 3.3.14 +Patch: 00 +Date: 2022-03-24 +-------------------------------------------------------------------------------- +RELEASE NOTES: +-------------------------------------------------------------------------------- + +New version, man. Continuing development of EDID and monitor features, bug +fixes, normal fixes. + +-------------------------------------------------------------------------------- +KNOWN ISSUES: + +1. Failed to handle case for monitor positions of array type: 2-2, 3-1, 1-3, +4-4. I'm not sure what structure those are really arranged in, but might be +worth adding in the x+y pos values along with the row-col values. + +2. For Monitors and graphics Device ports, if using non free nvidia driver and: +nvidia-drm.modeset=1 not set in grub kernel boot parameters, there will be no +/sys/class/drm data for the nvidia device, and thus no ports data, and no +monitor data. + +3. A class of high count DP or DVI port IDs are changed by Xorg drivers to for +example: DP-6 > DP-2-3. This is very difficult to handle and will in general +probably fail unfortunately because that level of port ID abstraction is just +reazlly hard to deal with dynamically. + +4. A to-do item: add bus ID children on --slots. This will probablby be in next +inxi. + +-------------------------------------------------------------------------------- +BUGS: + +1. None outside of the various fixes. + +-------------------------------------------------------------------------------- +FIXES: + +1. In sensors, failed to pull out BAT sensor data. In most cases, this would not +lead to any issues, but it could have. + +2. This one just slipped my mind, I'd meant to do it, but in Montitor-x:, the +primary ID should have been the 'real' kernel ID, not the mapped: ID, which is +the X.org ID when different from the kernel ID. So mapped should be the Xorg +version when they are different from the kernel version. + +3. In Graphics, monitors can show > 1 ratio, failed to set all to :, resulting +in: ratio: 3:2 or 16/10 modes:. Also fixed ParseEDID to output an array of +ratios, which can then be processed as wanted. + +4. Monitor map fixes: +* Handle case in monitors where display ID: eDP and sys ID: eDP-1, this only +works if 1 monitor in array. There's a variety of this type of failure, when +X.org or its drivers decide to call the port ID XYZ with no number at all. All +those possible cases are now handled, like eDP > eDP-1, VGA > VGA-1, and so on. + +* Added fallback, if no match, and if only 1 monitor, just map them to eachother +if other mappings failed. Prompted by things like: s: DP-6 > d: DP-2-3; +s: eDP-1 > d: DP-4, which are just impossible to create logic to map. + +5. Removed 'ati' driver from xorg drivers list, it's simply a wrapper for r128, +mach64, or radeon (and maybe amdgpu), and shows as failed, unloaded, or loaded, +because of this. ati basically assigns the correct driver, that is, but is not +itself a driver. Thanks mrmazda for spotting this issue. + +6. Typo on QDI => Quantum Data. + +7. Added fallback for monitor model, now using vendor code plus product code +if nothing found for vendor nice name or model. This will show as 'model-id:' +instead of model: to help differentiate the two. + +8. Added Monitor product_code to manufacturer if no model name is found. + +9. get_pci_vendor was trimming at ' / ' if the product string also contained +' / '. Fix is to ignore 1 character 'words' in the logic. + +10. In Slots, failed to remove_duplicates in the slot info field, leading to +redundant output strings. See Enhancement 3 and Code 4. + +11. See Change 3, finally made -S section use full key: value pair, which makes +stuff more explicit, like: + +System: + Host: yawn + Kernel: 5.16.0-11.1-liquorix-amd64 + arch: x86_64 + bits: 64 + compiler: gcc + v: 11.2.0 + Desktop: Xfce + v: 4.16.0 + tk: Gtk + v: 3.24.24 + info: xfce4-panel + wm: xfwm + v: 4.16.1 + vt: 7 + dm: + 1: LightDM + v: 1.26.0 + 2: SDDM + note: stopped + Distro: Debian GNU/Linux bookworm/sid + +12. Fix for mageia and lsb distro data, force use of os-release for mageia if +detected. That overrides the forced use of lsb release for mandrake/mandriva, +because for some reason mageia has decided to carry ALL the legacy distro files: +'/etc/lsb-release', +'/etc/lsb-release.d', +'/etc/mageia-release', +'/etc/mandrake-release', +'/etc/mandrakelinux-release', +'/etc/mandriva-release', +'/etc/os-release', +'/etc/redhat-release', +'/etc/system-release' +which is really not what this stuff is intended for, if it's an actual derived +distro from a living base, then yes, include the base file, but all these have +the same distro id data for mageia, none for the derived distros. + +Also, fixed an lsb release thing to avoid using codename if codename contains +release number as well. Since lsb_release is totally legacy at this point, who +cares if we might miss a specific codename here and there on legacy system. + +-------------------------------------------------------------------------------- +ENHANCEMENTS: + +1. Added Color Characteristics to EDID parser, for some reason that had been +left out. + +2. Added advanced EDID output option --edid, that allows for showing more +advanced EDID data than is appropriate for most users cases. Ihcludes errors, +color characteristics chroma: (chromacity), full modes, not just min/max. + +3. In --slots, added bus-ID. + +Also extended report quality, made more granular, got rid of single blob from +Type and Designation and now get more accurate and useful data. + +4. In cases with > 1 DM, check to see if one or more are stopped or disabled, = +and add (stopped) if it was detected in running service as stopped. + +-------------------------------------------------------------------------------- +CHANGES: + +1. Reversed monitor ID and mapped: ID values, that was a mistake, the mapped: +item was supposed to contain the X.org mapped name, and the primary ID was +supposed to be the actual real ID the kernel uses. Not a huge deal either way, +but there it is. + +2. Include disabled but connected Monitors. This works around nvidia bug showing +monitors disabled when they are enabled, but also allows for showing connected +monitors, though without as much data. + +3. Made the last holdout -S > -Sa use strict full key: value pair output, like +Desktop: XFCE v: 4.14.12 and so on. + +-------------------------------------------------------------------------------- +DOCUMENTATION: + +1. Added help/man for --edid info. + +-------------------------------------------------------------------------------- +CODE: + +1. In ParseEDID: made new key: edid_error, which contains an array ref of 1 or +more edid errors. The previous version did a poor job and returned only the +first error found, so there could have been > 1 error, and you'd never know it. + +This changes check_parsed_edid to _check_parsed_edid(). and adds a utility tool +_edid_error, which grabs the message from main::message, giving better output +integration. + +This also allows for future error handling expansion quite easily. + +2. In map_monitor_ids() fixed matching pattern, made more robust and explicit, +to catch things like s: eDP-1 d: eDP or eDP-1-1, both have been seen. Also added +fallback for single monitor, just map them to eachother if mapping failed. + +3. get_pci_vendor() added test for using anything that is 1 character length, +to not break on 1 character length string matches. + +4. Fully refactored --slots, that was originally written purely as a proof of +concept in terms of adding a new feature during the original inxi 2.9 rewrite, +and was never actually touched after that. + +-------------------------------------------------------------------------------- +-- Harald Hope - Thu, 24 Mar 2022 12:01:50 -0800 + ================================================================================ Version: 3.3.13 Patch: 00