Шаг 3. Пакет драйверов для устройства установлен
После того как Windows выберет лучший пакет драйверов для нового устройства, Windows устанавливает пакет драйверов, выполнив следующие действия:
- На основе директив в INF-файлепакета драйверов Windows устанавливает пакет драйвера на устройство. Например, это могут быть следующие сведения:
- Копирует двоичные файлы драйвера и другие связанные файлы в расположения на жестком диске в соответствии с любой соответствующей директивой INF CopyFiles.
- Выполняет операции реестра в соответствии с любой соответствующей директивой INF AddReg.
- Назначает класс настройки устройства устройству из записей Class и ClassGuid в разделе Версия INF.
- После установки пакета драйверов на устройстве устройство будет перезапущено.
- В рамках повторной обработки устройства из-за перезапуска диспетчер Plug and Play (PnP) определяет соответствующий драйвер функции и любые дополнительные драйверы фильтров для устройства и пытается создать стек устройства и запустить устройство. Диспетчер PnP вызывает подпрограмму DriverEntry для любого необходимого драйвера, который еще не загружен. Затем диспетчер PnP вызывает подпрограмму AddDevice для каждого драйвера, начиная с драйверов нижнего фильтра, затем драйвера функции и, наконец, любых драйверов верхнего фильтра. При необходимости диспетчер PnP назначает ресурсы устройству и отправляет IRP_MN_START_DEVICE драйверам устройства.
После завершения этого шага устройство будет установлено и готово к использованию.
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Windows driver documentation
Как написать свой первый Linux device driver
Цель данной статьи — показать принцип реализации драйверов устройств в системе Linux, на примере простого символьного драйвера.
Для меня же, главной целью является подвести итог и сформировать базовые знания для написания будущих модулей ядра, а также получить опыт изложения технической литературы для публики, т.к. через полгода я буду выступать со своим дипломным проектом (да я студент).
Это моя первая статья, пожалуйста не судите строго!
P.S
Получилось слишком много букв, поэтому я принял решение разделить статью на три части:
Часть 1 — Введение, инициализация и очистка модуля ядра.
Часть 2 — Функции open, read, write и trim.
Часть 3 — Пишем Makefile и тестируем устройство.
Перед вступлением, хочу сказать, что здесь будут изложены базовые вещи, более подробная информация будет изложена во второй и последней части данной статьи.
Подготовительные работы
UPD.
Спасибо Kolyuchkin за уточнения.
Символьный драйвер (Char driver) — это, драйвер, который работает с символьными устройствами.
Символьные устройства — это устройства, к которым можно обращаться как к потоку байтов.
Пример символьного устройства — /dev/ttyS0, /dev/tty1.
UPD.
К вопросу про проверсию ядра:
~$ uname -r 4.4.0-93-generic
Драйвер представляет каждое символьное устройство структурой scull_dev, а также предостовляет интерфейс cdev к ядру.
struct scull_dev < struct scull_qset *data; /* Указатель на первый кусок памяти */ int quantum; /* Размер одного кванта памяти */ int qset; /* Количество таких квантов */ unsigned long size; /* Размер используемой памяти */ struct semaphore sem; /* Используется семафорами */ struct cdev cdev; /* Структура, представляющая символьные устройства */ >; struct scull_dev *scull_device;
Устройство будет представлять связный список указателей, каждый из которых указывает на структуру scull_qset.
struct scull_qset < void **data; struct scull_qset *next; >;
Для наглядности посмотрите на картинку.
Для регистрации устройства, нужно задать специальные номера, а именно:
MAJOR — старший номер (является уникальным в системе).
MINOR — младший номер (не является уникальным в системе).
В ядре есть механизм, который позволяет регистрировать специализированные номера вручную, но такой подход нежелателен и лучше вежливо попросить ядро динамически выделить их для нас. Пример кода будет ниже.
После того как мы определили номера для нашего устройства, мы должны установить связь между этими номерами и операциями драйвера. Это можно сделать используя структуру file_operations.
struct file_operations scull_fops = < .owner = THIS_MODULE, .read = scull_read, .write = scull_write, .open = scull_open, .release = scull_release, >;
В ядре есть специальные макросы module_init/module_exit, которые указывают путь к функциям инициализации/удаления модуля. Без этих определений функции инициализации/удаления никогда не будут вызваны.
module_init(scull_init_module); module_exit(scull_cleanup_module);
Здесь будем хранить базовую информацию об устройстве.
int scull_major = 0; /* MAJOR номер*/ int scull_minor = 0; /* MINOR номер*/ int scull_nr_devs = 1; /* Количество регистрируемых устройств */ int scull_quantum = 4000; /* Размер памяти в байтах */ int scull_qset = 1000; /* Количество квантов памяти */
Последним этапом подготовительной работы будет подключение заголовочных файлов.
Краткое описание приведено ниже, но если вы хотите копнуть поглубже, то добро пожаловать на прекрасный сайт: lxr
#include /* Содержит функции и определения для динамической загрузки модулей ядра */ #include /* Указывает на функции инициализации и очистки */ #include /* Содержит функции регистрации и удаления драйвера */ #include /* Содержит необходимые функции для символьного драйвера */ #include /* Содержит функцию ядра для управления памятью */ #include /* Предоставляет доступ к пространству пользователя */
Инициализация
Теперь давайте посмотрим на функцию инициализации устройства.
static int scull_init_module(void) < int rv, i; dev_t dev; rv = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull"); if (rv) < printk(KERN_WARNING "scull: can't get major %d\n", scull_major); return rv; >scull_major = MAJOR(dev); scull_device = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL); if (!scull_device) < rv = -ENOMEM; goto fail; >memset(scull_device, 0, scull_nr_devs * sizeof(struct scull_dev)); for (i = 0; i < scull_nr_devs; i++) < scull_device[i].quantum = scull_quantum; scull_device[i].qset = scull_qset; sema_init(&scull_device[i].sem, 1); scull_setup_cdev(&scull_device[i], i); >dev = MKDEV(scull_major, scull_minor + scull_nr_devs); return 0; fail: scull_cleanup_module(); return rv; >
Первым делом, вызывая alloc_chrdev_region мы регистрируем диапазон символьных номеров устройств и указываем имя устройства. После вызовом MAJOR(dev) мы получаем старший номер.
Далее проверяется вернувшееся значение, если оно является кодом ошибки, то выходим из функции. Стоит отметить, что при разработке реального драйвера устройства следует всегда проверять возвращаемые значения, а также указатели на любые элементы (NULL?).
rv = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull"); if (rv) < printk(KERN_WARNING "scull: can't get major %d\n", scull_major); return rv; >scull_major = MAJOR(dev);
Если вернувшееся значение не является кодом ошибки, продолжаем выполнять инициализацию.
Выделяем память, делая вызов функции kmalloc и обязательно проверяем указатель на NULL.
UPD
Стоит упомянуть, что вместо вызова двух функций kmalloc и memset, можно использовать один вызов kzalloc, который выделят область памяти и инициализирует ее нулями.
scull_device = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL); if (!scull_device) < rv = -ENOMEM; goto fail; >memset(scull_device, 0, scull_nr_devs * sizeof(struct scull_dev));
Продолжаем инициализацию. Главная здесь функция — это scull_setup_cdev, о ней мы поговорим чуть ниже. MKDEV служит для хранения старший и младших номеров устройств.
for (i = 0; i < scull_nr_devs; i++) < scull_device[i].quantum = scull_quantum; scull_device[i].qset = scull_qset; sema_init(&scull_device[i].sem, 1); scull_setup_cdev(&scull_device[i], i); >dev = MKDEV(scull_major, scull_minor + scull_nr_devs);
Возвращаем значение или обрабатываем ошибку и удаляем устройство.
return 0; fail: scull_cleanup_module(); return rv; >
Выше были представлены структуры scull_dev и cdev, которые реализуют интерфейс между нашим устройством и ядром. Функция scull_setup_cdev выполняет инициализацию и добавление структуры в систему.
static void scull_setup_cdev(struct scull_dev *dev, int index) < int err, devno = MKDEV(scull_major, scull_minor + index); cdev_init(&dev->cdev, &scull_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &scull_fops; err = cdev_add(&dev->cdev, devno, 1); if (err) printk(KERN_NOTICE "Error %d adding scull %d", err, index); >
Удаление
Функция scull_cleanup_module вызывается при удалении модуля устройства из ядра.
Обратный процесс инициализации, удаляем структуры устройств, освобождаем память и удаляем выделенные ядром младшие и старшие номера.
void scull_cleanup_module(void) < int i; dev_t devno = MKDEV(scull_major, scull_minor); if (scull_device) < for (i = 0; i < scull_nr_devs; i++) < scull_trim(scull_device + i); cdev_del(&scull_device[i].cdev); >kfree(scull_device); > unregister_chrdev_region(devno, scull_nr_devs); >
Полный код
#include #include #include #include #include #include int scull_major = 0; int scull_minor = 0; int scull_nr_devs = 1; int scull_quantum = 4000; int scull_qset = 1000; struct scull_qset < void **data; struct scull_qset *next; >; struct scull_dev < struct scull_qset *data; int quantum; int qset; unsigned long size; unsigned int access_key; struct semaphore sem; struct cdev cdev; >; struct scull_dev *scull_device; int scull_trim(struct scull_dev *dev) < struct scull_qset *next, *dptr; int qset = dev->qset; int i; for (dptr = dev->data; dptr; dptr = next) < if (dptr->data) < for (i = 0; i < qset; i++) kfree(dptr->data[i]); kfree(dptr->data); dptr->data = NULL; > next = dptr->next; kfree(dptr); > dev->size = 0; dev->quantum = scull_quantum; dev->qset = scull_qset; dev->data = NULL; return 0; > struct file_operations scull_fops = < .owner = THIS_MODULE, //.read = scull_read, //.write = scull_write, //.open = scull_open, //.release = scull_release, >; static void scull_setup_cdev(struct scull_dev *dev, int index) < int err, devno = MKDEV(scull_major, scull_minor + index); cdev_init(&dev->cdev, &scull_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &scull_fops; err = cdev_add(&dev->cdev, devno, 1); if (err) printk(KERN_NOTICE "Error %d adding scull %d", err, index); > void scull_cleanup_module(void) < int i; dev_t devno = MKDEV(scull_major, scull_minor); if (scull_device) < for (i = 0; i < scull_nr_devs; i++) < scull_trim(scull_device + i); cdev_del(&scull_device[i].cdev); >kfree(scull_device); > unregister_chrdev_region(devno, scull_nr_devs); > static int scull_init_module(void) < int rv, i; dev_t dev; rv = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull"); if (rv) < printk(KERN_WARNING "scull: can't get major %d\n", scull_major); return rv; >scull_major = MAJOR(dev); scull_device = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL); if (!scull_device) < rv = -ENOMEM; goto fail; >memset(scull_device, 0, scull_nr_devs * sizeof(struct scull_dev)); for (i = 0; i < scull_nr_devs; i++) < scull_device[i].quantum = scull_quantum; scull_device[i].qset = scull_qset; sema_init(&scull_device[i].sem, 1); scull_setup_cdev(&scull_device[i], i); >dev = MKDEV(scull_major, scull_minor + scull_nr_devs); printk(KERN_INFO "scull: major = %d minor = %d\n", scull_major, scull_minor); return 0; fail: scull_cleanup_module(); return rv; > MODULE_AUTHOR("Your name"); MODULE_LICENSE("GPL"); module_init(scull_init_module); module_exit(scull_cleanup_module);
С удовольствием выслушаю конструктивную критику и буду ждать feedback’a.
Если вы нашли ошибки или я не правильно изложил материал, пожалуйста, укажите мне на это.
Для более быстрой реакции пишите в ЛС.
Литература
- Linux device drivers 3rd edition
- Essential linux device drivers
Использование диспетчер устройств для удаления устройств и пакетов драйверов
На этой странице описывается удаление пакета устройств или драйверов в Windows 10 и Windows 11. Перед удалением устройства рекомендуется физически отключить устройство из системы. Если устройство удаляется до отключения, Windows может повторно обнаружить устройство и переустановить для него драйверы в период между удалением и отключением устройства.
Сначала откройте раздел Параметры (это можно сделать с помощью сочетания Windows+I клавиш) и введите Удалить. Выберите Добавить или удалить программы. Если пакет устройства или драйвера, который вы хотите удалить, отображается в списке программ, нажмите кнопку Удалить.
Если пакет устройства или драйвера не отображается в списке, необходимо использовать диспетчер устройств для удаления устройства. Если это устройство является единственным устройством, использующим пакет драйверов, пакет драйвера также можно удалить с помощью диспетчер устройств. Чтобы запустить диспетчер устройств, нажмите кнопку Пуск, введите диспетчер устройств и нажмите клавишу ВВОД.
Затем выполните следующие действия:
- Выберите меню Вид и включите параметр Показать скрытые устройства.
- Разверните узел, представляющий тип устройства, которое требуется удалить, выберите правой кнопкой мыши запись устройства для устройства, которое требуется удалить, и выберите Удалить.
- Если вы хотите удалить пакет драйверов в диалоговом окне Подтверждение удаления устройства , выберите параметр Удалить программное обеспечение драйвера для этого устройства . Когда все будет готово для завершения операции, нажмите кнопку ОК.
Также может потребоваться перезагрузить компьютер.
Дополнительные сведения об удалении драйверов и пакетов драйверов см. в разделе Удаление устройств и пакетов драйверов.
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Windows driver documentation
Перевод «Device Driver,» на русский
If the error occurred after the installation of a new or updated device driver, you should remove or replace the driver.
Если ошибка происходит после установки нового или обновленного драйвера устройства, драйвер необходимо удалить или заменить.
Instead of the normal graphics device driver, Safe Mode uses standard VGA graphics mode.
Вместо нормального графического драйвера устройства, безопасный режим использует стандартный графический режим VGA.
To enable the device driver, click Yes.
Чтобы включить драйвер устройства, нажмите кнопку Да.
To select a device driver, select the device driver in the list, and then click OK.
Чтобы выбрать драйвер устройства, выберите драйвер устройства в списке и нажмите кнопку ОК.
In most situations, this BSOD error may be caused by faulty operations performed by a device driver, a newly installed application, or an operating system update.
В большинстве случаев эта ошибка BSOD может быть вызвана ошибочными операциями, выполняемыми драйвером устройства, недавно установленным приложением или обновлением операционной системы.
Windows Device Manager shows an error when there is a problem with a device driver, a conflict of system resources or other hardware problems.
Диспетчер устройств Windows выдает ошибку, когда возникает проблема с драйвером устройства, конфликтом системных ресурсов или другие проблемы с оборудованием.
While NCP tended to act like a device driver, the new protocol would be more like a communications protocol.
В то время как NCP действовал в роли драйвера устройства, новинка должна была в большей мере напоминать коммуникационный протокол.
It also creates a restore point right before a major system event, like installing a new device driver, app, or running Windows update.
Он также создает точку восстановления прямо перед основным системным событием, например, установку нового драйвера устройства, приложения или запуск обновления Windows.
Since this error is usually caused by a faulty device driver, check official download sites for device drivers, particularly for chipsets and video devices, and update or install a new version as necessary.
Поскольку эта ошибка обычно вызвана неисправным драйвером устройства, проверьте официальные сайты загрузки драйверов устройств, особенно на чипсеты и видеоустройства, и при необходимости обновите или установите новую версию.
A device driver, also known as a computer driver is a program that controls a particular type of device that is attached to your computer.
Драйвер устройства, также известный как драйвер компьютера, представляет собой программу, которая управляет устройством определенного типа, которое подключено к вашему компьютеру.
It means that the operating system has detected a problem with a device driver, and the automatic shutdown of the computer is executed to prevent damage and possible loss of data from unsaved work.
Это означает, что операционная система обнаружила проблему с драйвером устройства, а также автоматическое отключение компьютера выполняется, чтобы предотвратить повреждение и возможную потерю данных из несохраненная.
In principle, a user or third party could install a standard AT expansion card, but since this required the writing of a special device driver, in practice this was very rare.
В принципе пользователь мог установить стандартную карту расширения для АТ, но так как это требовало написания драйвера устройства, то на практике такое делалось очень редко.
While NCP tended to act like a device driver, the new protocol would be more like a communications protocol.
В то время как протокол NCP выступал больше как драйвер устройства, новый протокол больше напоминал протокол связи.
An auxiliary display platform converts the information into a format understood by a device driver, which then filters the information as desired for its particular hardware device before the information is communicated.
Платформа вспомогательного дисплея конвертирует информацию в формат, понимаемый драйвером устройства, который затем фильтрует информацию желательным образом для своего конкретного аппаратного устройства перед тем, как информация будет передана.
If the error occurred after the installation of a new or updated device driver, system service, or third-party application, the new software should be removed or disabled to isolate the cause.
Если рассматриваемая ошибка впервые возникает после установки нового или обновленного драйвера устройства, системной службы или программы стороннего разработчика, новое программное обеспечение следует удалить или отключить.
When you enable a device driver, any Configuration Manager 2007 client computer can install the device driver until it has been disabled.
Если включен драйвер устройства, все клиентские компьютеры Configuration Manager 2007 могут устанавливать этот драйвер устройства, пока он не будет отключен.
To complete the installation of the device driver, you must detach the device and reattach it. For more information, see Uninstall or Reinstall a Device.
Чтобы завершить установку драйвера устройства, необходимо отсоединить устройство и повторно подсоединить его. Дополнительные сведения см. в разделе Установка и удаление устройства.
If a device driver is causing a problem or you want to suspend deployment of a device driver, you can disable the device driver by clearing the Enable these drivers and allow computers to install them check box.
Если драйвер устройства вызывает проблему или требуется отложить развертывание драйвера устройства, этот драйвер устройства можно отключить, сняв флажок Разрешить эти драйверы и позволить компьютерам их установку.
To delete the device driver, locate the device driver in the Drivers pane and right-click the device driver and select Delete. Alternatively, select Delete in the Drivers Actions pane.
Чтобы удалить драйвер устройства, найдите его на панели Драйверы, щелкните драйвер устройства правой кнопкой мыши и выберите пункт Удалить.