Простой пример функции io_devctl()
Клиентский вызов devctl() формально определен так:
#include
#include
#include
int devctl(int fd , int dcmd , void * dev_data_ptr ,
size_t nbytes , int * dev_info_ptr );
Прежде чем рассматривать эту функцию с позиций администратора ресурсов, надо сначала понять, что это за зверь. Функция 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() . Ниже представлен очень простой пример, который предполагается использовать для настройки каналов и частоты дискретизации для аудиоустройства, как упоминалось выше.
/*
* io_devctl1.c
*/
#include
#include
#include
#include
#include
#include
#define DCMD_AUDIO_SET_CHANNEL_MONO 1
#define DCMD_AUDIO_SET_CHANNEL_STEREO 2
#define DCMD_AUDIO_SET_SAMPLE_RATE_CD 3
#define DCMD_AUDIO_SET_SAMPLE_RATE_DAT 4
int io_devctl(resmgr_context_t *ctp, io_devctl_t *msg,
iofunc_ocb_t *ocb) {
int sts;
// 1) Проверить, не является ли это обычным
// POSIX-совместимым devctl()
if ((sts =
iofunc_devctl_default(ctp, msg, ocb)) !=
_RESMGR_DEFAULT) {
return (sts);
}
// 2) Узнать, что за команда, и отработать ее
switch (msg->i.dcmd) {
case DCMD_AUDIO_SET_CHANNEL_MONO:
audio_set_nchannels(1);
break;
case DCMD_AUDIO_SET_CHANNEL_STEREO:
audio_set_nchannels(2);
break;
case DCMD_AUDIO_SET_SAMPLE_RATE_CD:
audio_set_samplerate(44100);
break;
case DCMD_AUDIO_SET_SAMPLE_RATE_DAT:
audio_set_samplerate(48000);
break;
// 3) Если мы не знаем такой команды, отвергнуть ее
default:
return (ENOSYS);
}
// 4) Сказать клиенту, что все отработано
memset(imsg->о, 0, sizeof(msg->о));
SETIOV(ctp->iov, &msg->o, sizeof(msg->o));
return (_RESMGR_NPARTS(1));
}
Этап 1
На первом этапе мы снова видим применение вспомогательной функции, на этот раз — функции iofunc_devctl_default() , которая используется для выполнения всей обработки по умолчанию для devctl() . Если вы не поставляете свою версию io_devctl() , а только инициализируете таблицы функций ввода/вывода и установления соединения при помощи iofunc_func_init() , будет вызвана именно iofunc_devctl_default() . Мы включаем ее в нашу версию io_devctl() , потому что мы хотим, чтобы она обработала для нас все стандартные POSIX-варианты вызова devctl() . Затем мы проверяем возвращаемое значение; если это не _RESMGR_DEFAULT, значит, функция iofunc_devctl_default() «обработала» запрос, и нам остается только возвратить это значение, выдав его за «наше».
Если возвращенное значение является константой _RESMGR_DEFAULT, это говорит нам, что вспомогательная функция не обработала запрос, и что мы должны выяснить, является ли он одним из «наших».
Этап 2
Эта проверка выполняется на этапе 2 при помощи инструкции switch
/ case
. Мы просто проверяем значение dcmd , которое клиентский код указал во втором параметре функции devctl() , на предмет совпадения с какой-нибудь из «наших» команд. Обратите внимание, что для выполнения фактической «работы» для клиента мы вызываем фиктивные функции audio_set_nchannels() и audio_set_samplerate() . Здесь важно отметить, что мы преднамеренно избегаем обсуждения области данных функции devctl() . Вы можете подумать: «А что если я хочу установить частоту дискретизации в некое значение n ? Как это сделать?» На этот вопрос мы ответим в следующем примере io_devctl() , который представлен ниже.
Читать дальше