misc的意思是混合、杂项的,因此misc驱动也叫杂项驱动。当我们板子上的某些外设在无法进行分类的时候就可以使用该项驱动。
所有的杂项驱动都共用一个主设备号(10),不同的子杂项驱动使用不同的子设备号。
与字符驱动不同的地方在于,misc设备驱动会自动地去创建cdev,因此,在我们需要去创建一个字符设备的时候,其实完全可以用misc设备驱动去替代它。
misc设备驱动,实际上就是向Linux内核,也就是利用misc驱动core提供的接口去注册一个miscdevice,miscdevice则其实是一个结构体,定义在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 struct attribute_group **groups;
const char *nodename;
umode_t mode;
};
注册一个misc设备驱动,我们主要关注上面有注释的三个点(minor,name,fops)。
1、minor:子设备号。
因为这里主设备号已经固定,所以我们只需要申请,或者是注册一个子设备号。为什么说是注册呢?因为Linux内核已经定义好了许多子设备号,我们只要拿来使用即可。
#define PSMOUSE_MINOR 1
#define MS_BUSMOUSE_MINOR 2 /* unused */
#define ATIXL_BUSMOUSE_MINOR 3 /* unused */
/*#define AMIGAMOUSE_MINOR 4 FIXME OBSOLETE */
#define ATARIMOUSE_MINOR 5 /* unused */
#define SUN_MOUSE_MINOR 6 /* unused */
......
#define MISC_DYNAMIC_MINOR 255
上述子设备号同样被定义在include/linux/miscdevice.h中。
在我们纠结要定义哪一个子设备号时,我们可以直接使用MISC_DYNAMIC_MINOR这个宏来注册,它会根据杂项驱动的使用状态来动态注册子设备号。
2、name:设备名字。
当misc设备驱动注册成功之后,就会在/dev/下生成一个叫做name的文件节点。
3、fops:文件操作合集。
写过或者了解过字符设备驱动的朋友应该知道这个是什么。用户可以通过/dev/下的文件节点,来进行open、close、read、write、ioctl等操作,以此实现用户层和内核层的交互。
好的,当我们设置好上面的参数后,我们就可以调用接口,向Linux内核注册这个miscdevice了。
需要用到的接口如下:
int misc_register(struct miscdevice * misc)
/*函数参数和返回值含义如下:
misc:要注册的 MISC 设备。
返回值:负数,失败;0,成功。*/
当然,有注册就有注销了,接口如下:
int misc_deregister(struct miscdevice *misc)
/*函数参数和返回值含义如下:
misc:要注销的 MISC 设备。
返回值:负数,失败;0,成功。*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static int ts_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return 0;
}
static int ts_read(struct file * file,char * buf,size_t count,loff_t * f_ops)
{
return count;
}
static int ts_write(struct file * file,char * buf,size_t count,loff_t * f_ops)
{
return 0;
}
static int ts_open(struct inode * inode,struct file * file)
{
return 0;
}
static int ts_release(struct inode * inode, struct file * file)
{
return 0;
}
static struct file_operations ts_fops={
.owner = THIS_MODULE,
.open = ts_open,
.read = ts_read,
.unlocked_ioctl = ts_unlocked_ioctl,
.release = ts_release,
.write = ts_write,
};
static struct miscdevice ts_miscdev = {
.minor = MISC_DYNAMIC_MINOR,//动态分配子设备号
.name = "ts_dev",
.fops = &ts_fops,
};
/*******************************************************
Function:
Driver Install function.
Input:
None.
Output:
Executive Outcomes. 0---succeed.
********************************************************/
static int __devinit goodix_ts_init(void)
{
……
ret = misc_register(&ts_miscdev);
if (ret < 0){
printk("misc dev register failed!\n");
return ret;
}
return ret;
}
/*******************************************************
Function:
Driver uninstall function.
Input:
None.
Output:
Executive Outcomes. 0---succeed.
********************************************************/
static void __exit goodix_ts_exit(void)
{
……
misc_deregister(&ts_miscdev);
}
late_initcall(goodix_ts_init);
module_exit(goodix_ts_exit);
MODULE_DESCRIPTION("GTP Series Driver");
MODULE_LICENSE("GPL");