File was renamed from bsp/drivers/x86_64/ldd2_chrdev.c |
| | |
| | | /* |
| | | * Copyright (C) 2024 LingYun IoT System Studio |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * |
| | | * A character skeleton driver example in linux kernel. |
| | | */ |
| | | |
| | | #include <linux/module.h> |
| | | #include <linux/init.h> |
| | | #include <linux/kernel.h> /* printk() */ |
| | | #include <linux/slab.h> /* kmalloc() */ |
| | | #include <linux/fs.h> /* everything... */ |
| | | #include <linux/errno.h> /* error codes */ |
| | | #include <linux/types.h> /* size_t */ |
| | | #include <linux/cdev.h> /* cdev */ |
| | | #include <linux/fcntl.h> /* O_ACCMODE */ |
| | | #include <linux/uaccess.h> /* copy_*_user */ |
| | | #include <linux/slab.h> /* kmalloc() */ |
| | | #include <linux/version.h> /* kernel version code */ |
| | | #include <linux/uaccess.h> /* copy_from/to_user() */ |
| | | #include <linux/moduleparam.h> |
| | | |
| | | /* device name and major number */ |
| | | #define DEV_NAME "chrdev" |
| | | #define DEV_SIZE 1024 |
| | | #define CONFIG_AUTODEV 1 /* Auto create device node in driver or not */ |
| | | |
| | | //#define DEV_MAJOR 79 |
| | | #ifndef DEV_MAJOR |
| | | #define DEV_MAJOR 0 |
| | | #endif |
| | | |
| | | int dev_major = DEV_MAJOR; |
| | | int dev_major = 0; |
| | | module_param(dev_major, int, S_IRUGO); |
| | | |
| | | #define BUF_SIZE 1024 |
| | | typedef struct chrdev_s |
| | | { |
| | | struct cdev cdev; |
| | | #ifdef CONFIG_AUTODEV |
| | | struct class *class; |
| | | struct device *device; |
| | | #endif |
| | | char *data; /* data buffer */ |
| | | uint32_t size; /* data buffer size */ |
| | | uint32_t bytes; /* data bytes in the buffer */ |
| | |
| | | int rv; |
| | | |
| | | /* malloc and initial device read/write buffer */ |
| | | dev.data = kmalloc(DEV_SIZE, GFP_KERNEL); |
| | | dev.data = kmalloc(BUF_SIZE, GFP_KERNEL); |
| | | if( !dev.data ) |
| | | { |
| | | printk(KERN_ERR " %s driver kmalloc() failed\n", DEV_NAME); |
| | | return -ENOMEM; |
| | | } |
| | | dev.size = DEV_SIZE; |
| | | dev.size = BUF_SIZE; |
| | | dev.bytes = 0; |
| | | memset(dev.data, 0, dev.size); |
| | | |
| | | /* dynamic alloc device node major number if not set */ |
| | | /* allocate device number */ |
| | | if(0 != dev_major) |
| | | { |
| | | devno = MKDEV(dev_major, 0); |
| | |
| | | return -ENODEV; |
| | | } |
| | | |
| | | /* setup and register cdev into kernel */ |
| | | /* initialize cdev and setup fops */ |
| | | cdev_init(&dev.cdev, &chrdev_fops); |
| | | dev.cdev.owner = THIS_MODULE; |
| | | |
| | | /* register cdev to linux kernel */ |
| | | rv = cdev_add(&dev.cdev, devno, 1); |
| | | if( rv ) |
| | | { |
| | |
| | | goto failed1; |
| | | } |
| | | |
| | | #ifdef CONFIG_AUTODEV |
| | | /* create device node in user space */ |
| | | #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0) |
| | | dev.class = class_create(DEV_NAME); |
| | | #else |
| | | dev.class = class_create(THIS_MODULE, DEV_NAME); |
| | | #endif |
| | | if (IS_ERR(dev.class)) { |
| | | rv = PTR_ERR(dev.class); |
| | | goto failed2; |
| | | } |
| | | |
| | | dev.device = device_create(dev.class, NULL, MKDEV(dev_major, 0), NULL, DEV_NAME); |
| | | if( !dev.device ) |
| | | { |
| | | rv = -ENODEV; |
| | | printk(KERN_ERR "%s driver create device failed\n", DEV_NAME); |
| | | goto failed3; |
| | | } |
| | | #endif |
| | | |
| | | printk(KERN_INFO "%s driver on major[%d] installed.\n", DEV_NAME, dev_major); |
| | | return 0; |
| | | |
| | | #ifdef CONFIG_AUTODEV |
| | | failed3: |
| | | class_destroy(dev.class); |
| | | |
| | | failed2: |
| | | cdev_del(&dev.cdev); |
| | | #endif |
| | | |
| | | failed1: |
| | | unregister_chrdev_region(devno, 1); |
| | | kfree(dev.data); |
| | | |
| | | printk(KERN_ERR "%s driver installed failed.\n", DEV_NAME); |
| | | return rv; |
| | |
| | | |
| | | static void __exit chrdev_exit(void) |
| | | { |
| | | #ifdef CONFIG_AUTODEV |
| | | device_del(dev.device); |
| | | class_destroy(dev.class); |
| | | #endif |
| | | |
| | | cdev_del(&dev.cdev); |
| | | unregister_chrdev_region(MKDEV(dev_major,0), 1); |
| | | |