Ядерное программирование → Пишем первый драйвер
В этой статье я расскажу как написать модуль ядра для символьного устройства. Назовем его chardev. Это устройство будет выполнять несколько функций: нам будет предоставлена возможность открывать файл устройства на чтение функцией open() из другой программы и читать его содержимое утилитой cat. Устройство не будет поддерживать запись, но будет детектировать попытки обращения к нему на запись и возвращать ошибку. Файл устройства необходимо будет создать вручную и программа нас об этом предупредит.
Итак, вот исходник с комментариями к нему:
Основные заголовочные файлы и файл asm/uaccess.h для функции put_user() которая перемещает данные из буфера обмена (пространство юзера) в ядро.
Прототипы функций. (статичны, чтобы избежать конфликта имен)
device_open() — Вызывается, когда процесс пытается открыть файл устройства
device_release() — Вызывается, когда процесс закрывает файл устройства
device_read() — Вызывается, когда процесс пытается прочитать уже открытый файл устройства
device_write() — Вызывается, когда процесс пытается записать в устройство
Макросы и объявления переменных
Major — старший номер устройства
Device_Open — открыто ли устройство?
msg — Наша строка для вывода
msg_Ptr — указатель на строку
Без комментариев, читаем предыдущий пост
Методы инициализации и удаления модуля
Функция выводит в консоль строку msg и подсчитывает сколько раз она это сделала
Функция делает устройство доступным для чтения.
Функция вызывается, когда процесс пытается прочитать уже открытый файл устройства.
Функция детектирует обращения на запись и выводит ошибку.
Пример makefile:
obj-m += chardev.o
Итак, вот исходник с комментариями к нему:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>Основные заголовочные файлы и файл asm/uaccess.h для функции put_user() которая перемещает данные из буфера обмена (пространство юзера) в ядро.
int init_module(void);
void cleanup_module(void);
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);Прототипы функций. (статичны, чтобы избежать конфликта имен)
device_open() — Вызывается, когда процесс пытается открыть файл устройства
device_release() — Вызывается, когда процесс закрывает файл устройства
device_read() — Вызывается, когда процесс пытается прочитать уже открытый файл устройства
device_write() — Вызывается, когда процесс пытается записать в устройство
#define SUCCESS 0
#define DEVICE_NAME "chardev"
#define BUF_LEN 80
static int Major;
static int Device_Open = 0;
static char msg[BUF_LEN];
static char *msg_Ptr;Макросы и объявления переменных
Major — старший номер устройства
Device_Open — открыто ли устройство?
msg — Наша строка для вывода
msg_Ptr — указатель на строку
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};Без комментариев, читаем предыдущий пост
int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &fops);
if (Major < 0) {
printk("Registering the character device failed with %d\n",
Major);
return Major;
}
printk("<1>I was assigned major number %d. To talk to\n", Major);
printk("<1>the driver, create a dev file with\n");
printk("'mknod /dev/chardev c %d 0'.\n", Major);
printk("<1>Try various minor numbers. Try to cat and echo to\n");
printk("the device file.\n");
printk("<1>Remove the device file and module when done.\n");
return 0;
}void cleanup_module(void)
{
unregister_chrdev(Major, DEVICE_NAME);
}Методы инициализации и удаления модуля
static int device_open(struct inode *inode, struct file *file)
{
static int counter = 0;
if (Device_Open)
return -EBUSY;
Device_Open++;
sprintf(msg, "I already told you %d times Hello world!\n", counter++);
msg_Ptr = msg;
try_module_get(THIS_MODULE);
return SUCCESS;
}Функция выводит в консоль строку msg и подсчитывает сколько раз она это сделала
static int device_release(struct inode *inode, struct file *file)
{
Device_Open--;
module_put(THIS_MODULE);
return 0;
}Функция делает устройство доступным для чтения.
static ssize_t device_read(struct file *filp,
char *buffer,
size_t length,
loff_t * offset)
{
int bytes_read = 0; //кол-во байт в буфере
if (*msg_Ptr == 0)
return 0; //Если конец сообщения то вернуть 0 как конец файла
while (length && *msg_Ptr) {
put_user(*(msg_Ptr++), buffer++);
length--;
bytes_read++;
} //Если нет, то перенести данные из буфера в пространство ядра
return bytes_read; //вернуть сколько байт прочитано
}Функция вызывается, когда процесс пытается прочитать уже открытый файл устройства.
static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
printk("<1>Sorry, this operation isn't supported.\n");
return -EINVAL;
}Функция детектирует обращения на запись и выводит ошибку.
Пример makefile:
obj-m += chardev.o
- +1
- jack291
- 02 октября 2011, 14:35

Комментарии (0)
RSS свернуть / развернутькомментировать