Commit d3c2c1c0 authored by Pavel Vainerman's avatar Pavel Vainerman

Сконвертировал из koi8-r в utf8

parent dc5d9687
/* /*
* charbridge.c - * charbridge.c - Пример создания символьного устройства
* / * доступного на запись/чтение
* *
* : http://www.opennet.ru/docs/RUS/lkmpg26/ * Пример взят с: http://www.opennet.ru/docs/RUS/lkmpg26/
* * и модифицирован
*/ */
#include <linux/module.h> /* */ #include <linux/module.h> /* Необходимо для любого модуля */
#include <linux/kernel.h> /* - ! */ #include <linux/kernel.h> /* Все-таки мы работаем с ядром! */
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/sched.h> /* */ #include <linux/sched.h> /* Взаимодействие с планировщиком */
#include <linux/poll.h> #include <linux/poll.h>
#include <asm/uaccess.h> /* get_user put_user */ #include <asm/uaccess.h> /* определения функций get_user и put_user */
#include <linux/pipe_fs_i.h> #include <linux/pipe_fs_i.h>
#include <linux/version.h> #include <linux/version.h>
...@@ -29,25 +29,25 @@ ...@@ -29,25 +29,25 @@
//#define DEBUG 1 //#define DEBUG 1
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
// : // Реализован циклический буфер:
// wpos ( ) // При записи происходит сдвиг wpos (позиции записи)
// rpos ( ) // При чтении сдвигается rpos (позиция чтения)
// , ... // При достижении конца буфера, данные опять пишутся в начало...
// WARNING! ԣ () ! // WARNING! Данные БУДУТ затёрты (потеряны) если запись происходит быстрее чем чтение!
// rpos (. do_write). // При этом rpos принудительно сдвигается до текущей позиции записи (см. do_write).
// , ԣ , // И получается, что читающий процесс теряет часть затёртых данных,
// ... // которые не успел прочесть...
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
/* /*
* * Информация об устройстве
* *
*/ */
struct Device_Info struct Device_Info
{ {
int open; int open;
char buf[BUF_LEN]; char buf[BUF_LEN];
unsigned int wpos; // ... unsigned int wpos; // очередная позиция для записи...
unsigned int rpos; // ... unsigned int rpos; // очередная позиция для чтения...
dev_t rdev; dev_t rdev;
spinlock_t lock; spinlock_t lock;
// long int timeout; // long int timeout;
...@@ -62,8 +62,8 @@ static int dev_major = 0; ...@@ -62,8 +62,8 @@ static int dev_major = 0;
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
inline static int get_index( int minor ) inline static int get_index( int minor )
{ {
// 0..99 - sideA0...sideA99 // Миноры от 0..99 - для sideA0...sideA99
// 100..199 - sideB0...sideB99 // Миноры от 100..199 - для sideB0...sideB99
if( minor >= MAX_PAIR ) if( minor >= MAX_PAIR )
minor -= MAX_PAIR; minor -= MAX_PAIR;
...@@ -145,22 +145,22 @@ static int do_wait_empty( struct Device_Info* idev ) ...@@ -145,22 +145,22 @@ static int do_wait_empty( struct Device_Info* idev )
} }
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
/* /*
* , A(1) * Вызывается когда процесс, открывший файл устройство A(1)
* . * пытается считать из него данные.
*/ */
static ssize_t do_read(struct file *file, /* . include/linux/fs.h */ static ssize_t do_read(struct file *file, /* см. include/linux/fs.h */
char __user * buffer, /* */ char __user * buffer, /* буфер для сообщения */
size_t length, /* */ size_t length, /* размер буфера */
loff_t * offset, loff_t * offset,
struct Device_Info* idev) struct Device_Info* idev)
{ {
ssize_t ret = 0; ssize_t ret = 0;
int bytes_read = 0; // , int bytes_read = 0; // Количество байт, фактически записанных в буфер
/* /*
* O_NONBLOCK, * Если установлен флаг O_NONBLOCK, то процесс не должен приостанавливаться
* , , * В этом случае, если файл уже открыт, необходимо вернуть код ошибки
* -EAGAIN, " " * -EAGAIN, что означает "попробуйте в другой раз"
*/ */
if ((file->f_flags & O_NONBLOCK) && check_empty(idev) ) if ((file->f_flags & O_NONBLOCK) && check_empty(idev) )
return -EAGAIN; return -EAGAIN;
...@@ -173,14 +173,14 @@ static ssize_t do_read(struct file *file, /* 油. include/linux/fs.h */ ...@@ -173,14 +173,14 @@ static ssize_t do_read(struct file *file, /* 油. include/linux/fs.h */
if( ret < 0 ) if( ret < 0 )
return ret; return ret;
// // захватываем ресурс
spin_lock(&idev->lock); spin_lock(&idev->lock);
#ifdef DEBUG #ifdef DEBUG
printk("(charbridge): read from %s: (%p,%p,%d)\n", idev->name, file, buffer, length); printk("(charbridge): read from %s: (%p,%p,%d)\n", idev->name, file, buffer, length);
#endif #endif
// // запись данных в буфер пользователя
// while( length && *(idev->beg) ) { // while( length && *(idev->beg) ) {
while( length && idev->rpos!=idev->wpos ) while( length && idev->rpos!=idev->wpos )
{ {
...@@ -192,7 +192,7 @@ static ssize_t do_read(struct file *file, /* 油. include/linux/fs.h */ ...@@ -192,7 +192,7 @@ static ssize_t do_read(struct file *file, /* 油. include/linux/fs.h */
bytes_read++; bytes_read++;
} }
// // освобождаем ресурс
spin_unlock(&idev->lock); spin_unlock(&idev->lock);
#ifdef DEBUG #ifdef DEBUG
...@@ -203,7 +203,7 @@ static ssize_t do_read(struct file *file, /* 油. include/linux/fs.h */ ...@@ -203,7 +203,7 @@ static ssize_t do_read(struct file *file, /* 油. include/linux/fs.h */
} }
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
/* /*
* A * Вызывается при попытке записи в файл устройства A
*/ */
static ssize_t static ssize_t
do_write(struct file *file, do_write(struct file *file,
...@@ -213,9 +213,9 @@ do_write(struct file *file, ...@@ -213,9 +213,9 @@ do_write(struct file *file,
ssize_t i = 0; ssize_t i = 0;
/* /*
* O_NONBLOCK, * Если установлен флаг O_NONBLOCK, то процесс не должен приостанавливаться
* , , * В этом случае, если файл уже открыт, необходимо вернуть код ошибки
* -EAGAIN, " " * -EAGAIN, что означает "попробуйте в другой раз"
*/ */
if ((file->f_flags & O_NONBLOCK) && !check_empty(idev) ) if ((file->f_flags & O_NONBLOCK) && !check_empty(idev) )
return -EAGAIN; return -EAGAIN;
...@@ -234,14 +234,14 @@ do_write(struct file *file, ...@@ -234,14 +234,14 @@ do_write(struct file *file,
{ {
get_user(idev->buf[idev->wpos], buffer + i); get_user(idev->buf[idev->wpos], buffer + i);
idev->wpos++; idev->wpos++;
#warning !!! #warning НАДО ОБДУМАТЬ ДАННУЮ ЛОГИКУ!!!
// , // если достигли конца буфера, то пишем
// ... // опять в начало...
if( idev->wpos >= BUF_LEN ) if( idev->wpos >= BUF_LEN )
idev->wpos = 0; idev->wpos = 0;
// rpos, // сдвигаем rpos, имитируя потерю данных
// ... // которые не успели вычитать...
if( idev->wpos == idev->rpos ) if( idev->wpos == idev->rpos )
{ {
#ifdef DEBUG #ifdef DEBUG
...@@ -253,14 +253,14 @@ do_write(struct file *file, ...@@ -253,14 +253,14 @@ do_write(struct file *file,
spin_unlock(&idev->lock); spin_unlock(&idev->lock);
// WaitQ. // Возобновить работу процессов из WaitQ.
#ifdef DEBUG #ifdef DEBUG
printk("(charbridge): write to %s beg=%d end=%d wake_up...\n", idev->name, idev->rpos, idev->wpos ); printk("(charbridge): write to %s beg=%d end=%d wake_up...\n", idev->name, idev->rpos, idev->wpos );
#endif #endif
wake_up_interruptible(&idev->waitq); wake_up_interruptible(&idev->waitq);
wake_up_interruptible(&idev->pollq); wake_up_interruptible(&idev->pollq);
// // Вернуть количество записанных байт
return i; return i;
} }
...@@ -286,7 +286,7 @@ static unsigned int do_poll( struct file *file, struct poll_table_struct *wait, ...@@ -286,7 +286,7 @@ static unsigned int do_poll( struct file *file, struct poll_table_struct *wait,
} }
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
/* /*
Инициализация списка устройств
*/ */
static void device_init( struct Device_Info* idev, char* name ) static void device_init( struct Device_Info* idev, char* name )
{ {
...@@ -305,7 +305,7 @@ static void device_init( struct Device_Info* idev, char* name ) ...@@ -305,7 +305,7 @@ static void device_init( struct Device_Info* idev, char* name )
} }
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
/* /*
* * Вызывается когда процесс пытается открыть файл устройства
*/ */
static int device_open(struct inode *inode, struct file *file) static int device_open(struct inode *inode, struct file *file)
{ {
...@@ -373,12 +373,12 @@ static int device_release(struct inode *inode, struct file *file) ...@@ -373,12 +373,12 @@ static int device_release(struct inode *inode, struct file *file)
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
/* /*
* , * Вызывается когда процесс, открывший файл устройства
* . * пытается считать из него данные.
*/ */
static ssize_t device_read(struct file *file, /* . include/linux/fs.h */ static ssize_t device_read(struct file *file, /* см. include/linux/fs.h */
char __user * buffer, /* */ char __user * buffer, /* буфер для сообщения */
size_t length, /* */ size_t length, /* размер буфера */
loff_t * offset) loff_t * offset)
{ {
unsigned int minor = MINOR(file->f_mapping->host->i_rdev); unsigned int minor = MINOR(file->f_mapping->host->i_rdev);
...@@ -392,7 +392,7 @@ static ssize_t device_read(struct file *file, /* 油. include/linux/fs.h */ ...@@ -392,7 +392,7 @@ static ssize_t device_read(struct file *file, /* 油. include/linux/fs.h */
return -EBADFD; return -EBADFD;
} }
// // читаем из буфера ДРУГОГО устройства
if( !check_sideB(minor) ) if( !check_sideB(minor) )
return do_read(file,buffer, length,offset,&deviceB[ind]); return do_read(file,buffer, length,offset,&deviceB[ind]);
...@@ -402,7 +402,7 @@ static ssize_t device_read(struct file *file, /* 油. include/linux/fs.h */ ...@@ -402,7 +402,7 @@ static ssize_t device_read(struct file *file, /* 油. include/linux/fs.h */
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
/* /*
* * Вызывается при попытке записи в файл устройства
*/ */
static ssize_t static ssize_t
device_write(struct file *file, device_write(struct file *file,
...@@ -426,7 +426,7 @@ device_write(struct file *file, ...@@ -426,7 +426,7 @@ device_write(struct file *file,
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
static unsigned int device_poll( struct file *file, struct poll_table_struct *ptable ) static unsigned int device_poll( struct file *file, struct poll_table_struct *ptable )
{ {
// ģ // ждём данных в другом устройстве
unsigned int minor = MINOR(file->f_mapping->host->i_rdev); unsigned int minor = MINOR(file->f_mapping->host->i_rdev);
unsigned int ind = get_index( minor ); unsigned int ind = get_index( minor );
if( ind < 0 ) if( ind < 0 )
...@@ -444,14 +444,14 @@ static unsigned int device_poll( struct file *file, struct poll_table_struct *pt ...@@ -444,14 +444,14 @@ static unsigned int device_poll( struct file *file, struct poll_table_struct *pt
} }
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
/* /*
* , ioctl . * Вызывается, когда процесс пытается выполнить операцию ioctl над файлом устройства.
* inode file : * Кроме inode и структуры file функция получает два дополнительных параметра:
* ioctl . * номер ioctl и дополнительные аргументы.
* *
*/ */
int device_ioctl(struct inode *inode, /* . include/linux/fs.h */ int device_ioctl(struct inode *inode, /* см. include/linux/fs.h */
struct file *file, /* */ struct file *file, /* то же самое */
unsigned int ioctl_num, /* ioctl */ unsigned int ioctl_num, /* номер и аргументы ioctl */
unsigned long ioctl_param) unsigned long ioctl_param)
{ {
int i; int i;
...@@ -459,18 +459,18 @@ int device_ioctl(struct inode *inode, /* 油. include/linux/fs.h */ ...@@ -459,18 +459,18 @@ int device_ioctl(struct inode *inode, /* 油. include/linux/fs.h */
char ch; char ch;
/* /*
* ioctl * Реакция на различные команды ioctl
*/ */
switch (ioctl_num) { switch (ioctl_num) {
case IOCTL_SET_MSG: case IOCTL_SET_MSG:
/* /*
* ( ) * Принять указатель на сообщение (в пространстве пользователя)
* . . * и переписать в буфер. Адрес которого задан в дополнительно аргументе.
*/ */
temp = (char *)ioctl_param; temp = (char *)ioctl_param;
/* /*
* * Найти длину сообщения
*/ */
get_user(ch, temp); get_user(ch, temp);
for (i = 0; ch && i < BUF_LEN; i++, temp++) for (i = 0; ch && i < BUF_LEN; i++, temp++)
...@@ -481,21 +481,21 @@ int device_ioctl(struct inode *inode, /* 油. include/linux/fs.h */ ...@@ -481,21 +481,21 @@ int device_ioctl(struct inode *inode, /* 油. include/linux/fs.h */
case IOCTL_GET_MSG: case IOCTL_GET_MSG:
/* /*
* - * Передать текущее сообщение вызывающему процессу -
* . * записать по указанному адресу.
*/ */
i = device_read(file, (char *)ioctl_param, 99, 0); i = device_read(file, (char *)ioctl_param, 99, 0);
/* /*
* \0 * Вставить в буфер завершающий символ \0
*/ */
put_user('\0', (char *)ioctl_param + i); put_user('\0', (char *)ioctl_param + i);
break; break;
case IOCTL_GET_NTH_BYTE: case IOCTL_GET_NTH_BYTE:
/* /*
* (ioctl_param) * Этот вызов является вводом (ioctl_param) и
* ( ) * выводом (возвращаемое значение функции) одновременно
*/ */
// return Message[ioctl_param]; // return Message[ioctl_param];
return 0; return 0;
...@@ -505,26 +505,26 @@ int device_ioctl(struct inode *inode, /* 油. include/linux/fs.h */ ...@@ -505,26 +505,26 @@ int device_ioctl(struct inode *inode, /* 油. include/linux/fs.h */
return SUCCESS; return SUCCESS;
} }
/* */ /* Объявлнеия */
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
/* /*
* - * В этой структуре хранятся адреса функций-обработчиков
* , . * операций, производимых процессом над устройством.
* , * Поскольку указатель на эту структуру хранится в таблице устройств,
* init_module. * она не может быть локальной для init_module.
* NULL. * Отсутствующие указатели в структуре забиваются значением NULL.
*/ */
struct file_operations Fops = { struct file_operations Fops = {
.read = device_read, .read = device_read,
.write = device_write, .write = device_write,
.ioctl = device_ioctl, // .ioctl = device_ioctl,
.open = device_open, .open = device_open,
.release = device_release, /* close */ .release = device_release, /* оно же close */
.poll = device_poll .poll = device_poll
}; };
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
/* /*
* - * Инициализация модуля - Регистрация символьного устройства
*/ */
int init_module() int init_module()
{ {
...@@ -533,12 +533,12 @@ int init_module() ...@@ -533,12 +533,12 @@ int init_module()
char nm2[NAM_LEN]; char nm2[NAM_LEN];
/* /*
* ( - ) * Регистрация символьного устройства (по крайней мере - попытка регистрации)
*/ */
dev_major = register_chrdev(0, DEVICE_FILE_NAME, &Fops); dev_major = register_chrdev(0, DEVICE_FILE_NAME, &Fops);
/* /*
* * Отрицательное значение означает ошибку
*/ */
if (dev_major < 0) { if (dev_major < 0) {
printk("(charbridge): %s failed with %d\n", printk("(charbridge): %s failed with %d\n",
...@@ -561,34 +561,34 @@ int init_module() ...@@ -561,34 +561,34 @@ int init_module()
} }
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
/* /*
* - /proc * Завершение работы модуля - дерегистрация файла в /proc
*/ */
void cleanup_module() void cleanup_module()
{ {
int ret = 0; int ret = 0;
// // Дерегистрация устройства
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
unregister_chrdev(dev_major, DEVICE_FILE_NAME); unregister_chrdev(dev_major, DEVICE_FILE_NAME);
#else #else
ret = unregister_chrdev(dev_major, DEVICE_FILE_NAME); ret = unregister_chrdev(dev_major, DEVICE_FILE_NAME);
#endif #endif
// -- // Если обнаружена ошибка -- вывести сообщение
if (ret < 0) if (ret < 0)
printk("Error in module_unregister_chrdev: %d\n", ret); printk("Error in module_unregister_chrdev: %d\n", ret);
} }
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR); /* */ MODULE_AUTHOR(DRIVER_AUTHOR); /* Автор модуля */
MODULE_DESCRIPTION(DRIVER_DESC); /* */ MODULE_DESCRIPTION(DRIVER_DESC); /* Назначение модуля */
/* /*
* /dev/cbsideAxx(Bxx). * Этот модуль использует устройство /dev/cbsideAxx(Bxx).
* * В будущих версиях ядра
* MODULE_SUPPORTED_DEVICE * макрос MODULE_SUPPORTED_DEVICE может быть использован
* , * для автоматической настройки модуля, но пока
* . * он служит исключительно в описательных целях.
*/ */
MODULE_SUPPORTED_DEVICE("cbside"); MODULE_SUPPORTED_DEVICE("cbside");
/* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */
/* /*
* charbridge.h - ioctl. * charbridge.h - определения ioctl.
* *
* , , , * Определения, которые здесь находятся, должны помещаться в заголовочный файл потому,
* (charbridge.c), * что они потребуются как модулю ядра (charbridge.c), так и
* (ioctl.c) * вызывающему процессу (ioctl.c)
*/ */
#ifndef CHARBRIDGE_H #ifndef CHARBRIDGE_H
...@@ -12,63 +12,63 @@ ...@@ -12,63 +12,63 @@
#include <linux/ioctl.h> #include <linux/ioctl.h>
/* /*
* . ioctl, * Старший номер устройства. В случае использования ioctl,
* , * мы уже лишены возможности воспользоваться динамическим номером,
* . * поскольку он должен быть известен заранее.
*/ */
#define MAJOR_NUM 255 #define MAJOR_NUM 255
/* /*
* "" * Количество "пар" устройств
* ( ) * (миноров получается в два раза больше)
* .. , sideA * Т.к. логика построена на том, чтобы для sideA
* 0..99, sideB 100...199 * использовать номера от 0..99, а для sideB 100...199
* "" 100! * ТО "ПАР" УСТРОЙСТВ НЕ МОЖЕТ БЫТЬ БОЛЬШЕ 100!
*/ */
#define MAX_DEV 10 #define MAX_DEV 10
#define MAX_PAIR 100 #define MAX_PAIR 100
// 0..99 - sideA0...sideA99 // Миноры от 0..99 - для sideA0...sideA99
// 100..199 - sideB0...sideB99 // Миноры от 100..199 - для sideB0...sideB99
/* /*
* * Операция передачи сообщения драйверу устройства
*/ */
#define IOCTL_SET_MSG _IOR(MAJOR_NUM, 0, char *) #define IOCTL_SET_MSG _IOR(MAJOR_NUM, 0, char *)
/* /*
* _IOR , * _IOR означает, что команда передает данные
* * от пользовательского процесса к модулю ядра
* *
* , MAJOR_NUM -- . * Первый аргумент, MAJOR_NUM -- старший номер устройства.
* *
* -- * Второй аргумент -- код команды
* ( ). * (можно указать иное значение).
* *
* -- , * Третий аргумент -- тип данных, передаваемых в ядро
*/ */
/* /*
* * Операция получения сообщения от драйвера устройства
*/ */
#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *) #define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *)
/* /*
* IOCTL . * Эта команда IOCTL используется для вывода данных.
* , * Нам по прежнему нужен буфер, размещенный в адресном пространстве
* , . * вызывающего процесса, куда это сообщение должно быть переписано.
*/ */
/* /*
* n- * Команда получения n-ного байта сообщения
*/ */
#define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int) #define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int)
/* /*
* IOCTL , . * Здесь команда IOCTL работает как на ввод, так и на вывод.
* (n), * Она принимает от пользователя номер байта (n),
* n- (Message[n]). * и возвращает n-ный байт сообщения (Message[n]).
*/ */
/* /*
* * Имя файла устройства
*/ */
#define DEVICE_FILE_NAME "cbside" #define DEVICE_FILE_NAME "cbside"
//#define DEV1_NAME "/dev/cbsideA" //#define DEV1_NAME "/dev/cbsideA"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment