summaryrefslogtreecommitdiffstats
path: root/initrd/initrd-stuff/bin/screenres
blob: 4a9f5fd97b048a20552d19e09528521d6c55ed4c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#!/bin/sh
#
# Author(s):    Felix Endres
#               Dirk von Suchodoletz, 04-07-2006
#
# Copyright:    (c) 2006 - RZ Universitaet Freiburg
#
# Description:
#
# This script gives information about recommended display modes for the 
# attached monitor

# The script tries to guess whether the attached monitor is a lcd or
# a crt based on age, display size and pixel size.
# For CRTs the script tries to determine which screen modes are
# convenient to work with:
# - High resolutions are not recommended for small displays, because
#   everything on the screen would be too tiny.
# - The highest resolution is not recommended if the refresh rate is
#   not known or lower than 80 Hz
# - Though the mode 1400x1050 never shows up in the ddc info, it is
#   Recommended as a replacement for 1600x1200 if that one is not.
#

## For CRTs determine recommended screen modes ####################################################

# enable debugging in higher debug levels
[ -z "$DEBUGLEVEL" ] && DEBUGLEVEL=0
[ $DEBUGLEVEL -gt 1 ] && DEBUG="yes"
# heavy debugging output in level 3 and above ...
[ $DEBUGLEVEL -gt 3 -a $DEBUGLEVEL -lt 8 -o $DEBUGLEVEL -eq 14 ] && set -x

# Define some default output values if the script fails to find better values
# Empty defaults, s.t. hwautocfg defines the defaults
default_horiz_freq_range_khz="" #"31.5-63.5"
default_vert_freq_range_hz=""   #"60-90"
default_recommended_screen_modes="" #'"1024x768" "800x600" "640x480"'


calculate_max_horizontal_freq () {
    highest_resolution=` echo $screen_resolutions | sed -n 's/"\([0-9x]*\)".*/\1/p'`
    [ -z $highest_resolution ] && return # if the highest resolution can not be extracted, the frequency can not be calculated 
    freq_for_highest_res=`sed -n /$highest_resolution'/s/[^@]*@\([0-9]\{2,3\}\).*/\1/p' $tmp_ddcprobe_output | sort -nr|sed -n 1p`
    if [ -z "$freq_for_highest_res" ]; then
        #Search for a number followed by the term "Hz" in the same line as the highest resolution
	freq_for_highest_res=`sed -n /$highest_resolution'/s/.*[^a-zA-Z0-9]\([0-9]\{2,3\}\)[ \t]*[Hh][Zz].*/\1/p' $tmp_ddcprobe_output | sort -nr|sed -n 1p`
    fi
    [ -n "$DEBUG" ] && echo "  # Vertical Frequency for highest resolution.: $freq_for_highest_res"
    if [ -z "$freq_for_highest_res" ]; then
        [ -n "$DEBUG" ] && echo "Vertical Frequency not available. Calculation not possible. Return default value."
        horiz_freq_range_khz=$default_horiz_freq_range_khz
        return
    fi

    highest_res_line_count=` echo $highest_resolution | sed -n 's/.*[0-9]*x//p'`
    [ -n "$DEBUG" ] && echo "  # of lines in highest res.: $highest_res_line_count"
    horiz_freq_khz=$(( $highest_res_line_count * $freq_for_highest_res / 950)) # 950 = 0,95 * 1000 (invisible range * Kilohertz)
    [ -n "$DEBUG" ] && echo "  Assumed Horizontal Frequency: $horiz_freq_khz"
    horiz_freq_range_khz="31.5-$horiz_freq_khz"
}
determine_recommended_crt_modes () {
    ## Introduce the standard resolution 1400x1050 as it is seldom in the list the monitors output, though supported
    [ -n "$DEBUG" ] && echo "Screen Modes: $screen_resolutions"
    if [ -z "`echo $screen_resolutions|sed -n /1400/p`" ]; then
	[ -n "$DEBUG" ] && echo "Inserting 1400x1050 (if 1600x.... is present"
        # Insert "1400x1050" after 1600x.... (of course only if a 1600er res. is there because 1400x1050 would otherwise be listed)
        screen_resolutions=`echo $screen_resolutions|sed  's/\(.*"1600x[0-9]*"\)\(.*\)/\1 "1400x1050"\2/'`
    fi
    # For CRTs check if the highest frequency can be displayed with reasonable refresh rate (> 80Hz)
    highest_resolution=` echo $screen_resolutions | sed -n 's/"\([0-9x]*\)" .*/\1/p'`
    #Search for an @ in the same line as the highest resolution; FIXME: Sort only considers the vertical resolution
    freq_for_highest_res=`sed -n /$highest_resolution'/s/[^@]*@\([0-9]\{2,3\}\).*/\1/p' $tmp_ddcprobe_output | sort -nr|sed -n 1p`
    #echo $freq_for_highest_res
    if [ -z "$freq_for_highest_res" ]; then
        #Search for a number followed by the term "Hz" in the same line as the highest resolution
	freq_for_highest_res=`sed -n /$highest_resolution'/s/.*[^a-zA-Z0-9]\([0-9]\{2,3\}\)[ \t]*[Hh][Zz].*/\1/p' $tmp_ddcprobe_output | sort -nr|sed -n 1p`
    fi
    # Assure that the highest resolution is removed if we do not know at what refresh rate it is displayed
    # Chances are it would be flickering at that resolution
    if [ -z "$freq_for_highest_res" ]; then 
        freq_for_highest_res=75 # Assume 75 Hz to be the least a monitor is able to do.
    fi
    # Cut the first resolution if it is displayed with less than 85Hz
    # It's assumed here, that the second best resolution will be displayed with > 85Hz
    if [ $freq_for_highest_res -lt 85 ]; then
        screen_resolutions=` echo $screen_resolutions | sed -n 's/"[0-9x]*" \(.*\)/\1/p'`
    fi
    define_max_recommended_horizontal_pixel_count # sets max_wanted_resolution
#    max_wanted_resolution="$?"
    [ -n "$DEBUG" ] && echo "  The screen is too small for resolutions greater than ${max_wanted_resolution}x...."
    # Fetch the first resolution in the list
    new_highest_resolution=` echo $screen_resolutions | sed -n 's/"\([0-9x]*\)" .*/\1/p'`
    [ -n "$DEBUG" ] && echo "  new highest resolution: $new_highest_resolution"
    new_highest_horizontal_resolution=`echo $new_highest_resolution | sed -n 's/\([0-9]*\)x.*/\1/p'`
    [ -n "$DEBUG" ] && echo "  new_highest_horizontal_resolution: $new_highest_horizontal_resolution"
    while [ $new_highest_horizontal_resolution -gt $max_wanted_resolution ]; do
      # Cut the highest resolution because the display size is to small for it to be convenient
      screen_resolutions=` echo $screen_resolutions | sed -n 's/"[0-9x]*" \(.*\)/\1/p'`
      new_highest_resolution=` echo $screen_resolutions | sed -n 's/"\([0-9x]*\)".*/\1/p'`
      [ -n "$DEBUG" ] && echo "  new highest resolution: $new_highest_resolution"
      new_highest_horizontal_resolution=`echo $new_highest_resolution | sed -n 's/\([0-9]*\)x.*/\1/p'`
      [ -n "$DEBUG" ] && echo "  new_highest_horizontal_resolution: $new_highest_horizontal_resolution"
    done
    ##########
}

define_max_recommended_horizontal_pixel_count () {
    ## To high resolutions are not wanted on small screens #####################################
    # For 15 inch and below
    if [ $screen_size_in_qcm -lt 704 ]; then max_wanted_resolution=1024
    # For 15" to 17"
    elif [ $screen_size_in_qcm -lt 918 ]; then max_wanted_resolution=1280
    # For 17" to 19"
    elif [ $screen_size_in_qcm -gt 1121 ]; then max_wanted_resolution=1400
    else max_wanted_resolution=50000 # Accept any resolution on Monitors above 19"
    fi
    [ -n "$DEBUG" ] && echo "  Max. recommended resolution: $max_wanted_resolution"
    #return $max_wanted_resolution
}


#TODO command line arguments processing (--help --defaults)
tmp_ddcprobe_output=$1
if [ -z $tmp_ddcprobe_output ]; then
    tmp_ddcprobe_output=/tmp/ddcprobe_output
    ddcprobe | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" \
      > ${tmp_ddcprobe_output} 
fi
# fixme: parameter I is not compatible with busybox - how to circumvent?
failed=`sed -n '/edid.*failed/p' ${tmp_ddcprobe_output}`
if [ -n "$failed" ]; then
    echo "Error: Display seems to be incapable of providing DDC Information"
    # Print Defaults OPTIMIZEME: The defaults could be command line parameters
    echo "Recommended Screen Modes: $default_recommended_screen_modes" 
    echo "Horizontal Frequency Range (kHz): $default_horiz_freq_range_khz"
    echo "Vertical Frequency Range (Hz): $default_vert_freq_range_hz"
    exit 1;
fi
screen_size_in_qcm=$((`sed -n "s/screen.*size[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\).*/\1 *  \2/p" ${tmp_ddcprobe_output}`))
max_pixels=$((`echo "\`sed -n '/edid/,$s/.*[ \t]\([0-9]\{3,4\}\)x\([0-9]\{3,4\}\).*/\2 * \1/p' ${tmp_ddcprobe_output}|sort -rn| sed -n 1p\`"`))
manufacturing_year=`sed -n 's/manufact.*\([12][90][0-9][0-9]\).*/\1/p' ${tmp_ddcprobe_output}`

[ -n "$DEBUG" ] && echo "Maximal Resolution: $max_pixels"
#                                                                640x400 (below)
if [ -z $screen_size_in_qcm ] || [ -z $manufacturing_year ] || [ 256000 -gt $max_pixels ] ; then
    echo "Error: Display seems to be incapable of providing all relevant DDC Information"
    # Print Defaults OPTIMIZEME: The defaults could be command line parameters
    echo "Recommended Screen Modes: $default_recommended_screen_modes" 
    echo "Horizontal Frequency Range (kHz): $default_horiz_freq_range_khz"
    echo "Vertical Frequency Range (Hz): $default_vert_freq_range_hz"
    exit 1;
fi

## Determine probabilitiy for TFT ###########################################
pix_per_qcm=$(($max_pixels/$screen_size_in_qcm))
echo "Display size:	$screen_size_in_qcm qcm"
echo "Max Pixels per qcm:	$pix_per_qcm"
echo "Manufacturing year:	$manufacturing_year"
# Set probability for having an LCD by means of age and size
# 15" ~ 30.6cm x 23cm
# 17" ~ 34cm x 27cm (17,1")
# 19" ~ 38,6cm x 29cm
# if older than 1998 it is most probably not a LCD
if [ $manufacturing_year -lt 1998 ] ;then tft_probability=1
# if older than 2002 is probably no LCD, especially if larger than 15"
elif [ $manufacturing_year -lt 2002 ];then 
    if [ $screen_size_in_qcm -gt 704 ]; then tft_probability=1
    else tft_probability=20
    fi
# if older than 2003 is maybe no LCD, yet for sure if larger than 17"
elif [ $manufacturing_year -lt 2003 ];then 
    if [ $screen_size_in_qcm -gt 918 ]; then tft_probability=5
    else tft_probability=40
    fi
# if older than 2005 is probable an LCD, but not if larger than 19"
elif [ $manufacturing_year -lt 2005 ];then 
    if [ $screen_size_in_qcm -gt 1121 ]; then tft_probability=10
    else tft_probability=60
    fi
# in 2005 few people would buy a (new) CRT
elif [ $manufacturing_year -lt 2006 ];then tft_probability=90 
# after 2006 nobody would buy a new CRT
else tft_probability=99
fi
if [ $pix_per_qcm -gt 1599 ]; then tft_probability=$(($tft_probability - 15))
else tft_probability=$(($tft_probability + 15))
fi
if [ -n "$DEBUG" ];then
    echo -ne "Is a TFT: "
    if [ $tft_probability -ge 50 ]; then
	echo -n "true"
    else echo -n "false"
    fi
    echo " ($tft_probability)"
fi

# Find the lines with two times 3 to 4 digits delimited by an x. Print with the two values reverted, so sort sorts w.r.t the 2nd value. Then swap back
# Minor problem: If two Modes are found in a line, the second one is used.
screen_resolutions=`sed -n '/edid/,$s/\(.*[ \t]\)*\([0-9]\{3,4\}\) *x *\([0-9]\{3,4\}\).*/\3 x \2/p' ${tmp_ddcprobe_output}| sort -rn | sort -rnu | sed -n 's/\([0-9]\{3,4\}\) x \([0-9]\{3,4\}\).*/"\2x\1"/p' `
screen_resolutions=`echo $screen_resolutions`
echo "Supported Screen Modes: $screen_resolutions"



######## Vertical and horizontal frequency ranges #########
# find a line with the word range and and numbers with a minus in the middle (e.g 123-321)
frequency_ranges=`sed '/range/!d;s/[^0-9]*\([1-9][0-9]\)[ \t]*-[ \t]*\([1-9][0-9]*\)[^0-9]*\([1-9][0-9]*\)[ \t]*-[ \t]*\([1-9][0-9]*\).*/\1-\2 \3-\4/' ${tmp_ddcprobe_output}`

set -- $frequency_ranges # split into $1 und $2 
if [ -z "$frequency_ranges" ] && [ $tft_probability -lt 50 ]; then
    calculate_max_horizontal_freq # gives us $horiz_freq_range_khz
    horiz_freq_range="$horiz_freq_range_khz"
else horiz_freq_range=$1
fi
########################################


if [ $tft_probability -lt 50 ]; then
    determine_recommended_crt_modes;
fi

echo "Recommended Screen Modes: $screen_resolutions"

#Fixme: How to Calculate the Vertical Refresh rate?
echo "Horizontal Frequency Range (kHz): $horiz_freq_range"
echo "Vertical Frequency Range (Hz): $2"