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