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 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
|
#!/bin/bash
# Prototype video quirk database handler that does not rely on HAL.
# only needed on x86, quickly exit on other architectures as this is rather
# expensive
ARCH=`uname -m`
if [ "$ARCH" = "${ARCH%86}" -a "$ARCH" = "${ARCH#x86}" ]; then
exit 0;
fi
shopt -s extglob
. "${PM_FUNCTIONS}"
[[ $PM_DEBUG ]] && {
export PS4='${BASH_SOURCE}@${LINENO}(${FUNCNAME[0]}): ';
set -x
}
possible_video_quirks=" --quirk-dpms-on
--quirk-dpms-suspend
--quirk-s3-mode
--quirk-s3-bios
--quirk-vbe-post
--quirk-vbe-post
--quirk-vga-mode-3
--quirk-vbemode-restore
--quirk-vbestate-restore
--quirk-reset-brightness
--quirk-radeon-off
--quirk-no-fb
--quirk-save-pci"
possible_system_properties="system.firmware.version
system.firmware.vendor
system.firmware.release_date
system.hardware.vendor
system.hardware.product
system.hardware.version
system.board.product
system.board.version
system.board.vendor
system.hardware.primary_video.vendor
system.hardware.primary_video.product
system.hardware.primary_video.driver
system.hardware.primary_video.using_kms
system.kernel.version"
has_video_parameters() {
local p params=$(get_parameters)
[[ $params ]] || return 1
for p in $params; do
[[ $possible_video_quirks = *$p* ]] && return
done
return 1
}
# video specific helper functions.
# Are we using the nVidia binary driver?
using_nvidia() { [[ -d /sys/module/nvidia ]]; }
# How about the ATI one?
using_fglrx() { [[ -d /sys/module/fglrx ]]; }
# OK, what about a driver that is using kernel modesetting?
using_kms() { grep -q -E '(nouveau|drm)fb' /proc/fb; }
# Get some video related values when HAL has not gotten them for us, or
# HAL is not available.
videoget() {
local dev pci
pci="/sys/bus/pci/devices"
for dev in "$pci"/*; do
[[ -f "${dev}/class" ]] || continue
[[ "$(cat "${dev}/class")" = "0x030000" ]] || continue
case $1 in
vendor) RES="$(cat "${dev}/vendor")" ;;
device) RES="$(cat "${dev}/device")" ;;
driver)
if [[ -L ${dev}/driver ]]; then
RES="$(readlink "${dev}/driver")"
RES="${RES##*/}"
elif using_nvidia; then
RES=nvidia
elif using_fglrx; then
RES=fglrx
fi
;;
using_kms)
if using_kms; then
RES=true
else
RES=false
fi
;;
esac
break
done
}
# Get some important information about this system.
# If we have /sys/class/dmi/id, life is easy, and we do not need to
# depend on HAL or dmidecode.
_dmisysget() {
[[ -r /sys/class/dmi/id/$1 ]] || RES=""
read RES < "/sys/class/dmi/id/$1"
}
dmisysget() {
case $1 in
system.firmware.vendor) _dmisysget bios_vendor ;;
system.firmware.version) _dmisysget bios_version ;;
system.firmware.release_date) _dmisysget bios_date ;;
system.hardware.vendor) _dmisysget sys_vendor ;;
system.hardware.product) _dmisysget product_name ;;
system.hardware.version) _dmisysget product_version ;;
system.board.product) _dmisysget board_name ;;
system.board.version) _dmisysget board_version ;;
system.board.vendor) _dmisysget board_vendor ;;
system.hardware.primary_video.vendor) videoget vendor ;;
system.hardware.primary_video.product) videoget device ;;
system.hardware.primary_video.driver) videoget driver ;;
system.hardware.primary_video.using_kms) videoget using_kms ;;
system.kernel.version) RES=$(uname -r) ;;
*) return 1
esac
}
# Get system information using dmidecode. Slow and ugly, but
# should be supported just about everywhere.
_dmidecodeget() {
RES=$(dmidecode -s $1)
}
dmidecodeget() {
case $1 in
system.firmware.vendor) _dmidecodeget bios-vendor ;;
system.firmware.version) _dmidecodeget bios-version ;;
system.firmware.release_date) _dmidecodeget bios-release-date;;
system.hardware.vendor) _dmidecodeget system-manufacturer;;
system.hardware.product) _dmidecodeget system-product-name;;
system.hardware.version) _dmidecodeget system-version;;
system.board.product) _dmidecodeget baseboard-product-name;;
system.board.version) _dmidecodeget baseboard-version;;
system.board.vendor) _dmidecodeget baseboard-manufacturer;;
*) return 1
esac
}
# If we have HAL, it has already done most of the work for us.
halget() {
local hgp="hal-get-property --udi /org/freedesktop/Hal/devices/computer --key"
case $1 in
system.firmware.version) RES=$($hgp "$1") ;;
system.firmware.vendor) RES=$($hgp "$1") ;;
system.firmware.release_date) RES=$($hgp "$1") ;;
system.hardware.vendor) RES=$($hgp "$1") ;;
system.hardware.product) RES=$($hgp "$1") ;;
system.hardware.version) RES=$($hgp "$1") ;;
system.board.product) RES=$($hgp "$1") ;;
system.board.version) RES=$($hgp "$1") ;;
system.board.vendor) RES=$($hgp "$1") ;;
*) return 1
esac
}
canonicalize_dmivar() {
[[ $1 =~ ^[a-z._-]+$ && $possible_system_properties = *$1* ]] || return 1
echo "${1//[-.]/_}"
}
# Precache the DMI and other information we will need as shell variables.
# This will make things easier when we start running for real.
precache_dmivars() {
local p q f
for q in $possible_system_properties; do
p=$(canonicalize_dmivar $q) || return 1
RES=""
for f in dmisysget halget dmidecodeget; do
"$f" "$q" && break || continue 2
done
RES="${RES##+( )}"
RES="${RES%%+( )}"
read "$p" <<<$RES
done
RES=""
}
# Use bash variable indirection to set RES to the actual parameter
# we are looking for. Sanity check the variable we were passed to
# keep things sane.
getprop() {
RES=""
local p
if ! p=$(canonicalize_dmivar $1); then
echo "Unable to obtain DMI information for $1" >&2
exit 1
fi
RES="${!p}"
}
# test to see if the parameter passed is a decimal or hexidecimal number
# Note the complete lack of floating point support.
isnum() {
[[ $1 =~ ^[0-9]+\$ || $1 =~ ^0[xX][0-9a-fA-F]+\$ ]]
}
# for all the matching functions,
# $2 = the given constant (or regular expression),
# $1 = the raw data grabbed from HAL or dmidecode or wherever
regex() { [[ $1 =~ ${2//;/|} ]]; }
regex_ncase() {
local r
shopt -s nocasematch
regex "$1" "$2"
r=$?
shopt -u nocasematch
return $r
}
regex_inverse() { ! regex "$1" "$2"; }
compare_eq() { [[ $1 = $2 ]]; }
compare_ne() { [[ $1 != $2 ]]; }
compare_gt() { [[ $1 > $2 ]]; }
compare_ge() { compare_eq "$@" || compare_gt "$@"; }
compare_lt() { [[ $1 < $2 ]]; }
compare_le() { compare_eq "$@" || compare_lt "$@"; }
numeric_compare_eq() { (( $1 == $2 )); }
numeric_compare_ne() { (( $1 != $2 )); }
numeric_compare_gt() { (( $1 > $2 )); }
numeric_compare_ge() { (( $1 >= $2 )); }
numeric_compare_lt() { (( $1 < $2 )); }
numeric_compare_le() { (( $1 <= $2 )); }
numeric_compare_eq_list() {
local key val
# $1 = key val to compare
# $2 = list to compare to
key=$1
val="${2//;/ }"
for x in $val; do
(( $key == $x )) && return 0
done
return 1
}
# Helper function for nVidia g80 gpus. They require extra special handling
# when not using the nVidia binary driver.
have_nvidia_g80() {
numeric_compare_eq $system_hardware_primary_video_vendor 0x10de || return
numeric_compare_eq_list $system_hardware_primary_video_product \
'0x190;0x191;0x192;0x193;0x194;0x195;0x196;0x197;0x198;0x199;0x19a;0x19b;0x19c;0x19d;0x19e;0x19f;0x400;0x401;0x402;0x403;0x404;0x405;0x406;0x407;0x408;0x409;0x40a;0x40b;0x40c;0x40d;0x40e;0x40f;0x420;0x421;0x422;0x423;0x424;0x425;0x426;0x427;0x428;0x429;0x42a;0x42b;0x42c;0x42d;0x42e;0x42f' || return
}
# Helper function for recent Intel framebuffer drivers.
have_smart_intel() {
local kernel_rev=$system_kernel_revision
local driver=$system_hardware_primary_video_driver
# currently, intel kernel modesetting is not quite smart enough
# we still need acpi s3 kernel modesetting hooks, so don't remove those
# options if they were passed.
[[ $driver = i915 && ( $kernel_rev > 2.6.26 || $kernel_rev = 2.6.26 ) ]]
}
# find the appropriate quirks for this system using the native-format
# quirks database. Since the database is tree-ish, we use some stupid
# recursion tricks.
# $1 = whether to ignore what we are reading
_find_native() {
local action key matcher regex
while read action key matcher regex; do
[[ $action && ${action:0:1} != '#' ]] || continue
case $action in
match)
if [[ $1 = ignore ]]; then
_find_native $1
else
getprop "$key"
[[ $matcher && $regex ]] || find_native ignore
# if this matcher matches, look at nodes farther out.
if $matcher "$RES" "$regex"; then
_find_native work
else
_find_native ignore
fi
fi
;;
endmatch)
[[ $found ]] && return 0 || return 1 ;;
addquirk) [[ $1 = ignore ]] && continue
found=true
add_parameters "$key"
;;
delquirk) [[ $1 = ignore ]]&& continue
found=true
remove_parameters "$key"
;;
esac
done
}
find_native() (
[[ -f $1 ]] || return 1
exec <"$1"
_find_native work
res=$?
get_parameters
return $res
)
# If we resumed, write out the quirks we used as our last known
# working ones for this hardware, kernel, driver, and KMS setting.
write_last_known_working() (
local matcher quirk
precache_dmivars
exec >"$PM_LKW_QUIRKS"
for prop in system.firmware.version system.firmware.vendor \
system.firmware.release_date system.hardware.vendor \
system.hardware.product system.hardware.version \
system.board.product system.board.version system.board.vendor \
system.hardware.primary_video.vendor \
system.hardware.primary_video.product \
system.hardware.primary_video.driver \
system.hardware.primary_video.using_kms \
system.kernel.version; do
getprop "$prop"
if isnum "$RES"; then
matcher=numeric_compare_eq
else
matcher=compare_eq
fi
echo "match $prop $matcher ${RES}"
done
if [[ $QUIRKS ]]; then
for quirk in $QUIRKS; do
echo "addquirk $quirk"
done
else
echo "addquirk --quirk-none"
fi
for ((x=1; x<14; x++)); do
echo endmatch
done
)
case $1 in
suspend|hibernate)
# Aaand.... GO
# cache all the properties we will need.
precache_dmivars
# This logic can also be expressed using entries in the quirkdb,
# but I am too lazy to do that until a final quirk database is
# formalized.
if has_parameter --quirk-test && has_video_parameters; then
# The user is explicitly testing video parameters.
# Use them without the usual filtering. This may cause the system
# to blow up, but they explicitly asked for it.
remove_parameters --quirk-test
echo "Quirk testing mode enabled."
elif using_kms; then
# Using kernel modesetting? No quirks, and do not change vts.
remove_parameters $possible_video_quirks
add_parameters --quirk-no-chvt
echo "Kernel modesetting video driver detected, not using quirks."
elif using_nvidia; then
# Ditto for nVidia binary drivers
remove_parameters $possible_video_quirks
echo "nVidia binary video drive detected, not using quirks."
elif using_fglrx; then
# fglrx may or may not have to change vts, reports one
# way or the other welcome.
remove_parameters $possible_video_quirks
add_parameters --quirk-none
echo "ATI Catalyst driver detected, not using quirks."
elif have_nvidia_g80; then
# nVidia G80 GPUs require special handling when not using nvidia
# binary drivers. I do not know if noveau requires help or not.
remove_parameters $possible_video_quirks
add_parameters --quirk-vbe-post
echo "nVidia g80 series card detected."
else
# Go ahead and get our quirks.
if has_video_parameters; then
# Parameters from the command line take precedence
# over the database, so do not query it.
echo "Using quirks passed as parameters."
elif [[ $PM_QUIRKS ]]; then
# If we have $PM_QUIRKS. use it instead of the quirk database
add_parameters $PM_QUIRKS
echo "Using PM_QUIRKS environment variable for quirks."
# If we were not passed any quirks on the command line,
# get them from the database.
elif QUIRKS=$(find_native "$PM_LKW_QUIRKS"); then
# Known working quirks from our last run are still valid.
# Use them.
add_parameters $QUIRKS
echo "Using last known working set of quirks."
else
# Our known working quirks from the last run are either
# nonexistent or invalid. Either way, start over.
rm "$PM_LKW_QUIRKS" >/dev/null 2>&1
for f in "$PM_QUIRKDB"/*.quirkdb
do
QUIRKS=$(find_native "$f") && break
done
# some default quirks if we did not get any.
if [[ -z $QUIRKS ]]; then
QUIRKS="--quirk-vbe-post --quirk-dpms-on
--quirk-dpms-suspend --quirk-vbestate-restore
--quirk-vbemode-restore --quirk-vga-mode-3"
echo "No quirk database entry for this system, using default."
else
echo "Using quirks for this system from quirk database."
fi
add_parameters $QUIRKS
savestate video_quirks "$QUIRKS"
fi
if have_smart_intel; then
# Intel without KMS does not require most quirks, no matter
# what anything else says. The only ones that seem to
# matter are the --quirk-s3 ones, so remove everything else.
remove_parameters --quirk-dpms-on \
--quirk-dpms-suspend \
--quirk-vbe-post \
--quirk-vbe-post \
--quirk-vga-mode-3 \
--quirk-vbemode-restore \
--quirk-vbestate-restore \
--quirk-reset-brightness \
--quirk-radeon-off \
--quirk-no-fb \
--quirk-save-pci
echo "Cleaning up quirks not needed by Intel video cards."
fi
fi
;;
thaw|resume)
if state_exists video_quirks; then
QUIRKS=$(restorestate video_quirks);
write_last_known_working
echo "Saving last known working quirks: $QUIRKS"
elif has_parameter --store-quirks-as-lkw; then
for x in $(get_parameters); do
for y in $possible_video_quirks; do
[[ $x = $y ]] && QUIRKS=" $QUIRKS $x"
done
done
write_last_known_working
echo "Saving last known working quirks: $QUIRKS"
fi
;;
esac
|