广西智能网站建设报价,wordpress分页代码,360优化大师官方下载,福建建设厅网站首页前言 misc 的意思是混合、杂项的#xff0c;因此 MISC 驱动也叫做杂项驱动。也就是当我们板子上的某些外设无法进行分类的时候就可以使用 MISC 驱动。 MISC 驱动其实就是最简单的字符设备驱动#xff0c;通常嵌套在 platform 总线驱动中#xff0c;实现复杂的驱动#xff0…前言 misc 的意思是混合、杂项的因此 MISC 驱动也叫做杂项驱动。也就是当我们板子上的某些外设无法进行分类的时候就可以使用 MISC 驱动。 MISC 驱动其实就是最简单的字符设备驱动通常嵌套在 platform 总线驱动中实现复杂的驱动接下来就来讲下一下MISC的使用其实总结就是一句话用MISC 设备驱动来简化字符设备驱动的编写也就是替代我们之前注册字符设备的那一堆操作。 一.MISC设备驱动简介 所有的 MISC 设备驱动的主设备号都为 10不同的设备使用不同的从设备号。随着 Linux字符设备驱动的不断增加设备号变得越来越紧张尤其是主设备号 MISC 设备驱动就用于解决此问题。 MISC 设备会自动创建 cdev不需要像我们以前那样手动创建因此采用 MISC 设备驱动可以简化字符设备驱动的编写。 1.miscdevice 设备结构体
同样的我们要使用MISC就需要向 Linux 注册一个 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;
}; 这个结构体需要我们填入的参数有minor、 name 和 fops 这三个成员变量。
1minor minor 表示子设备号 MISC 设备的主设备号为 10这个是固定的需要用户指定子设备号 Linux 系统已经预定义了一些 MISC 设备的子设备号这些预定义的子设备号定义在include/linux/miscdevice.h 文件中如下所示
#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 APOLLO_MOUSE_MINOR 7 /* unused */
#define PC110PAD_MINOR 9 /* unused */
......
#define VHOST_VSOCK_MINOR 241
#define RFKILL_MINOR 242
#define MISC_DYNAMIC_MINOR 255
我们在使用的时候可以从这些预定义的子设备号中挑选一个当然也可以自己定义只要这个子设备号没有被其他设备使用接口。
2name name 就是此 MISC 设备名字当此设备注册成功以后就会在/dev 目录下生成一个名为 name的设备文件。 3fops
fops 是字符设备的操作函数集合 MISC 设备驱动最终是需要使用用户提供的 fops操作集合。也就是之前我们自己手动注册字符设备的操作函数
/* 设备操作函数结构体 */
static const struct file_operations gpioled_fops {.owner THIS_MODULE,.open gpioled_open,.read gpioled_read,.write gpioled_write,.release gpioled_release
}; 2.miscdevice 注册函数
函数原型如下:
int misc_register(struct miscdevice * misc)函数参数和返回值含义如下
misc要注册的 MISC 设备。
返回值 负数失败 0成功。
以前我们需要自己调用一堆的函数去创建设备比如在以前的字符设备驱动中我们会使用如下几个函数完成设备创建过程 /* 传统的创建设备过程 */
alloc_chrdev_region(); /* 申请设备号 */
cdev_init(); /* 初始化 cdev */
cdev_add(); /* 添加 cdev */
class_create(); /* 创建类 */
device_create(); /* 创建设备 */ 现在我们可以直接使用 misc_register 一个函数来完成上面的传统的创建设备过程中的这些步骤。如下所示 ret misc_register(led_miscdev);if(ret 0){printk(misc device register failed!\r\n);return -EFAULT;} 3.misc_deregister卸载函数
当我们卸载设备驱动模块的时候需要调用 misc_deregister 函数来注销掉 MISC 设备函数原型如下
int misc_deregister(struct miscdevice *misc)函数参数和返回值含义如下
misc要注销的 MISC 设备。
返回值 负数失败 0成功。
以前注销设备驱动的时候我们需要调用一堆的函数去删除此前创建的 cdev、设备等等内容如下所示
/* 传统的删除设备的过程 */
cdev_del(); /* 删除 cdev */
unregister_chrdev_region(); /* 注销设备号 */
device_destroy(); /* 删除设备 */
class_destroy(); /* 删除类 */ 现在我们只需要一个 misc_deregister 函数即可完成传统的删除设备的过程中的这些工作。关于MISC 设备驱动就讲解到这里接下来我们就使用 platform 加 MISC 驱动框架来编写 led驱动。如下所示
misc_deregister(led_miscdev); 二、设备树的修改
在设备树下的根节点添加以下结点 gpioled{#address-cells 1;#size-cells 1;compatible led-gpio;pinctrl-names default;pinctrl-0 pinctrl_led;gpios gpio1 3 GPIO_ACTIVE_LOW;state okay;};
在iomux节点下添加; pinctrl_led:ledgrp{fsl,pin/* 配置 GPIO1_IO03 的 IO 属性 *bit 16:0 HYS 关闭 *bit [15:14]: 00 默认下拉 *bit [13]: 0 kepper 功能 *bit [12]: 1 pull/keeper 使能 *bit [11]: 0 关闭开路输出 *bit [7:6]: 10 速度 100Mhz *bit [5:3]: 110 R0/6 驱动能力 *bit [0]: 0 低转换率 */MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10B0; 三、驱动代码的编写
1.引入框架 框架就使用我们之前的platfrom-led的框架不过在peobe函数里面我们要把关于那些字符设备注册初始化的部分删除了
static int led_probe(struct platform_device *dev)
{myled_init(gpioled);return 0;
} 剩下gpio初始化部分就可以了。
2.创建miscdevice结构体
#define DEVICE_NAME miscled
#define DEVICE_MINOR 145 /* 子设备号 *//* MISC设备结构体 */
static struct miscdevice led_miscdev {.minor DEVICE_MINOR,.name DEVICE_NAME,.fops gpioled_fops,
};
3.使用.miscdevice 注册函数
/*当谁列表的设备和驱动匹配上后执行的peobe函数*/
static int led_probe(struct platform_device *dev)
{int ret 0;myled_init(gpioled);ret misc_register(led_miscdev);if(ret 0){printk(misc device register failed!\r\n);return -EFAULT;}return 0;
}
4.misc_deregister卸载函数
static int led_remove(struct platform_device *dev)
{gpio_set_value(gpioled.led_gpio,1);gpio_free(gpioled.led_gpio);misc_deregister(led_miscdev);printk(gpioled exit!\r\n);return 0;
}
完整代码
/**************头文件区域*********************************************************/
#include linux/ide.h
#include linux/fs.h
#include linux/init.h
#include linux/module.h
#include linux/cdev.h
#include linux/types.h
#include linux/kernel.h
#include linux/errno.h#include linux/of.h
#include linux/of_address.h
#include linux/of_gpio.h
#include linux/irq.h
#include linux/poll.h
#include linux/platform_device.h
#include linux/fcntl.h
#include linux/miscdevice.h#include asm/mach/map.h
#include asm/uaccess.h
#include linux/io.h
/**********************************************************************************//************************函数定义-begin***********************************************/
static int gpioled_release(struct inode *inode, struct file *file);
static ssize_t gpioled_read(struct file *file, char __user *buf, size_t size, loff_t *ptr);
static ssize_t gpioled_write(struct file *file, const char __user *buf, size_t size, loff_t *ptr);
static int gpioled_open(struct inode *inode , struct file *file);
static int led_probe(struct platform_device *dev);
static int led_remove(struct platform_device *dev);
/************************函数定义-end********************************************//************************宏定义-begin***********************************************/
#define DEVICE_NAME miscled
#define DEVICE_MINOR 145 /* 子设备号 */
#define DEVICE_CNT 1
#define BEEP_ON 1
#define BEEP_OFF 0
/************************宏定义-end********************************************//************************结构体定义-begin***********************************************/
/* dtsled设备信息结构体 */
struct dts_dev
{dev_t devid; /* 设备号 */struct cdev cdev; /* cdev */struct class *class; /* 类 */struct device *device; /* 设备 */struct device_node *nd; /* 设备节点 */int led_gpio; /* led 所使用的 GPIO 编号 */
};
struct dts_dev gpioled; /* led设备 *//* 设备操作函数结构体 */
static const struct file_operations gpioled_fops {.owner THIS_MODULE,.open gpioled_open,.read gpioled_read,.write gpioled_write,.release gpioled_release
};/* MISC设备结构体 */
static struct miscdevice led_miscdev {.minor DEVICE_MINOR,.name DEVICE_NAME,.fops gpioled_fops,
};/* 匹配列表 */
static const struct of_device_id led_of_match[] {{ .compatible led-gpio },{ /* Sentinel */ }
};static struct platform_driver led_driver {.driver {.name imx6ul-led,.of_match_table led_of_match,},.probe led_probe,.remove led_remove,
};
/************************结构体定义-end***********************************************//************************file_operations操作函数-begin***********************************************/
static int gpioled_release(struct inode *inode, struct file *file)
{printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);return 0;
}
static ssize_t gpioled_read(struct file *file, char __user *buf, size_t size, loff_t *ptr)
{printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);return 0;
}
static ssize_t gpioled_write(struct file *file, const char __user *buf, size_t size, loff_t *ptr)
{int ret;unsigned char databuf[1];unsigned char ledstate;struct dts_dev *dev file-private_data;ret __copy_from_user(databuf,buf,size);if(ret 0){printk(kernel write failed!\r\n);return -EFAULT;}ledstate databuf[0];if(ledstate BEEP_OFF){ gpio_set_value(dev-led_gpio,1);}else if(ledstate BEEP_ON){gpio_set_value(dev-led_gpio,0);}return 0;
}
static int gpioled_open(struct inode *inode , struct file *file)
{printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);file-private_data gpioled; /* 设置私有数据 */ return 0;
}
/************************file_operations操作函数-end***********************************************//*****************led初始化函数************************/
static int myled_init(struct dts_dev *dev)
{int ret 0;/* 1、设置 led 所使用的 GPIO */ dev-nd of_find_node_by_path(/gpioled);if(dev-nd NULL){printk(gpioled node cant not found!\r\n);return -EINVAL;}else{printk(gpioled node hase been found!\r\n);}/* 2、 获取设备树中的 gpio 属性得到 led 所使用的 led 编号 */ dev-led_gpio of_get_named_gpio(dev-nd,gpios,0);if(dev-led_gpio 0){printk(cant get led-gpio\r\n);return -EINVAL;}printk(led-gpio num %d\r\n, dev-led_gpio); /* 3、设置 GPIO1_IO03 为输出并且输出高电平默认关闭 led 灯 */ ret gpio_request(dev-led_gpio,led);if(ret 0){printk(led-gpio request fail\r\n); return -EINVAL;}ret gpio_direction_output(dev-led_gpio,1);if(ret 0) {printk(cant set gpio!\r\n);}return ret;
}/************************platfrom操作函数-begin***********************************************/
/*当谁列表的设备和驱动匹配上后执行的peobe函数*/
static int led_probe(struct platform_device *dev)
{int ret 0;myled_init(gpioled);ret misc_register(led_miscdev);if(ret 0){printk(misc device register failed!\r\n);return -EFAULT;}return 0;
}
static int led_remove(struct platform_device *dev)
{gpio_set_value(gpioled.led_gpio,1);gpio_free(gpioled.led_gpio);misc_deregister(led_miscdev);printk(gpioled exit!\r\n);return 0;
}
/************************platfrom操作函数-endn***********************************************/static int __init gpioled_init(void)
{return platform_driver_register(led_driver);
}static void __exit gpioled_exit(void)
{platform_driver_unregister(led_driver);
}module_init(gpioled_init);
module_exit(gpioled_exit);
MODULE_LICENSE(GPL);
MODULE_AUTHOR(oudafa);
四、编写测试 APP
这里的测试APP和之前得没什么区别不用改
#include stdio.h
#include unistd.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdlib.h
#include string.h/** description : main主程序* param - argc : argv数组元素个数* param - argv : 具体参数* return : 0 成功;其他 失败*/
int main(int argc, char *argv[])
{int fd, retvalue;char *filename;unsigned char databuf[1];if(argc ! 3){printf(Error Usage!\r\n);return -1;}filename argv[1];/* 打开led驱动 */fd open(filename, O_RDWR);if(fd 0){printf(file %s open failed!\r\n, argv[1]);return -1;}databuf[0] atoi(argv[2]); /* 要执行的操作打开或关闭 *//* 向/dev/led文件写入数据 */retvalue write(fd, databuf, sizeof(databuf));if(retvalue 0){printf(LED Control Failed!\r\n);close(fd);return -1;}retvalue close(fd); /* 关闭文件 */if(retvalue 0){printf(file %s close failed!\r\n, argv[1]);return -1;}return 0;
}
五、运行测试
1.编写makefile
并且使用make命令得到.ko文件和APP文件
KERN_DIR /home/odf/linux-imx/linux-imxall:clearmake -C $(KERN_DIR) Mpwd modules $(CROSS_COMPILE)gcc -o miscledApp miscledApp.c clean:clearmake -C $(KERN_DIR) Mpwd modules cleanrm -rf modules.orderrm -f miscledAppobj-m miscled.o
2.加载模块
将编译出来 .ko文件 和 app文件 这两个文件拷贝到 rootfs/lib/modules/4.1.15 目录中目录中重启开发板进入到目录 rootfs/lib/modules/4.1.15 目录中中输入如下命令加载 驱动模块
insmod miscled.ko
所有的 misc 设备都属于同一个类 /sys/class/misc 目录下就是 misc 这个类的所有设备每个设备对应一个子目录。 驱动与设备匹配成功以后就会生成/dev/miscled这个设备驱动文件输入如下命令查看这个文件的主次设备号
ls -l /sys/class/misc
结果如下所示 从上面可以看出 /dev/misc_beep 这个设备的主设备号为 10次设备号为 144和我们驱动程序里面设置的一致。 3.测试代码
输入如下命令打开 led
./misc_beep_app /dev/miscled 1输入如下命令关闭 led
./misc_beep_app /dev/miscled 0