Эта книга распространяется в надежде на то, что она будет вам полезна, но без каких-либо гарантий, в том числе и без подразумеваемых гарантий высокого спроса или пригодности для специфических целей



страница10/18
Дата21.11.2016
Размер1.25 Mb.
Просмотров4045
Скачиваний0
1   ...   6   7   8   9   10   11   12   13   ...   18

4.4. Отключение устройства


Мы не можем позволить выгружать модуль по прихоти суперпользователя. Если файл устройства удалить после того как он будет открыт процессом, то может возникнуть ситуация когда процесс попытается обратиться к выгруженному драйверу (в конце концов процесс даже не подозревает, что такое могло произойти). В результате произойдет попытка обращения к тому участку памяти, где ранее находилась функция обработки запроса. Если вам повезет, то этот участок памяти окажется не затертым ядром и вы получите сообщение об ошибке. Если не повезет -- то произойдет переход в середину "чужой" функции. Результат такого "вызова" трудно предугадать заранее

Обычно, если какая-то операция должна быть отвергнута, функция возвращает код ошибки (отрицательное число). В случае с функциейcleanup_module() это невозможно, поскольку она не имеет возвращаемого значения. Однако, для каждого модуля в системе имеется счетчик обращений, который хранит число процессов, использующих модуль. Вы можете увидеть это число в третьем поле, в файле /proc/devices. Если это поле не равно нулю, то rmmod не сможет выгрузить модуль. Обратите внимание: вам нет нужды следить за состоянием счетчика в cleanup_module(), это делает система, внутри системного вызова sys_delete_module (определение функции вы найдете в файле linux/module.c). Вы не должны изменять значение счетчика напрямую, тем не менее, ядро предоставляет в ваше распоряжение функции, которые увеличивают и уменьшают значение счетчика обращений:



  • try_module_get(THIS_MODULE): увеличивает счетчик обращений на 1.

try_module_put(THIS_MODULE): уменьшает счетчик обращений на 1.

Очень важно сохранять точное значение счетчика! Если Вы каким-либо образом потеряете действительное значение, то вы никогда не сможете выгрузить модуль. Тут, милые мои мальчики и девочки, поможет только перезагрузка! Это обязательно случиться с вами, рано или поздно, при разработке какого-либо модуля!


4.5. chardev.c


Следующий пример создает устройство с именем chardev. Вы можете читать содержимое файла устройства с помощью команды cat или открывать его на чтение из программы (функцией open()). Посредством этого файла драйвер будет извещать о количестве попыток обращения к нему. Модуль не поддерживает операцию записи (типа: echo "hi" > /dev/chardev), но определяет такую попытку и сообщает пользователю о том, что операция записи не поддерживается.

Пример 4-1. chardev.c

/*

* chardev.c: Создает символьное устройство, доступное только для чтения



* возвращает сообщение, с указанием количества произведенных попыток чтения из файла устройства

*/
#include

#include

#include

#include /* определение функции put_user */
/*

* Прототипы функций, обычно их выносят в заголовочный файл (.h)

*/

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 *);
#define SUCCESS 0

#define DEVICE_NAME "chardev" /* Имя устройства, будет отображаться в /proc/devices */

#define BUF_LEN 80 /* Максимальная длина сообщения */
/*

* Глобальные переменные, объявлены как static, воизбежание конфликтов имен.

*/
static int Major; /* Старший номер устройства нашего драйвера */

static int Device_Open = 0; /* Устройство открыто?

* используется для предотвращения одновременного

* обращения из нескольких процессов */

static char msg[BUF_LEN]; /* Здесь будет собираться текст сообщения */

static char *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)

{

/*


* Отключение устройства

*/

int ret = unregister_chrdev(Major, DEVICE_NAME);



if (ret < 0)

printk("Error in unregister_chrdev: %d\n", ret);

}
/*

* Обработчики

*/
/*

* Вызывается, когда процесс пытается открыть файл устройства, например командой

* "cat /dev/chardev"

*/

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;

}
/*

* Вызывается, когда процесс закрывает файл устройства.

*/

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, /* см. include/linux/fs.h */



char *buffer, /* буфер, куда надо положить данные */

size_t length, /* размер буфера */

loff_t * offset)

{

/*



* Количество байт, фактически записанных в буфер

*/

int bytes_read = 0;


/*

* Если достигли конца сообщения,

* вернуть 0, как признак конца файла

*/

if (*msg_Ptr == 0)



return 0;
/*

* Перемещение данных в буфер

*/

while (length && *msg_Ptr) {


/*

* Буфер находится в пространстве пользователя (в сегменте данных),

* а не в пространстве ядра, поэтому простое присваивание здесь недопустимо.

* Для того, чтобы скопировать данные, мы используем функцию put_user,

* которая перенесет данные из пространства ядра в пространство пользователя.

*/

put_user(*(msg_Ptr++), buffer++);


length--;

bytes_read++;

}
/*

* В большинстве своем, функции чтения возвращают количество байт, записанных в буфер.

*/

return bytes_read;



}
/*

* Вызывается, когда процесс пытается записать в устройство,

* например так: echo "hi" > /dev/chardev

*/

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;

}

Пример 4-2. Makefile



obj-m += chardev.o


Каталог: files
files -> Основная часть 1 История создания школы
files -> Методические рекомендации по проведению Дня Знаний, посвященного Году кино в РФ
files -> Подросток и компьютерные игры
files -> Программа духовно-нравственного развития и воспитания обучающихся на уровне среднего общего образования
files -> Правила закаливания… Выпуск №1. Чтоб улыбка сияла. Мама первый стоматолог
files -> О существовании значения игры преследования
files -> Учебное пособие по нейрохирургии. Часть I. Краткая история нейрохирургии. Черепно-мозговая травма санкт-Петербург 2015


Поделитесь с Вашими друзьями:
1   ...   6   7   8   9   10   11   12   13   ...   18


База данных защищена авторским правом ©nethash.ru 2019
обратиться к администрации

войти | регистрация
    Главная страница


загрузить материал