На первом этапе мы снова видим применение вспомогательной функции, на этот раз — функции 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(), который представлен ниже.Этап 3
Этот этап — дань концепции защитного программирования. Мы возвращаем код ошибки ENOSYS, чтобы сообщить клиенту, что мы не распознали его запрос.
Этап 4
Наконец, мы обнуляем возвратную структуру и устанавливаем на нее одноэлементный вектор ввода/вывода. Затем мы возвращаем библиотеке администратора ресурсов единицу (1) через макрос _RESMGR_NPARTS()
, сообщая ей тем самым, что мы возвращаем одноэлементный вектор ввода/вывода. Это и будет возвращено клиенту. Как вариант, мы могли бы применить макрос _RESMGR_PTR():// Вместо этого
// 4) Сказать клиенту, что это сработало
memset(imsg->о, 0, sizeof(msg->о));
SETIOV(&ctp->iov, &msg->о, sizeof(msg->o));
return (_RESMGR_NPARTS(1));
//Мы могли бы сделать так:
// 4) Сказать клиенту, что это сработало
memset(imsg->о, 0, sizeof(msg->о));
return (_RESMGR_PTR(ctp, imsg->o, sizeof(msg->o)));
Причиной тому, что мы здесь обнулили возвращаемую структуру (вспомните, в примерах io_read()
и io_write() мы этого не делали) является то, что в данном случае возвращаемая структура имеет реальное содержимое! (В случае с io_read() мы возвращали только собственно данные и число считанных байт — никакой «возвращаемой структуры» не было; в случае же с io_write() единственным возвращаемым значением было число записанных байт.)Пример функции io_devctl()
, имеющей дело с даннымиВ предыдущем примере io_devctl()
мы подняли вопрос о том, как устанавливать произвольные значения частоты дискретизации, Очевидно, создание большого количества констант DCMD_AUDIO_SET_SAMPLE_RATE_* было бы не самым оптимальным решением — у нас бы просто не хватило разрядности поля dcmd.С клиентской стороны мы будем использовать указатель на частоту дискретизации, dev_data_ptr
, которую мы просто передадим как целое, поэтому поле nbytes будет содержать число байт в целом числе (для 32-разрядных машин это 4). Будем предполагать, что для этих целей определена константа DCMD_AUDIO_SET_SAMPLE_RATE.Также неплохо было бы уметь считывать текущее значение частоты дискретизации. Для этого мы также будем использовать переменные dev_data_ptr
и nbytes, как описано выше, но в обратном направлении — администратор ресурсов запишет nbytes данных в ячейку памяти, на которую указывает dev_data_ptr, вместо чтения данных из этой ячейки. Предположим, что для этого определена константа DCMD_AUDIO_GET_SAMPLE_RATE.Давайте посмотрим, что в таком случае происходит в функции io_devctl()
администратора ресурсов (того, что обсуждалось в предыдущем примере, мы здесь касаться не будем):/*
* io_devctl2.с
*/
#include
#include
#include
#include
#include
#include
#include
#define DCMD_AUDIO_SET_SAMPLE_RATE 1