1 //头文件
2 #include <linux/init.h>
3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include 12 #include 13 #include 14 15 16 #include 17 #include 18 #include 19 #include 20 #include 21 22 #define BUTTON_iOC_GET_DATA 0x4321 23 struct mem_data{ 24 char buf[128]; 25 }; 26 27 //定义一个按键的数据包 28 struct button_event{ 29 int code; //按键的名称---键值:KEY_DOWN 30 int value; //按键的状态---按下:1,松开:0 31 }; 32 33 //设计一个描述按键的结构体类型 34 struct buttons{ 35 char *name; //名称 36 unsigned int irqno; //中断号 37 int gpio; //按键对应的gpio口 38 int code; //键值 39 unsigned long flags; //触发方式 40 }; 41 42 //定义一个数组来保存多个按键的数据 43 struct buttons buttons_set[] = { 44 [0] = { 45 .name = 'key1_up', 46 .irqno = IRQ_EINT(0), 47 .gpio = S5PV210_GPH0(0), 48 .code = KEY_UP, 49 .flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, 50 }, 51 [1] = { 52 .name = 'key2_down', 53 .irqno = IRQ_EINT(1), 54 .gpio = S5PV210_GPH0(1), 55 .code = KEY_DOWN, 56 .flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, 57 }, 58 [2] = { 59 .name = 'key3_left', 60 .irqno = IRQ_EINT(2), 61 .gpio = S5PV210_GPH0(2), 62 .code = KEY_LEFT, 63 .flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, 64 }, 65 [3] = { 66 .name = 'key4_right', 67 .irqno = IRQ_EINT(3), 68 .gpio = S5PV210_GPH0(3), 69 .code = KEY_RIGHT, 70 .flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, 71 }, 72 }; 73 74 //面向对象编程----设计设备的类型 75 struct s5pv210_button{ 76 //unsigned int major; 77 dev_t devno; 78 struct class * cls; 79 struct device * dev; 80 struct cdev *cdev; 81 unsigned int irqno; 82 struct button_event event; 83 wait_queue_head_t wq_head; 84 85 int have_data; //表示当前是否有数据可读,可读--1,不可读--0 86 87 void * virt_mem; 88 struct tasklet_struct tasklet; 89 }; 90 struct s5pv210_button *button_dev; 91 92 //中断下半部的处理函数-----该函数会被内核线程执行 93 void button_irq_tasklet(unsigned long data) 94 { 95 printk('--------^_^ %s------------n',__FUNCTION__); 96 97 //此时有数据可读 98 button_dev->have_data = 1; 99 100 //从等待队列中唤醒阻塞的进程 101 wake_up_interruptible(&button_dev->wq_head); 102 103 } 104 105 106 //实现中断处理函数--------当触发中断时会被执行 107 irqreturn_t button_irq_svc(int irqno, void *dev) 108 { 109 int value; 110 struct buttons *p; 111 printk('--------^_^ %s------------n',__FUNCTION__); 112 113 //获取当前触发中断的按键信息 114 p = (struct buttons *)dev; 115 116 //获取产生中断的gpio口的值 117 value = gpio_get_value(p->gpio); 118 //判断是按下还是松开 119 if(value){ 120 //松开 121 printk('kernel:%s up!n',p->name); 122 button_dev->event.code = p->code; 123 button_dev->event.value = 0; 124 }else{ 125 //按下 126 printk('kenel:%s pressed!n',p->name); 127 button_dev->event.code = p->code; 128 button_dev->event.value = 1; 129 } 130 131 //将tasklet对象加入到内核线程中 132 tasklet_schedule(&button_dev->tasklet); 133 134 return IRQ_HANDLED; 135 } 136 137 //实现设备操作接口 138 int button_open(struct inode *inode, struct file *filp) 139 { 140 141 printk('--------^_^ %s------------n',__FUNCTION__); 142 143 return 0; 144 } 145 ssize_t button_read(struct file *filp , char __user *buf , size_t size, loff_t *flags) 146 { 147 int ret; 148 printk('--------^_^ %s------------n',__FUNCTION__); 149 //判读open时,有没有设置flags为NONBLOCK 150 if(filp->f_flags & O_NONBLOCK && !button_dev->have_data) 151 return -EAGAIN; 152 153 //判断此时是否有数据可读 154 wait_event_interruptible(button_dev->wq_head,button_dev->have_data); 155 156 //将内核数据转换为用户空间数据 157 ret = copy_to_user(buf,&button_dev->event,size); 158 if(ret > 0){ 159 printk('copy_to_user error!n'); 160 return -EFAULT; 161 } 162 163 //将数据返回给应用空间后,清空数据包,同时将hava_data置零 164 memset(&button_dev->event,0,sizeof(button_dev->event)); 165 button_dev->have_data = 0; 166 return size; 167 } 168 169 ssize_t button_write(struct file *filp, const char __user *buf, size_t size, loff_t *flags) 170 { 171 172 printk('--------^_^ %s------------n',__FUNCTION__); 173 174 return size; 175 } 176 177 long button_ioctl(struct file *filp, unsigned int cmd , unsigned long args) 178 { 179 void __user *argp; 180 struct mem_data data; 181 int ret; 182 printk('--------^_^ %s------------n',__FUNCTION__); 183 argp = (void __user *)args; 184 185 switch(cmd){ 186 case BUTTON_iOC_GET_DATA: 187 memset(data.buf,0,sizeof(data.buf)); 188 memcpy(data.buf, button_dev->virt_mem,sizeof(data.buf)); 189 ret = copy_to_user(argp,&data,sizeof(data)); 190 if(ret > 0){ 191 return -EFAULT; 192 } 193 break; 194 default: 195 printk('unkown cmd!n'); 196 } 197 198 return 0; 199 } 200 201 int button_mmap(struct file *filp, struct vm_area_struct *vma) 202 { 203 unsigned int addr; 204 printk('--------^_^ %s------------n',__FUNCTION__); 205 206 //1,获得一块物理内存空间-----将申请的虚拟空间转换为对应的物理空间 207 addr = virt_to_phys(button_dev->virt_mem); 208 209 //2,将物理内存映射到虚拟空间---应用空间 210 211 vma->vm_flags |= VM_IO; 212 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 213 214 if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, 215 PAGE_SIZE, vma->vm_page_prot)) { 216 printk(KERN_ERR '%s: io_remap_pfn_range failedn',__func__); 217 return -EAGAIN; 218 } 219 220 return 0; 221 } 222 223 unsigned int button_poll(struct file *filp, struct poll_table_struct *pts) 224 { 225 unsigned int mask = 0; 226 printk('--------^_^ %s------------n',__FUNCTION__); 227 228 //1,将等待队列头注册到系统中(VFS) 229 poll_wait(filp,&button_dev->wq_head,pts);
上一篇:代码示例_ioctl
下一篇:代码示例_LCD控制
推荐阅读最新更新时间:2026-03-19 11:02
- 基于 Blackfin 数字信号处理器 (DSP) 的 ADZS-BF518F-EZLITE、ADSP-BF518F EZ-Kit Lite 评估系统
- 使用 ON Semiconductor 的 CAT3200Z 的参考设计
- LTC2162 演示板,16 位 65Msps ADC,LVDS 输出,5-140MHz
- 使用 Analog Devices 的 LTC3526BEDC-2 的参考设计
- LT3091HT7 在极低输出电压下低压降操作的典型应用
- 蓝牙协议分析工具nRF52840 MDK USB Dongle
- NCV2902DR2G 维恩桥振荡器运算放大器的典型应用
- LTC4100EGN 演示板,智能电池充电器 DCIN = 15V-20V / 3.5V
- TC78H620FNG 双桥直流有刷电机驱动器评估板
- 带有 DRP w/Try.SRC 和 Type-C 插座的 PTN5110 USB PD 的典型应用



HexView支持固件合并二进制比较
51单片机常用的头文件
嵌入式系统技术与设计
非常经典的关于LLC的杨波博士论文
1-292148-8






京公网安备 11010802033920号