28.4. Операции над устройством. Поиск устройств

28.4. Операции над устройством. Поиск устройств

Наш модуль пока еще не может называться «драйвером» в прямом смысле этого слова: устройство-то он регистрирует, но не позволяет выполнить ни одной операции с ним — ведь структура file_operations пуста.

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

// Структура для хранения состояния устройства

struct device_state {

 int dev_open; // 1 - устройство открыто, 0 - закрыто

 ssize_t byte_read; // Количество прочитанных

                    // из устройства байтов

 ssize_t byte_write; // Количество записанных байтов

};

// Массив для хранения информации о состоянии устройств

static struct device_state state[2];

В принципе, можно обойтись и без кода поиска устройств — без него модуль будет проще (а значит, надежнее), да и работать он будет быстрее. Обойти поиск устройств можно следующим образом. Мы не знаем, сколько устройств типа device будет у конечного пользователя. Поэтому вместо массива state (он будет описан ниже) нужно использовать динамический список, который будет содержать информацию о каждом устройстве типа device. При загрузке модуля список будет содержать всего один элемент — для устройства /dev/device0. Если устройств этого типа в системе нет вообще, будем просто считать, что устройство device0 закрыто, а при попытке обращения к нему будем сообщать, что оно занято. По мере поступления запросов программ на открытие других устройств /dev/deviceX будем добавлять в наш список новые элементы.

Если же вам все-таки хочется узнать конкретное количество устройств /dev/deviceX, установленных у пользователя, можно просто просмотреть содержимое каталога /dev и посчитать количество файлов device*.

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

Листинг 28.7. Функция открытия устройства

static int device_open(struct inode *inode, struct file *fp) {

 struct device_state *dev_state;

 printk("My module: try to open device with minor number %d ",

  MINOR(inode->i_rdev));

 devastate = &state[MINOR(inode->i_rdev)];

 if (dev_state->dev_open) {

  printk("Devise is busy ");

  return -EBUSY;

 }

 dev_state->dev_open = 1;

 dev_state->byte_read = 0;

 dev_state->byte_write = 0;

 MOD_INC_USE_COUNT;

 return 0;

}

Младший номер устройства мы получаем с помощью вызова MINOR (inode->i_rdev). Если устройство уже открыто, мы выводим сообщение: Devise is busy. В противном случае устанавливаем флаг открытия устройства, обнуляем byte_read и byte_write, а также увеличиваем счетчик использования данного модуля (MOD_INC_USE_COUNT).

Функция закрытия устройства сбрасывает флаг dev_open и уменьшает счетчик использования устройства.

Листинг 28.8. Функция закрытия устройства

static int device_close(struct inode *inode, struct file *fp) {

 struct device_state *dev_state;

 printk("My module: try to close device with minor number %d ",

  MINOR(inode->i_rdev));

 dev_state = &state[MINOR(inode->i_rdev)];

 if (!dev_state->dev_open) {

  printk("Device is not open ");

  return 0;

 }

 dev_state->dev_open=0;

 MOD_DEC_USE_COUNT;

 return 0;

}

Теперь нам нужно указать ядру, какие функции нужно использовать для открытия и закрытия устройства:

struct file_operations FO = {

open: device_open,

release: device_close

};

Полный код модуля устройства device вместе с функциями открытия и закрытия устройства, а также структурой file_operations приведен в следующем листинге:

Листинг 28.9. Модуль устройства device (module.с)

#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 dhsilabs@mail.ru");

MODULE_DESCRIPTION("Linux kernel module");

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

static int Major;

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

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

struct file_operations FO {

 open:    device_open,

 release: device_close

};

// Структура для хранения состояния устройства

struct device_state {

 int dev_open; // 1 - устройство открыто, 0 — закрыто

 ssize_t byte_read; // Количество прочитанных байтов

                    // из устройства

 ssize_t byte_write; // Количество записанных байтов

};

// Массив для хранения информации о состоянии устройств

static struct device_state state[2];

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

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, PQRT_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 ");

  release_mem_region(MEM_START, MEM_QTY);

  release_region(PORT_START, PORT_QTY);

  return -EBUSY;

 }

 printk("My module: IRQ allocated ");

 return 0;

}

void cleanup_module() {

 // Освобождаем порты ввода-вывода

 release_region(PORT_START, PORT_QTY);

 printk("My module: release io ports ");

 // Освобождаем память

 release_mem_region(MEM_START, MEM_QTY);

 printk("My module: release memory ");

 // Освобождаем прерывание

 free_irq(IRQ_NUM, NULL);

 printk("My module: release irq ");

 // Отменяем регистрацию устройства

 if (unregister_chrdev(Major, DEV_NAME) < 0) {

  printk("My module: cannot to unregister device ");

 }

 printk("My module: device unregistered ");

 return;

}

static int device_open(struct inode *inode,

 struct file *fp) {

 struct device_state *dev_state;

 printk("My module: try to open device with minor number %d ",

  MINOR(inode->i_rdev));

 dev_state = &state[MINOR(inode->i_rdev)];

 if (dev__state->dev_open) {

  printk("Devise is busy ");

  return -EBUSY;

 }

 dev_state->dev_open = 1;

 dev_state->byte_read = 0;

 dev_state->byte_write = 0;

 MOD_INC_USE_COUNT;

 return 0;

}

static int device_close(struct inode *inode, struct file

 *fp) {

 struct device_state *dev_state;

 printk("My module: try to close device with minor number %d ",

  MINOR(inode->i_rdev));

 dev_state = &state[MINOR(inode->i_rdev)];

 if (!dev_state->dev_open) {

  printk("Device is not open ");

  return 0;

 }

 dev_state->dev_open = 0;

 MOD_DEC_USE_COUNT;

 return 0;

}

Теперь модуль для абстрактного устройства device готов. Вы можете написать небольшую программку, которая пыталась бы выполнить операции с нашим устройством: открыть его и закрыть — других операций мы не определили. Для определения других действий используется та же структура file_operations. Листинг 28.10 показывает, как она объявлена в файле /usr/src/linux-2.4/include/linux/fs.h.

Листинг 28.10. Фрагмент файла /usr/src/linux-2.4/include/linux/fs.h

struct file_operations {

 struct module *owner;

 loff_t (*llseek)(struct file*, loff_t, int);

 ssize_t (*read)(struct file*, char*, size_t, loff_t*);

 ssize_t (*write)(struct file*, const char*,

  size_t, loff_t*);

 int (*readdir)(struct file*, void*, filldir_t);

 unsigned int (*poll) (struct file*,

  struct poll_table_struct*);

 int (*ioctl)(struct inode*, struct file*, unsigned int,

  unsigned long);

 int (*mmap)(struct file*, struct vm_area_struct*);

 int (*open)(struct inode*, struct file*);

 int (*flush)(struct file*);

 int (*release)(struct inode*, struct file*);

 int (*fsync)(struct file*, struct dentry*,

  int datasync);

 int (*fasync)(int, struct file*, int);

 int (*lock)(struct file*, int, struct file_lock*);

 ssize_t (*readv)(struct file*, const struct iovec*,

  unsigned long, loff_t*);

 ssize_t (*writev)(struct file*, const struct iovec*,

  unsigned long, loff_t*);

 ssize_t (*sendpage)(struct file*, struct page*, int, size_t,

  loff_t*, int);

 unsigned long (*get_unmapped_area)(struct file*, unsigned long,

  unsigned long, unsigned long, unsigned long);

};

Как использовать структуру file_operations, думаю, ясно. Например, нам нужно описать обработчики записи и чтения устройства — функции device_write() и device_read():

struct file_operations FO = {

 open: device_open,

 release: device_close,

 read: device_read,

 write: device_write

};

Обработчики чтения и записи пишутся «по образу и подобию» обработчиков открытия и закрытия устройства, то есть сначала нам нужно определить младший номер с помощью вызова MINOR(), а затем произвести операцию с устройством.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Яндекс. Поиск – быстрый поиск документов

Из книги Microsoft Office автора Леонтьев Виталий Петрович

Яндекс. Поиск – быстрый поиск документов Документы, как известно, имеют премерзкое свойство накапливаться. И чем больше документов, тем труднее в их залежах найти нужный. Электронные документы здесь не слишком отличаются от бумажных. Проблема места для хранения, правда,


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

Из книги Windows Vista без напряга автора Жвалевский Андрей Валентинович

8.3. Подключение устройств Аппетит всегда приходит во время еды. Когда вы покупаете свой первый компьютер, кажется, что в нем есть все. В нем столько «всего», что вам никогда не освоить всех его возможностей. Но проходит время, технологии развиваются, ваши запросы растут, и


Значки устройств

Из книги Windows Vista автора Вавилов Сергей

Значки устройств Значок – это небольшой графический элемент, который указывает на приложение, документ, каталог, устройство или какой-то другой объект. Любой значок имеет подпись, которая является именем представляемого объекта. Значки в Windows служат для обозначения


11.6. Диспетчер устройств

Из книги Самоучитель работы на компьютере автора Колисниченко Денис Николаевич

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


Глава 12 Поиск с предпочтением: эвристический поиск

Из книги Программирование на языке Пролог для искусственного интеллекта автора Братко Иван

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


Обнаружение устройств

Из книги Программирование КПК и смартфонов на .NET Compact Framework автора Климов Александр П.

Обнаружение устройств Теперь надо написать код для кнопки butFindDevs, предназначенной для обнаружения устройств. При тестировании примера необходимо направить инфракрасные порты устройств друг на друга. Код, ответственный за выполнение этой задачи, приведен в листинге


5.11.2. Файлы устройств

Из книги Ubuntu 10. Краткое руководство пользователя автора Колисниченко Д. Н.

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


Диспетчер устройств

Из книги Недокументированные и малоизвестные возможности Windows XP автора Клименко Роман Александрович

Диспетчер устройств Диспетчер устройств входит в стандартную консоль devmgmt.msc и имеет GUID-номер {74246BFC-4C96-11D0-ABEF-0020AF6B0B7A}. После вызова данной консоли откроется окно, подобное приведенному на рис. 10.3.Окно Диспетчера устройств отображает все установленное на компьютере


6.2. Номера устройств

Из книги Программирование для Linux. Профессиональный подход автора Митчелл Марк

6.2. Номера устройств ОС Linux идентифицирует устройства двумя числами: старшим номером устройства и младшим номером устройства. Старший номер указывает на то, какой драйвер соответствует устройству. Соответствие между старшими номерами устройств и драйверами жестко


Поиск на научных сайтах с использованием платформы Flexum «Поиск по научным сайтам»

Из книги Профессиональный поиск в Интернете автора Кутовенко Алексей

Поиск на научных сайтах с использованием платформы Flexum «Поиск по научным сайтам» Тема научного поиска не прошла мимо разработчиков персональных поисковиков. Подробному рассказу о возможностях таких поисковых систем посвящена отдельная глава нашей книги (см. главу 6).


Драйверы устройств

Из книги Операционная система UNIX автора Робачевский Андрей М.

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


«Айпад» чихнул, у планшеток простуда: что случилось с самым перспективным мобильным устройством XXI века? Евгений Золотов

Из книги Цифровой журнал «Компьютерра» № 223 автора Журнал «Компьютерра»

«Айпад» чихнул, у планшеток простуда: что случилось с самым перспективным мобильным устройством XXI века? Евгений Золотов Опубликовано 29 апреля 2014 Быть номером первым — это не только наслаждаться славой, а ещё и всегда, по малейшему поводу, быть проверяемым на прочность.


4.3. Операции сравнения и логические операции

Из книги C++ для начинающих автора Липпман Стенли

4.3. Операции сравнения и логические операции Символ операции Значение Использование ! Логическое НЕ !expr меньше exprexpr = Меньше либо равно expr=expr больше exprexpr = больше либо равно expr=expr == равно expr==expr != не равно expr!=expr логическое


Профили устройств

Из книги Цифровая фотография. Трюки и эффекты автора Гурский Юрий Анатольевич

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