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