From b8e5f60912c77d52214c21e67fa91ec5f522c54c Mon Sep 17 00:00:00 2001 From: guowenxue <guowenxue@gmail.com> Date: Mon, 23 Dec 2024 16:33:12 +0800 Subject: [PATCH] Update x86 example driver --- /dev/null | 68 ---- bsp/drivers/.gitignore | 40 ++ bsp/drivers/x86/driver/chrdev3.c | 150 +++------- bsp/drivers/x86/driver/chrdev4.c | 121 +++---- bsp/drivers/x86/driver/chrdev1.c | 131 +++++++++ bsp/drivers/x86/driver/chrdev2.c | 81 +---- bsp/drivers/x86/apps/app_chrdev3.c | 60 ++++ bsp/drivers/x86/apps/app_chrdev2.c | 52 +++ bsp/drivers/x86/driver/Makefile | 20 + bsp/drivers/x86/apps/container_of.c | 35 ++ bsp/drivers/x86/apps/makefile | 0 bsp/drivers/x86/driver/hello.c | 28 ++ 12 files changed, 490 insertions(+), 296 deletions(-) diff --git a/bsp/drivers/.gitignore b/bsp/drivers/.gitignore new file mode 100644 index 0000000..b515394 --- /dev/null +++ b/bsp/drivers/.gitignore @@ -0,0 +1,40 @@ +# 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 diff --git a/bsp/drivers/x86/apps/app_chrdev2.c b/bsp/drivers/x86/apps/app_chrdev2.c new file mode 100644 index 0000000..af2574f --- /dev/null +++ b/bsp/drivers/x86/apps/app_chrdev2.c @@ -0,0 +1,52 @@ +/* + * 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; +} diff --git a/bsp/drivers/x86/apps/app_chrdev3.c b/bsp/drivers/x86/apps/app_chrdev3.c new file mode 100644 index 0000000..5664f23 --- /dev/null +++ b/bsp/drivers/x86/apps/app_chrdev3.c @@ -0,0 +1,60 @@ +/* + * 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; +} diff --git a/bsp/drivers/x86/apps/container_of.c b/bsp/drivers/x86/apps/container_of.c new file mode 100644 index 0000000..b58fa4f --- /dev/null +++ b/bsp/drivers/x86/apps/container_of.c @@ -0,0 +1,35 @@ +#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; +} + diff --git a/bsp/drivers/x86_64/testapp/makefile b/bsp/drivers/x86/apps/makefile similarity index 100% rename from bsp/drivers/x86_64/testapp/makefile rename to bsp/drivers/x86/apps/makefile diff --git a/bsp/drivers/x86/driver/Makefile b/bsp/drivers/x86/driver/Makefile new file mode 100644 index 0000000..0238f43 --- /dev/null +++ b/bsp/drivers/x86/driver/Makefile @@ -0,0 +1,20 @@ + 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 diff --git a/bsp/drivers/x86/driver/chrdev1.c b/bsp/drivers/x86/driver/chrdev1.c new file mode 100644 index 0000000..413589d --- /dev/null +++ b/bsp/drivers/x86/driver/chrdev1.c @@ -0,0 +1,131 @@ +/* + * 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>"); diff --git a/bsp/drivers/x86_64/ldd2_chrdev.c b/bsp/drivers/x86/driver/chrdev2.c similarity index 71% rename from bsp/drivers/x86_64/ldd2_chrdev.c rename to bsp/drivers/x86/driver/chrdev2.c index 11492f5..12dd37f 100644 --- a/bsp/drivers/x86_64/ldd2_chrdev.c +++ b/bsp/drivers/x86/driver/chrdev2.c @@ -1,37 +1,31 @@ +/* + * 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 */ @@ -115,11 +109,11 @@ } 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) @@ -128,17 +122,17 @@ 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); @@ -156,9 +150,11 @@ 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 ) { @@ -167,41 +163,11 @@ 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; @@ -209,11 +175,6 @@ 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); diff --git a/bsp/drivers/x86_64/ldd3_ioctl.c b/bsp/drivers/x86/driver/chrdev3.c similarity index 62% copy from bsp/drivers/x86_64/ldd3_ioctl.c copy to bsp/drivers/x86/driver/chrdev3.c index 295808d..1b4777b 100644 --- a/bsp/drivers/x86_64/ldd3_ioctl.c +++ b/bsp/drivers/x86/driver/chrdev3.c @@ -1,50 +1,31 @@ +/* + * 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 */ @@ -109,19 +90,29 @@ 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. @@ -132,32 +123,26 @@ 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) @@ -179,12 +164,12 @@ } 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) @@ -193,17 +178,17 @@ 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); @@ -221,9 +206,11 @@ 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 ) { @@ -232,41 +219,11 @@ 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; @@ -274,11 +231,6 @@ 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); diff --git a/bsp/drivers/x86_64/ldd3_ioctl.c b/bsp/drivers/x86/driver/chrdev4.c similarity index 71% rename from bsp/drivers/x86_64/ldd3_ioctl.c rename to bsp/drivers/x86/driver/chrdev4.c index 295808d..0744798 100644 --- a/bsp/drivers/x86_64/ldd3_ioctl.c +++ b/bsp/drivers/x86/driver/chrdev4.c @@ -1,50 +1,33 @@ +/* + * 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 */ @@ -109,19 +92,29 @@ 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. @@ -132,32 +125,26 @@ 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) @@ -179,12 +166,12 @@ } 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) @@ -193,17 +180,17 @@ 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); @@ -221,9 +208,11 @@ 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 ) { @@ -232,7 +221,6 @@ 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); @@ -244,25 +232,22 @@ 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); @@ -274,10 +259,8 @@ 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); diff --git a/bsp/drivers/x86/driver/hello.c b/bsp/drivers/x86/driver/hello.c new file mode 100644 index 0000000..b29dd08 --- /dev/null +++ b/bsp/drivers/x86/driver/hello.c @@ -0,0 +1,28 @@ +/* + * 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>"); diff --git a/bsp/drivers/x86_64/Makefile b/bsp/drivers/x86_64/Makefile deleted file mode 100644 index a14dce4..0000000 --- a/bsp/drivers/x86_64/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# Linux driver build kernel source code path on X86 server -KERNAL_DIR ?= /lib/modules/$(shell uname -r)/build - -ARCH=${shell uname -p} - -# Fix bug: module verification failed: signature and/or required key missing - tainting kernel -CONFIG_MODULE_SIG=n - -# Linux kernel modules -obj-m += ldd1_hello.o -obj-m += ldd2_chrdev.o -obj-m += ldd3_ioctl.o - -modules: - $(MAKE) -C $(KERNAL_DIR) M=$(shell pwd) modules - @make clear - -clear: - @rm -f *.o .*.cmd *.cmd *.mod *.mod.c - @rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f - @rm -f .*ko.cmd .*.o.cmd .*.o.d - @rm -f *.unsigned - -clean: - @rm -f *.ko diff --git a/bsp/drivers/x86_64/ldd1_hello.c b/bsp/drivers/x86_64/ldd1_hello.c deleted file mode 100644 index 93a0e12..0000000 --- a/bsp/drivers/x86_64/ldd1_hello.c +++ /dev/null @@ -1,20 +0,0 @@ -#include <linux/init.h> -#include <linux/module.h> -#include <linux/kernel.h> - -static __init int hello_init(void) -{ - printk(KERN_ALERT "hello module installed.\n"); - return 0; -} - -static __exit void hello_exit(void) -{ - printk(KERN_ALERT "hello module removed.\n"); -} - -module_init(hello_init); -module_exit(hello_exit); - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_AUTHOR("GuoWenxue <guowenxue@gmail.com>"); diff --git a/bsp/drivers/x86_64/testapp/app2_chrdev.c b/bsp/drivers/x86_64/testapp/app2_chrdev.c deleted file mode 100644 index 8378243..0000000 --- a/bsp/drivers/x86_64/testapp/app2_chrdev.c +++ /dev/null @@ -1,74 +0,0 @@ -/********************************************************************************* - * Copyright: (C) 2023 Avnet - * All rights reserved. - * - * Filename: file.c - * Description: This file - * - * Version: 1.0.0(2023年11月02日) - * Author: Guo Wenxue <guowenxue@avnet.com> - * ChangeLog: 1, Release initial version on "2023年11月02日 14时47分52秒" - * - ********************************************************************************/ - -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> - -/* 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) - -int main (int argc, char **argv) -{ - char *devname = "/dev/chrdev"; - char buf[1024]; - int rv, fd; - int value = 0x12345678; - - fd = open(devname, O_RDWR|O_TRUNC); - 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)); - return 2; - } - printf("Write %d bytes data okay\n", rv); - -#if 0 - lseek(fd, 3, SEEK_SET); -#endif - - 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)); - return 3; - } - printf("Read %d bytes data: %s\n", rv, buf); - -#if 0 - ioctl(fd, CHRDEV_IOCSET, &value); - value = 0; - ioctl(fd, CHRDEV_IOCGET, &value); - printf("ioctl() read value=0x%0x\n", value); -#endif - - close(fd); - return 0; -} - diff --git a/bsp/drivers/x86_64/testapp/app3_ioctl.c b/bsp/drivers/x86_64/testapp/app3_ioctl.c deleted file mode 100644 index da89b72..0000000 --- a/bsp/drivers/x86_64/testapp/app3_ioctl.c +++ /dev/null @@ -1,68 +0,0 @@ -/********************************************************************************* - * Copyright: (C) 2023 Avnet - * All rights reserved. - * - * Filename: file.c - * Description: This file - * - * Version: 1.0.0(2023年11月02日) - * Author: Guo Wenxue <guowenxue@avnet.com> - * ChangeLog: 1, Release initial version on "2023年11月02日 14时47分52秒" - * - ********************************************************************************/ - -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> - -/* 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) - -int main (int argc, char **argv) -{ - char *devname = "/dev/chrdev"; - char buf[1024]; - int rv, fd; - int value = 0x12345678; - - fd = open(devname, O_RDWR|O_TRUNC); - 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)); - return 2; - } - 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)); - return 3; - } - printf("Read %d bytes data: %s\n", rv, buf); - - ioctl(fd, CHRDEV_IOCSET, &value); - value = 0; - ioctl(fd, CHRDEV_IOCGET, &value); - printf("ioctl() read value=0x%0x\n", value); - - close(fd); - return 0; -} - -- Gitblit v1.9.1