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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 959 - (hide annotations) (download)
Wed Apr 20 01:10:30 2011 UTC (13 years ago) by anssi
File size: 12691 byte(s)
Fix ahead-of-X-server loading of proprietary and fglrx kernel modules.
1 anssi 912 #!/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 anssi 958 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 anssi 912
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 anssi 959 [ -n "$xorg_drivers" ] || xorg_drivers="$driver"
202 anssi 912 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.30