From f5c330abb65b94a5fbdcd1e09977b9269402801c Mon Sep 17 00:00:00 2001
From: guowenxue <guowenxue@gmail.com>
Date: Thu, 04 Apr 2024 02:47:30 +0800
Subject: [PATCH] Driver:IGKBoard-All: Add x86_64 linux driver
---
kernel/drivers/x86_64/Makefile | 25 +
kernel/drivers/x86_64/testapp/makefile | 32 ++
kernel/drivers/x86_64/ldd1_hello.c | 20 +
kernel/drivers/x86_64/testapp/app2_chrdev.c | 74 +++++
kernel/drivers/x86_64/testapp/app3_ioctl.c | 68 +++++
kernel/drivers/x86_64/ldd2_chrdev.c | 230 +++++++++++++++++
kernel/drivers/x86_64/ldd3_ioctl.c | 295 ++++++++++++++++++++++
7 files changed, 744 insertions(+), 0 deletions(-)
diff --git a/kernel/drivers/x86_64/Makefile b/kernel/drivers/x86_64/Makefile
new file mode 100644
index 0000000..a14dce4
--- /dev/null
+++ b/kernel/drivers/x86_64/Makefile
@@ -0,0 +1,25 @@
+# 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/kernel/drivers/x86_64/ldd1_hello.c b/kernel/drivers/x86_64/ldd1_hello.c
new file mode 100644
index 0000000..93a0e12
--- /dev/null
+++ b/kernel/drivers/x86_64/ldd1_hello.c
@@ -0,0 +1,20 @@
+#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/kernel/drivers/x86_64/ldd2_chrdev.c b/kernel/drivers/x86_64/ldd2_chrdev.c
new file mode 100644
index 0000000..11492f5
--- /dev/null
+++ b/kernel/drivers/x86_64/ldd2_chrdev.c
@@ -0,0 +1,230 @@
+
+#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/version.h> /* kernel version code */
+#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;
+module_param(dev_major, int, S_IRUGO);
+
+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 */
+} chrdev_t;
+
+static struct chrdev_s dev;
+
+static ssize_t chrdev_read (struct file *file, char __user *buf, size_t count, loff_t *f_pos)
+{
+ struct chrdev_s *dev = file->private_data;
+ ssize_t nbytes;
+ ssize_t rv = 0;
+
+ /* no data in buffer */
+ if( !dev->bytes )
+ return 0;
+
+ /* copy data to user space */
+ nbytes = count>dev->bytes ? dev->bytes : count;
+ if( copy_to_user(buf, dev->data, nbytes) )
+ {
+ rv = -EFAULT;
+ goto out;
+ }
+
+ /* update return value and data bytes in buffer */
+ rv = nbytes;
+ dev->bytes -= nbytes;
+
+out:
+ return rv;
+}
+
+static ssize_t chrdev_write (struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
+{
+ struct chrdev_s *dev = file->private_data;
+ ssize_t nbytes;
+ ssize_t rv = 0;
+
+ /* no space left */
+ if( dev->bytes >= dev->size )
+ return -ENOSPC;
+
+ /* check copy data bytes */
+ if( dev->size - dev->bytes < count)
+ nbytes = dev->size - dev->bytes;
+ else
+ nbytes = count;
+
+ /* copy data from user space */
+ if( copy_from_user(&dev->data[dev->bytes], buf, nbytes) )
+ {
+ rv = -EFAULT;
+ goto out;
+ }
+
+ /* update return value and data bytes in buffer */
+ rv = nbytes;
+ dev->bytes += nbytes;
+
+out:
+ return rv;
+}
+
+static int chrdev_open (struct inode *inode, struct file *file)
+{
+ struct chrdev_s *dev; /* device struct address */
+
+ /* get the device struct address by container_of() */
+ dev = container_of(inode->i_cdev, struct chrdev_s, cdev);
+
+ /* save the device struct address for other methods */
+ file->private_data = dev;
+
+ 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 */
+ .read = chrdev_read, /* read() implementation */
+ .write = chrdev_write, /* write() implementation */
+ .release = chrdev_close, /* close() implementation */
+};
+
+static int __init chrdev_init(void)
+{
+ dev_t devno;
+ int rv;
+
+ /* malloc and initial device read/write buffer */
+ dev.data = kmalloc(DEV_SIZE, GFP_KERNEL);
+ if( !dev.data )
+ {
+ printk(KERN_ERR " %s driver kmalloc() failed\n", DEV_NAME);
+ return -ENOMEM;
+ }
+ dev.size = DEV_SIZE;
+ dev.bytes = 0;
+ memset(dev.data, 0, dev.size);
+
+ /* dynamic alloc device node major number if not set */
+ 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;
+ }
+
+ /* setup and register cdev into kernel */
+ cdev_init(&dev.cdev, &chrdev_fops);
+ dev.cdev.owner = THIS_MODULE;
+ rv = cdev_add(&dev.cdev, devno, 1);
+ if( rv )
+ {
+ rv = -ENODEV;
+ printk(KERN_ERR "%s driver regist failed, rv=%d\n", DEV_NAME, 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);
+
+ kfree(dev.data);
+
+ 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/kernel/drivers/x86_64/ldd3_ioctl.c b/kernel/drivers/x86_64/ldd3_ioctl.c
new file mode 100644
index 0000000..295808d
--- /dev/null
+++ b/kernel/drivers/x86_64/ldd3_ioctl.c
@@ -0,0 +1,295 @@
+
+#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/version.h> /* kernel version code */
+#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;
+module_param(dev_major, int, S_IRUGO);
+
+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 */
+} chrdev_t;
+
+static struct chrdev_s dev;
+
+static ssize_t chrdev_read (struct file *file, char __user *buf, size_t count, loff_t *f_pos)
+{
+ struct chrdev_s *dev = file->private_data;
+ ssize_t nbytes;
+ ssize_t rv = 0;
+
+ /* no data in buffer */
+ if( !dev->bytes )
+ return 0;
+
+ /* copy data to user space */
+ nbytes = count>dev->bytes ? dev->bytes : count;
+ if( copy_to_user(buf, dev->data, nbytes) )
+ {
+ rv = -EFAULT;
+ goto out;
+ }
+
+ /* update return value and data bytes in buffer */
+ rv = nbytes;
+ dev->bytes -= nbytes;
+
+out:
+ return rv;
+}
+
+static ssize_t chrdev_write (struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
+{
+ struct chrdev_s *dev = file->private_data;
+ ssize_t nbytes;
+ ssize_t rv = 0;
+
+ /* no space left */
+ if( dev->bytes >= dev->size )
+ return -ENOSPC;
+
+ /* check copy data bytes */
+ if( dev->size - dev->bytes < count)
+ nbytes = dev->size - dev->bytes;
+ else
+ nbytes = count;
+
+ /* copy data from user space */
+ if( copy_from_user(&dev->data[dev->bytes], buf, nbytes) )
+ {
+ rv = -EFAULT;
+ goto out;
+ }
+
+ /* update return value and data bytes in buffer */
+ rv = nbytes;
+ dev->bytes += nbytes;
+
+out:
+ return rv;
+}
+
+/* The ioctl() implementation */
+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);
+
+ /*
+ * 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;
+
+ /*
+ * the direction is a bitmask, and VERIFY_WRITE catches R/W transfers.
+ * `Type' is user-oriented, while access_ok is kernel-oriented,
+ * so the concept of "read" and "write" is reversed
+ */
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ 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;
+ 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);
+ break;
+
+ default:
+ return -ENOTTY;
+ }
+
+ return rv;
+}
+
+static int chrdev_open (struct inode *inode, struct file *file)
+{
+ struct chrdev_s *dev; /* device struct address */
+
+ /* get the device struct address by container_of() */
+ dev = container_of(inode->i_cdev, struct chrdev_s, cdev);
+
+ /* save the device struct address for other methods */
+ file->private_data = dev;
+
+ 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 */
+ .read = chrdev_read, /* read() implementation */
+ .write = chrdev_write, /* write() implementation */
+ .release = chrdev_close, /* close() implementation */
+ .unlocked_ioctl = chrdev_ioctl, /* ioctl() implementation */
+};
+
+static int __init chrdev_init(void)
+{
+ dev_t devno;
+ int rv;
+
+ /* malloc and initial device read/write buffer */
+ dev.data = kmalloc(DEV_SIZE, GFP_KERNEL);
+ if( !dev.data )
+ {
+ printk(KERN_ERR " %s driver kmalloc() failed\n", DEV_NAME);
+ return -ENOMEM;
+ }
+ dev.size = DEV_SIZE;
+ dev.bytes = 0;
+ memset(dev.data, 0, dev.size);
+
+ /* dynamic alloc device node major number if not set */
+ 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;
+ }
+
+ /* setup and register cdev into kernel */
+ cdev_init(&dev.cdev, &chrdev_fops);
+ dev.cdev.owner = THIS_MODULE;
+ rv = cdev_add(&dev.cdev, devno, 1);
+ if( rv )
+ {
+ rv = -ENODEV;
+ printk(KERN_ERR "%s driver regist failed, rv=%d\n", DEV_NAME, 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);
+
+ kfree(dev.data);
+
+ 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/kernel/drivers/x86_64/testapp/app2_chrdev.c b/kernel/drivers/x86_64/testapp/app2_chrdev.c
new file mode 100644
index 0000000..8378243
--- /dev/null
+++ b/kernel/drivers/x86_64/testapp/app2_chrdev.c
@@ -0,0 +1,74 @@
+/*********************************************************************************
+ * 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/kernel/drivers/x86_64/testapp/app3_ioctl.c b/kernel/drivers/x86_64/testapp/app3_ioctl.c
new file mode 100644
index 0000000..da89b72
--- /dev/null
+++ b/kernel/drivers/x86_64/testapp/app3_ioctl.c
@@ -0,0 +1,68 @@
+/*********************************************************************************
+ * 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;
+}
+
diff --git a/kernel/drivers/x86_64/testapp/makefile b/kernel/drivers/x86_64/testapp/makefile
new file mode 100644
index 0000000..f5bb853
--- /dev/null
+++ b/kernel/drivers/x86_64/testapp/makefile
@@ -0,0 +1,32 @@
+#********************************************************************************
+# Copyright: (C) 2023 LingYun IoT System Studio
+# All rights reserved.
+#
+# Filename: Makefile
+# Description: This file used to compile all the C file to respective binary,
+# and it will auto detect cross compile or local compile.
+#
+# Version: 1.0.0(11/08/23)
+# Author: Guo Wenxue <guowenxue@gmail.com>
+# ChangeLog: 1, Release initial version on "11/08/23 16:18:43"
+#
+#*******************************************************************************
+
+
+BUILD_ARCH=$(shell uname -m)
+ifneq ($(findstring "x86_64" "i386", $(BUILD_ARCH)),)
+ CROSS_COMPILE?=arm-linux-gnueabihf-
+endif
+
+CC=${CROSS_COMPILE}gcc
+
+SRCFILES = $(wildcard *.c)
+BINARIES=$(SRCFILES:%.c=%)
+
+all: ${BINARIES}
+
+%: %.c
+ $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
+
+clean:
+ rm -f ${BINARIES}
--
Gitblit v1.9.1