/* List of printk Log Levels: Log Level | Macro | Priority Code | Purpose 0 | KERN_EMERG | <0> | System is unstable (panic-level message). 1 | KERN_ALERT | <1> | Immediate action required. 2 | KERN_CRIT | <2> | Critical errors (serious issues). 3 | KERN_ERR | <3> | General errors (non-critical). 4 | KERN_WARNING| <4> | Warnings (might cause issues). 5 | KERN_NOTICE | <5> | Normal but notable conditions. 6 | KERN_INFO | <6> | Informational messages (default for general logs). 7 | KERN_DEBUG | <7> | Debugging messages (used for development). */ #include #include #include #include #include #include #include #include #include #include #define CHAR_DEV_NAME "demo_cdev" #define MAX_LENGTH 4000 #define SUCCESS 0 static char *char_device_buf; struct cdev *demo_cdev; dev_t mydev; //device tree as an instance //We are using this because all character //drivers belongs to device tree. static int char_dev_open(struct inode *inode, struct file *file){ printk(KERN_INFO "chr_drv_dynamic :: open operation invoked \n"); return SUCCESS; } static int char_dev_release(struct inode *inode, struct file *file){ printk(KERN_INFO "chr_drv_dynamic :: release opration invoked\n"); return SUCCESS; } static ssize_t char_dev_read(struct file *file, char *buf, size_t lbuf, loff_t *ppos){ printk(KERN_INFO "chr_dev_dynamic :: read operation invoked\n"); return 0; } static ssize_t char_dev_write(struct file *file, const char *buf, size_t lbuf, loff_t *ppos){ printk(KERN_INFO "chr_drv_dynamic :: write operation invoked \n"); return lbuf; } /* This syntax is called "Designated initialization"*/ /* This is allowed in C after C99*/ static struct file_operations char_dev_fops = { .owner = THIS_MODULE, //To define the ownership of this struct .read = char_dev_read, //When file is read .write = char_dev_write, //When file is written on .open = char_dev_open, //When file is open .release = char_dev_release //When file is closed }; static int __init char_dev_init(void){ int ret, count = 1; //this alloc_chrdev_region will acquire //major number dynamically. if(alloc_chrdev_region(&mydev, 0, count, CHAR_DEV_NAME) < 0){ printk(KERN_ERR "failed to reserve major/minor range\n"); return -1; } //cdev_alloc function is used to allocate //a character device. if( !(demo_cdev = cdev_alloc())){ printk(KERN_ERR "cdev_alloc() failed\n"); unregister_chrdev_region(mydev, count); return -1; } //It is used to initialize one //character device allocated. //Also to mention the capabilities //of this character device, we also //mention char_dev_fops. cdev_init(demo_cdev, &char_dev_fops); //cdev_add is used to add character device //to character device list. ret = cdev_add(demo_cdev, mydev, count); if( ret < 0 ){ printk(KERN_INFO "Error registering device driver\n"); cdev_del( demo_cdev ); unregister_chrdev_region(mydev, count); return -1; } printk(KERN_INFO"\nDevice Registered: %s\n", CHAR_DEV_NAME); printk(KERN_INFO"Major number = %d, Minor number = %d\n", MAJOR (mydev), MINOR (mydev)); char_device_buf = (char *)kmalloc(MAX_LENGTH, GFP_KERNEL); return 0; } static void __exit char_dev_exit(void){ cdev_del(demo_cdev); unregister_chrdev_region(mydev,1); kfree(char_device_buf); printk(KERN_INFO "\n Driver unregistered \n"); } module_init(char_dev_init); module_exit(char_dev_exit); MODULE_AUTHOR("Junet Hossain"); MODULE_DESCRIPTION("Character Device Driver - Test"); MODULE_LICENSE("GPL");