唤醒的条件是buff不空.当程序被唤醒时,则调用copy_to_user函数将数据拷贝到用户进程中进行打印出来.
8.修改测试驱动程序err_led.c.
首先外部引入myprintk函数,然后将测试驱动程序的printk全部修改为myprintk函数.
1 extern int myprintk(const char *fmt, ...); //引入外部声明
2
3 static int key_open(struct inode *inode, struct file *file)
4 {
5 myprintk('<0>function open!nn'); //将printk修改未myprintk
6 return 0;
7 }
9.编译测试:
注意加载驱动的顺序.
①加载mymsg.ko驱动程序
②加载test/err_led.ko驱动程序:发现板子上的err_led灯闪烁,等led闪烁完毕
③读取 cat /proc/mymsg: 发现成功的打印出我们err_led要打印的消息,如下图
④卸载test/err_led.ko:发现板子上的err_led等闪烁,等闪烁完毕
⑤读取 cat /proc/mymsg: 再消息最末尾多了一条goodbye的消息,成功
⑥卸载mymsg.ko驱动程序
附上驱动程序mymsg_4.c
1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 11 12 #define MYLOG_BUF_LEN 1024 13 14 //定义proc的entry结构体 15 static struct proc_dir_entry *myentry; 16 static char mylog_buf[MYLOG_BUF_LEN]; //数据缓冲区 17 static char tmp_buf[MYLOG_BUF_LEN]; //数据缓冲区 18 static int mylog_r = 0; 19 static int mylog_w = 0; 20 21 static DECLARE_WAIT_QUEUE_HEAD(mylog_wait); 22 23 //判断是否为空 24 static int is_mylog_empty(void) 25 { 26 return (mylog_r == mylog_w); 27 } 28 //判断是否已满 29 static int is_mylog_full(void) 30 { 31 return (((mylog_w + 1) % MYLOG_BUF_LEN) == mylog_r); 32 } 33 //写入字符 34 static void mylog_putc(char c) 35 { 36 if(is_mylog_full) 37 { 38 //丢弃一个数据 39 mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN; 40 } 41 mylog_buf[mylog_w] = c; 42 mylog_w = (mylog_w + 1) % MYLOG_BUF_LEN; 43 44 /* 唤醒等待数据的进程 */ 45 wake_up_interruptible(&mylog_wait); 46 } 47 //读取字符 48 static int mylog_getc(char *p) 49 { 50 if(is_mylog_empty()) 51 return 0; 52 *p = mylog_buf[mylog_r]; 53 mylog_r = (mylog_r + 1) % MYLOG_BUF_LEN; 54 return 1; 55 } 56 57 //打印输出 参考vsprintf.c 的 sprintf 58 int myprintk(const char *fmt, ...) 59 { 60 va_list args; 61 int i,j; 62 63 va_start(args, fmt); 64 i = vsnprintf(tmp_buf, INT_MAX, fmt, args); 65 va_end(args); 66 for(j = 0; j 67 { 68 mylog_putc(tmp_buf[j]); 69 } 70 return 1; 71 } 72 EXPORT_SYMBOL(myprintk); 73 74 //实现读函数 参考kmsg.c 75 static ssize_t mymsg_read(struct file *file, char __user *buf,size_t count, loff_t *ppos) 76 { 77 int error; 78 int i = 0; //所读的数据的个数 79 char c; 80 81 //以非阻塞打开,并且数据队列为空 82 if ((file->f_flags & O_NONBLOCK) && is_mylog_empty()) 83 return -EAGAIN; 84 85 //等待直到队列非空 86 error = wait_event_interruptible(mylog_wait,!is_mylog_empty()); 87 88 /* copy_to_user 若是没错,获取字符串成功 */ 89 while( !error && (mylog_getc(&c)) && i < count ){ 90 error = __put_user(c, buf); //等同copy_to_user 91 buf++; 92 i++; 93 } 94 if(!error) 95 error = i; 96 return error; 97 } 98 99 //定义file_operation结构体 100 static struct file_operations proc_mymsg_operations = { 101 .read = mymsg_read, 102 }; 103 //入口函数 104 static int mymsg_init(void) 105 { 106 //sprintf(mylog_buf, '%s', 'abcdefghijklmnn'); //模拟伪造buf的数据 107 //创建proc的条目 108 myentry = create_proc_entry('mymsg',S_IRUSR,NULL); //S_IRUSR:400 只读 109 110 if(myentry) 111 myentry->proc_fops = &proc_mymsg_operations; 112 113 114 return 0; 115 } 116 //出口函数 117 static void mymsg_exit(void) 118 { 119 remove_proc_entry('mymsg', NULL); 120 } 121 122 module_init(mymsg_init); 123 module_exit(mymsg_exit); 124 125 MODULE_LICENSE('GPL'); 126 MODULE_AUTHOR('Lover雪儿'); 127 128 129 /* 130 1.环形缓冲区 131 空: R == W 132 写: buf[W] = val; 133 W = (W+1) % 10; 134 读: val = buf[R] 135 R = (R+1) % 10 136 137 138 139 */ 附上测试驱动程序err_led.c: 1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include 12 #include 13 #include 14 15 #define Driver_NAME 'err_led_dev' 16 #define DEVICE_NAME 'err_led_dev' 17 18 static int major = 0; 19 20 //auto to create device node 21 static struct class *drv_class = NULL; 22 static struct class_device *drv_class_dev = NULL; 23 24 //寄存器基址; 25 static unsigned long base_iomux; //iomux基址 0X 43FA C000 - 0X 43FA FFFF 26 static unsigned long base_gpio3; //gpio3 0X 53FA 4000 - 0X 53FA 7FFF 27 // MUX_CTL模式选择 配置寄存器 28 #define MUX_CTL (*(volatile unsigned long *)(base_iomux + 0x0060)) 29 // PAD_CTL GPIO常用功能设置 30 #define PAD_CTL (*(volatile unsigned long *)(base_iomux + 0x0270)) 31 // GPIO DR 数据寄存器 DR 32 #define DR_GPIO3 (*(volatile unsigned long *)(base_gpio3 + 0x0000)) 33 // GPIO GDIR 方向控制寄存器 GDIR 34 #define GDIR_GPIO3 (*(volatile unsigned long *)(base_gpio3 + 0x0004)) 35 36 37 extern int myprintk(const char *fmt, ...); 38 39 static int key_open(struct inode *inode, struct file *file) 40 { 41 myprintk('<0>function open!nn'); 42 return 0; 43 } 44 45 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) 46 { 47 return 0; 48 } 49 50 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) 51 { 52 myprintk('<0>function write!nn'); 53 return 1; 54 } 55 56 static int key_release(struct inode *inode, struct file *filp) 57 { 58 myprintk('<0>function write!nn'); 59 return 0; 60 } 61 62 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg) 63 { 64 myprintk('<0>function ioctl!nn'); 65 return 0; 66 } 67 static struct file_operations key_fops = { 68 .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ 69 .open = key_open, 70 .read = key_read, 71 .write = key_write, 72 .release= key_release, 73 .ioctl = key_ioctl, 74 }; 75 76 void gpio_addr(void){ 77 myprintk('<0>addr base_iomux : %x n',base_iomux); 78 myprintk('<0>addr base_gpio3 : %x n',base_gpio3); 79 myprintk('<0>addr MUX_CTL : %x n',&MUX_CTL); 80 myprintk('<0>addr PAD_CTL : %x n',&PAD_CTL); 81 myprintk('<0>addr GDIR_GPIO3 : %x n',&GDIR_GPIO3); 82 myprintk('<0>addr DR_GPIO3 : %x n',&DR_GPIO3); 83 } 84 85 void led_on_off(void){ 86 ssleep(1); 87 DR_GPIO3 |= (0x01 << 23); //将GPIO2_23置1 88 ssleep(1); 89 DR_GPIO3 &= ~(0x01 << 23); //将GPIO2_23清零 90 ssleep(1); 91 DR_GPIO3 |= (0x01 << 23); //将GPIO2_23置1 92 ssleep(1); 93 DR_GPIO3 &= ~(0x01 << 23); //将GPIO2_23清零
上一篇:调试分析之 根据内核报错信息PC指针分析错误
下一篇:iMX257引脚配置函数/内存读写函数
推荐阅读最新更新时间:2024-11-13 16:47
设计资源 培训 开发板 精华推荐
- 具有无源平衡功能的 6 节 EV/HEV 集成电池监视器和保护器参考设计
- 具有短路保护功能的 MC78M15ABDTRKG 15V 电流提升的典型应用
- LTC2938HDE ±5V 电源监视器的典型应用电路,看门狗已禁用且未使用的输入为高电平
- ADM00434,用于 MCP19035 300 kHz 同步降压控制器的评估板
- 使用 NXP Semiconductors 的 TDA8927J 的参考设计
- 使用 RP40-11015DFR DC/DC 转换器并根据 EN55022 A 类(单输出)进行 EMC 滤波的典型应用
- LTC1741CFW 演示板,12 位/65 Msps 低噪声 ADC,Ain < 40MHz
- LTC3388-1 演示板、20V 高效率纳米级功率降压型稳压器
- LSM303D适配器板,标准DIL 24插座
- 智能浇花
- 有奖直播:新科技、新课堂、新学期~ ADI软件定义无线电ADALM-Pluto入门实战
- 【边分享,边成长,11月有奖】EEWORLD优秀主题/回复第16期活动开始拉
- 有奖活动 | 来PI PowiGaN技术学习中心,解密高可靠性和耐用性氮化镓(GaN)技术
- 有奖评测:50套来自恩智浦全新快速物联网原型设计套件(价值350元)
- 中秋芯币兑大礼
- 【EEWORLD第三十一届】2011年10月社区明星人物揭晓!
- 泰克有奖看视频 深入浅出剖析高速信号的抖动和眼图
- Vicor| 适用于电池生命周期各个阶段的高密度电源转换器
- 直播已结束【艾迈斯欧司朗高效能源存储解决方案,工业级数据采集前端集成电路产品分享】