/[soft]/drakx-kbd-mouse-x11/trunk/tools/display_driver_helper
ViewVC logotype

Contents of /drakx-kbd-mouse-x11/trunk/tools/display_driver_helper

Parent Directory Parent Directory | Revision Log Revision Log


Revision 959 - (show annotations) (download)
Wed Apr 20 01:10:30 2011 UTC (9 years, 2 months ago) by anssi
File size: 12691 byte(s)
Fix ahead-of-X-server loading of proprietary and fglrx kernel modules.
1 #!/bin/sh
2 #
3 # Display driver helper
4 #
5 # Copyright (c) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi>
6 #
7 # - Load drivers for specified modaliases, skipping disabled display drivers
8 # that would cause conflicts (KMS vs. vesa, KMS vs. proprietary).
9 # - Get information about enabled driver modules
10 # - Check that the loaded modules are correct
11 #
12 # Licensed under terms of GPLv2 or later.
13 #
14 # When updating, check:
15 # - the variables below
16 # - check_driver function
17 # - check_dkms_status function
18 #
19
20 if [ -n "$DEBUG_DISPLAY_DRIVER_HELPER" ]; then
21 echo "$(date) $*" >> /dev/ddh_debug
22 exec 2>>/dev/ddh_debug
23 set -x
24 fi
25
26 export LC_ALL=C
27
28 KMS_DRIVERS="i915 radeon nouveau"
29 # module names at run-time (hence nvidia instead of nvidia*):
30 KNOWN_MODULES="i915|radeon|nouveau|fglrx|nvidia"
31
32 XORG_i915="intel"
33 CONFLICTS_i915=""
34
35 XORG_nouveau="nouveau"
36 CONFLICTS_nouveau="nv nvidia"
37
38 XORG_radeon="ati radeon"
39 CONFLICTS_radeon="fglrx"
40
41 # Note: no /usr
42 # See end of script for descriptions of global variables.
43 check_driver() {
44 local name="$1"
45 case "$name" in
46 i915)
47 # implicitely loaded by X.org
48 check_xorg $name 0 || return 1
49 IS_KMS=1
50 ;;
51 radeon)
52 # implicitely loaded by X.org
53 check_xorg $name 0 || return 1
54 IS_KMS=1
55 # radeon needs to loaded before X server
56 NEEDS_LOAD_NOW=1
57 ;;
58 nouveau)
59 # these KMS drivers require an explicit directive in xorg.conf
60 check_xorg $name 1 || return 1
61 IS_KMS=1
62 ;;
63 fglrx)
64 check_xorg fglrx 1 || return 1
65 check_dkms fglrx || return 1
66 ;;
67 nvidia)
68 # manually installed driver or a call from check_loaded()
69 UNSURE=1
70 check_xorg nvidia 1 || return 1
71 ;;
72 nvidiafb)
73 # this is only reached if nvidiafb is manually unblacklisted
74 return 2
75 ;;
76 nvidia*)
77 [ "$name" = "nvidia_current" ] && name=nvidia-current
78 # there are multiple co-installable driver versions, so check
79 # the active alternative as well
80 check_gl /etc/$name/ld.so.conf || return 1
81 check_xorg nvidia 1 || return 1
82 check_dkms $name || return 1
83 ;;
84 *)
85 # unknown, will be loaded only if no known drivers were found
86 return 2
87 ;;
88 esac
89 return 0
90 }
91
92 # Return success if there is no new pending DKMS build (needed to disallow
93 # speedboot on very early boot).
94 # Previously failed build or a missing module is counted as no pending build.
95 # Note: no /usr
96 check_dkms_status() {
97 [ -e /etc/alternatives/gl_conf ] || return 0
98 # return fast for non-DKMS
99 check_gl /etc/ld.so.conf.d/GL/standard.conf && return 0
100
101 local active="$(ls -l /etc/alternatives/gl_conf | awk '{ print $NF }')"
102
103 local modname=
104
105 case $active in
106 /etc/nvidia*/ld.so.conf)
107 modname="nvidia${active#*nvidia}"
108 modname="${modname%/*}"
109 ;;
110 /etc/ld.so.conf.d/GL/ati.conf)
111 modname="fglrx"
112 ;;
113 *)
114 # Unknown DKMS-looking driver,
115 # allow speedboot.
116 return 0
117 ;;
118 esac
119 check_dkms "$modname" 1
120 }
121
122 # Check if all loaded kernel modules have correct xorg.conf
123 check_loaded() {
124 for module in $(grep -oE "^($KNOWN_MODULES) " /proc/modules); do
125 check_driver "$module" || return 1
126 done
127 return 0
128 }
129
130 # Check that specified DKMS driver is not queued for build for the current
131 # kernel. Used to check if we 1) should disable speedboot for this boot
132 # (--check-dkms-status), and 2) if should should load the currently
133 # existing driver (--load). Doing otherwise might cause us to load a wrong old
134 # version of the driver that had been installed using e.g. binary DKMS
135 # packages.
136 # Note: no /usr
137 check_dkms() {
138 local driver="$1"
139 local force="$2"
140
141 # If called from DKMS itself or we are not in rc.sysinit anymore,
142 # there are no pending builds.
143 if [ -z "$force" ]; then
144 [ "$DKMS_AUTOLOAD_MODULE" = "$driver" ] && return 0
145 [ -z "$STARTUP" ] && [ ! -f "/dev/.in_sysinit" ] && return 0
146 fi
147
148 local found=
149 local uname_r="$(uname -r)"
150
151 for dir in /var/lib/dkms/$driver/*; do
152 [ -e "$dir" ] || return 0 # no module, no build; or no /var
153 [ -L "$dir" ] && continue # not a module version
154 found=1 # module version found
155 [ -e "$dir/$uname_r" ] && return 0
156 [ -e "/var/lib/dkms-binary/$driver/$(basename "$dir")/$uname_r" ] && return 0
157
158 if [ -e "$dir/build/make.log" ]; then
159 # Build has failed for some kernel, check if it is this one.
160 # If so, there is no point in returning 1.
161 grep -q "^DKMS make\.log.* $uname_r " && return 0
162 fi
163 done
164
165 # if module versions were found but none were built for this kernel, return 1
166 [ -n "$found" ] && return 1 || return 0
167 }
168
169 # Note: no /usr
170 check_gl() {
171 local alt_inode="$(stat -L -c%i $1 2>/dev/null)"
172 [ -n "$alt_inode" ] || return 1
173 [ -n "$GL_INODE" ] || GL_INODE="$(stat -L -c%i /etc/alternatives/gl_conf 2>/dev/null)"
174 [ "$alt_inode" = "$GL_INODE" ] || return 1
175 return 0
176 }
177
178 # Note: no /usr
179 get_xorg_drivers() {
180 if [ -z "$XORG_DRIVERS" ]; then
181 XORG_DRIVERS="$(cat /etc/X11/xorg.conf /etc/X11/xorg.conf.d/*.conf 2>/dev/null |
182 awk -F'"' -vORS=' ' -vIGNORECASE=1 '
183 /^[[:space:]]+*section[[:space:]]+"device"/ { device=1 }
184 /endsection/ { device=0 }
185 /^[[:space:]]*driver[[:space:]]*".*"/ { if (device) drivers[$2]=$2 }
186 END { for (driver in drivers) print driver }
187 ')"
188 [ -n "$XORG_DRIVERS" ] || XORG_DRIVERS="-"
189 fi
190 }
191
192 # Note: no /usr
193 # parameter 1: xorg driver
194 # parameter 2: 1 the check if the driver is explicitely enabled
195 # 0 means that check only for conflicts
196 check_xorg() {
197 local driver="$1"
198 local explicit_only="$2"
199
200 eval local xorg_drivers=\"\$XORG_$driver\"
201 [ -n "$xorg_drivers" ] || xorg_drivers="$driver"
202 eval local conflicts=\"\$CONFLICTS_$driver\"
203
204 get_xorg_drivers
205
206 conflict_found=
207 for enabled_driver in $XORG_DRIVERS; do
208 for xorg_driver in $xorg_drivers; do
209 [ "$enabled_driver" = "$xorg_driver" ] && return 0
210 done
211
212 # if the X.org driver can be loaded implicitely, check that
213 # there are no conflicting drivers that override the driver
214 if [ "$explicit_only" = "0" -a -z "$conflict_found" ]; then
215 for conflict in vesa $conflicts; do
216 if [ "$enabled_driver" = "$conflict" ]; then
217 conflict_found=1
218 continue 2
219 # continue loop to check for an explicit load
220 fi
221 done
222 fi
223 done
224
225 # in case of a conflict, do not load the module
226 [ -n "$conflict_found" ] && return 1
227
228 # no driver is selected - don't load if explicit_only is 1
229 [ "$explicit_only" = "1" ] && return 1
230
231 # implicit load allowed; still don't load if no xorg.conf (i.e. live cd)
232 [ -e "/etc/X11/xorg.conf" ]
233 }
234
235 # Load the driver for the specified modalias, if configured.
236 # Note: no /usr
237 load_driver() {
238 local modulename
239 local load_default=1
240
241 # NOTE: UPDATE when module-init-tools is upgraded to get better performance
242 # modprobe has -R option:
243 #for modulename in $(/home/anssi/module-init-tools-3.12/build/modprobe -Rq "$1"); do
244 # modprobe does not have -R option:
245 for mod in $(/sbin/modprobe -biqvn "$1"); do
246 [ "$mod" = "insmod" ] && continue
247 modulename="${mod##*/}"
248 modulename="${modulename%%.*}"
249
250 check_driver "$modulename"
251 case $? in
252 1) # a driver which needs handling by this script matches
253 # the modalias, but was not configured - do not run
254 # the generic modprobe if no other drivers are
255 # configured either
256 load_default=
257 continue
258 ;;
259 2) continue
260 ;;
261 esac
262
263 if [ -n "$IS_KMS" ]; then
264 grep -q "^$modulename " /proc/modules && return 0
265 echo "$modulename" > /dev/.late_kms 2>/dev/null
266 # If NEEDS_LOAD_NOW is not set and plymouth is running,
267 # skip loading the driver to avoid quitting plymouth.
268 # The driver will be loaded later by X server itself.
269 [ -z "$NEEDS_LOAD_NOW" ] && /bin/plymouth --ping 2>/dev/null && return 0
270 /bin/plymouth quit 2>/dev/null
271 fi
272 /sbin/modprobe -b "$modulename" && return 0
273 done
274
275 # no specially handled modules were loaded, so load all modules normally
276 # unless $load_default was set above
277 [ -z "$load_default" ] || /sbin/modprobe -b "$1"
278 }
279
280 is_kms_allowed() {
281 for driver in $KMS_DRIVERS; do
282 # Check all drivers for conflicts only.
283 check_xorg $driver 0 || return 1
284 done
285 return 0
286 }
287
288 get_initrd_kms_drivers() {
289 local initrd="$1"
290
291 local kms_drivers="$(echo "$KMS_DRIVERS" | tr " " "|")"
292 zcat "$initrd" | cpio -t --quiet | sed -nr "s,.*/($kms_drivers)\.ko.*$,\1,p"
293 }
294
295 # Check that the initrd doesn't contain disabled modules
296 check_initrd() {
297 local initrd="$1"
298 local initrd_drivers="$(get_initrd_kms_drivers "$initrd")"
299 for driver in $initrd_drivers; do
300 check_driver "$driver" || return 1
301 done
302 for driver2 in $(get_active_kms_drivers); do
303 for driver in $initrd_drivers; do
304 [ "$driver" = "$driver2" ] && continue 2
305 done
306 # An enabled module for present hardware was not in initrd
307 return 1
308 done
309 return 0
310 }
311
312 get_active_kms_drivers() {
313 local kms_drivers=
314 for device in $(grep -l 0x03 /sys/bus/pci/devices/0000\:0*/class); do
315 [ -e "$device" ] || continue
316 device="$(dirname $device)"
317 [ -f "$device/modalias" ] || continue
318 modalias="$(cat "$device/modalias")"
319 for mod in $(/sbin/modprobe --first-time -biqvn "$modalias" 2>&1); do
320 modulename="${mod##*/}"
321 modulename="${modulename%%.*}"
322 IS_KMS=
323 check_driver "$modulename" || continue
324 [ -n "$IS_KMS" ] && echo $modulename
325 done
326 done
327 }
328
329 usage() {
330 cat <<EOF
331 Usage: $0 action [arguments]
332
333 Known actions:
334
335 --load MODALIAS
336 Load drivers matching MODALIAS, checking that they are enabled and
337 configured.
338
339 --load-dkms-autoload MODNAME MODALIAS
340 Same as --load, but assume MODNAME is built and correct so that
341 checking dkms status is unnecessary.
342
343 --is-disabled MODNAME
344 Checks whether the driver corresponding to MODNAME is disabled (e.g.
345 a conflicting driver is configured, etc.). Unknown MODNAMEs are
346 considered not disabled.
347
348 --is-enabled-kms MODNAME
349 Checks whether the driver corresponding to MODNAME is enabled and
350 MODNAME is a known KMS module. Note that drivers may be enabled even
351 if there is no such hardware. This just checks that there are
352 no conflicting drivers in use etc.
353
354 --is-kms-allowed
355 Checks whether it is ok to load KMS drivers in initrd. This returns
356 a failure when a conflicting driver is set up (vesa or a proprietary
357 one).
358
359 --get-all-kms-drivers
360 Get a list of the known KMS drivers.
361
362 --get-active-kms-drivers
363 Get a list of the known KMS drivers which are enabled and the hardware
364 is present.
365
366 --get-initrd-kms-drivers INITRD
367 Get a list of the known KMS drivers in initrd INITRD.
368
369 --check-dkms-status
370 Checks if there are no pending DKMS builds for the currently enabled
371 drivers.
372
373 --check-loaded
374 Checks that there are no disabled drivers loaded.
375
376 --check-speedboot
377 Does --check-dkms-status and --check-loaded.
378
379 --check-loaded-strict
380 As --check-loaded, and consider ambigious cases (e.g. nvidia where
381 we can't detect if the loaded driver has the correct version) as
382 failure.
383
384 --check-initrd INITRD
385 Check that INITRD doesn't contain disabled KMS drivers.
386 EOF
387 }
388
389 # clear global variables
390
391 # cache for check_gl()
392 GL_INODE=
393
394 # cache for check_xorg()
395 XORG_DRIVERS=
396
397 # The driver is a KMS enabled driver. This will cause the script to quit
398 # plymouth when a driver is loaded by --load and NEEDS_LOAD_NOW below is set.
399 # This is done as plymouth is still attached to the default framebuffer (the
400 # issues caused by not doing this don't seem to be fatal, though, but the
401 # display may be lost completely until plymouth eventually stops).
402 # There is no option in plymouth to "reload" a driver, it expects any KMS
403 # driver to be loaded be before starting it.
404 IS_KMS=
405
406 # This KMS driver needs to be loaded before X server starts, so load it now
407 # even if we have to shut down plymouth (see above).
408 NEEDS_LOAD_NOW=
409
410 # dkms module that was built when calling from DKMS
411 DKMS_AUTOLOAD_MODULE=
412
413 # Set by check_loaded() when it can't be sure that the correct driver is loaded
414 # (e.g. in case of the multiple proprietary nvidia drivers which all identify as
415 # "nvidia" in loaded modules list).
416 UNSURE=
417
418 case "$1" in
419 --load)
420 load_driver "$2"
421 ;;
422 --load-dkms-autoload)
423 DKMS_AUTOLOAD_MODULE="$2"
424 load_driver "$3"
425 ;;
426 --is-disabled)
427 check_driver "$2"
428 [ $? -eq 1 ]
429 # unknown (2) are not considered disabled :)
430 ;;
431 --is-enabled-kms)
432 check_driver "$2" && [ -n "$IS_KMS" ]
433 ;;
434 --is-kms-allowed)
435 is_kms_allowed
436 ;;
437 --check-dkms-status)
438 check_dkms_status
439 ;;
440 --get-all-kms-drivers)
441 echo $KMS_DRIVERS
442 ;;
443 --get-active-kms-drivers)
444 get_active_kms_drivers
445 ;;
446 --get-initrd-kms-drivers)
447 get_initrd_kms_drivers "$2"
448 ;;
449 --check-initrd)
450 check_initrd "$2"
451 ;;
452 --check-loaded)
453 check_loaded
454 ;;
455 --check-loaded-strict)
456 check_loaded && [ -z "$UNSURE" ]
457 ;;
458 --check-speedboot)
459 check_dkms_status && check_loaded
460 ;;
461 *)
462 usage
463 ;;
464 esac

  ViewVC Help
Powered by ViewVC 1.1.28