因為之前介紹的網站 (http://www.tldp.org/LDP/lkmpg/2.6/html/x892.html) 上所提供的例子有錯,所以在這邊舉另一個例子。IOCTL 的範例包含 3 部分:kernel module、header file、ioctl user mode 程式。Kernel moduel 的部分是要需要建立一個 character device,以印出 "Hello ioctl world”,header file 是定義 _IO 巨集的地方,_IO macro 是要用來建裡 ioctl number 的,而 user mode 的程式是呼叫 ioctl 了範例,另外你還需要一個 Makefile 去 build 這的 module。
Compile 完之後,載入 kernel module ( insmod ioctl_basic.ko) 並從 dmesg 中去檢查 kernel moduel 的 major number,然後利用 mknod 命令去建立一個 character device file,例如,major number 是 247 的話:
mknod /dev/temp c 247 0
接著執行 user mode 程式令 kernel module 輸出訊息,接著就能在 dmesg 的輸出中看到 "Hello ioctl world”。
Makefile:
obj-m += ioctl_basic.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Kernel moduel: ioctl_basic.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h> // required for various structures related to files liked fops.
#include <linux/semaphore.h>
#include <linux/cdev.h>
#include "ioctl_basic.h" //ioctl header file
#include <linux/version.h>
static int Major;
int open(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "Inside open \n");
return 0;
}
int release(struct inode *inode, struct file *filp) {
printk (KERN_INFO "Inside close \n");
return 0;
}
int ioctl_funcs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
int data=10,ret;
switch(cmd) {
case IOCTL_HELLO:
printk(KERN_INFO "Hello ioctl world");
break;
}
return ret;
}
struct file_operations fops = {
open: open,
ioctl: ioctl_funcs,
release: release
};
struct cdev *kernel_cdev;
int char_arr_init (void) {
int ret;
dev_t dev_no,dev;
kernel_cdev = cdev_alloc();
kernel_cdev->ops = &fops;
kernel_cdev->owner = THIS_MODULE;
printk (" Inside init module\n");
ret = alloc_chrdev_region( &dev_no , 0, 1,"char_arr_dev");
if (ret < 0) {
printk("Major number allocation is failed\n");
return ret;
}
Major = MAJOR(dev_no);
dev = MKDEV(Major,0);
printk (" The major number for your device is %d\n", Major);
ret = cdev_add( kernel_cdev,dev,1);
if(ret < 0 )
{
printk(KERN_INFO "Unable to allocate cdev");
return ret;
}
return 0;
}
void char_arr_cleanup(void) {
printk(KERN_INFO " Inside cleanup_module\n");
cdev_del(kernel_cdev);
unregister_chrdev_region(Major, 1);
}
MODULE_LICENSE("GPL");
module_init(char_arr_init);
module_exit(char_arr_cleanup);
Header file: ioctl_basic.h
#include <linux/ioctl.h>
#define IOC_MAGIC 'k'
#define IOCTL_HELLO _IO(IOC_MAGIC,0)
User mode 程式: user_basic_ioctl.c
#include <stdio.h>
#include <fcntl.h>
#include "ioctl_basic.h" //ioctl header file
main ( ) {
int fd;
fd = open("/dev/temp", O_RDWR);
if (fd == -1)
{
printf("Error in opening file \n");
exit(-1);
}
ioctl(fd,IOCTL_HELLO); //ioctl call
close(fd);
}