Поделиться через


Координация запросов ввода-вывода с состоянием питания компонента

[Применимо только к KMDF]

Драйвер KMDF для устройства с несколькими компонентами должен отправлять запросы только компонентам, которые находятся в активном состоянии. Как правило, драйвер назначает очереди ввода-вывода компонентам или наборам компонентов.

Сначала рассмотрим очередь, назначенную одному компоненту. Драйвер запускает очередь, когда компонент становится активным и останавливает очередь, когда компонент становится бездействующий. Таким образом, когда KMDF вызывает обработчик запросов для очереди, устройство находится в полностью включенном состоянии (D0), и необходимый компонент активен. Обработчик запросов может безопасно получить доступ к оборудованию компонента.

Та же концепция применяется к очереди, назначенной набору компонентов. В этом случае драйвер запускает очередь, когда все компоненты в наборе активны. Драйвер останавливает очередь, когда один из компонентов становится неактивным.

В этом разделе описывается, как драйвер KMDF для устройства с несколькими компонентами может реализовать такую поддержку в ситуации с несколькими типами запросов, требующими различных сочетаний компонентов.

Пример

Для каждого типа запроса, поддерживаемого драйвером, определите необходимые компоненты. Например, рассмотрим устройство с тремя компонентами: 0, 1 и 2, для которых драйвер получает три типа запросов: A, B и C. Требования к компоненту запросов приведены следующим образом:

Тип запроса Необходимые компоненты
А 0,2
Б 1
С 0,1,2

В этом примере существует три отдельных набора компонентов, по одному для каждого типа запроса. Драйвер предоставляет одну очередь ввода-вывода, управляемую питанием для устройства, а также одну дополнительную очередь, управляемую питанием, соответствующую каждому набору компонентов. В приведенном выше примере драйвер создает одну первичную очередь и три вторичные очереди, одну из которых соответствует каждому набору компонентов. Эта конфигурация очереди показана на следующей схеме:

Схема, показывающая реализацию очереди для устройства с несколькими компонентами с типами запросов A, B и C.

Драйвер поддерживает битовую маску для каждого набора компонентов. Каждый бит в битовой маске представляет состояние активности или простоя одного из компонентов. Если бит задан, компонент активен. Если бит очищается, компонент неактивен.

При поступлении запроса обработчик запроса для очереди верхнего уровня определяет компоненты, необходимые запросу, и вызывает PoFxActivateComponent для каждого из них. Затем обработчик запросов перенаправит запрос в очередь вторичного ввода-вывода, соответствующую набору этого компонента.

Когда компонент становится активным, платформа управления питанием (PoFx) вызывает подпрограмму ComponentActiveConditionCallback драйвера. В этом обратном вызове драйвер задает бит, соответствующий указанному компоненту, в каждой битовой маске, в которой представлен этот компонент. Если заданы все биты в заданной битовой маске, все компоненты в соответствующем наборе активны. Для каждого набора компонентов, который полностью активен, драйвер вызывает WdfIoQueueStart , чтобы запустить соответствующую вторичную очередь ввода-вывода.

Например, рассмотрим гипотетическое устройство выше. Предположим, что компонент 0 активен, а компоненты 1 и 2 неактивны. Когда компонент 2 становится активным, PoFx вызывает подпрограмму ComponentActiveConditionCallback компонента. Типы запросов A и C используют компонент 2, поэтому драйвер управляет битовыми масками для этих двух типов запросов. Так как теперь заданы все биты в битовой маске для типа A запроса, драйвер запускает очередь для типа A запроса. Однако не все биты задаются для типа запроса C (компонент 1 по-прежнему неактивен). Драйвер не запускает очередь для типа запроса C.

При запуске вторичной очереди ввода-вывода платформа начинает доставку запросов, хранящихся в очереди. В обработчике запросов для вторичной очереди ввода-вывода драйвер может безопасно обработать запросы, так как компонент активен, а ссылка на питание была взята на компонент для каждого из запросов.

После завершения обработки запроса драйвер вызывает PoFxIdleComponent для каждого компонента, используемого запросом, а затем завершает запрос. Когда больше нет запросов, использующих компонент, фреймворк энергопотребления вызывает процедуру ComponentIdleConditionCallback драйвера.

В этом обратном вызове драйвер очищает бит, соответствующий указанному компоненту, в каждой битовой маске, где представлен этот компонент. Если заданная битовая маска указывает, что компонент является первым в соответствующем наборе для перехода к условию простоя, драйвер вызывает WdfIoQueueStop , чтобы остановить соответствующую вторичную очередь ввода-вывода. Таким образом, драйвер гарантирует, что очередь не отправляет запросы, если все компоненты в соответствующем наборе не активны.

Рассмотрим еще раз приведенный выше пример. Предположим, что все компоненты активны, и поэтому запускаются все очереди. Когда компонент 1 становится неактивным, PoFx вызывает подпрограмму ComponentIdleConditionCallback для компонента 1. В этом обратном вызове драйвер манипулирует битовыми масками для типов запросов B и C, так как они используют компонент 1. Так как компонент 1 является первым компонентом, который становится неактивным для обоих типов запросов, драйвер останавливает очереди для типов запросов B и C.

Предположим, что на этом этапе компонент 0 становится бездействующим. В ComponentIdleConditionCallback для компонента 0 драйвер манипулирует битовыми масками для типов запросов A и C. Так как компонент 0 является первым компонентом, который становится неактивным для типа запроса A (компонент 2 по-прежнему активен), драйвер останавливает очередь для типа запроса A. Однако для типа запроса C компонент 0 не является первым компонентом, который становится неактивным. Драйвер не останавливает очередь для типа запроса C (это произошло ранее).

Чтобы использовать метод, описанный в этом примере, драйвер также должен зарегистрировать функцию обратного вызова EvtIoCanceledOnQueue для каждой из своих вторичных очередей. Если запрос был бы отменен в тот момент, когда находится во вторичной очереди, драйвер может использовать этот обратный вызов, чтобы вызвать PoFxIdleComponent для каждого соответствующего компонента. При этом освобождается ссылка на питание, которую обработчик запросов взял при вызове PoFxActivateComponent, прежде чем перенаправил запрос во вторичную очередь.