<div align="center">
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- Contents -->
<ins class="adsbygoogle"
     style="display:inline-block;width:728px;height:90px"
     data-ad-client="ca-pub-1411820076951016"
     data-ad-slot="3793401480"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</div>

Excuse the ads! We need some help to keep our site up.

<div id="google_translate_element"></div><script type="text/javascript">
function googleTranslateElementInit() {
  new google.translate.TranslateElement({pageLanguage: 'ko', layout: google.translate.TranslateElement.InlineLayout.SIMPLE, multilanguagePage: true, gaTrack: true, gaId: 'UA-92563911-1'}, 'google_translate_element');
}
</script><script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>

List

ioctl(Input/Output control)

DESCRIPTION

SYNOPSIS

#include <sys/ioctl.h>
int ioctl(int d, int request, ...);


Using macros to generate ioctl command numbers

MacroDescription
_IO(int type, int number)type, number 값만 전달하는 단순한 ioctl에 사용됩니다.
_IOR(int type, int number, data_type) 디바이스 드라이버에서 데이터를 읽는 ioctl에 사용됩니다
_IOW(int type, int number, data_type)디바이스 드라이버에서 데이터를 쓰는 ioctl에 사용됩니다
_IORW(int type, int number, data_type)디바이스 드라이버에서 데이터를 쓰고 읽는 ioctl에 사용됩니다.
ArgumentDescription
type
  • 장치 드라이버에 고유하게 선택된 8 비트 정수입니다. 
  • 같은 파일 기술자에 ''청취 할 수있는 다른 드라이버와 충돌하지 않도록 선택해야합니다. 
  • 예를 들어 커널 내부에서 소켓 파일 설명 자로보낸 ioctl 은 두 스택에서 모두 검사 될 수 있기 때문에 TCP 및 IP 스택은 고유 한 번호를 사용 합니다.
number
  • 8 비트 정수
  • '드라이버 내 에서 드라이버가 서비스하는 서로 다른 종류의 ioctl 명령 마다 고유 번호를 선택해야 합니다.
data_type
  • 클라이언트와 드라이버간에 교환되는 바이트 수를 계산하는 데 사용되는 유형 이름입니다. 
struct ioctl_info{
       unsigned long size;
       unsigned int buf[128];
};
 
#define             IOCTL_MAGIC         'G'
#define             SET_DATA			_IOW(IOCTL_MAGIC, 2 , ioctl_info )
#define             GET_DATA			_IOR(IOCTL_MAGIC, 3 , ioctl_info )
FunctionDescription
_IOC_NR()number 필드 값을 읽는 매크로
_IOC_TYPE()type 필드 값을 읽는 매크로
_IOC_SIZE() data_type 필드 크기를 읽는 매크로
_IOC_DIR()읽기와 쓰기 속성 필드 값을 읽는 매크로


Example


Source code of module

chardev_ioctl

#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <asm/current.h>
#include <linux/uaccess.h>
 
#include "chardev.h"
MODULE_LICENSE("Dual BSD/GPL");
 
#define DRIVER_NAME "chardev"
     
static const unsigned int MINOR_BASE = 0;
static const unsigned int MINOR_NUM  = 1;
static unsigned int chardev_major;
static struct cdev chardev_cdev;
static struct class *chardev_class = NULL;

static int     chardev_open(struct inode *, struct file *);
static int     chardev_release(struct inode *, struct file *);
static ssize_t chardev_read(struct file *, char *, size_t, loff_t *);
static ssize_t chardev_write(struct file *, const char *, size_t, loff_t *);
static long chardev_ioctl(struct file *, unsigned int, unsigned long);

struct file_operations s_chardev_fops = {
    .open    = chardev_open,
    .release = chardev_release,
    .read    = chardev_read,
    .write   = chardev_write,
    .unlocked_ioctl = chardev_ioctl,
};

static int chardev_init(void)
{
    int alloc_ret = 0;
    int cdev_err = 0;
    int minor = 0;
    dev_t dev;
 
    printk("The chardev_init() function has been called.");
     
    alloc_ret = alloc_chrdev_region(&dev, MINOR_BASE, MINOR_NUM, DRIVER_NAME);
    if (alloc_ret != 0) {
        printk(KERN_ERR  "alloc_chrdev_region = %d\n", alloc_ret);
        return -1;
    }
    //Get the major number value in dev.
    chardev_major = MAJOR(dev);
    dev = MKDEV(chardev_major, MINOR_BASE);
 
    //initialize a cdev structure
    cdev_init(&chardev_cdev, &s_chardev_fops);
    chardev_cdev.owner = THIS_MODULE;
 
    //add a char device to the system
    cdev_err = cdev_add(&chardev_cdev, dev, MINOR_NUM);
    if (cdev_err != 0) {
        printk(KERN_ERR  "cdev_add = %d\n", alloc_ret);
        unregister_chrdev_region(dev, MINOR_NUM);
        return -1;
    }
 
    chardev_class = class_create(THIS_MODULE, "chardev");
    if (IS_ERR(chardev_class)) {
        printk(KERN_ERR  "class_create\n");
        cdev_del(&chardev_cdev);
        unregister_chrdev_region(dev, MINOR_NUM);
        return -1;
    }
 
    device_create(chardev_class, NULL, MKDEV(chardev_major, minor), NULL, "chardev%d", minor);
    return 0;
}
 
static void chardev_exit(void)
{
    int minor = 0; 
    dev_t dev = MKDEV(chardev_major, MINOR_BASE);
     
    printk("The chardev_exit() function has been called.");

    device_destroy(chardev_class, MKDEV(chardev_major, minor));
 
    class_destroy(chardev_class);
    cdev_del(&chardev_cdev);
    unregister_chrdev_region(dev, MINOR_NUM);
}

static int chardev_open(struct inode *inode, struct file *file)
{
    printk("The chardev_open() function has been called.");
    return 0;
}
 
static int chardev_release(struct inode *inode, struct file *file)
{
    printk("The chardev_close() function has been called.");
    return 0;
}
 
static ssize_t chardev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
    printk("The chardev_write() function has been called.");   
    return count;
}
 
static ssize_t chardev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
    printk("The chardev_read() function has been called.");
    return count;
}
 
static struct ioctl_info info;
static long chardev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    printk("The chardev_ioctl() function has been called.");
 
    switch (cmd) {
        case SET_DATA:
            printk("SET_DATA\n");
            if (copy_from_user(&info, (void __user *)arg, sizeof(info))) {
                return -EFAULT;
            }
	    printk("info.size : %ld, info.buf : %s",info.size, info.buf);
            break;
        case GET_DATA:
            printk("GET_DATA\n");
            if (copy_to_user((void __user *)arg, &info, sizeof(info))) {
                return -EFAULT;
            }
            break;
        default:
            printk(KERN_WARNING "unsupported command %d\n", cmd);
 
        return -EFAULT;
    }
    return 0;
}

module_init(chardev_init);
module_exit(chardev_exit);
#ifndef CHAR_DEV_H_
#define CHAR_DEV_H_
#include <linux/ioctl.h>
 
struct ioctl_info{
       unsigned long size;
       char buf[128];
};
  
#define             IOCTL_MAGIC         'G'
#define             SET_DATA            _IOW(IOCTL_MAGIC, 2 ,struct ioctl_info)
#define             GET_DATA            _IOR(IOCTL_MAGIC, 3 ,struct ioctl_info)
 
#endif
obj-m := chardev.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean

Source code of Test program

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h> 
#include "chardev.h"
 
int main()
{
    int fd;
    struct ioctl_info set_info; 
    struct ioctl_info get_info; 

 	set_info.size = 100;
	strncpy(set_info.buf,"lazenca.0x0",11);

    if ((fd = open("/dev/chardev0", O_RDWR)) < 0){
        printf("Cannot open /dev/chardev0. Try again later.\n");
    }
 
    if (ioctl(fd, SET_DATA, &set_info) < 0){
        printf("Error : SET_DATA.\n");
    }


    if (ioctl(fd, GET_DATA, &get_info) < 0){
        printf("Error : SET_DATA.\n");
    }
 
 	printf("get_info.size : %ld, get_info.buf : %s\n", get_info.size, get_info.buf);
 
    if (close(fd) != 0){
        printf("Cannot close.\n");
    }
    return 0;
}

Make & Run

lazenca0x0@ubuntu:~/Kernel/Module/ioctl$ make
make -C /lib/modules/4.18.0-11-generic/build M=/home/lazenca0x0/Kernel/Module/ioctl modules
make[1]: Entering directory '/usr/src/linux-headers-4.18.0-11-generic'
Makefile:982: "Cannot use CONFIG_STACK_VALIDATION=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel"
  CC [M]  /home/lazenca0x0/Kernel/Module/ioctl/chardev.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/lazenca0x0/Kernel/Module/ioctl/chardev.mod.o
  LD [M]  /home/lazenca0x0/Kernel/Module/ioctl/chardev.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.18.0-11-generic'
lazenca0x0@ubuntu:~/Kernel/Module/ioctl$ sudo insmod chardev.ko 
[sudo] password for lazenca0x0: 
lazenca0x0@ubuntu:~/Kernel/Module/ioctl$ ./test 
get_info.size : 100, get_info.buf : lazenca.0x0
lazenca0x0@ubuntu:~/Kernel/Module/ioctl$ dmesg |tail
[   53.358158] rfkill: input handler disabled
[   97.190519] chardev: loading out-of-tree module taints kernel.
[   97.190571] chardev: module verification failed: signature and/or required key missing - tainting kernel
[   97.191019] The chardev_init() function has been called.
[  117.777326] The chardev_open() function has been called.
[  117.777328] The chardev_ioctl() function has been called.
[  117.777329] SET_DATA
[  117.777330] info.size : 100, info.buf : lazenca.0x0
[  117.777331] The chardev_ioctl() function has been called.
[  117.777331] GET_DATA
lazenca0x0@ubuntu:~/Kernel/Module/ioctl$ 

References

<div align="center">
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- Contents -->
<ins class="adsbygoogle"
     style="display:inline-block;width:728px;height:90px"
     data-ad-client="ca-pub-1411820076951016"
     data-ad-slot="3793401480"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</div>