Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
Шрифт:
Прежде чем рассматривать эту функцию с позиций администратора ресурсов, надо сначала понять, что это за зверь. Функция devctl применяется для «нестандартных» и «управляющих» операций. Например, вы можете записывать данные в звуковую плату (реальные оцифрованные звуковые фрагменты, которые звуковая плата должна будет конвертировать в аналоговый аудиосигнал) и принять решение об изменении числа каналов от одного (моно) до двух (стерео) или об изменении частоты дискретизации данных от стандарта CD (44.1 кГц) к стандарту DAT (48 кГц). Такие вещи было бы правильно делать при помощи функции devctl. При написании администратора ресурсов вы можете решить, что вам вообще не нужны никакие devctl, и что всю необходимую функциональность
Функция devctl принимает 5 аргументов:
fd | Дескриптор файла администратора ресурсов, которому вы посылаете команду devctl. |
dcmd | Собственно команда — комбинация из двух разрядов направления обмена данными и 30 разрядов команды (см. ниже). |
dev_data_ptr | Указатель на область данных, которые передаются, принимаются или и то, и другое. |
nbytes | Размер области данных, на которую указывает dev_data_ptr. |
dev_info_ptr | Переменная для дополнительной информации, установку которой может выполнить администратор ресурса. |
Двумя старшими разрядами команды dcmd кодируется направление обмена данными, если он вообще имеет место. Подробности см. выше в описании функций ввода/вывода (параграф «io_devctl»).
Когда администратор ресурсов принимает сообщение _IO_DEVCTL, оно обрабатывается вашей функцией io_devctl. Ниже представлен очень простой пример, который предполагается использовать для настройки каналов и частоты дискретизации для аудиоустройства, как упоминалось выше.
На первом этапе мы снова видим применение вспомогательной функции, на этот раз — функции iofunc_devctl_default, которая используется для выполнения всей обработки по умолчанию для devctl. Если вы не поставляете свою версию io_devctl, а только инициализируете таблицы функций ввода/вывода и установления соединения при помощи iofunc_func_init, будет вызвана именно iofunc_devctl_default. Мы включаем ее в нашу версию io_devctl, потому что мы хотим, чтобы она обработала для нас все стандартные POSIX-варианты вызова devctl. Затем мы проверяем возвращаемое значение; если это не _RESMGR_DEFAULT, значит, функция iofunc_devctl_default «обработала» запрос, и нам остается только возвратить это значение, выдав его за «наше».
Если возвращенное значение является константой _RESMGR_DEFAULT, это говорит нам, что вспомогательная функция не обработала запрос, и что мы должны выяснить, является ли он одним из «наших».
Эта проверка выполняется на этапе 2 при помощи инструкции
Этот этап — дань концепции защитного программирования. Мы возвращаем код ошибки ENOSYS, чтобы сообщить клиенту, что мы не распознали его запрос.
Наконец, мы обнуляем возвратную структуру и устанавливаем на нее одноэлементный вектор ввода/вывода. Затем мы возвращаем библиотеке администратора ресурсов единицу (1) через макрос _RESMGR_NPARTS, сообщая ей тем самым, что мы возвращаем одноэлементный вектор ввода/вывода. Это и будет возвращено клиенту. Как вариант, мы могли бы применить макрос _RESMGR_PTR: