Библиотека сайта 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
$
Предыдущий раздел: | Оглавление | Следующий раздел: |
Драйверы: примеры реализации | Множественное открытие устройства |