ARM开发之杂项设备的编写----以LED驱动为例

    xiaoxiao2021-03-25  187

    平台:S5PV210

    杂项设备的好处:

    有了字符型设备后,为什么要用杂项设备?

    1.节省主设备号,所有杂项设备的主设备号都是10

    2.杂项设备开发起来比字符型设备简单

    开发步骤:

    1.定义1个杂项设备

    2.定义杂项设备的文件操作集

    3.申请物理内存区

    4.获取相应的虚拟地址

    5.注册混杂设备

    6.示例代码

    1.定义杂项设备

    static struct miscdevice led_misc = { .minor = MISC_DYNAMIC_MINOR, .name = "misc_led", .fops = &fops, };如上代码:其中.minor代表动态生成次设备号,不用改。

    .name表示这个混杂设备文件结点的名字,用户程序用open在 /dev 目录下打开文件的就是 .name 的值。

    .fops代表杂项设备的文件操作集

    2.定义文件操作集

    static struct file_operations fops = { .owner = THIS_MODULE, .open = misc_open, .write = misc_write, };文件操作集表示了杂项设备用了哪些系统调用,如上代码就是用了 open 和 write。

    第一个参数不用变,.owner一定写THIS_MODULE,用于初始化。

    3.申请物理内存区

    static struct resource *res = NULL; res = request_mem_region(0xE0200280,8,"LED");上面表示,控制LED的物理地址为0XE0200280开始,8个字节,并把这段内存起名为LED

    4.获取相应虚拟地址。

    操作系统操作的都是虚拟地址。

    static unsigned int va = NULL; va = ioremap(0xE02000A0,8);va就是物理地址映射的虚拟地址的起始地址。

    5.注册杂项设备

    int ret; ret = misc_register(&led_misc); if(ret < 0) { printk("misc register is error\n"); return -1; }misc_register()的参数就是第一步定义的杂项设备变量。

    6.示例代码(LED驱动)

    #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/cdev.h> #include <linux/io.h> #include <linux/ioport.h> #include <linux/device.h> #include <linux/miscdevice.h> static struct resource* res = NULL; static unsigned int *GPJ2CON_VA = NULL; static unsigned int *GPJ2DAT_VA = NULL; static char wbuf[1]; static ssize_t misc_write(struct file *f, const char __user*buf, size_t len, loff_t *t) { copy_from_user(wbuf,buf,len); if(wbuf[0] == '0') { *GPJ2DAT_VA &=~0xf; } if(wbuf[0] == '1') { *GPJ2DAT_VA &=~0xf; *GPJ2DAT_VA |=0xf; } return 0; } /*2.定义文件操作集*/ static struct file_operations fops={ .owner = THIS_MODULE, .write = misc_write, }; /*1.定义misc杂项设备变量*/ static struct miscdevice misc_led={ .minor = MISC_DYNAMIC_MINOR, .name = "led_misc", .fops = &fops, }; static int __init misc_init(void) { int ret; /*3.申请物理内存*/ res = request_mem_region(0xe0200280,8,"LED"); if(res == NULL) { printk("failed to request_mem_region\n"); goto failed_request_mem; } /*4.获取虚拟地址*/ GPJ2CON_VA = ioremap(0xe0200280,8); if(GPJ2CON_VA == NULL) { printk("failed to ioremap\n"); goto failed_ioremap; } GPJ2DAT_VA = GPJ2CON_VA + 1; /*5注册杂项设备*/ ret = misc_register(&misc_led); if(ret<0) { printk("failed to register misc\n"); goto failed_register; } printk("init completed\n"); return 0; failed_register: iounmap(GPJ2CON_VA); failed_ioremap: release_mem_region(0xe0200280,8); failed_request_mem: return -1; } static void __exit misc_exit(void) { iounmap(GPJ2CON_VA); release_mem_region(0xe0200280,8); misc_deregister(&misc_led); } module_init(misc_init); module_exit(misc_exit); MODULE_LICENSE("GPL"); 用户程序测试代码:

    #include <stdio.h> #include <fcntl.h> int main() { char buf[1]; buf[0]='0'; int fd = open("/dev/led_misc",O_WRONLY); if(fd<0) { perror("failed to open"); return -1; } while(1) { write(fd,buf,1); sleep(1); buf[0] = '1'; write(fd,buf,1); sleep(1); buf[0] = '0'; } return 0; }

    转载请注明原文地址: https://ju.6miu.com/read-5872.html

    最新回复(0)