diff --git a/Linux/KernelDriver/Char/Makefile b/Linux/KernelDriver/Char/Makefile new file mode 100644 index 0000000..f0acc3e --- /dev/null +++ b/Linux/KernelDriver/Char/Makefile @@ -0,0 +1,14 @@ +obj-m:= \ + demochar.o + +demochar-objs:= \ + demo_char.o + +EXTRA_CFLAGS += \ + -I$(PWD) + +all: + $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean \ No newline at end of file diff --git a/Linux/KernelDriver/Char/demo_char.c b/Linux/KernelDriver/Char/demo_char.c new file mode 100644 index 0000000..f456eda --- /dev/null +++ b/Linux/KernelDriver/Char/demo_char.c @@ -0,0 +1,134 @@ +/** + * @file demo_char.c + * @author Rick Chan (cy187lion@sina.com) + * @brief Linux char driver demo. + * @version 0.1.0 + * @date 2020-04-27 + * + * @copyright Copyright (c) 2020 + * + */ +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Rick Chan"); +MODULE_LICENSE("GPL"); + +#define DEMO_MAGIC 'R' +#define DEMO_IOC_SIZE 8 +#define DEMO_CTL_IOC _IOC(_IOC_READ|_IOC_WRITE, DEMO_MAGIC, 0, DEMO_IOC_SIZE) +#define DEMO_CTL_IO _IO(DEMO_MAGIC, 1) +#define DEMO_CTL_IOR _IOR(DEMO_MAGIC, 2, uint16_t) +#define DEMO_CTL_IOW _IOW(DEMO_MAGIC, 3, int32_t) +#define DEMO_CTL_IOWR _IOWR(DEMO_MAGIC, 4, uint32_t) +#define DEMO_CTL_MAX 5 + +static int demo_open(struct inode *inode, struct file* filp) +{ + return 0; +} + +static int demo_release(struct inode *inode, struct file* filp) +{ + return 0; +} + +static loff_t demo_llseek(struct file *filp, loff_t offset, int origin) +{ + return filp->f_pos; +} + +static ssize_t demo_read(struct file *filp, char __user *buffer, size_t count, loff_t *offset) +{ + const char __user *p = buffer; + return p-buffer; +} + +static ssize_t demo_write(struct file *filp, const char __user *buffer, size_t count, loff_t *offset) +{ + const char __user *p = buffer; + return p-buffer; +} + +static long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + // 检测 cmd 合法性 + if (DEMO_MAGIC!=_IOC_TYPE(cmd)) + return -EINVAL; + if (DEMO_CTL_MAX<_IOC_NR(cmd)) + return -EINVAL; + + switch(cmd) + { + case DEMO_CTL_IOC: + { + uint8_t tmp[DEMO_IOC_SIZE]; + copy_from_user(&tmp, (void*)arg, _IOC_SIZE(cmd)); + copy_to_user((void*)arg, &tmp, _IOC_SIZE(cmd)); + } + break; + case DEMO_CTL_IO: + break; + case DEMO_CTL_IOR: + { + uint16_t tmp = 0x55AA; + copy_to_user((void*)arg, &tmp, _IOC_SIZE(cmd)); + } + break; + case DEMO_CTL_IOW: + { + int32_t tmp = 0; + copy_from_user(&tmp, (void*)arg, _IOC_SIZE(cmd)); + } + break; + case DEMO_CTL_IOWR: + { + uint32_t tmp = 0; + copy_from_user(&tmp, (void*)arg, _IOC_SIZE(cmd)); + copy_to_user((void*)arg, &tmp, _IOC_SIZE(cmd)); + } + break; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static int demo_mmap(struct file* filp, struct vm_area_struct* vma) +{ + return 0; +} + +static struct file_operations demo_fops = { + .owner = THIS_MODULE, + .open = demo_open, + .release = demo_release, + .llseek = demo_llseek, + .read = demo_read, + .write = demo_write, + .unlocked_ioctl = demo_ioctl, + .mmap = demo_mmap +}; + +static struct miscdevice demo_dev = { + .minor = MISC_DYNAMIC_MINOR, // Dynamically allocate minor. + .name = "demo_char", + .fops = &demo_fops, +}; + +static int __init demo_init(void) +{ + misc_register(&demo_dev); + return 0; +} + +static void __exit demo_exit(void) +{ + misc_deregister(&demo_dev); +} + +module_init(demo_init); +module_exit(demo_exit);