天天看點

linux裝置驅動之字元裝置cdev_del: 

#include <linux/init.h>

#include <linux/module.h>

#include <linux/device.h>

#include <linux/fs.h>

#include <linux/proc_fs.h>

#include <linux/slab.h>

#include <linux/cdev.h>

#include <linux/uaccess.h> 

#include <linux/printk.h>

#include <linux/err.h>

#include <linux/miscdevice.h>

#include <linux/sysfs.h>

#include "freg.h"

//#define  FREG_DEV_T   

#ifdef   FREG_DEV_T 

#define  FREG_MAJOR  243

#define  FREG_MINOR  0

#endif 

// 主裝置号和從裝置号變量

static int freg_major = 0;

static int freg_minor = 0; 

// 裝置類型和裝置變量

//static struct class* freg_class = NULL;

static struct fake_reg_dev*  freg_dev = NULL;

//

static struct proc_dir_entry* freg_dir, *freg;

// 傳統的裝置檔案操作方法

static int freg_open(struct inode* inode, struct file* filp);

static int freg_release(struct inode* inode, struct file* filp);

static ssize_t freg_read(struct file * filp, char __user * buf, size_t size, loff_t * ppos);

static ssize_t freg_write(struct file * filp, const char __user * buf, size_t size, loff_t * ppos);

static int freg_open(struct inode* inode, struct file* filp)

{

filp->private_data = freg_dev;

pr_info("lxf %s\n",__func__);

return 0;

}

static int freg_release(struct inode* inode, struct file* filp)

{

pr_info("lxf %s\n",__func__);

return 0;

}

static  ssize_t freg_read(struct file * filp, char __user * buf, size_t size, loff_t * ppos)

{

      int cnt =0;

char val[4]={0};

pr_info("lxf %s bf lock\n",__func__);

mutex_lock(&freg_dev->freg_mutex);

cnt = sprintf(val,"%d\n",freg_dev->val);

cnt = simple_read_from_buffer(buf, size, ppos, val, cnt); 

mutex_unlock(&freg_dev->freg_mutex);

      pr_info("lxf %s af lock\n",__func__);

return cnt;

}

static  ssize_t freg_write(struct file * filp, const char __user * buf, size_t size, loff_t * ppos)

{

 char mem[10];

 int cnt;

 pr_info("lxf %s\n",__func__);

         mutex_lock(&freg_dev->freg_mutex);

 cnt =  simple_write_to_buffer(mem, size, ppos, buf, sizeof(freg_dev->val));

 freg_dev->val = (int)simple_strtoul(mem, NULL, 10);

 mutex_unlock(&freg_dev->freg_mutex);

return cnt;

}

// 傳統的裝置檔案操作方法表

static struct file_operations freg_fops =

{

.owner = THIS_MODULE,

.open = freg_open,

.release = freg_release,

.read    = freg_read,

.write   = freg_write,

};

ssize_t freg_proc_read(struct file *file, char __user * buf, size_t size, loff_t * ppos)

{

  int cnt =0;

    char* page ;

page = kzalloc(128,GFP_KERNEL);

cnt = sprintf(page,"%d\n",freg_dev->val);

pr_info("lxf %d\n", freg_dev->val);

cnt = simple_read_from_buffer(buf, size, ppos, page, cnt);                                             

kfree(page);

return cnt;

}

ssize_t freg_proc_write(struct file *file, const char __user * buf, size_t count, loff_t * ppos)

{

             pr_info("lxf %s\n",__func__);

freg_dev->val = (int)simple_strtoul(buf, NULL, 10);

pr_info("lxf %d\n", freg_dev->val);

return count;

}

static struct file_operations proc_fops =

{

.owner = THIS_MODULE,

.read    = freg_proc_read,

.write   = freg_proc_write,

};

int  freg_creat_proc(void)

{

freg_dir =  proc_mkdir("freg_dir", NULL);

freg     = proc_create_data("freg", 0666, freg_dir, &proc_fops, freg_dev);

if (!freg)

{

return -1;

}

return 0;

}

static struct kobject* freg_device; //sysfs kobject

//static DEVICE_ATTR(tp_info, 0444, msm_tp_module_id_show, NULL);

static ssize_t  freg_sys_show(struct device *dev,

struct device_attribute * attr, char *buf)

{

pr_info("lxf %s\n",__func__);

return  sprintf(buf,"%d\n",freg_dev->val);

}

ssize_t freg_sys_store (struct device *dev, struct device_attribute *attr,

const char *buf, size_t count)

{

pr_info("lxf %s\n",__func__);

 freg_dev->val = (int)simple_strtoul(buf, NULL, 10);

return  count;

}

 static  DEVICE_ATTR(freg_info,  0666, freg_sys_show,  freg_sys_store);

static int  freg_creat_sysfs(void)

{

int ret = 0;

freg_device = kobject_create_and_add("freg_sys",NULL);

if (!freg_device)

{

pr_info("lxf subsystem_register failed\n");

ret = -ENOMEM;

return ret;

}

ret = sysfs_create_file(freg_device, &dev_attr_freg_info.attr);

if (ret)

{

pr_info("lxf sysfs_create_file fail\n");

kobject_del(freg_device);

}

return 0;

}

static int __init freg_init(void)

{

int ret;

dev_t devno;

struct class *myclass;

 //建立字元裝置

#ifdef  FREG_DEV_T

freg_major = FREG_MAJOR;

freg_minor = FREG_MAJOR;

#endif 

devno = MKDEV(freg_major, freg_minor);

if (freg_major)

{

ret = register_chrdev_region(devno, 1, "freg_cdev");

if (ret)

{

printk(KERN_INFO "lxf register_chrdev_region fail\n");

return ret;

}

}

else 

{

ret  = alloc_chrdev_region(&devno, 0, 1, "freg_cdev");

if (ret)

{

printk(KERN_INFO "lxf alloc_chrdev_region fail\n");

return ret;

}

freg_major = MAJOR(devno);

freg_minor = MINOR(devno);

}

freg_dev = kzalloc(sizeof(struct fake_reg_dev), GFP_KERNEL);

if (IS_ERR_OR_NULL(freg_dev))

{

printk(KERN_INFO "lxf kzalloc fail\n");

ret = -ENOMEM;

goto fail_malloc;

}

cdev_init(&freg_dev->dev,&freg_fops);

freg_dev->dev.owner = THIS_MODULE;

//freg_dev->val = 521;

mutex_init(&freg_dev->freg_mutex);

// 添加字元裝置

ret = cdev_add(&freg_dev->dev, devno, 1);

if (ret)

{

printk(KERN_INFO "lxf register_chrdev_region fail\n");

goto cdev_del;

}

//建立相關節點

   myclass = class_create(THIS_MODULE, "freg_cdev_driver");

   device_create(myclass, NULL, devno, NULL,"freg_cdev");

freg_creat_proc();

freg_creat_sysfs();

pr_info("lxf freg_init sucessfully\n");

return ret;

cdev_del: 

cdev_del(&freg_dev->dev);

fail_malloc:

unregister_chrdev_region(devno, 1);

return ret;

}

static void __exit freg_exit(void)

{

//登出裝置

cdev_del(&freg_dev->dev);

kfree(freg_dev);

unregister_chrdev_region(freg_dev->dev.dev, 1);

//删除節點

remove_proc_entry("freg", freg_dir);

remove_proc_entry("freg_dir", NULL);

sysfs_remove_file(freg_device, &dev_attr_freg_info.attr);

kobject_del(freg_device);

}

module_init(freg_init);

module_exit(freg_exit);

MODULE_AUTHOR("lxf");

MODULE_DESCRIPTION("this driver just for test");

MODULE_LICENSE("GPL v2");