最简单的LED驱动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | #include "asm-generic/errno-base.h" #include "asm-generic/gpio.h" #include "asm/uaccess.h" #include <linux/module.h> #include <linux/poll.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/miscdevice.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/mutex.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/stat.h> #include <linux/init.h> #include <linux/device.h> #include <linux/tty.h> #include <linux/kmod.h> #include <linux/gfp.h> #include <linux/gpio/consumer.h> #include <linux/platform_device.h> #include <linux/of_gpio.h> #include <linux/of_irq.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/slab.h> #include <linux/fcntl.h> #include <linux/timer.h> //gpio结构体 struct gpio_desc{ int gpio; //GPIO编号 int irq; //中断号 char *name; //名字 } ; //PI0 = LED0 PF3 = LED1 static struct gpio_desc gpios[2] = { {128, 0, "led0" , }, {83, 0, "led1" , }, }; static int major = 0; //设备号 static struct class *gpio_class; //读函数 static ssize_t gpio_drv_read ( struct file *file, char __user *buf, size_t size, loff_t *offset) { char tmp_buf[2]; int err; int count = sizeof (gpios)/ sizeof (gpios[0]); //计算GPIO个数 if (size != 2) //应用层必须是读2个字节 return -EINVAL; //先读一下应用层buf来判断需要读取哪个IO引脚 err = copy_from_user(tmp_buf, buf, 1); if (tmp_buf[0] >= count) //判断读取的引脚号是否超出范围 return -EINVAL; //获取GPIO引脚电平 tmp_buf[1] = gpio_get_value(gpios[tmp_buf[0]].gpio); err = copy_to_user(buf, tmp_buf, 2); //返回给应用层 return 2; } //写函数 static ssize_t gpio_drv_write( struct file *file, const char __user *buf, size_t size, loff_t *offset) { unsigned char ker_buf[2]; int err; if (size != 2) //应用层必须是写两个字节 return -EINVAL; //读一下应用层buf来判断需要写哪个IO引脚 err = copy_from_user(ker_buf, buf, size); if (ker_buf[0] >= sizeof (gpios)/ sizeof (gpios[0])) //判断要写的引脚号是否超出范围 return -EINVAL; //根据写指定的GPIO引脚与电平 gpio_set_value(gpios[ker_buf[0]].gpio, ker_buf[1]); return 2; } //字符操作集 static struct file_operations gpio_key_dev_fops = { .owner = THIS_MODULE, .read = gpio_drv_read, .write = gpio_drv_write, }; static int __init gpio_drv_init( void ) { int err; int i; //计算有几个gpio int count = sizeof (gpios)/ sizeof (gpios[0]); printk( "%s %s line %d\n" , __FILE__, __FUNCTION__, __LINE__); for ( i = 0; i < count; i++){ err = gpio_request(gpios[i].gpio, gpios[i].name); //向内核申请gpio if (err < 0) { printk( "can not request gpio %s %d\n" , gpios[i].name, gpios[i].gpio); return -ENODEV; } //配置GPIO为输出,默认电平为高 gpio_direction_output(gpios[i].gpio, 1); } //注册字符设备 major = register_chrdev(0, "100ask_led" , &gpio_key_dev_fops); //创建类 gpio_class = class_create(THIS_MODULE, "100ask_led_class" ); if (IS_ERR(gpio_class)) { printk( "%s %s line %d\n" , __FILE__, __FUNCTION__, __LINE__); unregister_chrdev(major, "100ask_led_class" ); return PTR_ERR(gpio_class); } //创建设备 device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "100ask_led" ); return err; } //驱动出口函数 //注意:注销时一定要后注册(创建)的要先注销(摧毁) static void __exit gpio_drv_exit( void ) { int i; int count = sizeof (gpios)/ sizeof (gpios[0]); //摧毁设备 device_destroy(gpio_class, MKDEV(major, 0)); //摧毁类 class_destroy(gpio_class); //注销字符设备 unregister_chrdev(major, "100ask_led" ); for (i = 0; i < count; i++){ //释放GPIO gpio_free(gpios[i].gpio); } } module_init(gpio_drv_init); module_exit(gpio_drv_exit); MODULE_LICENSE( "GPL" ); |
应用层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <poll.h> #include <signal.h> static int fd; int main( int argc, char * argv[]) { int ret; char buf[2]; int i; if (argc < 2){ printf ( "Usage: %s <0|1|2|...> [on | off]\n" , argv[0]); return -1; } fd = open( "/dev/100ask_led" , O_RDWR); if (fd < 0){ printf ( "can not open file /dev/100ask_led\n" ); return -1; } if (argc == 3){ buf[0] = strtol (argv[1], NULL, 0); if ( strcmp (argv[2], "on" ) == 0) buf[1] = 0; else buf[1] = 1; ret = write(fd, buf, 2); if (ret < 0){ printf ( "write error\r\n" ); } } else { buf[0] = strtol (argv[1], NULL, 0); ret = read(fd, buf, 2); if (ret == 2) { printf ( "led %d status is %s\n" , buf[0], buf[1] == 0 ? "on" : "off" ); } } close(fd); return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异