杂项字符设备、早期字符设备、标准字符设备的编程实现

杂项字符设备:

        杂项字符设备特点:

            1.关联函数:misc_register()、misc_deregister()

            2.主设备号规定为10,只需要分配次设备号minor(杂项设备最多只能分配255个,0~255)

            3.设备初始化时,设备节点文件自动创建(与早期字符设备手动创建不一样)


使用案例: 
         (三个程序案例实现的功能都是一样的,不同之处已用颜色标出(一些函数涉及的结构体差异没有标出),大家可以跳过)       

#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <asm/uaccess.h>



#define  GPM4CON  0x110002e0         //GPIO功能配置寄存器物理地址
#define  GPM4DAT  0x110002e4          //GPIO状态寄存器物理地址

static  unsigned long*  ledcon = NULL;
static  unsigned long*  leddat = NULL;


        //  上层关联函数write(int  fd,  void*  buf,  int  count);


        //自定义write操作函数

static  ssize_t  led_write(struct file * filp, const char __user * buff, size_t count, loff_t * offet)
{
char  buf[32] = {0};
int ret = 0;

ret = copy_from_user(buf,  buff,  min(count, sizeof(buf)));            //实现用户层与底层链接函数
if(strncmp(buf, "led on", strlen("led on")) == 0)
{
*leddat  &=  0xf0;
}
else if(strncmp(buf, "led off", strlen("led off")) == 0)
{
*leddat |= 0x0f;
}
else
{
printk("***cmd  error!***\n");
}

return min(count, sizeof(buf));
}


//文件操作集合定义初始化。   给上层应用层留操作接口
static  struct file_operations g_tfops = {
.owner = THIS_MODULE,
.write = led_write,
};



  //********杂项字符函数结构体***********

static  struct miscdevice   g_tmiscdev = {
.minor = MISC_DYNAMIC_MINOR,    //MISC_DYNAMIC_MINOR==255  表示系统自动分配次设备号
.name = "led_misc",
.fops = &g_tfops,                //自定义write操作函数(上面定义)
};


        //******主函数入口*******

static  int  __init  pyw_module_init(void)
{
printk("hello  module! 你好\n");


ledcon = ioremap(GPM4CON, 4);            //地址映射,将物理地址映射成虚拟地址,供内核使用
leddat = ioremap(GPM4DAT, 4);              //地址映射,将物理地址映射成虚拟地址,供内核使用
*ledcon  &=  0xffff0000;
*ledcon  |=  0x00001111;
*leddat  |=  0x0f;

misc_register(&g_tmiscdev);

return 0;
}

        //******主函数出口*******
static  void  __exit  pyw_module_exit(void)
{
printk("byebye  %s\n", "module");
misc_deregister(&g_tmiscdev);


*leddat  |=  0x0f;
iounmap(ledcon);
iounmap(leddat);
}


module_init(pyw_module_init);
module_exit(pyw_module_exit);


早期字符设备:

        早期字符设备特点:

            1. 与杂项相比,早期字符设备需要自己创建节点文件,但编程上少了一层结构体

            2. majoy主设备号:0~255(10外:10号为杂项字符设备专用号)     minor:0~255


#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <linux/fs.h>
#include <asm/uaccess.h>

#define  GPM4CON  0x110002e0
#define  GPM4DAT  0x110002e4 

static  unsigned long*  ledcon = NULL;
static  unsigned long*  leddat = NULL;

//  write(int  fd,  void*  buf,  int  count);
static  ssize_t  led_write(struct file * filp, const char __user * buff, size_t count, loff_t * offet)
{
char  buf[32] = {0};
int ret = 0;

ret = copy_from_user(buf,  buff,  min(count, sizeof(buf)));
if(strncmp(buf, "led on", strlen("led on")) == 0)
{
*leddat  &=  0xf0;
}
else if(strncmp(buf, "led off", strlen("led off")) == 0)
{
*leddat |= 0x0f;
}
else
{
printk("***cmd  error!***\n");
}

return min(count, sizeof(buf));
}



//文件操作集合定义初始化。   给上层应用层留操作接口
static  struct file_operations g_tfops = {
.owner = THIS_MODULE,
.write = led_write,   
};


static  int  g_major = 0;

static  int  __init  pyw_module_init(void)
{
printk("hello  module! 你好\n");

ledcon = ioremap(GPM4CON, 4);
leddat = ioremap(GPM4DAT, 4);
*ledcon  &=  0xffff0000;
*ledcon  |=  0x00001111;
*leddat  |=  0x0f;

g_major = register_chrdev(0, "led_xxx", &g_tfops);
printk("major = %d\n", g_major);

return 0;
}


static  void  __exit  pyw_module_exit(void)
{
printk("byebye  %s\n", "module");
unregister_chrdev(g_major, "led_xxx");


*leddat  |=  0x0f;
iounmap(ledcon);
iounmap(leddat);
}


module_init(pyw_module_init);
module_exit(pyw_module_exit);


标准字符设备

         标准字符串设备特点:

            1.标准字符设备使用复杂,较为少用。(杂类和早期都是封装好了标准字符设备相关函数,所以使用简单)

            2.模块加载后,需要自己手动创建节点文件

            3.majoy主设备号:0~2^12=4K  (10是给杂项设备使用的)       minor次设备号:0~2^20=1M


#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <linux/slab.h>




#define  BASEMINOR  0
#define  DEVCOUNT  4
#define  DEVNAME  "led_cdev"
#define  GPM4CON  0x110002e0
#define  GPM4DAT    0x110002e4


static  unsigned long* ledcon = NULL;
static  unsigned long* leddat = NULL;


static  ssize_t  led_write(struct file * filp, const char __user * buff, size_t count, loff_t * offet)
{
char  buf[32] = {0};
int ret = 0;

ret = copy_from_user(buf,  buff,  min(count, sizeof(buf)));
if(strncmp(buf, "led on", strlen("led on")) == 0)
{
*leddat  &=  0xf0;
}
else if(strncmp(buf, "led off", strlen("led off")) == 0)
{
*leddat |= 0x0f;
}
else
{
printk("***cmd  error!***\n");
}

return min(count, sizeof(buf));
}




static  struct file_operations  g_tfops = {
.owner = THIS_MODULE,
.write = led_write,
};




static  dev_t  g_dev = 0;
static  struct cdev* g_ptcdev = NULL;


static  int  __init  pyw_cdev_init(void)
{
ledcon = ioremap(GPM4CON, 4);
leddat = ioremap(GPM4DAT, 4);
*ledcon  &=  0xffff0000;
*ledcon  |=  0x00001111;
*leddat  |=  0x0f;


alloc_chrdev_region(&g_dev, BASEMINOR, DEVCOUNT, DEVNAME);                //申请设备号
g_ptcdev = cdev_alloc();                                                                              //申请标准字符设备结构体空间
cdev_init(g_ptcdev, &g_tfops);                                                                  //初始化赋值标准字符设备结构体变量
cdev_add(g_ptcdev, g_dev, DEVCOUNT);                                              //注册标准字符设备到内核总线


printk("major = %d\n", MAJOR(g_dev));
printk("minor = %d\n", MINOR(g_dev));


return 0;
}


static  void  __exit  pyw_cdev_exit(void)

{

     //****************与注册对应的资源释放***********************

cdev_del(g_ptcdev);
kfree(g_ptcdev);
unregister_chrdev_region(g_dev, DEVCOUNT);     //DEVCOUNT=0



iounmap(ledcon);
iounmap(leddat);
}


module_init(pyw_cdev_init);
module_exit(pyw_cdev_exit);



猜你喜欢

转载自blog.csdn.net/qq_35769746/article/details/80950783