Skąd jądro Linuksa wie, gdzie szukać firmware sterowników?

Kompiluję własne jądro pod Ubuntu i mam problem, że moje jądro nie wie, gdzie szukać firmware ' u. Pod Ubuntu 8.04 oprogramowanie układowe jest powiązane z wersją jądra tak samo jak moduły sterowników. Na przykład, kernel 2.6.24-24-generic przechowuje swoje moduły jądra w:

/lib/modules/2.6.24-24-generic

I jego firmware w:

/lib/firmware/2.6.24-24-generic

Kiedy kompiluję 2.6.24-24-generyczne jądro Ubuntu według " alternatywna metoda budowania: staromodny Debian Sposób " dostaję odpowiedni katalog modułów i wszystkie moje urządzenia działają z wyjątkiem tych wymagających oprogramowania układowego, takiego jak moja karta bezprzewodowa Intel (moduł ipw2200).

Dziennik jądra pokazuje na przykład, że gdy ipw2200 próbuje załadować firmware, podsystem jądra kontrolujący Ładowanie firmware nie jest w stanie go zlokalizować:

ipw2200: Detected Intel PRO/Wireless 2200BG Network Connection
ipw2200: ipw2200-bss.fw request_firmware failed: Reason -2

Errno-baza.h definiuje to jako:

#define ENOENT       2  /* No such file or directory */

(funkcja zwracająca ENOENT stawia minus przed nim.)

Próbowałem stworzyć dowiązanie symboliczne w /lib / firmware, gdzie nazwa mojego jądra wskazywała na katalog 2.6.24-24-generic, jednak spowodowało to ten sam błąd. To oprogramowanie nie jest GPL, dostarczone przez Intela i spakowane przez Ubuntu. Nie wierzę, że ma to jakikolwiek związek z konkretną wersją jądra. cmp pokazuje, że wersje w różnych katalogach są identyczne.

Skąd jądro wie, gdzie szukać firmware?

Update

Znalazłem To rozwiązanie dokładnie mam problem, jednak już nie działa, ponieważ Ubuntu wyeliminowało /etc/hotplug.d i nie przechowuje już swojego firmware w /usr/lib/hotplug/firmware.

Update2

Kolejne badania wykazały więcej odpowiedzi. Do wersji 92 udev, program firmware_helper to sposób, w jaki firmware został załadowany. Począwszy od udev 93 program ten został zastąpiony skryptem o nazwie firmware.sh zapewnienie identycznej funkcjonalności, o ile mogę powiedzieć. Oba te hardcode firmware ścieżka do /lib/firmware. Ubuntu nadal używa /lib/udev/firmware_helper binarnego.

Nazwa pliku firmware jest przekazywana do firmware_helper w zmiennej środowiskowej $FIRMWARE, która jest łączona ze ścieżką /lib/firmware i używana do ładowania firmware.

[19]} rzeczywiste żądanie załadowania firmware jest dokonywane przez sterownik (w moim przypadku ipw2200) za pomocą wywołania systemowego:
request_firmware(..., "ipw2200-bss.fw", ...);

Teraz gdzieś pomiędzy sterownikiem wywołującym request_firmware i firmware_helper patrząc na zmienną środowiskową $FIRMWARE, Nazwa pakietu jądra jest przygotowanie do nazwy firmware.

Więc kto to robi?
Author: wallyk, 2009-06-04

4 answers

Z punktu widzenia jądra, zobacz /usr/src / linux/Documentation/firmware_class / README:

 kernel(driver): calls request_firmware(&fw_entry, $FIRMWARE, device)

 userspace:
        - /sys/class/firmware/xxx/{loading,data} appear.
        - hotplug gets called with a firmware identifier in $FIRMWARE
          and the usual hotplug environment.
                - hotplug: echo 1 > /sys/class/firmware/xxx/loading

 kernel: Discard any previous partial load.

 userspace:
                - hotplug: cat appropriate_firmware_image > \
                                        /sys/class/firmware/xxx/data

 kernel: grows a buffer in PAGE_SIZE increments to hold the image as it
         comes in.

 userspace:
                - hotplug: echo 0 > /sys/class/firmware/xxx/loading

 kernel: request_firmware() returns and the driver has the firmware
         image in fw_entry->{data,size}. If something went wrong
         request_firmware() returns non-zero and fw_entry is set to
         NULL.

 kernel(driver): Driver code calls release_firmware(fw_entry) releasing
                 the firmware image and any related resource.

Jądro nie ładuje żadnego firmware ' u. Po prostu informuje userspace: "chcę firmware o nazwie xxx" i czeka aż userspace przekieruje obraz firmware z powrotem do jądra.

Teraz, na Ubuntu 8.04,

$ grep firmware /etc/udev/rules.d/80-program.rules
# Load firmware on demand
SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware_helper"

Więc jak już odkryłeś, udev jest skonfigurowane do uruchamiania firmware_helper, gdy jądro prosi o firmware.

$ apt-get source udev
Reading package lists... Done
Building dependency tree
Reading state information... Done
Need to get 312kB of source archives.
Get:1 http://us.archive.ubuntu.com hardy-security/main udev 117-8ubuntu0.2 (dsc) [716B]
Get:2 http://us.archive.ubuntu.com hardy-security/main udev 117-8ubuntu0.2 (tar) [245kB]
Get:3 http://us.archive.ubuntu.com hardy-security/main udev 117-8ubuntu0.2 (diff) [65.7kB]
Fetched 312kB in 1s (223kB/s)
gpg: Signature made Tue 14 Apr 2009 05:31:34 PM EDT using DSA key ID 17063E6D
gpg: Can't check signature: public key not found
dpkg-source: extracting udev in udev-117
dpkg-source: unpacking udev_117.orig.tar.gz
dpkg-source: applying ./udev_117-8ubuntu0.2.diff.gz
$ cd udev-117/
$ cat debian/patches/80-extras-firmware.patch

Jeśli przeczytasz źródło, okaże się, że Ubuntu napisał firmware_helper, który jest ciężko zakodowany, aby najpierw poszukać /lib/modules/$(uname -r)/$FIRMWARE, a następnie /lib/modules/$FIRMWARE, i żadnych innych lokalizacji. Tłumaczenie na sh, robi to w przybliżeniu tak:

echo -n 1 > /sys/$DEVPATH/loading
cat /lib/firmware/$(uname -r)/$FIRMWARE > /sys/$DEVPATH/data \
    || cat /lib/firmware/$FIRMWARE      > /sys/$DEVPATH/data
if [ $? = 0 ]; then
    echo -n  1 > /sys/$DEVPATH/loading
    echo -n -1 > /sys/$DEVPATH/loading
fi

Który jest dokładnie takim formatem, jakiego oczekuje jądro.


Krótko mówiąc: pakiet Ubuntu udev mA modyfikacje, które zawsze pojawiają się w /lib/firmware/$(uname -r) jako pierwsze. Ta polityka jest obsługiwana w przestrzeni użytkownika.

 40
Author: ephemient,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-04 22:15:23

Wow to bardzo przydatna informacja i doprowadziła mnie do rozwiązania mojego problemu podczas tworzenia niestandardowego modułu jądra USB dla urządzenia wymagającego oprogramowania układowego.

Zasadniczo, każde Ubuntu przynosi nowe odświeżenie hal, sysfs, devfs,udev i tak dalej...i wszystko się zmienia. Czytałem, że przestali używać Hala.

Więc powtórzmy to jeszcze raz, aby było odpowiednie dla najnowszych systemów [Ubuntu].

Na Ubuntu Lucid (ostatni w momencie pisania), /lib/udev/rules.d/50-firmware.rules jest używany. Plik ten wywołuje binarny /lib/udev/firmware, w którym dzieje się magia.

Listing: / lib/udev / rules.d / 50-firmware.Zasady

# firmware-class requests, copies files into the kernel
SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware --firmware=$env{FIRMWARE} --devpath=$env{DEVPATH}"

Magia powinna być czymś w tym stylu (Źródło: Linux Device Drivers, 3rd Ed., Ch. 14: Model Urządzenia Linux):

  • echo 1 do loading
  • skopiuj firmware do data
  • W przypadku awarii, echo -1 do loading i zatrzymanie procesu ładowania firmware
  • echo 0 do loading (sygnał jądra)
  • wtedy, a specyficzny moduł jądra odbiera dane i wypycha je do urządzenia

Jeśli spojrzysz na stronę źródłową Lucid dla udev, w udev-151/extras/firmware/firmware.c, źródle tego binarnego firmware /lib/udev / firmware, to dokładnie to, co się dzieje.

Fragment: Lucid source, udev-151 / dodatki / firmware / firmware.c

    util_strscpyl(datapath, sizeof(datapath), udev_get_sys_path(udev), devpath, "/data", NULL);
    if (!copy_firmware(udev, fwpath, datapath, statbuf.st_size)) {
            err(udev, "error sending firmware '%s' to device\n", firmware);
            set_loading(udev, loadpath, "-1");
            rc = 4;
            goto exit;
    };

    set_loading(udev, loadpath, "0");

Dodatkowo wiele urządzeń używa formatu Intel HEX (pliki tekstowe zawierające sumę kontrolną i inne rzeczy) (wiki to nie mam reputacji i nie mam możliwości linkowania). Program kernel ihex2fw (wywołany z Makefile w kernel_source/lib / firmware na .Pliki HEX) konwertuje te pliki HEX do arbitralnie zaprojektowanego formatu binarnego, który jądro Linuksa pobiera z request_ihex_firmware, ponieważ uważali, że czytanie plików tekstowych w jądrze było głupie (to spowolniłoby sprawę).

 11
Author: Andy Matteson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-10 07:04:55

W obecnych systemach Linux jest to obsługiwane przez udev i firmware.agent.

 1
Author: David Schmitt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-04 12:12:18

Linux 3.5.7 Gentoo, mam ten sam problem. Rozwiązany:

emerge ipw2200-firmware

Następnie przejdź do /usr / src / linux

make menucofig

W sterowniku urządzenia usuń wszystkie niepotrzebne sterowniki wirless, Ustaw Intell 2200 jako moduł i przekompiluj.

make
make modules_install
cp arch/x86/boot/bzImage /boot/kernel-yourdefault
 1
Author: MaxV,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-26 10:54:56