Библиотека сайта rus-linux.net
| Цилюрик О.И. Модули ядра Linux | ||
| Назад | Внешние интерфейсы модуля | Вперед |
Управляющие операции устройства
Здесь (архив ioctl.tgz), для реализации уже знакомых нам операций регистрации устройства, мы умышленно воспользуемся, так называемым, старым методом регистрации символьного устройства (register_chrdev()). Но эта техника потеряла актуальности, и используются на сегодня — это и будет наш третий альтернативный способ создания устройства. Но, помимо этого, пользуясь тем, что способ регистрации устройства никоим образом не связан с реализующими операции функциями, мы дополним схему нашего устройства обработчиком управляющих операций ioctl(), что и есть главной целью нашего следующего примера:
hello_dev.c :
#include "ioctl.h"
#include "../dev.h"
// Работа с символьным устройством в старом стиле...
static int hello_open( struct inode *n, struct file *f ) {
// ... при этом MINOR номер устройства должна обслуживать функция open:
// unsigned int minor = iminor( n );
return 0;
}
static int hello_release( struct inode *n, struct file *f ) {
return 0;
}
static int hello_ioctl( struct inode *n, struct file *f,
unsigned int cmd, unsigned long arg ) {
if( ( _IOC_TYPE( cmd ) != IOC_MAGIC ) ) return -ENOTTY;
switch( cmd ) {
case IOCTL_GET_STRING:
if( copy_to_user( (void*)arg, hello_str, _IOC_SIZE( cmd ) ) ) return -EFAULT;
break;
default:
return -ENOTTY;
}
return 0;
}
static const struct file_operations hello_fops = {
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_release,
.read = hello_read,
.ioctl = hello_ioctl
};
#define HELLO_MAJOR 200
#define HELLO_MODNAME "hello_dev"
static int __init hello_init( void ) {
int ret = register_chrdev( HELLO_MAJOR, HELLO_MODNAME, &hello_fops );
if( ret < 0 ) {
printk( KERN_ERR "Can not register char device\n" );
goto err;
}
err:
return ret;
}
static void __exit hello_exit( void ) {
unregister_chrdev( HELLO_MAJOR, HELLO_MODNAME );
}
Заголовочный файл, совместно используемый и модулем, и работающим с ним пользовательским процессом, служащий для их согласованного использования типов и констант:
ioctl.h :
typedef struct _RETURN_STRING {
char buf[ 160 ];
} RETURN_STRING;
#define IOC_MAGIC 'h'
#define IOCTL_GET_STRING _IOR( IOC_MAGIC, 1, RETURN_STRING )
Пользовательский (тестовый) процесс, пользующийся вызовами ioctl():
ioctl.c :
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include "ioctl.h"
#define ERR(...) fprintf( stderr, "\7" __VA_ARGS__ ), exit( EXIT_FAILURE )
int main( int argc, char *argv[] ) {
int dfd; // дескриптор устройства
if( ( dfd = open( "/dev/hello", O_RDWR ) ) < 0 ) ERR( "Open device error: %m\n" );
RETURN_STRING buf;
if( ioctl( dfd, IOCTL_GET_STRING, &buf ) ) ERR( "IOCTL_GET_STRING error: %m\n" );
fprintf( stdout, (char*)&buf );
close( dfd );
return EXIT_SUCCESS;
};
Makefile :
CURRENT = $(shell uname -r) KDIR = /lib/modules/$(CURRENT)/build PWD = $(shell pwd) DEST = /lib/modules/$(CURRENT)/misc TARGET = hello_dev obj-m := $(TARGET).o all: default ioctl default: $(MAKE) -C $(KDIR) M=$(PWD) modules ioctl: ioctl.h ioctl.c gcc ioctl.c -o ioctl
Испытываем полученное изделие:
$ sudo mknod -m0666 /dev/hello c 200 0
$ ls -l /dev | grep 200
crw-rw-rw- 1 root root 200, 0 Июн 19 00:55 hello
$ cat /dev/hello
cat: /dev/hello: Нет такого устройства или адреса
$ sudo insmod ./hello_dev.ko
$ echo $?
0
$ cat /dev/hello
Hello, world!
$ cat /proc/devices | grep hel
200 hello_dev
$ ./ioctl
Hello, world!
$ sudo rmmod hello_dev
$ ./ioctl
Open device error: No such device or address
$ cat /dev/hello
cat: /dev/hello: Нет такого устройства или адреса
$ ls -l /dev | grep 200
crw-rw-rw- 1 root root 200, 0 Июн 19 00:55 hello
$ cat /proc/devices | grep hel
$
| Предыдущий раздел: | Оглавление | Следующий раздел: |
| Драйверы: примеры реализации | Множественное открытие устройства |
