好记性不如铅笔头

C && C++, kernel, 编程

驱动学习笔记:IOCTL

CONTENTS

参考网址:

http://blog.csdn.net/yusiguyuan/article/details/16829299 】

http://www.cnblogs.com/geneil/archive/2011/12/04/2275372.html 】

http://116.62.110.235/blog/driving-study-notes-miscellaneous-equipment/ 】

Makefile:

obj-m := helloioctl.o
KERNEL_DIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
	make -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules
clean:
	rm *.o *.ko *.mod.c
 
.PHONY:clean

helloioctl.h:

#ifndef _HELLO_IOCTL_H_
#define _HELLO_IOCTL_H_

#include <linux/ioctl.h>

/* 定义幻数 */
#define IOC_MAGIC  'c'
/* 定义命令 */
#define IOC_PRINTNUM  _IO(IOC_MAGIC, 1)
#define IOC_GETNUM    _IOR(IOC_MAGIC, 2, int)
#define IOC_SETNUM    _IOW(IOC_MAGIC, 3, int)
#define IOC_MAX       3

#endif /* _HELLO_IOCTL_H_ */

helloioctl.c:

#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>

#include "helloioctl.h"

static int currNum = 0;

/*IO操作*/
long my_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    int err = 0;
    int ret = 0;
    
    /* 检测命令的有效性 */
    if (_IOC_TYPE(cmd) != IOC_MAGIC) 
        return -EINVAL;
    if (_IOC_NR(cmd) > IOC_MAX) 
        return -EINVAL;

    /* 根据命令类型,检测参数空间是否可以访问 */
    if (_IOC_DIR(cmd) & _IOC_READ)
        err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
    else if (_IOC_DIR(cmd) & _IOC_WRITE)
        err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
    if (err) 
        return -EFAULT;

    /* 根据命令,执行相应的操作 */
    switch(cmd) 
    {
    	case IOC_PRINTNUM:
    	printk(KERN_ALERT "currNum = %d\n",currNum);
    	break;
		
		case IOC_GETNUM: 
		ret = __put_user(currNum, (int *)arg);
        break;

		case IOC_SETNUM: 
		ret = __get_user(currNum, (int *)arg);
		break;

		default:  
		return -EINVAL;
    }
    return ret;
}


struct file_operations myfops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = my_ioctl,
};
struct miscdevice my_misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "helloioctl",
    .fops = &myfops,
};

static int hello_init(void)
{
	printk(KERN_ALERT "Hello, world\n");

	currNum = 0;

	misc_register(&my_misc);
	return 0;
}

static void hello_exit(void)
{
	printk(KERN_ALERT "Goodbye, world\n");
    misc_deregister(&my_misc);
}

module_init(hello_init);
module_exit(hello_exit);

插入驱动模块:

root@ubuntu:/home/cstriker1407/drivers/helloioctl# make
make -C /lib/modules/3.13.0-37-generic/build SUBDIRS=/home/cstriker1407/drivers/helloioctl modules
make[1]: 正在进入目录 `/usr/src/linux-headers-3.13.0-37-generic'
  CC [M]  /home/cstriker1407/drivers/helloioctl/helloioctl.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/cstriker1407/drivers/helloioctl/helloioctl.mod.o
  LD [M]  /home/cstriker1407/drivers/helloioctl/helloioctl.ko
make[1]:正在离开目录 `/usr/src/linux-headers-3.13.0-37-generic'
root@ubuntu:/home/cstriker1407/drivers/helloioctl# insmod helloioctl.ko
root@ubuntu:/home/cstriker1407/drivers/helloioctl# tail -f /var/log/kern.log
Nov  3 05:24:04 ubuntu kernel: [ 3633.887152] Hello, world
。。。
cstriker1407@ubuntu:/dev$ ls
。。。。。。
helloioctl
。。。。。。

编写测试代码testioctl.c:

#include <stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

#include "helloioctl.h"

int main()
{
    int fd = 0;
    int cmd;
    int arg = 0;
    
    fd = open("/dev/helloioctl",O_RDWR);
    if (fd < 0)
    {
        printf("Open helloioctl Error!\n");
        return -1;
    }
    
    printf("<--- Call IOC_PRINTNUM --->\n");
    cmd = IOC_PRINTNUM;
    if (ioctl(fd, cmd, &arg) < 0)
	{
		printf("Call cmd IOC_PRINTNUM fail\n");
		return -1;
    }
    
    printf("<--- Call IOC_SETNUM --->\n");
    cmd = IOC_SETNUM;
    arg = 100;
    if (ioctl(fd, cmd, &arg) < 0)
	{
		printf("Call cmd IOC_SETNUM fail\n");
		return -1;
	}

    printf("<--- Call IOC_GETNUM --->\n");
    cmd = IOC_GETNUM;
    if (ioctl(fd, cmd, &arg) < 0)
	{
		printf("Call cmd IOC_GETNUM fail\n");
		return -1;
    }
    printf("<--- In User Space IOC_GETNUM Get Data is %d --->\n\n",arg);    
    
    close(fd);
    return 0;    
}

测试IOCTL:

root@ubuntu:/home/cstriker1407/drivers/helloioctl# gcc testioctl.c
root@ubuntu:/home/cstriker1407/drivers/helloioctl# ./a.out 
<--- Call IOC_PRINTNUM --->
<--- Call IOC_SETNUM --->
<--- Call IOC_GETNUM --->
<--- In User Space IOC_GETNUM Get Data is 100 --->

root@ubuntu:/home/cstriker1407/drivers/helloioctl# rmmod helloioctl
root@ubuntu:/home/cstriker1407/drivers/helloioctl# tail -f /var/log/kern.log
Nov  3 05:29:35 ubuntu kernel: [ 3964.652611] currNum = 0
Nov  3 05:30:51 ubuntu kernel: [ 4040.750168] Goodbye, world

 

发表评论

15 − 1 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据