Чтение онлайн

ЖАНРЫ

Linux: Полное руководство

Аллен Питер В.

Шрифт:

Обратите внимание: мы написали драйвер так, что он захватывает порты и память от имени одного устройства — DEV_NAME. В реальности все гораздо сложнее: нужно захватывать ресурсы для каждого устройства данного типа. К тому же придется предусмотреть поиск устройств модулем: в нашем случае мы знаем, что устройств только два, но у конечного пользователя таких устройств может быть больше или меньше, поэтому наш модуль не будет универсален, если он будет поддерживать только два устройства.

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\n",

MINOR(inode->i_rdev));

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

 if (dev_state->dev_open) {

printk("Devise is busy\n");

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\n",

MINOR(inode->i_rdev));

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

 if (!dev_state->dev_open) {

printk("Device is not open\n");

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

Поделиться с друзьями: