字元驅動框架

shell_nut發表於2020-07-31

include <linux/module.h>

include <linux/kernel.h>

include <linux/init.h>

include <linux/fs.h>

include <linux/slab.h>

include <linux/uaccess.h>

include <linux/io.h>

include <linux/cdev.h>

include <linux/device.h>

define NEWCHR_NAME "chrdevbase"

define NEWCHR_COUNT 1

/* 字元裝置結構體 /
struct chrdevbase_dev{
struct cdev cdev; /
字元裝置 /
dev_t devid; /
裝置號 */
struct class class; / 類 */
struct device device; / 裝置 /
int major; /
主裝置號 /
int minor; /
次裝置號 */

};

struct chrdevbase_dev chrdev; /* 字元裝置 */

static int newchrled_open(struct inode *inode, struct file *filp)
{
return 0;
}

static int newchrled_release(struct inode *inode, struct file *filp)
{
return 0;
}

static ssize_t newchrled_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
int retvalue;
unsigned char databuf[1];

retvalue = copy_from_user(databuf, buf, count);
if(retvalue < 0) {
    printk("kernel write failed!\r\n");
    return -EFAULT;
}

return 0;

}

static const struct file_operations chrdev_fops = {
.owner = THIS_MODULE,
.write = newchrled_write,
.open = newchrled_open,
.release= newchrled_release,
};

/*入口 */
static int __init chrdevbase_init(void)
{
int ret = 0;
unsigned int val = 0;
printk("newchrled_init\r\n");

chrdev.major = 0;    /* 設定為0,表示由系統申請裝置號 */

/* 2,註冊字元裝置 */
if(chrdev.major){    /* 給定主裝置號 */
    chrdev.devid = MKDEV(chrdev.major, 0);
    ret = register_chrdev_region(chrdev.devid, NEWCHRLED_COUNT, NEWCHR_NAME);
} else {                /* 沒有給定主裝置號 */
    ret = alloc_chrdev_region(&chrdev.devid, 0, NEWCHRLED_COUNT, NEWCHR_NAME);
    chrdev.major = MAJOR(chrdev.devid);
    chrdev.minor = MINOR(chrdev.devid);
}
if(ret < 0) {
    printk("chrdev chrdev_region err!\r\n");
    goto fail_devid;
}
printk("chrdev major=%d, minor=%d\r\n", chrdev.major, chrdev.minor);

/* 3,註冊字元裝置 */
chrdev.cdev.owner = THIS_MODULE;
cdev_init(&chrdev.cdev, &chrdev_fops);
ret = cdev_add(&chrdev.cdev, chrdev.devid, NEWCHRLED_COUNT);
if(ret < 0) {
    goto fail_cdev;
}

/* 4,自動建立裝置節點 */
chrdev.class = class_create(THIS_MODULE, NEWCHR_NAME);
if (IS_ERR(chrdev.class)) {
    ret = PTR_ERR(chrdev.class);
	goto fail_class;
}

chrdev.device = device_create(chrdev.class, NULL,
		     chrdev.devid, NULL, NEWCHR_NAME);
if (IS_ERR(chrdev.device)) {
    ret = PTR_ERR(chrdev.device);
    goto fail_device;
}
	
return 0;

fail_device:
class_destroy(chrdev.class);
fail_class:
cdev_del(&chrdev.cdev);
fail_cdev:
unregister_chrdev_region(chrdev.devid, NEWCHRLED_COUNT);
fail_devid:
return ret;
}

/* 出口 */
static void __exit chrdevbase_exit(void)
{

unsigned int val = 0;
printk("chrdevbase_exit\r\n");

/* 1,刪除字元裝置 */
cdev_del(&chrdev.cdev);

/* 2,登出裝置號 */
unregister_chrdev_region(chrdev.devid, NEWCHRLED_COUNT);

/* 3,摧毀裝置 */
device_destroy(chrdev.class, chrdev.devid);

/* 4,摧毀類 */
class_destroy(chrdev.class);

}

/* 註冊和解除安裝驅動 */
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harold.xu");

相關文章