Чтобы сделать устройство доступным для системы и пользовательских программ, нужно его зарегистрировать. В заголовочном файле fs.h определены функции для регистрации символьных и блочных устройств. Все они начинаются с префикса register. Наше устройство будет символьным, поэтому для его регистрации мы будем использовать функцию register_chrdev. Вот ее прототип:

extern int register_chrdev(unsigned int, const char *,

 struct file_operations *);

Первый аргумент — это старший номер (major number) устройства, определяющий его тип. Если старший номер равен 0, то функция возвратит свободный старший номер для устройства нашего вида (символьное устройство).

Чтобы понять, для чего нужен старший номер, вспомним каталог /dev, содержащий файлы устройств. Файл /dev/tty1 — это терминал с номером 1. Старший номер определяет тип устройства — терминал (tty), а младший — его номер в системе (1). Человеку проще работать не с номерами. а с символьными именами устройств, поэтому каждому старшему номеру соответствует символьное обозначение.

При регистрации устройства нужно указать его тип — старший номер устройства. Но для этого нужно знать, какие номера свободны. Проще всего указать первым аргументом 0 — тогда функция возвратит первый свободный старший номер символьного устройства для вашей системы. Если старший номер указать явно, может возникнуть конфликт номеров, и наше устройство не будет зарегистрировано.

Второй параметр определяет имя устройства («device»). Последний параметр очень важен. Это структура указателей на функции для работы с нашим устройством. Наш модуль содержит таблицу доступных функций, а операционная система вызывает нужную функцию, когда пользовательской программе нужно выполнить операцию с файлом устройства (открытие/закрытие, чтение/запись). Таблица функций символьного устройства хранится в структуре file_operations, которая передается при регистрации устройства.

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

Листинг 28.6. Драйвер устройства /dev/device (без структуры file_operations)

#define MODULE

#define __KERNEL__

#include <linux/module.h>

#include <linux/init.h>

#include <linux/kernel.h>

#include <linux/fs.h> // регистрация устройств

#include <linux/ioport.h> // работа с портами ввода/вывода

#include <linux/sched.h> // резервирование прерывания

// Имя нашего устройства

#define DEV_NAME 'device'

// Порты ввода-вывода нашего устройства

#define PORT_START 0x2000 #define PORT_QTY 10

// Память нашего устройства

#define MEM_START 0x20000000

#define MEM_QTY 0x20

// Номер прерывания для нашего устройства

#define IRQ_NUM 9

MODULE_AUTHOR('Denis Kolisnichenko [email protected]');

MODULE_DESCRIPTION('Linux kernel module');

// Старший номер файла устройства

static int Major;

// Структура file_operations - пока пустая,

//но вскоре мы ее напишем

struct file_operations FO;

// Обработчик прерывания

void irq_handler(int irq, void *dev_id,

 struct pt_regs *regs) {

 return;

}

int init_module() {

 // Регистрируем устройство

 printk('My module: starting... ');

 Major = register_chrdev(0, DEV_NAME, &F0);

 if (Major < 0) {

  // Устройство не зарегистрировано

  printk('My module: registration failed ');

  return Major;

 }

 printk('My module: device registered, major number = %d ',

  Major);

 // Резервирование портов ввода-вывода

 printk('My module: allocating io ports ');

 if (check_region(PORT_START, PORT_QTY)) {

  printk('My module; allocation io ports failed ');

  return -EBUSY;

 }

 request_region(PORT_START, PORT_QTY, DEV_NAME);

 printk('My module: io ports allocated ');

 // Резервирование памяти

 if (check_mem_region(MEM_START, MEM_QTY)) {

  printk('My module: memory allocation failed ');

  release_region(PORT_START, PORT_QTY);

  return -EBUSY;

 }

 request_mem_region(MEM_START, MEM_QTY, DEV_NAME);

 printk('My module: memory allocated ');

 // Резервирование прерывания

 if (request_irq(IRQ_NUM, irq_handler, 0, DEV_NAME, NULL)) {

  printk('My module: IRQ allocation failed ');

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

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

Отметить Добавить цитату