驱动程序
| #include <linux/types.h> |
| #include <linux/kernel.h> |
| #include <linux/delay.h> |
| #include <linux/ide.h> |
| #include <linux/init.h> |
| #include <linux/module.h> |
| #include <linux/errno.h> |
| #include <linux/gpio.h> |
| #include <linux/cdev.h> |
| #include <linux/device.h> |
| |
| #include <asm/mach/map.h> |
| #include <asm/uaccess.h> |
| #include <asm/io.h> |
| |
| #define NEWCHRLED_NAME "newchrled" |
| #define NEWCHRLED_COUNT 1 |
| |
| #if 1 |
| #define CCM_CCGR1_BASE (0X020C406C) |
| #define SW_MUX_GPIO1_IO03_BASE (0X020E0068) |
| #define SW_PAD_GPIO1_IO03_BASE (0X020E02F4) |
| #define GPIO1_DR_BASE (0X0209C000) |
| #define GPIO1_GDIR_BASE (0X0209C004) |
| |
| |
| static void __iomem *IMX6U_CCM_CCGR1; |
| static void __iomem *SW_MUX_GPIO1_IO03; |
| static void __iomem *SW_PAD_GPIO1_IO03; |
| static void __iomem *GPIO1_DR; |
| static void __iomem *GPIO1_GDIR; |
| |
| #define LEDOFF 0 |
| #define LEDON 1 |
| #endif |
| |
| |
| void led_switch(u8 sta) |
| { |
| u32 val = 0; |
| if(sta == LEDON) { |
| val = readl(GPIO1_DR); |
| val &= ~(1 << 3); |
| writel(val, GPIO1_DR); |
| }else if(sta == LEDOFF) { |
| val = readl(GPIO1_DR); |
| val|= (1 << 3); |
| writel(val, GPIO1_DR); |
| } |
| } |
| |
| |
| |
| |
| struct newchrled_dev |
| { |
| struct cdev cdev; |
| struct class * class; |
| struct device * device; |
| dev_t devid; |
| int major; |
| int minor; |
| }; |
| |
| |
| static int newchrled_open(struct inode *inode, struct file *filp) |
| { |
| return 0; |
| } |
| |
| static ssize_t newchrled_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) |
| { |
| int retvalue; |
| unsigned char databuf[1]; |
| |
| retvalue = copy_from_user(databuf, buf, cnt); |
| if(retvalue < 0) { |
| printk("kernel write failed!\r\n"); |
| return -EFAULT; |
| } |
| led_switch(databuf[0]); |
| return 0; |
| } |
| |
| static int newchrled_release(struct inode *inode, struct file *filp) |
| { |
| return 0; |
| } |
| |
| struct newchrled_dev newchrled; |
| |
| static const struct file_operations newchrledfops={ |
| .owner = THIS_MODULE, |
| .write = newchrled_write, |
| .open = newchrled_open, |
| .release = newchrled_release, |
| }; |
| |
| |
| |
| static int __init newchr_init(void) |
| { |
| int ret = 0; |
| u32 val = 0; |
| |
| |
| |
| |
| IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4); |
| SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4); |
| SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, 4); |
| GPIO1_DR = ioremap(GPIO1_DR_BASE, 4); |
| GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE, 4); |
| |
| |
| val = readl(IMX6U_CCM_CCGR1); |
| val &= ~(3 << 26); |
| val |= (3 << 26); |
| writel(val, IMX6U_CCM_CCGR1); |
| |
| |
| |
| |
| writel(5, SW_MUX_GPIO1_IO03); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| writel(0x10B0, SW_PAD_GPIO1_IO03); |
| |
| |
| val = readl(GPIO1_GDIR); |
| val &= ~(1 << 3); |
| val |= (1 << 3); |
| writel(val, GPIO1_GDIR); |
| |
| |
| val = readl(GPIO1_DR); |
| val |= (1 << 3); |
| writel(val, GPIO1_DR); |
| |
| |
| |
| if (newchrled.major){ |
| newchrled.devid = MKDEV(newchrled.major, 0); |
| ret = register_chrdev_region(newchrled.devid, NEWCHRLED_COUNT, NEWCHRLED_NAME); |
| if (ret < 0) |
| { |
| printk("register_chrdev_region err\r\n"); |
| } |
| |
| }else |
| { |
| |
| ret = alloc_chrdev_region(&newchrled.devid, 0, NEWCHRLED_COUNT, NEWCHRLED_NAME); |
| newchrled.major = MAJOR(newchrled.devid); |
| newchrled.minor = MINOR(newchrled.devid); |
| if (ret < 0) |
| { |
| printk("newchrled chrdev_region err\r\n"); |
| return -1; |
| } |
| printk("newchrled major=%d, minor=%d\r\n",newchrled.major,newchrled.minor); |
| } |
| |
| |
| newchrled.cdev.owner = THIS_MODULE; |
| cdev_init(&newchrled.cdev, &newchrledfops); |
| |
| ret = cdev_add(&newchrled.cdev, newchrled.devid, NEWCHRLED_COUNT); |
| |
| |
| |
| newchrled.class = class_create(THIS_MODULE, NEWCHRLED_NAME); |
| if (IS_ERR(newchrled.class)){ |
| return PTR_ERR(newchrled.class); |
| } |
| |
| newchrled.device = device_create(newchrled.class, NULL, |
| newchrled.devid, NULL, NEWCHRLED_NAME); |
| if (IS_ERR(newchrled.device)){ |
| return PTR_ERR(newchrled.device); |
| } |
| |
| printk("newchr_init!\r\n"); |
| return 0; |
| } |
| |
| |
| |
| static void __exit newchr_exit(void) |
| { |
| |
| |
| led_switch(LEDOFF); |
| |
| |
| iounmap(IMX6U_CCM_CCGR1); |
| iounmap(SW_MUX_GPIO1_IO03); |
| iounmap(SW_PAD_GPIO1_IO03); |
| iounmap(GPIO1_DR); |
| iounmap(GPIO1_GDIR); |
| |
| |
| cdev_del(&newchrled.cdev); |
| |
| |
| unregister_chrdev_region(newchrled.devid, NEWCHRLED_COUNT); |
| |
| |
| device_destroy(newchrled.class, newchrled.devid); |
| |
| |
| class_destroy(newchrled.class); |
| |
| printk("newchr_exit!\r\n"); |
| } |
| |
| |
| |
| |
| module_init(newchr_init); |
| module_exit(newchr_exit); |
| |
| MODULE_LICENSE("GPL"); |
| MODULE_AUTHOR("qsy"); |
应用程序
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| |
| |
| |
| |
| |
| |
| int main(int args, char *argv[]) |
| { |
| int fd; |
| char *fielname; |
| unsigned char databuf[1]; |
| int retvalue = 0; |
| |
| if (args != 3) |
| { |
| printf("usage error\r\n"); |
| return -1; |
| } |
| |
| |
| fielname = argv[1]; |
| |
| |
| fd = open(fielname, O_RDWR); |
| if (fd < 0) |
| { |
| printf("file %s cant't open!\r\n"); |
| } |
| |
| databuf[0] = atoi(argv[2]); |
| |
| retvalue = write(fd, databuf, sizeof(databuf)); |
| if (retvalue < 0) |
| { |
| printf("write failed\r\n"); |
| close(fd); |
| return -1; |
| } |
| |
| close(fd); |
| return 0; |
| } |
makefile
| |
| KERNELDIR := /home/qsy/linux/linux_kernel/linux_kernel_nxp/kernel |
| CURRENT_PATH := $(shell pwd) |
| obj-m := newchrled.o |
| |
| build: kernel_modules |
| |
| kernel_modules: |
| $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules |
| clean: |
| $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现