guowenxue
2024-12-23 b8e5f60912c77d52214c21e67fa91ec5f522c54c
Update x86 example driver

Signed-off-by: guowenxue <guowenxue@gmail.com>
3 files renamed
7 files added
1 files copied
4 files deleted
905 ■■■■ changed files
bsp/drivers/.gitignore 40 ●●●●● patch | view | raw | blame | history
bsp/drivers/x86/apps/app_chrdev2.c 52 ●●●●● patch | view | raw | blame | history
bsp/drivers/x86/apps/app_chrdev3.c 60 ●●●●● patch | view | raw | blame | history
bsp/drivers/x86/apps/container_of.c 35 ●●●●● patch | view | raw | blame | history
bsp/drivers/x86/apps/makefile patch | view | raw | blame | history
bsp/drivers/x86/driver/Makefile 20 ●●●●● patch | view | raw | blame | history
bsp/drivers/x86/driver/chrdev1.c 131 ●●●●● patch | view | raw | blame | history
bsp/drivers/x86/driver/chrdev2.c 81 ●●●● patch | view | raw | blame | history
bsp/drivers/x86/driver/chrdev3.c 150 ●●●●● patch | view | raw | blame | history
bsp/drivers/x86/driver/chrdev4.c 121 ●●●●● patch | view | raw | blame | history
bsp/drivers/x86/driver/hello.c 28 ●●●●● patch | view | raw | blame | history
bsp/drivers/x86_64/Makefile 25 ●●●●● patch | view | raw | blame | history
bsp/drivers/x86_64/ldd1_hello.c 20 ●●●●● patch | view | raw | blame | history
bsp/drivers/x86_64/testapp/app2_chrdev.c 74 ●●●●● patch | view | raw | blame | history
bsp/drivers/x86_64/testapp/app3_ioctl.c 68 ●●●●● patch | view | raw | blame | history
bsp/drivers/.gitignore
New file
@@ -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
bsp/drivers/x86/apps/app_chrdev2.c
New file
@@ -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;
}
bsp/drivers/x86/apps/app_chrdev3.c
New file
@@ -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;
}
bsp/drivers/x86/apps/container_of.c
New file
@@ -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;
}
bsp/drivers/x86/apps/makefile
bsp/drivers/x86/driver/Makefile
New file
@@ -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
bsp/drivers/x86/driver/chrdev1.c
New file
@@ -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>");
bsp/drivers/x86/driver/chrdev2.c
File was renamed from bsp/drivers/x86_64/ldd2_chrdev.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);
bsp/drivers/x86/driver/chrdev3.c
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
@@ -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);
bsp/drivers/x86/driver/chrdev4.c
File was renamed from bsp/drivers/x86_64/ldd3_ioctl.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);
bsp/drivers/x86/driver/hello.c
New file
@@ -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>");
bsp/drivers/x86_64/Makefile
File was deleted
bsp/drivers/x86_64/ldd1_hello.c
File was deleted
bsp/drivers/x86_64/testapp/app2_chrdev.c
File was deleted
bsp/drivers/x86_64/testapp/app3_ioctl.c
File was deleted