Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
charbridge
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
UniSet project repositories
charbridge
Commits
d3c2c1c0
Commit
d3c2c1c0
authored
Apr 28, 2011
by
Pavel Vainerman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Сконвертировал из koi8-r в utf8
parent
dc5d9687
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
120 additions
and
120 deletions
+120
-120
charbridge.c
charbridge.c
+90
-90
charbridge.h
charbridge.h
+30
-30
No files found.
charbridge.c
View file @
d3c2c1c0
/*
* charbridge.c -
*
/
* charbridge.c -
Пример создания символьного устройства
*
доступного на запись/чтение
*
*
: htt
p://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_use
r */
#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 - side
A0...sideA99
//
100..199 - side
B0...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
,
/*
c
lose */
.
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
View file @
d3c2c1c0
/*
* 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"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment