1.杂项设备节点
一部分驱动需要和上层应用进行通信,一般需要生成设备节点,上层应用通过一套标准的借口函数调用设备节点就可以控制底层以及底层通信。下面就简单易用的杂项设备节点生成做一下简单介绍:
在开发板的终端输出cat /proc/misc
可以查看相应的杂项设备号。主设备号只有256个,远远不能满
足实际的需求,所以引入了杂项设备号,对于杂项设备主设备号为10,在linux系统中它都是固定的。
Linux 驱动分为字符设备、块设备、网络设备,但是这个分类不能包含所有的设备,所以将无法归类的设备统称为杂项设备,杂项设备可能用到字符设备、块设备、网络设备中的一项或者多项设备。
在linux目录中,使用命令ls drivers/char/
,可以查看到杂项设备的文件”misc.c”
2.杂项设备注册函数及结构体
杂项设备的头文件在include/linux/miscdevice.h
,有两个函数需要掌握:
struct miscdevice {
int minor;
const char *name;
const struct file_operations *fops;
struct list_head list;
struct device *parent;
struct device *this_device;
const char *nodename;
mode_t mode;
};
/* 杂项设备注册函数;一般在probe 中调用,参数是miscdevice*/
extern int misc_register(struct miscdevice * misc);
/*杂项设备卸载函数;一般是在hello_remove 中用于卸载驱动。*/
extern int misc_deregister(struct miscdevice *misc);
在结构体miscdevice中较为常用的几个:minor为设备号,MSIC_DYNAMIC_MINOR,这个宏定义可以查到为10;name设备名称;file_operations结构体在头文件”include/linux/fs.h”中:
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
.....
}
该结构体中的参数非常多,现就一些参数进行说明:struct module owner:一般是THIS_MODULE;int (*open) (struct inode , struct file ):对应上层的open 函数,打开文件;int (*release) (struct inode , struct file ):对应上层的close 函数,打开文件操作之后一般需要关闭;ssize_t (*read) (struct file , char _user , size_t, loff_t ):读函数,上层应用从底层读取函数;ssize_t (write) (struct file , const char __user , size_t, loff_t ):写函数,上层应用向底层传输数据;long (unlocked_ioctl) (struct file , unsigned int, unsigned long):这个函数功能和写
函数稍微有点重合,但是这个函数占用的内存非常小,主要针对IO 口的控制。
3.程序清单
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
/*注册杂项设备头文件*/
#include <linux/miscdevice.h>
/*注册设备节点的文件结构体*/
#include <linux/fs.h>
#define DRIVER_NAME "hello_ctl"
#define DEVICE_NAME "hello_ctl123"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("flywang");
static long hello_ioctl( struct file *files, unsigned int cmd, unsigned long arg){
printk("cmd is %d,arg is %d\n",cmd,arg);
return 0;
}
static int hello_release(struct inode *inode, struct file *file){
printk(KERN_EMERG "hello release\n");
return 0;
}
static int hello_open(struct inode *inode, struct file *file){
printk(KERN_EMERG "hello open\n");
return 0;
}
static struct file_operations hello_ops = {
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_release,
.unlocked_ioctl = hello_ioctl,
};
static struct miscdevice hello_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &hello_ops,
};
static int hello_probe(struct platform_device *pdv){
printk(KERN_EMERG "\tinitialized\n");
misc_register(&hello_dev);
return 0;
}
static int hello_remove(struct platform_device *pdv){
printk(KERN_EMERG "\tremove\n");
misc_deregister(&hello_dev);
return 0;
}
static void hello_shutdown(struct platform_device *pdv){
;
}
static int hello_suspend(struct platform_device *pdv,pm_message_t pmt){
return 0;
}
static int hello_resume(struct platform_device *pdv){
return 0;
}
struct platform_driver hello_driver = {
.probe = hello_probe,
.remove = hello_remove,
.shutdown = hello_shutdown,
.suspend = hello_suspend,
.resume = hello_resume,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
}
};
static int hello_init(void)
{
int DriverState;
printk(KERN_EMERG "hello world init!\n");
DriverState = platform_driver_register(&hello_driver);
printk(KERN_EMERG "\tDriverState is %d\n",DriverState);
return 0;
}
static void hello_exit(void)
{
printk(KERN_EMERG "hello world exit!\n");
platform_driver_unregister(&hello_driver);
}
module_init(hello_init);
module_exit(hello_exit);