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 --- bsp/drivers/x86/driver/chrdev3.c | 150 +++++++++++++++++--------------------------------- 1 files changed, 51 insertions(+), 99 deletions(-) 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); -- Gitblit v1.9.1