28 de juny 2009

instalación de firmwares de hardware no integrados en el kernel

A ver si el título cabe en una sola línea, pero no sabía muy bien como resumirlo.

Llevo todo el fin de semana intentando instalar una debian squeeze from scratch, pero no ha habido forma por algun problema con los paquetes daily de instalación disponibles y finalmente he tenido que instalar una estable (businescard) y upgradear a squeeze, entre instalación y upgrade he estado cerca de 2 horas, la conexión de casa hoy volvía a funcionar lenta, quizás el router estaba haciendo la siesta por el intenso calor que ha hecho hoy en la ciudad condal.

Una vez a squeeze he instalado todos mis programas y he puesto el escritorio con mas o menos la misma distribución que antes.

Tras hacer el checkeo del hardware he visto que la webcam y la wifi no funcionaban, así que he revisado los programas que había instalados (iwlwifi y v4l) y si lo estaban, tenía pinta de un problema de módulos ya que el dmesg ni siquiera soltaba errores al intentar cargar lo que vendrían a ser los drivers, los firmwares, unas librerías que actúan como puentes entre el núcleo del sistema operativo y el chip del componente de hardware.

Así que este post va de esto, como hacer que funcionen las cosas que por culpa de ser un hardware estraño, aún en desarrollo o directamente que sea tan nuevo que aún no haya habido tiempo para crear una comunidad para aquel hardware.

Normalmente tenemos comunidades que engloban varios subproyectos para cada uno de los hardwares, permitiendo así una amplia compatibilidad de dispositivos instalando un simple paquete (este ya precompilado en nuestro kernel) como podría ser v4l o iwlwifi.

Partimos de que algún programador haya sacado el firmware del dispositivo para linux, cada vez mas pero, nos encontramos que los propios fabricantes ya sacan estos firmwares (empaquetados para que no se pueda acceder al código), como podría ser intel o nvidia (este último con un basto .bin que te hace todo el trabajo sucio).

Vamos a ver así como vamos a integrar un firmware no contemplado en el kernel de linux. Además todo este proceso se puede realizar independientemente de la versión de kernel, si una cosa funciona ¿para qué vamos a cambiarla?

Primero de todo descargamos los sources del kernel completos (F) para poder compilarlos. Si buscamos un kernel mas antiguo tenemos este histórico. En el caso de hoy he tenido que instalar un kernel antiguo (2.6.27) para comprobar una cosa y me ha ido bien este directorio :)

Voy a usar como ejemplo el último kernel estable, el 2.6.30, todo indica que dentro de poco estará listo el 2.6.31 con un montón de nuevas funcionalidades.

# cd /usr/src
# wget -c http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.30.tar.gz
# tar xvjf linux-2.6.30.tar.gz
# ln -s linux-2.6.30 linux
# cd linux
# ls

Aquí tenemos el código del kernel, si te aburres puedes ir leyendo todas las líneas y entrando en todos sus directorios y revisar sus miles de ficheros, pero tenemos una forma mas sencilla de configurar el kernel. Será necesario instalar un par de paquetes.

# apt-get install build-essential libncurses5 libncurses-dev

y luego ya podremos entrar en el menú de configuración

# make menuconfig

Antes de empezar a toquetear fijaos en los dos últimos elementos del menú principal:

Load an Alternate Configuration File: para cargar la configuración de otro kernel que ya tengamos compilado, para no tener que ir configurando cosas a la que actualizas a un nuevo kernel.
Save an Alternate Configuration File: para guardar los cambios que vayamos haciendo, pero finalmente el fichero de configuración que importa es el .config

Los últimos kernels que he compilado los he compilado directamente tal como venían y no me ha dado problemas, incluso os diría que no he visto ningún kernel panic desde noviembre, en el hackmeeting (aquella frustración de compilación de kernel a las 5 de la madrugada, compilar requiere tiempo de espera y te permite hacer otras tareas lejos del ordenador).

Así que si tienes un procesador intel no muy antiguo te va a valer el kernel, sino en Processor type and features > Processor family podemos escoger entre un amplio abanico de procesadores, y si no está soportado simplemente tendrás que buscar el firmware para linux y modificar unos ficheritos y ya estará soportado :D

Tras una anécdota y un pequeño avance vamos a seguir adelante.

Haremos lo que queramos con el fichero de configuración, pero finalmente el que manda es el .config, hagamos lo que hagamos al salir nos pedirá como queremos llamar el fichero.

Ahora dejamos aparcado el .config y nos vamos a descargar el firmware.

Como el chipset de la wifi es de intel, tengo la ventaja de que los señores de intel ya me ofrecen un firmware cerrado, weno, menos da una piedra.

http://intellinuxwireless.org/?p=iwlwifi

Y en download vamos a descargar el firmware

http://intellinuxwireless.org/?n=downloads


En mi caso me descargo el de la serie 5000.

# cd /home/laura/bin/
# wget -c http://intellinuxwireless.org/iwlwifi/downloads/iwlwifi-5000-ucode-8.24.2.12.tgz
# tar xvzf iwlwifi-5000-ucode-8.24.2.12.tgz
# cd iwlwifi-5000-ucode-8.24.2.12
# ls

Normalmente junto al firmware tenemos un fichero README que nos ayudará a instalar el firmware en el kernel.

En los kernels mas nuevos hay habilitada una funcionalidad para cargar firmwares automáticamente.

Los firmwares del hardware tienen que copiarse siempre en /lib/firmware, este directorio es dónde va a buscar los firmwares que no vienen por defecto con el kernel y están presentes en el fichero .config del que he hablado antes.

En el README nos propone la forma de los kernels modernos:

Device Drivers ->
Generic Driver Options ->
Hotplug firmware loading support

Si no está soportado mas abajo en el README cuenta como agregarlo.

Luego estos firmwares los cargaríamos con el module-assistant que menciono en este otro post.

En este post voy a explicar como cargar directamente el soporte para el nuevo firmware.

Editaremos el .config y buscaremos los siguiente:

#CONFIG_IWLWIFI_DEBUG is not set
CONFIG_IWLAGN=m
CONFIG_IWLAGN_SPECTRUM_MEASUREMENT=y
CONFIG_IWLAGN_LEDS=y
CONFIG_IWL3945=m
CONFIG_IWL3945_SPECTRUM_MEASUREMENT=y
CONFIG_IWL5000=y

estos valores los encontraremos normalmente en la página web del proyecto o fabricante, sino en algun foro.

cada uno de las lineas hace referencia a un firmware o paquete (esta parte no la tengo muy clara aún hehe), la nomenclatura es:

y cargado en el kernel
m se carga como un módulo (modprobe modulo)

las líneas comentadas va a pasar de ellas, y para facilitar su búsqueda tenemos un "is not set" para poder filtrar rápidamente los módulos disponibles no configurados o desactivados, es importante documentarse antes de modificar cualquier valor de este fichero.

En el .config del kernel 2.6.30 he tenido que añadir estas líneas:

CONFIG_IWLAGN=m
CONFIG_IWLAGN_SPECTRUM_MEASUREMENT=y
CONFIG_IWLAGN_LEDS=y
CONFIG_IWL5000=y

ya que una se encontraba comentada o las otras que directamente no estaban.

Una vez finalizado este pequeño hack del kernel procedemos a compilarlo. Por comodidad ya tengo en mi buch de herramientas una línea compila-kernels ;)

# make && make install && make modules_install && mkinitramfs -o /boot/initrd.img-2.6.30 2.6.30 && update-grub

Al cabo de unos 20-60 minutos, depende de la potencia de la maquina tendremos el kernel compilado y preparado para reiniciar la máquina y comprobar que la instalación del driver ha sido fructuosa :)

0 comentaris:

Publica un comentari a l'entrada