среда, 12 декабря 2012 г.

Любите ли Вы I2C так, как это делаю я?

Сразу оговорюсь, этот пост будет неким винегретом про очередной этап допиливания коробки от Thecus с дистрибутивом openSUSE на борту.
Про то, как я искал дисплей на шине I2C, а нашел еще и градусник, как проходил туннели с OpenVPN в поисках медиасервера и как перекраивал флэшку на GPT лад.

"Видишь эту железяку?" (с)

Как-то так случилось, что на работе мне довелось разрабатывать специфический вариант интерфейса I2C в составе СнК. Разумеется, разработка предполагала какое-то функциональное тестирование в связке с процессором, но до написания драйвера мы не поднимались. И вот представился случай посмотреть как это делают квалифицированные люди.

Откуда ноги растут

При переводе N3200PRO с фирменного ПО на "народное", вполне ожидаемо отвалилось управление экраном и клавиатурой на передней панели. Конечно надежда теплилась, но последующие раскопки завалили ее искорки наглухо.
Мои требования к указанным девайсам простые - иметь возможность их выключить, дабы не привлекали внимание подрастающего поколения. В фирменном ПО, как опять же выяснилось в ходе раскопок, это делалось просто:
echo "LCM_DISPLAY 0" > /proc/thecus_io
echo "OSD_LED 0" > /proc/thecus_io
И экран с кнопочным диодом гасли.

Раскопки

В openSUSE искомое устройство в sysfs не появлялось. Благо Thecus позаботился о пытливом пользователе и предоставил благодатную почву для копания в виде исходных кодов своего ПО под лицензией GPL. Невнимательный взгляд на linux/drivers/i2c/chips/n3200plus_io.c  показал, что рыть надо на шину I2C и что шина эта сделана на базе некоего устройства CS5535. dmesg выявил конфликт между ACPI и драйвером этого устройства, который был улажен после указания опции acpi_enforce_resources=lax при загрузке ядра:
[ 15.280261] ACPI Warning: 0x00006100-0x000061ff SystemIO conflicts with Region \_SB_.GPIO 1 (20120320/utaddress-251)
[ 15.280310] ACPI: This conflict may cause random problems and system instability
[ 15.280327] ACPI: If an ACPI driver is available for this device, you should use it instead of the native driver
[ 15.280499] cs5535-gpio cs5535-gpio: reserved resource region [io 0x6100-0x61ff]
[ 15.280649] gpiochip_add: registered GPIOs 0 to 31 on device: cs5535-gpio
[ 15.280949] ACPI Warning: 0x00009c00-0x00009c3f SystemIO conflicts with Region \SCPP 1 (20120320/utaddress-251)
[ 15.280989] ACPI Warning: 0x00009c00-0x00009c3f SystemIO conflicts with Region \VSAB 2 (20120320/utaddress-251)
[ 15.281028] ACPI: This conflict may cause random problems and system instability
[ 15.281045] ACPI: If an ACPI driver is available for this device, you should use it instead of the native driver
[ 15.281189] cs5535-mfd 0000:00:0f.0: 5 devices registered.

[ 29.915716] cs5535-smb cs5535-smb: SCx200 device 'CS5535 ACB0' registered

ACPI много на себя берет, но не всё выполняет, поэтому нам приходится разрешать грузить нативный драйвер вместо ACPI'шного.

Далее я пошел по ложному пути, который вывел меня на едва не выпавшее из под контроля устройство, отвечающее за терморегуляцию коробки. По какой-то причине пакет, работающий с сенсорами не был установлен. Поставил, задействовал, нашел и настроил:
Do you want to probe the I2C/SMBus adapters now? (YES/no):
Using driver `scx200_acb' for device 0000:00:0f.0: CS5536 [Geode companion] ISA
Module i2c-dev loaded successfully.

Next adapter: CS5535 ACB0 (i2c-0)
Do you want to scan it? (YES/no/selectively):
Client found at address 0x2e
....
Probing for `Fintek F75375S/SP'... Success!
(confidence 7, driver `f75375s')
Probing for `SPD EEPROM'... Yes
(confidence 8, not a hardware monitoring chip)


Driver `f75375s':
* Bus `CS5535 ACB0'
Busdriver `scx200_acb', I2C address 0x2e
Chip `Fintek F75375S/SP' (confidence: 7)


# more /etc/sensors.d/f75375s.conf

chip "f75375-*"
label temp1 "CPU"
label temp2 "M/B"
label fan1 "FAN"
ignore fan2
set temp1_max 50
set temp1_max_hyst 45
set temp2_max 35
set temp2_max_hyst 30


ОК. Терморегулятор поставили под контроль, хотя он и по умолчанию был настроен на поддержание температуры 30 С. Ложный след привел в интересное место, но нам дальше.
Впрочем, я догадывался, что так просто дисплеи на шинах типа I2C не висят.

Пилите, Шура, они золотые!

Посмотрев повнимательнее в исходник, я увидел то, что сразу и не приметил. А именно слона. Хотя и с приставкой микро.
static struct i2c_driver pic16f877_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "pic16f877",
},
.probe = pic16f877_probe,
.remove = __devexit_p(pic16f877_remove),
.id_table = pic16f877_id,

.class = I2C_CLASS_HWMON,
.detect = pic16f877_detect,
.address_list = pic16f877_addr,
};
static struct i2c_client *pic16f877_client = NULL;

Что есть не что иное, как подключение на ядерную шину клиента I2C, который по совместительству микроконтроллер:

PIC16F87X Data Sheet 28/40-Pin 8-Bit CMOS FLASH Microcontrollers
Microcontroller Core Features:
...
Synchronous Serial Port (SSP) with SPI (Master mode) and I2C (Master/Slave)

Ну вот!

Я-то надеялся обойтись простеньким shell скриптом с применением i2cget/i2cset. А оказалось, что контроллеры просто так на диалог не идут. С ними нужно сперва по GPIO потрепаться и вообще, лучше довериться профессионалам.
Как говорил один литературный герой "Графа Монте-Кристо из меня не вышло. Придется ..." освоить кросскомпиляцию, т.к. ставить пакет разработчика на NAS не comme il faut, весь мой gecko-зоопарк работает на 64-битных системах, а коробка - на 32. Благо они (системы) на коробке и больших братьях установлены довольно схожие.
Профитом послужит возможность использовать, откопанное все в том же исходнике, подробное описание команд управления контроллером по I2C (через флуд в /proc/thecus_io разумеется) для работы со специфическими железяками от Thecus.

UPD: продолжение охоты на слона.

"Видишь эту деревяшку?" (с)

Новые возможности ставят нам новые задачи. Или как говорят, "Не было заботы, купила баба порося".

Имеем:

локальную сеть и в ней медиасервер с несколькими работающими клиентами в виде софтовых UPnP плееров на Android смартфонах и прочих ноутбуках (до телека и весьма удаленного WD TV Live Hub доберемся позднее).
Не гоже барину таскать за собой всю медиатеку, ибо не так это делается в лучших домах. Когда говорят, мол "сделайте NAS с UPnP и вся медия будет доступна Вам отовсюду", хочется, чтоб "отовсюду" имело более широкий смысл, чем квартирная локальная сеть.

Решение:

появилось само собой. В прошивку смартфона каким-то образом затесался клиент OpenVPN в виде бинарника, скомпилированного под ARM. Как впоследствии выяснилось, это лучше чем, имеющиеся в Play, Java аналоги (пока).
Я не буду расписывать все подробности настройки здесь. Они идеальным образом изложены в OpenVPN HOWTO. Сосредоточимся лишь на ключевых моментах, определяющих ход дела:
  1. UPnP медиасервера работают по широковещательному каналу.
  2. Загнать этот UDP трафик в маршрутизируемый туннель (TUN) у меня не получилось.
  3. "Если очень захотеть, можно в космос полететь"
То есть, туннель должен строиться на интерфейсах вида TAP. В итоге интерфейс будет совать нос непосредственно в сеть за туннелем и получать по соплям весь трафик, гоняемый в ней.
Желательно на стороне сервера поднимаемый туннель подключить к мосту на постоянной основе. Можете попробовать строить мосты по требованию.
Если в локалке адреса раздаются по DHCP, определите в настройках сервера диапазон адресов, которые будут выдаваться "кротам".
После подъема интерфейса на стороне клиента, необходимо добавить маршрут для широковещательного трафика. Маленький скриптик, написанный руками, сделает это за Вас по требованию.
#!/bin/sh
if [[ $1 == 'stop' ]] ; then
kill -15 `pidof openvpn`
exit 0
fi
/system/xbin/openvpn --config /etc/openvpn/client.tap.conf > /dev/null 2&>1
sleep 15
/system/xbin/bb/route add 239.255.255.250 dev tap0


# busybox route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
 default  
xx.xxx.xxx.82 0.0.0.0 UG 0 0 0 rmnet0
 xx.xxx.xxx.80 * 255.255.255.252 U 0 0 0 rmnet0
 xx.xxx.xxx.82 * 255.255.255.255 UH 0 0 0 rmnet0
 192.168.xxx.0 * 255.255.255.240 U 0 0 0 tap0
 239.255.255.250 * 255.255.255.255 UH 0 0 0 tap0


Я запускаю скрипт через Tasker. Задержка необходима на копание туннеля. Мой бинарник был скомпилирован так, что ожидал ifconfig и route в /system/xbin/bb/. Символические ссылки на busybox в указанном месте вполне его удовлетворили. Для обнаружения разного рода засад, в конфигурации ставим режим говорливости на средний. Максимальный понадобиться не должен. Потом прикрутите на ноль. Еще может понадобиться tcpdump, т.к. не все плееры умеют правильно говорить с медиасерверами. Встроенный от HTC говорит, но не понимает, а MediaHouse - запросто работает. VLC 2.0.3 работал, 2.0.4 перестал.
Скрипт с небольшим изменением заработает и на большом брате.
Настройки конфиденциальности с применением сертификатов на всех этапах подключения делаются "как учили".

В итоге

Имеем доступ к детским сказкам, папиной коллекции винила и семейным фото отовсюду, где есть доступ к Сети. Тарифный план на мобильный трафик желательно иметь скоростной и безлимитный. По 3G вполне себе можно слушать и даже смотреть, если загрузка сети позволит.

И напоследок про железный софт

Даже несмотря на то, что железяка моя вроде как не знает таких слов как UEFI, захотелось барину завести на загрузочной флэшке GPT. Ну нет же у неё ни дисков, ни головок!
А тут как раз задумал он перенести систему на флэшку покомпактнее и побыстрее.
Разметил, перенес. Надо бы и GRUB2 поставить как-то. А он не ставится. Ругается, некуда, мол, кору каку-то ставить. Давай, говорит, партицию специяльну! Пришлось барину, скрепя сердце, выпилить первые свободные сектора под эту кору. Благо невелика фитюлька.
# gdisk /dev/sda
GPT fdisk (gdisk) version 0.8.2

Partition table scan:
MBR: hybrid
BSD: not present
APM: not present
GPT: present

Found valid GPT with hybrid MBR; using GPT.

Command (? for help): p
Disk /dev/sda: 15687678 sectors, 7.5 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): 9F48B426-B5EA-4CEA-8A9F-3189755F721F
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 15687644
Partitions will be aligned on 2-sector boundaries
Total free space is 2013 sectors (1006.5 KiB)

Number Start (sector) End (sector) Size Code Name
1 2048 129023 62.0 MiB 8300 Boot
2 129024 15685631 7.4 GiB 8300 Root
3 34 2047 1007.0 KiB EF02 BIOS boot partition



Файловая система с кодом EF02 распознается GRUB'ом, как годная для размещения в ней core.img при grub-install --recheck /dev/sda

Конечно же переезд не прошел даром. Флэшка новая, ID у нее другой в sysfs прописывается. Пришлось курочить в initrd файл run_all с заменой старого ID на новый. Но все это мы уже проходили и отловили еще на виртуальной машине. Кто-то спросит: "ну и наф.. зачем это было надо?" Отвечу так же: "А шоб былО!"


UPD: в итоге я ушел от btrfs на ext4 и даже на выделенный хард. Как и почему, см. в конце следующего поста.


Ну как, словили лулзов?

И да простят меня лурки за обилие вредных ссылок в посте. Просто они первыми попадались в поиске гугля :)