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");

07-31 12:45