Какое из следующих действий обычно выполняется драйвером периферийного устройства

Обновлено: 06.07.2024

Добавление нового периферийного устройства (без возможности горячей замены) обычно включает в себя следующее:

Выключение системы

Подключение устройства к системе

Перезагрузка системы

Используйте процедуру добавления периферийного устройства, чтобы добавить в систему следующие устройства, которые не поддерживают горячее подключение:

Дополнительный диск

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

Как добавить периферийное устройство

Выполните шаги 2 и 3 раздела Как добавить драйвер устройства, если вам нужно добавить драйвер устройства для поддержки устройства.

Создайте файл /reconfigure.

Файл /reconfigure заставит программное обеспечение Solaris проверить наличие новых установленных устройств при следующем включении или загрузке системы.

Выключите систему.

Переводит систему в состояние инициализации 0, что является подходящим состоянием для отключения питания системы для добавления и удаления устройств.

Выключает систему через 30 секунд. По умолчанию 60 секунд.

Продолжает завершение работы системы без вмешательства пользователя. В противном случае вам будет предложено продолжить процесс выключения.

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

Для платформ SPARC безопасно отключать питание, если отображается запрос ok.

Для платформ Intel безопасно отключать питание, если отображается запрос для продолжения введите любую клавишу.

Информацию о расположении выключателя питания см. в руководстве по установке оборудования, прилагаемом к вашей системе.

Отключите питание всех внешних устройств.

Чтобы узнать, где находятся выключатели питания на любых периферийных устройствах, обратитесь к руководствам по установке оборудования, прилагаемым к вашим периферийным устройствам.

Установите периферийное устройство, убедившись, что добавляемое устройство имеет другой целевой номер, чем другие устройства в системе.

Часто в задней части диска можно найти небольшой переключатель для выбора целевого номера.

Сведения об установке и подключении устройства см. в руководстве по установке оборудования, прилагаемом к периферийному устройству.

Включите питание системы.

Система загружается в многопользовательский режим, и отображается запрос на вход.

Убедитесь, что периферийное устройство добавлено, попытавшись получить к нему доступ.

Информацию о доступе к устройству см. в Главе 29, Доступ к устройствам (обзор).

Как добавить драйвер устройства

Эта процедура предполагает, что устройство уже добавлено в систему. Если нет, см. раздел Что вам нужно для неподдерживаемых устройств.

Вставьте ленту, дискету или компакт-диск в дисковод.

Установите драйвер.

Определяет путь к устройству, содержащему пакет.

Идентифицирует имя пакета, содержащего драйвер устройства.

Убедитесь, что пакет добавлен правильно.

Системная подсказка возвращается без ответа, если пакет установлен правильно.

Пример — добавление драйвера устройства

В следующем примере показано, как установить и проверить пакет с именем XYZdrv.

Существует два основных типа драйверов Microsoft Windows:

Драйверы пользовательского режима выполняются в пользовательском режиме и обычно обеспечивают интерфейс между приложением Win32 и драйверами режима ядра или другими компонентами операционной системы.

Например, в Windows Vista все драйверы принтеров выполняются в пользовательском режиме. Дополнительные сведения о компонентах драйвера принтера см. в разделе Введение в печать.

Драйверы режима ядра выполняются в режиме ядра как часть исполнительной системы, состоящей из компонентов операционной системы режима ядра, которые управляют вводом-выводом, памятью Plug and Play, процессами и потоками, безопасностью, и так далее. Драйверы режима ядра обычно являются многоуровневыми. Как правило, драйверы более высокого уровня обычно получают данные от приложений, фильтруют данные и передают их драйверу более низкого уровня, поддерживающему функциональные возможности устройства.

Некоторые драйверы режима ядра также являются драйверами WDM, которые соответствуют модели драйверов Windows (WDM). Все драйверы WDM поддерживают Plug and Play и управление питанием. Драйверы WDM совместимы с исходным кодом (но не совместимы с двоичным кодом) в операционных системах Windows 98/Me и Windows 2000 и более поздних версиях.

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

На следующем рисунке драйверы режима ядра разделены на несколько типов.

диаграмма, иллюстрирующая типы драйверы режима ядра». /><br /></p>
<p>Как показано на рисунке, в стеке драйверов есть три основных типа драйверов режима ядра: самого высокого уровня, промежуточного и самого низкого уровня. Каждый тип незначительно отличается по структуре, но значительно отличается по функциональности:</p>
<p><em>Драйверы самого высокого уровня</em>. К драйверам самого высокого уровня относятся драйверы файловой системы (FSD), поддерживающие файловые системы, например:</p>
<p>Таблица размещения файлов (FAT)</p>
<p>Файловая система CD-ROM (CDFS)</p>
<p>Драйверы самого высокого уровня всегда зависят от поддержки базовых драйверов более низкого уровня, таких как функциональные драйверы промежуточного уровня и драйверы аппаратной шины самого низкого уровня.</p>
<p><em>Промежуточные драйверы</em>, такие как виртуальный диск, зеркало или <em>драйвер класса</em> для конкретного типа устройства. Промежуточные драйверы зависят от поддержки базовых драйверов более низкого уровня. Промежуточные драйверы подразделяются следующим образом:</p>
<p><em>Драйверы функций</em> управляют определенными периферийными устройствами на шине ввода-вывода.</p>
<p><em>Драйверы фильтров</em> вставляются выше или ниже функциональных драйверов.</p>
<p><em>Драйверы программной шины</em> представляют собой набор дочерних устройств, к которым могут присоединяться драйверы классов, функций или фильтров еще более высокого уровня.</p>
<p>Например, драйвер, управляющий многофункциональным адаптером с набором разнородных устройств на борту, является программным драйвером шины.</p>
<p>Любой поставляемый системой <em>драйвер класса</em>, который экспортирует системный интерфейс класса/миникласса, фактически является промежуточным драйвером с одним или несколькими связанными <em>драйверами миникласса</em> (иногда называются <em>минидрайверами</em>). Каждая связанная пара класса/минидрайвера обеспечивает функциональные возможности, эквивалентные функциональному драйверу или программному драйверу шины.</p>
<p><em>Драйверы самого низкого уровня</em> управляют шиной ввода-вывода, к которой подключены периферийные устройства. Драйверы самого низкого уровня не зависят от драйверов более низкого уровня.</p>
<p>Аппаратные <em>драйверы шины</em> поставляются системой и обычно управляют динамически настраиваемыми шинами ввода-вывода.</p>
<p>Драйверы аппаратных шин работают с диспетчером Plug and Play для настройки и перенастройки аппаратных ресурсов системы для всех дочерних устройств, подключенных к шинам ввода-вывода, которыми управляет драйвер. Эти аппаратные ресурсы включают сопоставления памяти устройства и запросов на прерывание (IRQ). (Драйверы аппаратной шины включают в себя некоторые функции, предоставляемые компонентом HAL в более ранних версиях операционной системы на базе Windows NT, чем Windows 2000.)</p>
<p><em>Устаревшие драйверы</em>, напрямую управляющие физическим устройством, являются драйверами самого низкого уровня.</p>
<p>В отличие от такой шины, как PCI, простая периферийная шина (SPB), такая как I²C или SPI, не предоставляет стандартизированных, специфичных для шины средств для передачи запросов на прерывание от периферийных устройств к процессору. Вместо этого периферийное устройство, подключенное к SPB, сигнализирует о прерывании через отдельный аппаратный путь, который находится за пределами как SPB, так и контроллера SPB. Детали этого пути прерывания, как правило, варьируются от одной аппаратной платформы к другой, но Windows скрывает эти детали от драйвера периферийного устройства, подключенного к SPB, чтобы драйвер мог работать на различных аппаратных платформах.</p>
<p>Как правило, линия запроса прерывания от периферийного устройства, подключенного к SPB, подключается к контакту на контроллере ввода-вывода общего назначения (GPIO), и контроллер GPIO передает прерывания от устройства к процессору. Дополнительные сведения см. в разделе Прерывания GPIO.</p>
<p>Драйвер периферийного устройства получает это прерывание GPIO как абстрактный ресурс прерывания Windows (CmResourceTypeInterrupt) и подключает прерывание к процедуре обслуживания прерываний драйвера (ISR). Абстракция ресурса прерывания скрывает от драйвера специфичные для платформы детали прерывания. Например, драйвер может игнорировать такие детали, как получение прерывания от вывода GPIO или от какого-либо другого источника. Чтобы поддерживать эту абстракцию, обработчику ловушки прерывания ядра, который работает в DIRQL, может потребоваться заглушить активный запрос на прерывание, очистив или временно маскируя прерывание на выводе GPIO. Аппаратные регистры контроллера GPIO обычно отображаются в памяти и доступны в DIRQL.</p>
<p>В отличие от этого, периферийное устройство, подключенное к SPB, не отображается в память, и ISR для этого устройства обычно должен работать на уровне IRQL = PASSIVE_LEVEL. Чтобы получить доступ к аппаратным регистрам в устройстве, ISR отправляет запросы ввода-вывода для выполнения последовательной передачи через SPB. Такие передачи выполняются относительно медленно и не могут выполняться в ISR, работающем на DIRQL. Однако ISR пассивного уровня может отправлять запрос ввода-вывода синхронно, а затем блокировать его до тех пор, пока запрос не будет выполнен.</p>
<p>Для прерывания, инициируемого фронтом, обработчик прерывания ядра автоматически очищает запрос на прерывание на выводе GPIO, а затем планирует выполнение ISR устройства на пассивном уровне. Обработчик ловушки должен очистить прерывание, чтобы предотвратить повторение того же прерывания после возврата обработчика ловушки.</p>
<p>Для прерывания, запускаемого по уровню, обработчик ловушки прерывания ядра автоматически маскирует запрос на прерывание на выводе GPIO, а затем планирует запуск ISR устройства на пассивном уровне. ISR должен очистить запрос на прерывание от устройства. После возврата ISR ядро ​​демаскирует запрос на прерывание на выводе GPIO.</p>
<p>Обработчик прерывания пассивного уровня устройства должен выполнять только начальное обслуживание прерывания, а затем возвращаться, чтобы не задерживать ISR пассивного уровня для других устройств. Как правило, драйвер должен отложить дополнительную обработку, связанную с прерыванием, на рабочий поток прерывания, который выполняется с более низким приоритетом, чем ISR.</p>
<p>Начиная с Windows 8, платформа драйверов пользовательского режима (UMDF) поддерживает ISR для драйверов UMDF. Драйвер UMDF для периферийного устройства SPB вызывает метод IWDFDevice3::CreateInterrupt для подключения ISR к прерыванию от устройства. Когда устройство сигнализирует о запросе на прерывание, обработчик ловушки ядра планирует запуск ISR на пассивном уровне. Дополнительные сведения см. в разделе Доступ к оборудованию и обработка прерываний.</p>
<p>Начиная с Windows 8 платформа драйверов режима ядра (KMDF) поддерживает ISR пассивного уровня. Драйвер KMDF для периферийного устройства SPB вызывает метод WdfInterruptCreate для подключения ISR пассивного уровня к прерыванию от устройства. Одним из входных параметров этого метода является указатель на структуру WDF_INTERRUPT_CONFIG, содержащую информацию о конфигурации для прерывания. Чтобы настроить ISR для работы на пассивном уровне, установите элемент PassiveHandling этой структуры в значение TRUE. Дополнительные сведения см. в разделе Поддержка прерываний пассивного уровня.</p>
<p>В этой главе описываются механизмы обработки прерываний, такие как регистрация, обслуживание и удаление прерываний. В этой главе содержится информация по следующим темам:</p>
<p>Прерывание — это аппаратный сигнал от устройства к ЦП. Он сообщает ЦП, что устройство требует внимания и что ЦП должен прекратить выполнять то, что он делает, и реагировать на устройство. Если процессор доступен (он не выполняет задачу с более высоким приоритетом), он приостанавливает текущий поток и, в конце концов, вызывает обработчик прерывания для этого устройства. Работа обработчика прерывания состоит в том, чтобы обслуживать устройство и не допускать его прерывания. Как только обработчик возвращается, ЦП возобновляет работу, которую он выполнял до возникновения прерывания.</p>
<p>DDI/DKI предоставляет интерфейсы для регистрации и обслуживания прерываний.</p>
<h2>Спецификация прерывания</h2>
<p>Спецификация прерывания — это информация, которую система использует для привязки источника прерывания устройства к конкретному обработчику прерывания устройства. Спецификация описывает информацию, предоставляемую аппаратным обеспечением системе при выполнении запроса на прерывание. Поскольку спецификация прерывания зависит от шины, содержащаяся в ней информация варьируется от шины к шине.</p>
<p>Спецификации прерывания обычно включают уровень прерывания шины. Для векторных прерываний спецификация включает вектор прерывания. На платформах IA спецификация прерывания определяет относительный приоритет прерывания устройства. Поскольку спецификации прерываний зависят от конкретной шины, см. справочные страницы для isa(4), eisa(4), sbus(4) и pci(4) для получения информации о спецификациях прерываний для этих шин.</p>
<h2>Номер прерывания</h2>
<p>При регистрации прерываний драйвер должен предоставить системе номер прерывания. Этот номер прерывания идентифицирует спецификацию прерывания, для которой драйвер регистрирует обработчик. Большинство устройств имеют одно прерывание: номер прерывания 0. Однако есть устройства, которые имеют разные прерывания для разных событий. Контроллер связи может иметь одно прерывание для готовности к приему и одно для готовности к передаче. Драйвер устройства обычно знает, сколько прерываний имеет устройство, но если драйвер должен поддерживать несколько вариантов контроллера, он может вызвать ddi_dev_nintrs(9F), чтобы узнать количество прерываний устройства.</p>
<h2>Прервать блокировку файлов cookie</h2>
<p>Файл cookie <tt>iblock</tt> — это непрозрачная структура данных, которая представляет информацию, необходимую системе для блокировки прерываний, и возвращается из ddi_get_iblock_cookie(9F) или ddi_get_soft_iblock_cookie(9F). Этот интерфейс использует номер прерывания для возврата файла cookie <tt>iblock</tt>, связанного с определенным источником прерывания. Значение файла cookie <tt>iblock</tt> (не адрес) должно быть передано в mutex_init(9F) при инициализации мьютексов драйвера, которые будут использоваться в процедуре прерывания. Значение файла cookie <tt>iblock</tt> получается путем передачи адреса файла cookie в ddi_get_iblock_cookie() или ddi_get_soft_iblock_cookie(). Например:</p>
<p>Шины реализуют прерывания двумя распространенными способами: векторным и опросным. Оба метода обычно обеспечивают уровень приоритета прерывания шины. Однако векторные устройства также предоставляют вектор прерывания; опрашиваемых устройств нет.</p>
<h2>Прерывания высокого уровня</h2>
<p>mutex_enter(9F) и mutex_exit(9F) в мьютексе, инициализированном файлом cookie <tt>iblock</tt>, связанным с прерыванием высокого уровня</p>
<p>Уровень прерывания шины сам по себе не определяет, прерывается ли устройство на высоком уровне: данный уровень прерывания шины может сопоставляться с высокоуровневым прерыванием на одной платформе, но сопоставляться с обычным прерыванием на другой платформе.< /p>
<p>Драйвер может выбрать, поддерживать ли устройства с высокоуровневыми прерываниями, но он всегда должен проверять — он не может предположить, что его прерывания не являются высокоуровневыми. Функция <tt>ddi_intr_hilevel</tt>(9F), учитывая номер прерывания, возвращает значение, указывающее, является ли прерывание высоким уровнем.</p>
<h2>Обычные прерывания</h2>
<p>Единственная информация, которую система имеет о прерывании устройства, — это либо уровень приоритета прерывания шины (например, IPL, на SBus в машине SPARC), либо номер запроса на прерывание (IRQ на шине ISA в машине IA, например).</p>
<p>Когда обработчик прерываний зарегистрирован, система добавляет его в список потенциальных обработчиков прерываний для каждой IPL или IRQ. Как только происходит прерывание, система должна определить, какое устройство из всех устройств, связанных с данной IPL или IRQ, фактически было прервано. Это достигается путем вызова всех обработчиков прерываний для назначенной IPL или IRQ до тех пор, пока один из обработчиков не примет прерывание.</p>
<p>Шины SBus, ISA, EISA и PCI могут поддерживать прерывания по запросу.</p>
<h2>Программные прерывания</h2>
<p>Solaris 9 DDI/DKI поддерживает программные прерывания, также известные как программные прерывания. Мягкие прерывания инициируются программным обеспечением, а не аппаратным устройством. Обработчики этих прерываний также должны быть добавлены в систему и удалены из нее. Обработчики программных прерываний работают в контексте прерывания и поэтому могут использоваться для выполнения многих задач, принадлежащих обработчику прерывания.</p>
<p>Обработчики аппаратных прерываний должны выполнять свои задачи быстро, поскольку во время работы они могут приостанавливать другие действия системы. Это особенно верно для высокоуровневых обработчиков прерываний, которые работают с более высокими уровнями приоритета, чем у системного планировщика. Обработчики прерываний высокого уровня маскируют операции всех прерываний с более низким приоритетом, включая прерывания системных часов. Следовательно, обработчик прерываний должен избегать действий (например, захвата мьютекса), которые могут привести к его переходу в спящий режим.</p>
<p>Если обработчик спит, система может зависнуть, потому что часы замаскированы и не могут запланировать спящий поток. По этой причине обработчики прерываний высокого уровня обычно выполняют минимальный объем работы на уровнях высокого приоритета и делегируют оставшиеся задачи программным прерываниям, которые выполняются ниже уровня приоритета обработчика прерываний высокого уровня. Поскольку обработчики программных прерываний работают ниже уровня приоритета системного планировщика, они могут выполнять работу, на которую не способен высокоуровневый обработчик прерываний.</p>
<p>Прежде чем драйвер устройства сможет получать и обслуживать прерывания, он должен зарегистрировать обработчик прерываний в системе, вызвав <tt>ddi_add_intr</tt>(9F). Регистрация прерываний предоставляет системе способ связать обработчик прерывания со спецификацией прерывания. Обработчик прерывания вызывается, когда устройство может быть ответственным за прерывание. Обработчик отвечает за определение того, должен ли он обрабатывать прерывание, и если да, то за его получение.</p>
<p>Существует потенциальное состояние гонки между добавлением обработчика прерывания и инициализацией мьютексов. Подпрограмма прерывания может быть вызвана, как только <tt>ddi_add_intr</tt>(9F) вернется, поскольку другое устройство может прервать выполнение и вызвать вызов обработчика. Это может привести к тому, что процедура прерывания будет вызвана до того, как какие-либо мьютексы будут инициализированы с помощью возвращенного файла cookie блока прерывания. Если процедура обработки прерывания захватывает мьютекс до того, как он будет инициализирован, это может привести к неопределенному поведению. Чтобы гарантировать, что это состояние гонки не возникнет, всегда инициализируйте мьютексы и любые другие данные, используемые в обработчике прерывания, перед добавлением прерывания.</p>
<p>Чтобы зарегистрировать обработчик прерывания драйвера, драйвер обычно выполняет следующие шаги в attach(9E).</p>
<p>Проверьте наличие прерываний высокого уровня, вызвав <tt>ddi_intr_hilevel</tt>(9F), чтобы выяснить, соответствует ли спецификация прерывания прерыванию высокого уровня. Если это так, одна из возможностей состоит в том, чтобы опубликовать сообщение об этом и вернуть <tt>DDI_FAILURE</tt>. См. пример 7–1.</p>
<p>Получите файл cookie <tt>iblock</tt>, вызвав <tt>ddi_get_iblock_cookie</tt>(9F).</p>
<p>Инициализируйте все связанные мьютексы с помощью файла cookie <tt>iblock</tt>, вызвав mutex_init(9F).</p>
<p>Зарегистрируйте обработчик прерывания, вызвав ddi_add_intr(9F).</p>
<p>В примере 7–1 показано, как установить обработчик прерываний.</p>
<h5>Пример 7–1 attach(9E) Процедура установки обработчика прерываний</h5>
<p>Обработчик прерывания выполняет ряд обязанностей.Некоторые из них требуются для платформы, а некоторые — для устройства. Все обработчики прерываний должны выполнять следующие действия:</p>
<p>Определить, прерывает ли устройство, и, возможно, отклонить прерывание. </p>
<p>Обработчик прерывания должен сначала проверить устройство и определить, выдало ли оно прерывание. Если это не так, обработчик должен вернуть <tt>DDI_INTR_UNCLAIMED</tt>. Этот шаг позволяет реализовать опрос устройств: он сообщает системе, выдало ли прерывание это устройство среди множества устройств с заданным уровнем приоритета прерывания.</p>
<p>Сообщите устройству, что оно обслуживается. </p>
<p>Это операция для конкретного устройства, но она требуется для большинства устройств. Например, устройства SBus должны прерываться до тех пор, пока драйвер не скажет им остановиться. Это гарантирует, что все устройства SBus, прерывающие работу с одинаковым уровнем приоритета, будут обслуживаться.</p>
<p>Выполнить любую обработку запросов ввода-вывода. </p>
<p>Устройства прерываются по разным причинам, например из-за выполнения передачи или ошибки передачи. Этот шаг может включать использование функций доступа к данным для чтения буфера данных устройства, проверки регистра ошибок устройства и соответствующей установки поля состояния в структуре данных. Диспетчеризация и обработка прерываний занимают относительно много времени.</p>
<p>Выполните любую дополнительную обработку, которая может предотвратить другое прерывание. </p>
<p>Например, прочитать следующий элемент данных с устройства.</p>
<p>Возврат <tt>DDI_INTR_CLAIMED</tt>.</p>
<p>В следующем примере показана процедура прерывания.</p>
<h5>Пример 7–2 Пример прерывания</h5>
<p>Большинство шагов, выполняемых подпрограммой прерывания, зависят от особенностей самого устройства. Обратитесь к руководству по оборудованию для устройства, чтобы определить причину прерывания, выявить условия ошибки и получить доступ к регистрам данных устройства.</p>
<p>Прерывания высокого уровня — это прерывания на уровне планировщика и выше. Этот уровень не позволяет запускать планировщик; следовательно, обработчики прерываний высокого уровня не могут быть вытеснены планировщиком, и они не могут полагаться на планировщик (то есть они не могут блокироваться из-за планировщика) — они могут использовать только блокировки взаимного исключения для блокировки.</p>
<p>По этой причине драйвер должен использовать ddi_intr_hilevel(9F), чтобы определить, использует ли он прерывания высокого уровня. Если <tt>ddi_intr_hilevel</tt>(9F) возвращает значение true, драйвер может не подключиться или использовать двухуровневую схему для обработки прерываний.</p>
<p>Предлагаемый метод заключается в добавлении обработчика прерывания высокого уровня, который просто запускает программное прерывание с более низким приоритетом для обработки устройства. Драйвер должен обеспечивать больший параллелизм, используя отдельный мьютекс для защиты данных от обработчика высокого уровня.</p>
<h2>Мьютексы высокого уровня</h2>
<p>Мьютекс, инициализированный файлом cookie блока прерывания, представляющим прерывание высокого уровня, называется мьютексом высокого уровня. При удерживании мьютекса высокого уровня на драйвер распространяются те же ограничения, что и на обработчик прерывания высокого уровня.</p>
<h2>Пример высокоуровневой обработки прерываний</h2>
<p>В примере, представленном в Примере 7–3, мьютекс высокого уровня ( xsp->high_mu ) используется только для защиты данных, совместно используемых обработчиком прерывания высокого уровня и обработчиком мягкого прерывания. Это включает в себя очередь, в которую обработчик прерывания высокого уровня добавляет данные (и из которой обработчик низкого уровня удаляет данные), и флаг, указывающий на то, что обработчик низкого уровня работает. Отдельный низкоуровневый мьютекс ( xsp->low_mu ) защищает остальную часть драйвера от обработчика программных прерываний.</p>
<h5>Пример 7–3 attach(9E) Стандартная обработка прерываний высокого уровня</h5>
<p>Подпрограмма прерывания высокого уровня обслуживает устройство и ставит данные в очередь. Подпрограмма высокого уровня запускает программное прерывание, если подпрограмма низкого уровня не выполняется, как показано в примере 7–4.</p>
<h5>Пример 7–4 Процедура прерывания высокого уровня</h5>
<p>Подпрограмма прерывания низкого уровня запускается подпрограммой обработки прерывания высокого уровня, запускающей программное прерывание. После запуска он должен продолжать это делать до тех пор, пока не останется ничего для обработки, как показано в примере 7–5.</p>
</p>
<p><b>Читайте также:</b></p>
<ul>

  <li><a href=Программное обеспечение для просмотра DVD на компьютере   

  • Как отключить блокировку рекламы в Opera
  •   
  • Программа школьного звонка
  •   
  • Как выйти из полноэкранного режима в AutoCad
  •   
  • Формат по образцу в Word как им пользоваться