/* * Copyright (C) 2024 LingYun IoT System Studio * Author: Guo Wenxue * * A character skeleton driver example in linux kernel. */ #include #include #include /* printk() */ #include /* everything... */ #include /* error codes */ #include /* size_t */ #include /* cdev */ #include /* kernel version code */ #include //#define CONFIG_DYNAMIC_ALLOC /* device name and major number */ #define DEV_NAME "chrdev" #ifdef CONFIG_DYNAMIC_ALLOC #define DEV_MAJOR 0 #else #define DEV_MAJOR 79 #endif int dev_major = DEV_MAJOR; module_param(dev_major, int, S_IRUGO); #ifdef CONFIG_DYNAMIC_ALLOC struct cdev *cdev; #else struct cdev cdev; #endif static int chrdev_open (struct inode *inode, struct file *file) { return 0; } static int chrdev_close (struct inode *node, struct file *file) { return 0; } static struct file_operations chrdev_fops = { .owner = THIS_MODULE, .open = chrdev_open, /* open() implementation */ .release = chrdev_close, /* close() implementation */ }; static int __init chrdev_init(void) { dev_t devno; int rv; /* 1. Allocate device number */ if(0 != dev_major) { devno = MKDEV(dev_major, 0); rv = register_chrdev_region(devno, 1, DEV_NAME); } else { rv = alloc_chrdev_region(&devno, 0, 1, DEV_NAME); dev_major = MAJOR(devno); } if(rv < 0) { printk(KERN_ERR "%s driver can't use major %d\n", DEV_NAME, dev_major); return -ENODEV; } /* 2. Allocate and initialize cdev */ #ifdef CONFIG_DYNAMIC_ALLOC cdev = cdev_alloc(); if( !cdev ) { printk(KERN_ERR "Unable to allocate cdev\n"); goto failed1; } cdev_init(cdev, &chrdev_fops); #else cdev_init(&cdev, &chrdev_fops); cdev.owner = THIS_MODULE; #endif /* 3. Register cdev to linux kernel */ #ifdef CONFIG_DYNAMIC_ALLOC rv = cdev_add(cdev, devno, 1); #else rv = cdev_add(&cdev, devno, 1); #endif if( rv ) { rv = -ENODEV; printk(KERN_ERR "%s driver regist failed, rv=%d\n", DEV_NAME, rv); goto failed1; } printk(KERN_INFO "%s driver on major[%d] installed.\n", DEV_NAME, dev_major); return 0; failed1: unregister_chrdev_region(devno, 1); printk(KERN_ERR "%s driver installed failed.\n", DEV_NAME); return rv; } static void __exit chrdev_exit(void) { #ifdef CONFIG_DYNAMIC_ALLOC cdev_del(cdev); #else cdev_del(&cdev); #endif unregister_chrdev_region(MKDEV(dev_major,0), 1); printk(KERN_INFO "%s driver removed!\n", DEV_NAME); return; } module_init(chrdev_init); module_exit(chrdev_exit); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("GuoWenxue ");