Шрифт:
Критически важный этап! Упустить его из виду очень просто, но это неизбежно приведет к «утечкам памяти». Обратите также внимание, как мы позаботились об освобождении памяти в случае неудачи на этапе 3.
Здесь мы используем макрос _IO_SET_WRITE_NBYTES для сохранения числа записанных байт, которое затем будет передано назад клиенту в качестве значения, возвращаемого функцией write. Важно отметить, что вы должны возвратить фактическое число байт! От этого зависит судьба клиента.
Пришло время навести лоск для функций stat, lseek и последующих write, аналогично тому, как мы это делали в нашей io_read (и опять мы изменяем смещение в ocb только в том случае, если это не сообщение типа _IO_XTYPE_OFFSET). Однако, поскольку мы выполняем запись в устройство, мы используем при этом константу IOFUNC_ATTR_MTIME вместо константы IOFUNC_ATTR_ATIME. Флаг MTIME означает «время модификации» (modification time) — функция write определенно его изменяет.
Последний этап прост: мы возвращаем константу EOK, которая сообщает библиотеке администратора ресурсов, что она должна ответить клиенту. Здесь наша работа закончена. Библиотека администратора ресурсов использует в ответе данные о числе записанных байт, которые мы сохранили с помощью макроса IO_SET_WRITE_NBYTES, и разблокирует клиента. Клиентская функция write возвратит число байт, записанное нашим устройством.
Простой пример функции io_devctl
Клиентский вызов devctl формально определен так:
Прежде чем рассматривать эту функцию с позиций администратора ресурсов, надо сначала понять, что это за зверь. Функция devctl применяется для «нестандартных» и «управляющих» операций. Например, вы можете записывать данные в звуковую плату (реальные оцифрованные звуковые фрагменты, которые звуковая плата должна будет конвертировать в аналоговый аудиосигнал) и принять решение об изменении числа каналов от одного (моно) до двух (стерео) или об изменении частоты дискретизации данных от стандарта CD (44.1 кГц) к стандарту DAT (48 кГц). Такие вещи было бы правильно делать при помощи функции devctl. При написании администратора ресурсов вы можете решить, что вам вообще не нужны никакие devctl, и что всю необходимую функциональность можно свести к стандартным функциям read и write. С другой стороны, вы можете захотеть использовать как вызовы devctl наряду с вызовами read и write, так и только devctl — это будет зависеть от вашего устройства.
Функция devctl принимает 5 аргументов:
fd | Дескриптор файла администратора ресурсов, которому вы посылаете команду devctl. |
dcmd | Собственно команда — комбинация из двух разрядов направления обмена данными и 30 разрядов команды (см. ниже). |
dev_data_ptr | Указатель на область данных, которые передаются, принимаются или и то, и другое. |
nbytes | Размер области данных, на которую указывает dev_data_ptr. |
dev_info_ptr | Переменная для дополнительной информации, установку которой может выполнить администратор ресурса. |
Двумя старшими разрядами команды dcmd кодируется направление обмена данными, если он вообще имеет место. Подробности см. выше в описании функций ввода/вывода (параграф «io_devctl»).
Когда администратор ресурсов принимает сообщение _IO_DEVCTL, оно обрабатывается вашей функцией io_devctl. Ниже представлен очень простой пример, который предполагается использовать для настройки каналов и частоты дискретизации для аудиоустройства, как упоминалось выше.