Авторизация

OpenID



Напомнить пароль
Регистрация
-->

Ядерное программированиеПишем первый драйвер

В этой статье я расскажу как написать модуль ядра для символьного устройства. Назовем его chardev. Это устройство будет выполнять несколько функций: нам будет предоставлена возможность открывать файл устройства на чтение функцией open() из другой программы и читать его содержимое утилитой cat. Устройство не будет поддерживать запись, но будет детектировать попытки обращения к нему на запись и возвращать ошибку. Файл устройства необходимо будет создать вручную и программа нас об этом предупредит.

Итак, вот исходник с комментариями к нему:

#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 свернуть / развернуть

комментировать

Ваше имя
Ваш e-mail (будет скрыто и используется только для отправки ответов на ваш комментарий)
Вы — гость, и вам запрещено использовать HTML-теги.
 
Введите цифры и буквы:



Блоги, Ядерное программирование, Пишем первый драйвер