Координация запросов ввода-вывода с состоянием питания компонента
[Относится только к KMDF]
Драйвер KMDF для многокомпонентного устройства должен отправлять запросы только к компонентам, которые находятся в активном состоянии. Как правило, драйвер назначает очереди ввода-вывода компонентам или наборам компонентов.
Сначала рассмотрим очередь, назначенную одному компоненту. Драйвер запускает очередь, когда компонент становится активным, и останавливает очередь при бездействии компонента. Таким образом, когда KMDF вызывает обработчик запросов для очереди, устройство находится в состоянии полного включения (D0), а необходимый компонент активен. Обработчик запросов может безопасно обращаться к оборудованию компонентов.
Эта же концепция применяется к очереди, назначенной набору компонентов. В этом случае драйвер запускает очередь, когда все компоненты в наборе активны. Драйвер останавливает очередь, когда любой из компонентов неактивно.
В этом разделе описывается, как драйвер KMDF для многокомпонентного устройства может реализовать такую поддержку в ситуации с несколькими типами запросов, для которых требуются различные сочетания компонентов.
Пример
Для каждого типа запроса, поддерживаемого драйвером, определите необходимые компоненты. Например, рассмотрим устройство с тремя компонентами: 0, 1 и 2, для которого драйвер получает три типа запросов: A, B и C. Ниже приведены требования к компонентам запросов.
Тип запроса | Необходимые компоненты |
---|---|
A | 0,2 |
B | 1 |
C | 0,1,2 |
В этом примере существует три отдельных набора компонентов, по одному для каждого типа запроса. Драйвер предоставляет одну очередь ввода-вывода по умолчанию, управляемую питанием, для устройства, а также одну дополнительную очередь, управляемую питанием, соответствующую каждому набору компонентов. В приведенном выше примере драйвер создает одну первичную и три вторичные очереди, по одной соответствующей каждому набору компонентов. Эта конфигурация очереди показана на следующей схеме:
Драйвер поддерживает битовую маску для каждого набора компонентов. Каждый бит в битовой маске представляет состояние "активный/ простой" одного из компонентов. Если бит задан, компонент активен. Если бит очищен, компонент бездействует.
При поступлении запроса обработчик запроса для очереди верхнего уровня определяет, какие компоненты требуются запросу, и вызывает PoFxActivateComponent для каждого из них. Затем обработчик запросов перенаправит запрос в вторичную очередь ввода-вывода, соответствующую набору этого компонента.
Когда компонент становится активным, платформа управления питанием (PoFx) вызывает подпрограмму ComponentActiveConditionCallback драйвера. В этом обратном вызове драйвер задает бит, соответствующий указанному компоненту, в каждой битовой маске, где этот компонент представлен. Если заданы все биты в данной битовой маске, все компоненты в соответствующем наборе активны. Для каждого набора компонентов, который является полностью активным, драйвер вызывает WdfIoQueueStart , чтобы запустить соответствующую вторичную очередь ввода-вывода.
Например, рассмотрим гипотетическое устройство выше. Предположим, что компонент 0 активен, а компоненты 1 и 2 простаивают. Когда компонент 2 становится активным, PoFx вызывает подпрограмму ComponentActiveConditionCallback этого компонента. Типы запросов A и C используют компонент 2, поэтому драйвер управляет битовой маской для этих двух типов запросов. Так как все биты в битовой маске для типа запроса A теперь заданы, драйвер запускает очередь для типа запроса A. Однако не все биты заданы для типа запроса C (компонент 1 по-прежнему простаивает). Драйвер не запускает очередь для типа запроса C.
При запуске вторичной очереди ввода-вывода платформа начинает доставлять запросы, хранящиеся в очереди. В обработчике запросов для вторичной очереди ввода-вывода драйвер может безопасно обрабатывать запросы, так как компонент активен и для каждого из запросов была взята ссылка на питание.
Когда драйвер завершает обработку запроса, он вызывает PoFxIdleComponent для каждого компонента, который использовался в запросе, а затем завершает запрос. Если больше нет запросов с использованием компонента, power Framework вызывает подпрограмму 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 перед перенаправлением запроса во вторичную очередь.