Update x86 example driver
Signed-off-by: guowenxue <guowenxue@gmail.com>
3 files renamed
7 files added
1 files copied
4 files deleted
New file |
| | |
| | | # vim |
| | | *.sw[a-z] |
| | | *.un~ |
| | | Session.vim |
| | | |
| | | app_chrdev* |
| | | container_of |
| | | |
| | | # make file |
| | | .* |
| | | !.gitignore |
| | | *~ |
| | | *.o |
| | | core |
| | | *.ko |
| | | *.mod.c |
| | | Module.symvers |
| | | modules.order |
| | | *.mod |
| | | *.a |
| | | |
| | | # misc-progs |
| | | nbtest |
| | | load50 |
| | | mapcmp |
| | | polltest |
| | | mapper |
| | | setlevel |
| | | setconsole |
| | | inp |
| | | outp |
| | | datasize |
| | | dataalign |
| | | netifdebug |
| | | asynctest |
| | | |
| | | # Allows for Eclipse CDT lookups without checking in linux source |
| | | linux_source_cdt |
| | | !.project |
| | | !.cproject |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2024 LingYun IoT System Studio |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * |
| | | * A character skeleton driver test code in user space. |
| | | */ |
| | | |
| | | #include <stdio.h> |
| | | #include <unistd.h> |
| | | #include <string.h> |
| | | #include <errno.h> |
| | | #include <sys/types.h> |
| | | #include <sys/stat.h> |
| | | #include <fcntl.h> |
| | | |
| | | int main (int argc, char **argv) |
| | | { |
| | | char *devname = "/dev/chrdev0"; |
| | | char buf[1024]; |
| | | int rv = 0; |
| | | int fd; |
| | | |
| | | fd = open(devname, O_RDWR); |
| | | if( fd < 0 ) |
| | | { |
| | | printf("Open device %s failed: %s\n", devname, strerror(errno)); |
| | | return 1; |
| | | } |
| | | |
| | | rv = write(fd, "Hello", 5); |
| | | if( rv< 0) |
| | | { |
| | | printf("Write data into device failed, rv=%d: %s\n", rv, strerror(errno)); |
| | | rv = 2; |
| | | goto cleanup; |
| | | } |
| | | printf("Write %d bytes data okay\n", rv); |
| | | |
| | | memset(buf, 0, sizeof(buf)); |
| | | rv = read(fd, buf, sizeof(buf)); |
| | | if( rv< 0) |
| | | { |
| | | printf("Read data from device failed, rv=%d: %s\n", rv, strerror(errno)); |
| | | rv = 3; |
| | | goto cleanup; |
| | | } |
| | | printf("Read %d bytes data: %s\n", rv, buf); |
| | | |
| | | cleanup: |
| | | close(fd); |
| | | return rv; |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2024 LingYun IoT System Studio |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * |
| | | * A character skeleton driver test code in user space. |
| | | */ |
| | | |
| | | #include <stdio.h> |
| | | #include <unistd.h> |
| | | #include <string.h> |
| | | #include <errno.h> |
| | | #include <sys/types.h> |
| | | #include <sys/stat.h> |
| | | #include <sys/ioctl.h> |
| | | #include <fcntl.h> |
| | | |
| | | #define CHR_MAGIC 'c' |
| | | #define CMD_READ _IOR(CHR_MAGIC, 0, int) |
| | | #define CMD_WRITE _IOW(CHR_MAGIC, 1, int) |
| | | |
| | | int main (int argc, char **argv) |
| | | { |
| | | char *devname = "/dev/chrdev0"; |
| | | int value; |
| | | int fd; |
| | | |
| | | fd = open(devname, O_RDWR); |
| | | if( fd < 0 ) |
| | | { |
| | | printf("Open device %s failed: %s\n", devname, strerror(errno)); |
| | | return 1; |
| | | } |
| | | |
| | | if( ioctl(fd, CMD_READ, &value) < 0 ) |
| | | { |
| | | printf("ioctl() failed: %s\n", strerror(errno)); |
| | | goto cleanup; |
| | | } |
| | | printf("Default value in driver: 0x%0x\n", value); |
| | | |
| | | value = 0x12345678; |
| | | if( ioctl(fd, CMD_WRITE, &value) < 0 ) |
| | | { |
| | | printf("ioctl() failed: %s\n", strerror(errno)); |
| | | goto cleanup; |
| | | } |
| | | printf("Wriee value into driver: 0x%0x\n", value); |
| | | |
| | | value = 0; |
| | | if( ioctl(fd, CMD_READ, &value) < 0 ) |
| | | { |
| | | printf("ioctl() failed: %s\n", strerror(errno)); |
| | | goto cleanup; |
| | | } |
| | | printf("Read value from driver : 0x%0x\n", value); |
| | | |
| | | cleanup: |
| | | close(fd); |
| | | return 0; |
| | | } |
New file |
| | |
| | | #include <stdio.h> |
| | | #include <stddef.h> |
| | | |
| | | #define container_of(ptr, type, member) ({ \ |
| | | const typeof(((type *)0)->member) *__mptr = (ptr); \ |
| | | (type *)((char *)__mptr - offsetof(type, member)); \ |
| | | }) |
| | | |
| | | struct student_s |
| | | { |
| | | char name[50]; |
| | | int age; |
| | | }; |
| | | |
| | | void print_student(int *p_age) |
| | | { |
| | | struct student_s *p_student; |
| | | |
| | | // 使用 container_of 获取指向 student_s 结构体的指针 |
| | | p_student = container_of(p_age, struct student_s, age); |
| | | |
| | | printf("Name: %s, Age: %d\n", p_student->name, p_student->age); |
| | | |
| | | return ; |
| | | } |
| | | |
| | | int main(void) |
| | | { |
| | | struct student_s student = {"Zhang San", 30}; |
| | | |
| | | print_student(&student.age); |
| | | |
| | | return 0; |
| | | } |
| | | |
New file |
| | |
| | | KERNAL_DIR ?= /lib/modules/$(shell uname -r)/build |
| | | PWD :=$(shell pwd) |
| | | |
| | | obj-m += hello.o |
| | | obj-m += chrdev1.o |
| | | obj-m += chrdev2.o |
| | | obj-m += chrdev3.o |
| | | obj-m += chrdev4.o |
| | | |
| | | modules: |
| | | $(MAKE) -C $(KERNAL_DIR) M=$(PWD) modules |
| | | @make clear |
| | | |
| | | clear: |
| | | @rm -f *.o *.cmd *.mod *.mod.c |
| | | @rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f |
| | | @rm -f .*.cmd .*.o.d |
| | | |
| | | clean: |
| | | @rm -f *.ko |
New file |
| | |
| | | /* |
| | | * 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/fs.h> /* everything... */ |
| | | #include <linux/errno.h> /* error codes */ |
| | | #include <linux/types.h> /* size_t */ |
| | | #include <linux/cdev.h> /* cdev */ |
| | | #include <linux/version.h> /* kernel version code */ |
| | | #include <linux/moduleparam.h> |
| | | |
| | | //#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 <guowenxue@gmail.com>"); |
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 */ |
| | |
| | | } |
| | | |
| | | static struct file_operations chrdev_fops = { |
| | | .owner = THIS_MODULE, |
| | | .open = chrdev_open, /* open() implementation */ |
| | | .read = chrdev_read, /* read() implementation */ |
| | | .write = chrdev_write, /* write() implementation */ |
| | | .release = chrdev_close, /* close() implementation */ |
| | | .owner = THIS_MODULE, |
| | | .open = chrdev_open, /* open() implementation */ |
| | | .read = chrdev_read, /* read() implementation */ |
| | | .write = chrdev_write, /* write() implementation */ |
| | | .release = chrdev_close, /* close() implementation */ |
| | | }; |
| | | |
| | | static int __init chrdev_init(void) |
| | |
| | | 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); |
| | | |
copy from bsp/drivers/x86_64/ldd3_ioctl.c
copy to bsp/drivers/x86/driver/chrdev3.c
File was copied from bsp/drivers/x86_64/ldd3_ioctl.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> |
| | | |
| | | #if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) |
| | | #define access_ok_wrapper(type,arg,cmd) access_ok(type, arg, cmd) |
| | | #else |
| | | #define access_ok_wrapper(type,arg,cmd) access_ok(arg, cmd) |
| | | #endif |
| | | |
| | | /* ioctl definitions, use 'z' as magic number */ |
| | | #define CHRDEV_IOC_MAGIC 'z' |
| | | #define CHRDEV_IOCRESET _IO(CHRDEV_IOC_MAGIC, 0) |
| | | #define CHRDEV_IOCSET _IOW(CHRDEV_IOC_MAGIC, 1, int) |
| | | #define CHRDEV_IOCGET _IOR(CHRDEV_IOC_MAGIC, 2, int) |
| | | #define CHRDEV_IOC_MAXNR 3 |
| | | |
| | | /* 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 */ |
| | |
| | | return rv; |
| | | } |
| | | |
| | | /* The ioctl() implementation */ |
| | | long chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| | | #if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) |
| | | #define access_ok_wrapper(type,arg,cmd) access_ok(type, arg, cmd) |
| | | #else |
| | | #define access_ok_wrapper(type,arg,cmd) access_ok(arg, cmd) |
| | | #endif |
| | | |
| | | /* ioctl definitions, use 'c' as magic number */ |
| | | #define CHR_MAGIC 'c' |
| | | #define CHR_MAXNR 2 |
| | | #define CMD_READ _IOR(CHR_MAGIC, 0, int) |
| | | #define CMD_WRITE _IOW(CHR_MAGIC, 1, int) |
| | | |
| | | static long chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| | | { |
| | | struct chrdev_s *dev = file->private_data; |
| | | int rv, data; |
| | | size_t bytes = sizeof(data); |
| | | static int value = 0xdeadbeef; |
| | | int rv = 0; |
| | | |
| | | /* |
| | | * extract the type and number bitfields, and don't decode |
| | | * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok() |
| | | */ |
| | | if (_IOC_TYPE(cmd) != CHRDEV_IOC_MAGIC) return -ENOTTY; |
| | | if (_IOC_NR(cmd) > CHRDEV_IOC_MAXNR) return -ENOTTY; |
| | | if (_IOC_TYPE(cmd) != CHR_MAGIC) return -ENOTTY; |
| | | if (_IOC_NR(cmd) > CHR_MAXNR) return -ENOTTY; |
| | | |
| | | /* |
| | | * the direction is a bitmask, and VERIFY_WRITE catches R/W transfers. |
| | |
| | | rv = !access_ok_wrapper(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); |
| | | else if (_IOC_DIR(cmd) & _IOC_WRITE) |
| | | rv = !access_ok_wrapper(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); |
| | | if (rv) return -EFAULT; |
| | | |
| | | switch(cmd) { |
| | | case CHRDEV_IOCRESET: |
| | | dev->bytes = 0; |
| | | memset(dev->data, 0, dev->size); |
| | | rv = 0; |
| | | if (rv) |
| | | return -EFAULT; |
| | | |
| | | switch (cmd) { |
| | | case CMD_READ: |
| | | if (copy_to_user((int __user *)arg, &value, sizeof(value))) |
| | | return -EFAULT; |
| | | break; |
| | | |
| | | /* Last 4 bytes in the buffer used to save ioctl() data*/ |
| | | case CHRDEV_IOCSET: |
| | | rv = __get_user(data, (int __user *)arg); |
| | | if( !rv ) |
| | | memcpy(&dev->data[dev->size-bytes], &data, bytes); |
| | | break; |
| | | |
| | | case CHRDEV_IOCGET: |
| | | memcpy(&data, &dev->data[dev->size-bytes], bytes); |
| | | rv = __put_user(data, (int __user *)arg); |
| | | case CMD_WRITE: |
| | | if (copy_from_user(&value, (int __user *)arg, sizeof(value))) |
| | | return -EFAULT; |
| | | break; |
| | | |
| | | default: |
| | | return -ENOTTY; |
| | | return -EINVAL; |
| | | } |
| | | |
| | | return rv; |
| | | return 0; |
| | | } |
| | | |
| | | static int chrdev_open (struct inode *inode, struct file *file) |
| | |
| | | } |
| | | |
| | | static struct file_operations chrdev_fops = { |
| | | .owner = THIS_MODULE, |
| | | .open = chrdev_open, /* open() implementation */ |
| | | .read = chrdev_read, /* read() implementation */ |
| | | .write = chrdev_write, /* write() implementation */ |
| | | .release = chrdev_close, /* close() implementation */ |
| | | .unlocked_ioctl = chrdev_ioctl, /* ioctl() implementation */ |
| | | .owner = THIS_MODULE, |
| | | .open = chrdev_open, /* open() implementation */ |
| | | .read = chrdev_read, /* read() implementation */ |
| | | .write = chrdev_write, /* write() implementation */ |
| | | .unlocked_ioctl = chrdev_ioctl, /* ioctl() implementation */ |
| | | .release = chrdev_close, /* close() implementation */ |
| | | }; |
| | | |
| | | static int __init chrdev_init(void) |
| | |
| | | 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); |
| | | |
File was renamed from bsp/drivers/x86_64/ldd3_ioctl.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> |
| | | |
| | | #if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) |
| | | #define access_ok_wrapper(type,arg,cmd) access_ok(type, arg, cmd) |
| | | #else |
| | | #define access_ok_wrapper(type,arg,cmd) access_ok(arg, cmd) |
| | | #endif |
| | | |
| | | /* ioctl definitions, use 'z' as magic number */ |
| | | #define CHRDEV_IOC_MAGIC 'z' |
| | | #define CHRDEV_IOCRESET _IO(CHRDEV_IOC_MAGIC, 0) |
| | | #define CHRDEV_IOCSET _IOW(CHRDEV_IOC_MAGIC, 1, int) |
| | | #define CHRDEV_IOCGET _IOR(CHRDEV_IOC_MAGIC, 2, int) |
| | | #define CHRDEV_IOC_MAXNR 3 |
| | | |
| | | /* 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 */ |
| | |
| | | return rv; |
| | | } |
| | | |
| | | /* The ioctl() implementation */ |
| | | long chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| | | #if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) |
| | | #define access_ok_wrapper(type,arg,cmd) access_ok(type, arg, cmd) |
| | | #else |
| | | #define access_ok_wrapper(type,arg,cmd) access_ok(arg, cmd) |
| | | #endif |
| | | |
| | | /* ioctl definitions, use 'c' as magic number */ |
| | | #define CHR_MAGIC 'c' |
| | | #define CHR_MAXNR 2 |
| | | #define CMD_READ _IOR(CHR_MAGIC, 0, int) |
| | | #define CMD_WRITE _IOW(CHR_MAGIC, 1, int) |
| | | |
| | | static long chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| | | { |
| | | struct chrdev_s *dev = file->private_data; |
| | | int rv, data; |
| | | size_t bytes = sizeof(data); |
| | | static int value = 0xdeadbeef; |
| | | int rv = 0; |
| | | |
| | | /* |
| | | * extract the type and number bitfields, and don't decode |
| | | * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok() |
| | | */ |
| | | if (_IOC_TYPE(cmd) != CHRDEV_IOC_MAGIC) return -ENOTTY; |
| | | if (_IOC_NR(cmd) > CHRDEV_IOC_MAXNR) return -ENOTTY; |
| | | if (_IOC_TYPE(cmd) != CHR_MAGIC) return -ENOTTY; |
| | | if (_IOC_NR(cmd) > CHR_MAXNR) return -ENOTTY; |
| | | |
| | | /* |
| | | * the direction is a bitmask, and VERIFY_WRITE catches R/W transfers. |
| | |
| | | rv = !access_ok_wrapper(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); |
| | | else if (_IOC_DIR(cmd) & _IOC_WRITE) |
| | | rv = !access_ok_wrapper(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); |
| | | if (rv) return -EFAULT; |
| | | |
| | | switch(cmd) { |
| | | case CHRDEV_IOCRESET: |
| | | dev->bytes = 0; |
| | | memset(dev->data, 0, dev->size); |
| | | rv = 0; |
| | | if (rv) |
| | | return -EFAULT; |
| | | |
| | | switch (cmd) { |
| | | case CMD_READ: |
| | | if (copy_to_user((int __user *)arg, &value, sizeof(value))) |
| | | return -EFAULT; |
| | | break; |
| | | |
| | | /* Last 4 bytes in the buffer used to save ioctl() data*/ |
| | | case CHRDEV_IOCSET: |
| | | rv = __get_user(data, (int __user *)arg); |
| | | if( !rv ) |
| | | memcpy(&dev->data[dev->size-bytes], &data, bytes); |
| | | break; |
| | | |
| | | case CHRDEV_IOCGET: |
| | | memcpy(&data, &dev->data[dev->size-bytes], bytes); |
| | | rv = __put_user(data, (int __user *)arg); |
| | | case CMD_WRITE: |
| | | if (copy_from_user(&value, (int __user *)arg, sizeof(value))) |
| | | return -EFAULT; |
| | | break; |
| | | |
| | | default: |
| | | return -ENOTTY; |
| | | return -EINVAL; |
| | | } |
| | | |
| | | return rv; |
| | | return 0; |
| | | } |
| | | |
| | | static int chrdev_open (struct inode *inode, struct file *file) |
| | |
| | | } |
| | | |
| | | static struct file_operations chrdev_fops = { |
| | | .owner = THIS_MODULE, |
| | | .open = chrdev_open, /* open() implementation */ |
| | | .read = chrdev_read, /* read() implementation */ |
| | | .write = chrdev_write, /* write() implementation */ |
| | | .release = chrdev_close, /* close() implementation */ |
| | | .unlocked_ioctl = chrdev_ioctl, /* ioctl() implementation */ |
| | | .owner = THIS_MODULE, |
| | | .open = chrdev_open, /* open() implementation */ |
| | | .read = chrdev_read, /* read() implementation */ |
| | | .write = chrdev_write, /* write() implementation */ |
| | | .unlocked_ioctl = chrdev_ioctl, /* ioctl() implementation */ |
| | | .release = chrdev_close, /* close() implementation */ |
| | | }; |
| | | |
| | | static int __init chrdev_init(void) |
| | |
| | | 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); |
| | |
| | | goto failed2; |
| | | } |
| | | |
| | | dev.device = device_create(dev.class, NULL, MKDEV(dev_major, 0), NULL, DEV_NAME); |
| | | dev.device = device_create(dev.class, NULL, MKDEV(dev_major, 0), NULL, "%s%d", DEV_NAME, 0); |
| | | 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); |
| | |
| | | |
| | | 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); |
New file |
| | |
| | | /* |
| | | * Copyright (C) 2024 LingYun IoT System Studio |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * |
| | | * Hello driver example in linux kernel. |
| | | */ |
| | | |
| | | |
| | | #include <linux/init.h> |
| | | #include <linux/module.h> |
| | | #include <linux/kernel.h> |
| | | |
| | | static __init int hello_init(void) |
| | | { |
| | | printk(KERN_ALERT "Hello, Linux kernel module.\n"); |
| | | return 0; |
| | | } |
| | | |
| | | static __exit void hello_exit(void) |
| | | { |
| | | printk(KERN_ALERT "Goodbye, Linux kernel module.\n"); |
| | | } |
| | | |
| | | module_init(hello_init); |
| | | module_exit(hello_exit); |
| | | |
| | | MODULE_LICENSE("Dual BSD/GPL"); |
| | | MODULE_AUTHOR("GuoWenxue <guowenxue@gmail.com>"); |