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