четверг, 21 марта 2013 г.

Ящерная отсебятина на экране Thecus

Компиляция модуля вывода информации на экран N3200PRO под новое ядро linux (openSUSE).
Bonus: Перенос системы на HDD и его перспективы.

Лирическое вступление

Не дошёл я до кросс-компиляции и остановился на установке заголовков и исходников ядра, пакетов make и gcc с зависимостями из репозитория своего дистрибутива непосредственно на целевую машину. Каюсь, смалодушничал. Впрочем, позабавиться нашлось с чем.
Мне, как изучавшему C только в институте и пользующемуся им только для отладки блоков в составе СнК (SoC), пришлось реально туго. Прошло довольно много времени и было совершено множество ненавязчивых попыток разобраться, пока до меня наконец дошло, что модуль cs5535-gpio из ядра 2.6.33 легким движением руки разработчиков превратился в cs5535-mfd и иже с ним еще к 2.6.38. А система-то уже на 3.4.28 (а на дворе и того дальше 3.8.xx). Как они говорят, теперь все стало проще. Это им проще, а мне-то теперь нужно не просто перекомпилировать модуль, но и привести его в соответствие новому драйверу южного моста ... (Host bridge: Advanced Micro Devices [AMD] CS5536 [Geode companion] Host Bridge)
Вот тут-то FLOSS открыло мне свое истинное лицо! И суть его была - "тебе надо, ты и пили!". Причем, судя по активности на форуме Thecus, мне предстояло быть первым, кто это если не сделает, то хотя бы расскажет, что сделал или попытался. Хорошо хоть, я догадываюсь о значении букв GPIO и I2C и покопаться в чужом коде иногда люблю.

Широко зажмурившись, я приступил...

Сперва посмотрим что видит ядро в нашем железе. В openSUSE dmesg пространно пишет обо всем. Без загрузки специальных драйверов голый драйвер для MFD и собственно наш южный мост отзываются вот так:
[ 51.084962] ACPI Warning: 0x00006100-0x000061ff SystemIO conflicts with Region \_SB_.GPIO 1 (20120320/utaddress-251)
[ 51.085009] ACPI: If an ACPI driver is available for this device, you should use it instead of the native driver
[ 51.085139] cs5535-mfd 0000:00:0f.0: MFD add devices failed: -16
[ 51.085325] cs5535-mfd: probe of 0000:00:0f.0 failed with error -16

Поэтому нам придется включить загрузку "нативных" драйверов для него, добавив в командную строку ядра опцию acpi_enforce_resources=lax(Когда-то раньше я это уже делал.) Теперь наблюдается более оживленная картина:

[ 35.663149] ACPI Warning: 0x00006100-0x000061ff SystemIO conflicts with Region \_SB_.GPIO 1 (20120320/utaddress-251)
[ 35.663197] ACPI: This conflict may cause random problems and system instability
[ 35.663214] ACPI: If an ACPI driver is available for this device, you should use it instead of the native driver
[ 35.663381] cs5535-gpio cs5535-gpio: reserved resource region [io 0x6100-0x61ff]
[ 35.663545] gpiochip_add: registered GPIOs 0 to 31 on device: cs5535-gpio
[ 35.663868] ACPI Warning: 0x00009c00-0x00009c3f SystemIO conflicts with Region \SCPP 1 (20120320/utaddress-251)
[ 35.663909] ACPI Warning: 0x00009c00-0x00009c3f SystemIO conflicts with Region \VSAB 2 (20120320/utaddress-251)
[ 35.663948] ACPI: This conflict may cause random problems and system instability
[ 35.663965] ACPI: If an ACPI driver is available for this device, you should use it instead of the native driver
[ 35.664209] cs5535-mfd 0000:00:0f.0: 5 devices registered.

[ 37.177810] cs5535-mfgpt cs5535-mfgpt: reserved resource region [io 0x6200-0x623f]
[ 37.177845] cs5535-mfgpt cs5535-mfgpt: 0 MFGPT timers available
[ 37.179228] cs5535-smb cs5535-smb: SCx200 device 'CS5535 ACB0' registered



Первая выделенная строка показывает зарезервированный диапазон адресов под GPIO, а вторая - что устройства перечисленные в драйвере на шине таки есть. То есть, заботы о регистрации устройства в адресном пространстве взял на себя общий драйвер, сняв их с конечных модулей устройств. Мелочь, а приятно.

make - insmod - depmod - modprobe

Руководств по компиляции модулей для ядра linux в Сети предостаточно. Если коротко, то к исходникам модуля нужен простой Makefile и далее анализатор вывода компилятора и компоновщика. Голова, то есть.

make

В исходник модуля пришлось внести небольшую правку для приведения его в соответствие с текущими заголовками ядра. А также убрать все заботы о GPIO, которые любезно на себя берет новые драйвера MFD, чтобы ядро не ругалось при загрузке модуля:

diff n3200plus_io.c N3200PRO_3.00.03_GPL/linux/drivers/i2c/chips/n3200plus_io.c

24c24
< #include <linux/reboot.h>
---
> #include <linux/notifier.h>
27a28
>
38c39
< static DEFINE_SEMAPHORE(n3200plus_io_sem);
---
> static DECLARE_MUTEX(n3200plus_io_sem);


Компоновщик же потребовал подключения исходника модуля клавиатуры ПДУ (N3200PRO_3.00.03_GPL/linux/drivers/input/keyboard/thecus_kbd.c), т.к. именно в нем описаны некоторые функции, применяемые в целевом модуле (в последующих версиях прошивки 5.хх зависимость сохраняется, но состав функций изменен). Поэтому, при загрузке в ядро, у нашего модуля появится соответствующая зависимость.

n3200plus_io.c:


extern void thecus_nec_ir_input(const int ir_code);
extern void thecus_rc5_ir_input(const int ir_code);
extern void thecus_mce_ir_input(const int ir_code);



В итоге получился такой Makefile:

obj-m += n3200plus_io.o
obj-m += thecus_kbd.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean


Далее make делает свое дело и на выходе получаются два *.ko файла - наши модули.

Историческая ремарка.
Выдержки по теме из немногословного вывода dmesg от Thecus (v.3.00.03):

cs5536_setup_onchipuart

...
input: thecus-kbd as /devices/virtual/input/input0
input: PC Speaker as /devices/platform/pcspkr/input/input1

...
i2c /dev entries driver
thecus_event : started

...
i2c i2c-0: Found pic16f877 at 0x36
pic16f877 0-0036: setting platform data
PIC_VER: 9
i2c i2c-0: Found F75375S at 0x2e
F75375S 0-002e: setting platform data
Attaching F75375
f753xx: Chip id: 306

Т. к. в конце функции инициализации модуля pic16f877_init производится регистрация драйвера микроконтроллера на шине I2C, к моменту старта модуля шина должна быть инициализирована и в /dev должны быть ноды шины. За это отвечает модуль i2c-dev. В процессе регистрации устройство обнаруживается на шине (pic16f877_detect) и с ним осуществляется короткий диалог (pic16f877_probe).

insmod

Пробуем вставить
# modprobe i2c-dev
dmesg: i2c /dev entries driver


# insmod  thecus-kbd.ko
dmesg: input: thecus-kbd as /devices/virtual/input/input4
# insmod  n3200plus_io.ko
Тихо вставляется.
Зато у нас появляется узел в /proc :
#cat /proc/thecus_io

depmod

depmod -nA | grep thecus
kernel/drivers/gpio/thecus/thecus_kbd.ko:
kernel/drivers/gpio/thecus/n3200plus_io.ko: kernel/drivers/i2c/i2c-core.ko kernel/drivers/gpio/thecus/thecus_kbd.ko
alias symbol:thecus_nec_ir_input thecus_kbd
alias symbol:thecus_rc5_ir_input thecus_kbd
alias symbol:thecus_mce_ir_input thecus_kbd

modinfo n3200plus_io
filename: /lib/modules/3.4.28-2.20-default/kernel/drivers/gpio/thecus/n3200plus_io.ko
license: GPL
description: Thecus N3200Plus MB PIC16F77 Driver and board depend io operation
author: citizen Lee <citizen_lee@thecus.com>
srcversion: 918962BCBDFEAB92FE7DF21
alias: i2c:pic16f877
depends: i2c-core,thecus_kbd
vermagic: 3.4.28-2.20-default SMP mod_unload modversions 586TSC
parm: debug:int

modinfo thecus_kbd
filename: /lib/modules/3.4.28-2.20-default/kernel/drivers/gpio/thecus/thecus_kbd.ko
license: GPL
description: Thecus keyboard device used for IR
author: citizen lee, <citizen_lee@thecus.com>
srcversion: 5D1C11E7A68A662F4DA359B
depends:
vermagic: 3.4.28-2.20-default SMP mod_unload modversions 586TSC
parm: dbg:set dbg=1 enable debug message output to stdout, dbg=0 disable it (int)

mopdprobe

В зависимости модуля добавляем i2c-dev

В настоящий момент работа над модулем приостановлена. Разбираться почему микроконтроллер не появляется на шине I2C после вроде как удачного опроса по GPIO сейчас не досуг.
Между делом команда openSUSE выпустила новый релиз 12.3 с новым ядром 3.7.xx. Обновление прошло успешно.

Краткий справочник доступных команд для нашего контроллера приведен в исходнике модуля.


Позднее я попробую разобраться с обработкой сигналов от клавиатуры на передней панели. Как это сделали в Thecus можно найти в скриптах прошивки. Осталось применить это для собственных нужд. А в еще более отдаленной перспективе - инспекция наличия на материнской плате железа подключенного к южному мосту или возможностей такового подключения. Пульт ДУ в скором времени может пригодиться.


От Flash к Flash + HDD

Как-то мне показалось не стабильной и не очень надежной загрузка и работа системы с USB свистка. Наверное все-таки показалось. Но я решил попробовать перенести систему на жесткий диск. Благо моя система хранения и резервирования данных пока предполагает наличие только двух занятых слотов. Причем шпиндель одного диска отключается через 10 минут простоя - после окончания ежедневного сохранения критических данных. (Хи-хи-хи... фото, книги и пр. :) ). Когда я доберусь по объему и скорости резервирования до реальной необходимости организации RAID5 я не знаю. Пусть это будет потенциалом. Поэтому есть возможность выделить диск под систему.
На виртуальной машине, к которой был подключен жесткий диск и DVD-диск с установочным образом, я быстро залил на хард систему, перевел на репозитории серии Current и перекинул настройки и прочий хлам с прежней системы. Но старый BIOS сказал "Не всё так просто!" и не дал загрузиться с SATA диска. Не нашел я в нем такой опции. Кто найдет, подскажите. (Версия Phoenix AwardBIOS v6.00PG 08/12/2008-AMD-GX3-6A3AXXXC-00) Пришлось делать смешанный вариант - почти так, как сделано в Thecus. Начальную загрузку производить с опять таки USB (они - с встроенной Flash), а собственно система стартует с винчестера.
То есть на флэшке лежит только каталог /boot с образами ядра, RAM-диска и конфигурацией и стадиями загрузчика, а на жестком диске - отдельными разделами копия /boot, корневой каталог, /home и swap, т.к. 1GB памяти может оказаться недостаточным для пакетной конвертации RAW фото, например.
При таком раскладе запись на флэшку делается только при обновлении ядра и загрузчика. И чтение - в начальный момент работы, после чего устройство оказывается отмонтированным и, таким образом, защищенным от случайного вмешательства.
Еще раз. Главное, не забыть продублировать /boot с жесткого диска на флэшку после обновления ядра!
Необходимость переноса /boot на флэшку возникла когда я принес хард в "коробку", то есть уже после, когда возможностей для таких подключений и разного рода исправлений не было. Поэтому установка загрузчика на флэшку была связана с некоторой PITA. Если коротко, то пришлось на флэшку ставить initrd со всеми модулями и дополнениями, чтобы жесткий диск завелся и отдал раздел с корневым каталогом. Плюс - в run_all.sh и /boot/grub/menu.lst прописывать правильные ID и UUID устройств, что уже вошло в привычку. И что примечательно, в /boot/grub/device.map флэшка прописывается последним устройством (hd4), а при загрузке-то оно (hd0), что должно быть учтено в menu.lst.
Кстати, GRUB2 сменился на GRUB. Просто так. Как-то проще с ним финты ушами делать.

В конце концов! 

Ребята из Thecus запросто занимают двумя отдельными RAID1 массивами на одном диске (у меня сейчас при загрузке с родной прошивки работает схема JBOD) порядка 500 МБ + 2 ГБ под свои системные нужды (mdadm -Q --detail /dev/md*).
Когда-нибудь я покушусь на их загрузочный Disk-on-Module (hda: AFAYA MDM 128M, ATA DISK drive) и запишу на него (или лучше на его клон) то, что сейчас ютится на USB свистке. Возможно посажу это все рядом и подправлю меню GRUB.
Как распаковать файл прошивки см. /img/www/function/adm/setupdfw.php

Как обновляется прошивка и что пишется в загрузочный и другие разделы см. полученный upgrade/up2.sh 

В итоге, с современными HDD по 2,5 - 3 ТБ на RAID5 разместятся логические тома, которые запросто вместят и систему и пользовательские данные и всё-всё-всё.
А пока потренируюсь на кошках ... то есть на гекконах :)