Как всегда, не претендуя на типичность случая, расскажу небольшую
историю о том, как ставил winmodem на Fedora Core 4. Мне помогло - не
исключено, что поможет и еще комуто. Педанты, как всегда, могут
поискать ошибки в тексте - тоже занятие.
С месяц назад получаю письмо: "Вот Вы писали про Fedor'у 4. Я
ставлю winmodem, и у меня сим-линк /dev/modem, который я создаю,
куда-то пропадает под этой системой". Тогда я просто съехал: да ты чё,
какой winmodem, это глупое занятие, возьми нормальный - и так далее
(если честно, не было сил разгибать мозги). Человек и пропал куда-то,
запил, наверное, с горя. И вот проходит месяц - и я оказываюсь в
глубоком лесу со своим ноутом, телефонным кабелем и этим, вы поняли.
winmodem'ом на борту. Награда нашла героя, пришлось все-таки поскрести
"чугунок" - давненько я под модемом никуда не ходил, а тем более под
winmodem'ом.
Ну, конечно, если начинать с конца, то ответ на главный вопрос
прост и всем известен. Конечно же, сим-линки, созданные в каталоге
/dev, не будут храниться, поскольку сама эта файловая система /dev в
FC4 создается на лету подсистемой udev как следствие нескольких
действий. Для начала ядро делает учет устройств в виде файловой системы
SYSFS, которая располагается (монтируется) в каталоге /sys. Это, так
сказать, "честные" устройства, обнаруженные в системе. После этого
запускается udev - вы и сами можете это проделать с помощью
/sys/udevstart.
Udev - это уровень "индерекции", то есть трансляции "физических"
устройств из /sys в логические в /dev. Для полноты изложения нужно
сказать, что тут задействована также система "горячего" подключения,
поскольку /sys может видоизменяться в процессе работы.
Сайт Linux Udev расположен по адресу www.kernel.org/pub/linux/utils/kernel/hotplug/udev...
Собственно, трансляция sys в dev может выполняться полностью
автоматически, без вашего вмешательства. Ядро, опрашивая драйверы, дает
устройствам вполне жизнеспособные имена и номера, например tty1. Однако
в некоторых случаях вы можете быть недовольны таким положением вещей -
это особенно верно для динамически подключаемых устройств, в частности
по USB. Например, вы подключаете USB-винчестер в различные разъемы - и
при этом он каждый раз будет называться по-разному. В результате вы не
можете написать удобную программу, поскольку не знаете, где ваше
устройство. Еще хуже, если однотипных устройств много: все они будут
называться одинаково, с разницей только в индексе - и в следующий раз
могут запросто поменяться местами. Это именно та проблема, с которой
так плохо справился DEVFS, отчего и пошел подальше.
Для того чтобы Udev мог что-то намутить с создаваемыми именами
устройств, существуют правила udev, расположенные в каталоге
/etc/udev/rules.d. На самом деле это настраивается в /etc/udev, но
менять настройку не в пределах нашей компетенции. Подобно, например,
стартовым скриптам, правила хранятся не в одном файле, а во всех
документах с расширением .rules (остальные игнорируются), располагаемых
в каталоге /etc/udev/rules.d. При этом файлы располагаются в алфавитном
порядке, и все строки из них читаются в один большой буфер; затем
каждое устройство из /sys будет "квалифицировано" согласно данным
правилам.
Обратите внимание на логику udev: поиск происходит до первого
совпадения, после чего устройство считается "обслуженным". Таким
образом для одного устройства во всех файлах может быть только одно
правило - то, которое будет найдено первым. В этом отличие от скриптов,
которые всегда будут выполнены все - один за одним в заданном порядке.
Это меняет и нашу логику: если в случае со скриптами мы, вероятно,
хотим, чтобы система сначала выполнила все стандартные настройки
(например запустила сетевые интерфейсы), а уже потом вносим свои
изменения, например задаем другой сетевой адрес. Специально для этих
целей существует ряд файлов-"постинициаторы".
В случае с правилами Udev "потома не будет" - первое же
попадание устройства в правила будет и последним. Следовательно, нам
нужно, чтобы наши правила проверялись раньше, чем системные по
умолчанию. Файл настроек по умолчанию начинается с префикса "50" - так
чтобы можно было что-то добавить до и после. Умные люди добавили также
файл с префиксом "10" для каких-то "очень важных" устройств - ну что ж,
назовемся как-то вроде /etc/udev/rules.d/00-ltmodem.rules и поместим
туда следующую строку:
KERNEL='ttyLTM0", NAME='%k', SYMLINK='modem', MODE='0660", GROUP='uucp'
Эта строка содержит (незримо) две части: ключевую, или
идентификатор, и триггер - то есть часть, которая будет "выполнена" для
устройства, которое совпадет с нашим ключом. Каждое устройство, как
было сказано выше, единожды проходит через этот "строй" - процесс
довольно нудный, в чем вы можете легко убедиться, запустив
/sbin/udevstart, Тем более что вам все равно придется это сделать после
внесения изменений, если вы не хотите перезагружать компьютер.
В данном случае устройство детектируется по "к-имени", то есть
так, как оно известно ядру. А именно - ttyLTM0. Конечно, это не самый
гибкий ход. Но я просто знаю, что более одного винмодема у меня быть не
может. В общем случае можно было бы записать "ttyLTM?", или даже
"ttyLTM*": значение звездочки и вопросительного знака точно такие, как
и в командной строке.
Конечно, один винчестер от другого по к-имени не отличишь - для
этого существует еще ряд признаков. Самый общий - SYSFS{имя файла}, что
обозначает сравнить значение в данном файле SYSFS для данного
устройства с заданным значением. Вся SYSFS состоит из
классифицированных каталогов. В этих каталогах лежат файлы с
параметрами устройств (вы можете сами на это посмотреть, вас там никто
не укусит). Вот идентификатор SYSFS и сравнивает значение такого
"атомарного файла" с некоторым значением.
Udev сам может сварганить ключ для любого подключенного
устройства. Если вы знаете, где оно находится в иерархии /sys
(благодаря линкам там все встречается по три раза - ищите, как вам
удобно, по типу или по шине подключения), то можете даже "вывернуть"
значения параметров с помощью утилиты udevinfo. Собственно, она как раз
и помогает искать параметры в /sys, в частности по "готовому" /dev -
устройству.
Например, узнаем, как в SYSFS называется наш модем, указав его "ноду" в devfs. Выполняем:
# /usr/bin/udevinfo -q path -n /dev/ttyLTM0
и получаем:
/class/tty/ttyLTM0
где полученный путь "абсолютно относителен" в системе /sys. Теперь
запросим все параметры (атрибуты, в терминах Udev), связанные с этим
устройством:
# usr/bin/udevinfo -a -p /class/tty/LTM0
...бла-бла-бла device '/sys/class/tty/ttyLTM0' has major:minor 62:64 looking at class device '/sys/class/tty/ttyLTM0': SUBSYSTEM=="tty" SYSFS{dev}=="62:64"
Параметры читаются так: q(uery), n(ode), p(ath), a(ttributes).
Конечно, вы легко можете скомбинировать два вызова в одной строке через
обратные кавычки или конструктив $(). Например, следующая строка выдает
всю известную системе информацию о моем флэш-накопителе:
#udevinfo -a -p `udevinfo -q path -n /dev/sda1`
Короче, мне достаточно к-имени - я и так доволен, тем более что
драйвер не предоставил никакой другой веской информации для
классификации винмодемов. Предполагается, что это PCI-устройства без
поддержки hotplug. Помимо SYSFS существуют и другие ключи, такие как
BUS или SUBSYSTEM,- но мне это уже совсем не надо. Учтите, если вы
задаете несколько ключей поиска, они должны совпасть все вместе - так
что указывайте так много ключей, сколько надо для "отсечения" вашего
устройства или группы устройств.
Когда устройство найдено, с помощью правил оно будет "причесано"
перед отправкой в /dev. NAME='%k' подставляет к-имя, говоря "называй
так, как хочет ядро", а точнее драйвер. Здесь же можно немного
покрутить с каталогами, написав, например, NAME='modems/%k', или с
самим именем:
NAME='momed%n' (где %n обозначает индекс, в нашем случае - 0).
Если мы не хотим задавать новое имя - значит, наше правило хочет
поиграть с правами доступа или сим-линком. Право 0660 называется "себе
и группе читать и писать" - это просто для понтов написано, поскольку
такое право прописано по умолчанию в /etc/udev/udev.conf в параметре
default_mode. Владелец устройств по умолчанию всегда root. Группа uucp
занимается всякими коммуникациями, так что все нужные приложения, вроде
PPP-дайлера, смогут получить доступ к модему.
В оригинальной доке советуют что-то там настраивать в
permissions.d - но, как я понял, эта техника уже ушла в прошлое, такого
каталога нет, а параметры владельца и файловых прав доступа вполне
доступны через rules.d. При этом в скриптах есть интересный код
"конвертация пермишенов в новый формат". Правильно - ну его, всё в один
файл, в одну строку. Устройство ttyLTM0 в SYSFS создаст наш драйвер
модема, например, по modprobe ltserial, который мы пока даже не
поставили. Да, именно так - стартуем модуль ltserial, а модем там тоже
окажется, скоро увидим почему.
Мы проследили путь с конца: от сим-линка и имени устройства в
/dev до /sys и далее - до драйвера. Теперь закончим это расследование в
обратном направлении, чтобы вы могли пользоваться результатом
практически.
В последнее время драйвер любого "нештатного" устройства
представляет собой модуль, загружаемый сервисом modprobe. Несмотря на
вялое сопротивление сторонников монолитного ядра, идея динамического
"уровня 0" вокруг мини-ядра - так, как это сделано в QNX (хотя это не
совсем точно - в QNX модули не располагаются в L0),- постепенно
становится стандартом де-факто. Впрочем, хорошо, конечно, когда есть
выбор. Кое-что действительно не имеет смысла загружать динамически.
Вообще-то, модуль загружает само ядро, и отчет об этом
помещается в файл /var/log/dmesg - для его просмотра даже существует
специальная утилита dmesg, так что можете просто запускать ее. Утилита
modprobe используется только для загрузки модулей в самом общем смысле:
сначала исследуются зависимости модуля, в том числе и "зависимости
зависимостей", после чего загружаются все модули, необходимые для
загрузки указанного.
В нашем случае для "создания" устройства в SYSFS достаточно в
любой момент (удачно) выполнить загрузку драйвера modprobe ltserial.
Модули расположены в каталоге "модули текущей сборки" - или, как это
часто пишут, /lib/modules/`uname -r`, где uname -r возвращает "релиз"
ядра. Например, в случае текущей сборки Fedora Core 4 это значение
будет '2.6.11-1.1369_FC4'. Вы можете выполнить эту команду и убедиться,
что на релиз легче ссылаться, как на uname -r :).
Поскольку модули могут зависеть друг от друга через внешние
ссылки (так называемые внешние символы, экспортируемые через декларации
EXPORT_SYMBOL), то для загрузки модуля система должна знать о таких
связях. В целях оптимизации (поиск всех внешних символов во всех
библиотеках - задача не скорая) данная информация кэшируется в файле
modules.dep, располагающийся в корневом каталоге модулей, путь к
которому мы только что обсуждали. Этот файл является текстовым, с очень
простым форматом, так что вы легко можете его исследовать. Утилита
modprobe ожидает, что modules.dep находится в актуальном состоянии. Для
этого после "заброски" новых модулей и перед запуском (явным или
неявным, при перезагрузке) modprobe нужно выполнить depmod -a - это
обновит modules.dep. Конечно, это надо проделать только один раз.
Допустим, что у нас уже есть два нужных модуля (мы-то движемся с
конца): ltmodem.ko и ltserial.ko. Скопируем их в какое-нибудь приметное
место внутри каталога модулей, например в /lib/modules/`uname
-r`/extra. Выполним обновление зависимостей depmod -a и убедимся, что в
modules.dep появились строки:
/lib/modules/2.6.11-1.1369_FC4/extra/ltserial.ko: /lib/modules/2.6.11-1.1369_FC4 /extra/ltmodem.ko /lib/modules/2.6.11-1.1369_FC4/extra/ltmodem.ko:
Как видите, модуль ltserial зависит от ltmodem, так что мы можем
выдать только modprobe ltserial - и ltmodem будет загружен
автоматически (маленькая радость). Если мы один раз загрузим модуль, он
и впредь будет загружаться, даже после перезагрузки. Выполним modprobe
ltmodem и посмотрим dmesg, где помимо прочего будут и такие строки:
ltmodem: module license 'Proprietary' taints kernel. Loading Lucent Modem Controller driver version 8.26-alk ACPI: PCI Interrupt 0000:00:09.1[A] -> Link [C185] -> GSI 11 (level, low) -> IRQ 11 Detected Parameters Irq=11 BaseAddress=0x3430 ComAddress=0x0 ttyLTM0 at I/O 0x3430 (irq = 11) is a Lucent/Agere Modem
Теперь, наконец, займемся самим драйвером, то есть двумя
упоминавшимися уже модулями *.ko (ko - от Kernel Object file).
Во-первых, обратите внимание на название драйвера - Ltmodem, в данном
случае это обозначает Lucent Technologies. В модеме используется
сигнальный процессор (DSP) этого известного производителя. Если вам не
так повезло, и у вас другая модель, то возможно, что проблем будет
больше, вплоть до неразрешимых - и действительно придется брать другой
модем. Это просто Lucent так любезна, что старается предоставлять
драйверы для своих юнитов, так же как и драйвера для беспроводных
карточек Orinoco и т.д. Под "и т.д." следует понимать компанию Agere и
ее продукцию, в которую это "практическое Bell-lab'ство" сейчас
превратилось.
Кстати, кроме "вынь"-модема на настоящем DSP (он "вынь" стал
только потому, что не на взаправдашнем СОМ-порту висит, а на PCI-шине),
существует еще и софт-модем Agere. И как с ним быть, наш драйвер не в
курсе. И даже спросить не у кого - производитель драйверы для Linux не
выпускает. Там и модема-то не видно, по сути, один жирный фирмварь,
который весь и надо бы портировать.
"Поддержка", однако, еще не значит "открытый код". Lucent только
предоставила базовый код виртуального COM-порта в бинарном виде, к
которому нужно линковать драйвер. В результате драйвер состоит из трех
частей: открытые, собираемые вами ltmodem.ko, ltserial.ko и закрытый
кусок кода - ltmdmobj.o (по факту - сим-линк на конкретную версию этой
библиотеки, на сегодня это 8.31). Загрузить отдельно либу с доками
можно на ltmodem.heby.de.
Текущая версия самого драйвера как целого - 2.6-alk-7. В данном
случае alk обозначает "форк", то есть ветку разработки, которую ведет
Алексей Кондратенко. Это как раз то, что нужно для ядра 2.6, с учетом
как раз SYSFS. Исходники можно получить по адресу alk.at.tut.by/ltmodem-2.6-alk-7.tar.bz2 или на нашем диске.
Конечно, другой бы вам еще рассказал, как настроить дозвон
модемом из командной строки, но это уж в другой раз. Я же просто залез
в KPPP, проверил модем опросом ATIn, потыкался в мини-терминал и,
удовлетворенный богоугодной работой, отправился в Большую Сеть.
Единственное что в "командах модема" пришлось поменять тоновый набор на
импульсный, ATDT на ATDP - но уж где и как все это делается, думаю, вы
найдете.
Если winmodem Lucent вам действительно нужен, то на КП-диске
лежат и файлы, и документы, необходимые для установки: файлы
универсальные, исходники, а вот инструкции только к FC4 - думаю, c
минимумом очевидных вариаций подойдет к любому ядру 2.6.
|