ioctl是设备驱动中的一个奇葩,所有不适合write,read等情况下,都可用它实现,有点像北方的杂烩菜。
言归正传,简单介绍下。
用户系统调用:int ioctl( int fd,unsigned long cmd, …)
驱动中对应的函数:
ioctl int(*ioctl)(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg),前两个参数和其他驱动函数一致,后面两个分别对应系统调用中的后两个。
道理就是这样简单,但是linux内核提供了一套标准方法来构造命令,后面再讲,首先测试下我们的ioctl。
下面是一个最简单的ioctl调用,麻雀虽小,五脏俱全。
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/cdev.h>
- #include <linux/fs.h>
- #include <linux/types.h>
- #include <linux/slab.h>
- #include <linux/uaccess.h>
- #include <linux/moduleparam.h>
- //#include <linux/>
- MODULE_LICENSE("Dual BSD/GPL");
- int major=0;
- module_param(major,int,0);
- int minor=0;
- module_param(minor,int,0);
- struct test_dev{
- char test[256];
- struct cdev cdev;
- };
- struct test_dev* my_dev;
- int test_open(struct inode *inode,struct file *filp)
- {
- printk(KERN_ALERT "open, tamclub");
- return 0;
- }
- static int test_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
- {
- switch(cmd){
- case 1:printk(KERN_ALERT "i o y");break;
- case 2:printk(KERN_ALERT "y o m");break;
- default:break;
- }
- }
- int test_release(struct inode *inode,struct file *filp)
- {
- printk(KERN_ALERT "close, tamclub");
- return 0;
- }
- static struct file_operations test_fops={
- .owner=THIS_MODULE,
- .open=test_open,
- .ioctl=test_ioctl,
- .release=test_release,
- };
- static int hello_init(void)
- {
- int ret;
- dev_t dev;
- my_dev=kmalloc(sizeof(struct test_dev),GFP_KERNEL);
- if(!my_dev){
- printk("bad kmalloc");
- return -ENOMEM;
- }
- if(major){
- dev=MKDEV(major,minor);
- ret=register_chrdev_region(dev,0,"test");
- }else{
- ret=alloc_chrdev_region(&dev,minor,1,"test");
- major=MAJOR(dev);
- printk(KERN_ALERT "%d",major);
- }
- if(ret<0){
- printk(KERN_ALERT "can't get major %d\n",major);
- }
- cdev_init(&my_dev->cdev,&test_fops);
- my_dev->cdev.owner=THIS_MODULE;
- my_dev->cdev.ops=&test_fops;
-
- ret=cdev_add(&my_dev->cdev,dev,1);
- if(ret){
- printk(KERN_ALERT "error %d",ret);
- }
- printk(KERN_ALERT "Hello, tmaclub\n");
- return 0;
- }
- static void hello_exit(void)
- {
- unregister_chrdev_region(MKDEV(major,minor),1);
- cdev_del(&my_dev->cdev);
- kfree(my_dev);
- printk(KERN_ALERT "Goodbye, tmaclub\n");
- }
- module_init(hello_init);
- module_exit(hello_exit);
下面是最简单的应用程序:
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdio.h>
- int main(void)
- {
- int fd;
- fd=open("/dev/my_dev",O_RDWR|O_NONBLOCK);
- if(fd != -1){
- printf("success");
- ioctl(fd,1);
- close(fd);
- }
- }
调试结果如下:
open, tamclub<1>i o y<1>close, tamclub
调试过程中出现了了点小问题,就是打不开/dev/my_dev(设备节点,mknod创建),原来是权限不够。
执行如下命令解决:chmod 777 /dev/my_dev,然后再执行应用程序。
上述虽然简单的实现了一个ioctl,但是如果内核中这样写,linux就成不了linux了。内核中提供了一套构建cmd和解析cmd的命令,用起来很方便,也避免了使用过程中的一些错误。
在Linux核心中是这样定义一个命令码的:
____________________________________
| 设备类型 | 序列号 | 方向 |数据尺寸|
|----------|--------|------|--------|
| 8 bit | 8 bit |2 bit |8~14 bit|
|----------|--------|------|--------|
上述所说的宏就是用来构造和解析这些命令码的,有兴趣的可以试下,其实完全一样。
阅读(2014) | 评论(0) | 转发(0) |