linux内核debug的一种方式:procfs
1 #include <linux/module.h> 2 3 #include <linux/compat.h> 4 #include <linux/types.h> 5 #include <linux/errno.h> 6 #include <linux/kernel.h> 7 #include <linux/major.h> 8 #include <linux/slab.h> 9 #include <linux/mm.h> 10 #include <linux/mman.h> 11 #include <linux/vt.h> 12 #include <linux/init.h> 13 #include <linux/linux_logo.h> 14 #include <linux/proc_fs.h> 15 #include <linux/seq_file.h> 16 #include <linux/console.h> 17 #include <linux/kmod.h> 18 #include <linux/err.h> 19 #include <linux/device.h> 20 #include <linux/efi.h> 21 #include <linux/fb.h> 22 #include <linux/delay.h> 23 #include <linux/version.h> 24 #include <linux/kthread.h> 25 #include <linux/poll.h> 26 27 /*Proc based contron intertace*/ 28 #define AUDIO_DEBUG_PROC_DIR "audio" 29 #define AUDIO_DEBUG_PROC_INFO "debuginfo" 30 #define MAX_BUF_WT_LEN 200 //do not bigger than one page size 1024 bytes 31 #define MAX_BUF_RD_LEN 2048 32 33 static struct proc_dir_entry *audio_proc_dir = NULL; 34 static struct proc_dir_entry *audio_proc_dbginfo_file = NULL; 35 36 static struct deca_device *audio_deca_dev=NULL; 37 static struct snd_device *audio_snd_dev=NULL; 38 39 static char *audio_info_buffer = NULL; 40 static __u32 g_dbg_show_en = 0; 41 static __u32 g_dbg_show_interval = 1; 42 static struct mutex audio_dbg_mutex; 43 wait_queue_head_t audio_dbg_wq; 44 static struct task_struct *audio_dbg_show_thread_ptr; 45 46 static char *audio_state(unsigned long state) 47 { 48 char *ret = NULL; 49 switch(state) 50 { 51 case 0: 52 ret="DETACH"; 53 break; 54 case 1: 55 ret="ATTACH"; 56 break; 57 case 2: 58 ret="IDLE"; 59 break; 60 case 4: 61 ret="PLAY"; 62 break; 63 case 8: 64 ret="PAUSE"; 65 break; 66 default: 67 ret="UNKNOWN"; 68 break; 69 } 70 return ret; 71 } 72 static char *audio_sub_state(unsigned long state) 73 { 74 char *ret = NULL; 75 switch(state) 76 { 77 case 0: 78 ret="IDLE"; 79 break; 80 case 1: 81 ret="NORMAL"; 82 break; 83 case 2: 84 ret="NO DATA"; 85 break; 86 case 4: 87 ret="NO BUFF"; 88 break; 89 default: 90 ret="UNKNOWN"; 91 break; 92 } 93 return ret; 94 } 95 static int audio_read_debug_info(char * buffer) 96 { 97 int len = 0; 98 unsigned long len_max = MAX_BUF_RD_LEN - 100; 99 struct audio_dbg_info dbg_info; 100 101 if(!audio_deca_dev || !audio_snd_dev) 102 { 103 return -EUNATCH; 104 } 105 106 if (RET_SUCCESS == deca_io_control(audio_deca_dev, DECA_GET_DBG_INFO, (UINT32)(&dbg_info))) 107 { 108 len += sprintf(&buffer[len],"\ndesc enable : %s\n", (1==dbg_info.snd.ad_en)?"yes":"no"); 109 if (len_max <= len) 110 goto out; 111 112 len += sprintf(&buffer[len],"deca state : %s(%d)\n", audio_state(dbg_info.deca.state), (int)dbg_info.deca.state); 113 if (len_max <= len) 114 goto out; 115 116 len += sprintf(&buffer[len],"deca sub state : %s(%d)\n", audio_sub_state(dbg_info.deca.sub_state), (int)dbg_info.deca.sub_state); 117 if (len_max <= len) 118 goto out; 119 120 len += sprintf(&buffer[len],"snd state : %s(%d)\n", audio_state(dbg_info.snd.state), (int)dbg_info.snd.state); 121 if (len_max <= len) 122 goto out; 123 124 len += sprintf(&buffer[len],"snd sub state : %s(%d)\n", audio_sub_state(dbg_info.snd.sub_state), (int)dbg_info.snd.sub_state); 125 if (len_max <= len) 126 goto out; 127 128 len += sprintf(&buffer[len],"+-----+------------------+------------------+------------------+------------------+\n"); 129 if (len_max <= len) 130 goto out; 131 len += sprintf(&buffer[len],"|BUFF |PCM(HEX BYTE) |DESC(HEX BYTE) |DD(HEX BYTE) |DDP(HEX BYTE) |\n"); 132 if (len_max <= len) 133 goto out; 134 135 /* deca buff info */ 136 len += sprintf(&buffer[len],"+-----+------------------+------------------+------------------+------------------+\n"); 137 if (len_max <= len) 138 goto out; 139 len += sprintf(&buffer[len],"|BS |%03d%%(%05x/%05x) |%03d%%(%05x/%05x) | | |\n", 140 (int)((dbg_info.deca.prog_bs_buff_rm*100)/(dbg_info.deca.prog_bs_buff_len)), 141 (unsigned int)dbg_info.deca.prog_bs_buff_rm, (unsigned int)dbg_info.deca.prog_bs_buff_len, 142 (int)((dbg_info.deca.desc_bs_buff_rm*100)/(dbg_info.deca.desc_bs_buff_len)), 143 (unsigned int)dbg_info.deca.desc_bs_buff_rm, (unsigned int)dbg_info.deca.desc_bs_buff_len); 144 if (len_max <= len) 145 goto out; 146 len += sprintf(&buffer[len],"+-----+------------------+------------------+------------------+------------------+\n"); 147 if (len_max <= len) 148 goto out; 149 len += sprintf(&buffer[len],"|CB |%03d%%(%05x/%05x) |%03d%%(%05x/%05x) | | |\n", 150 (int)((dbg_info.deca.prog_cb_buff_rm*100)/(dbg_info.deca.prog_cb_buff_len)), 151 (unsigned int)dbg_info.deca.prog_cb_buff_rm, (unsigned int)dbg_info.deca.prog_cb_buff_len, 152 (int)((dbg_info.deca.desc_cb_buff_rm*100)/(dbg_info.deca.desc_cb_buff_len)), 153 (unsigned int)dbg_info.deca.desc_cb_buff_rm, (unsigned int)dbg_info.deca.desc_cb_buff_len); 154 if (len_max <= len) 155 goto out; 156 157 /* snd buff info */ 158 len += sprintf(&buffer[len],"+-----+------------------+------------------+------------------+------------------+\n"); 159 if (len_max <= len) 160 goto out; 161 len += sprintf(&buffer[len],"|SYNC |%03d%%(%05x/%05x) |%03d%%(%05x/%05x) |%03d%%(%05x/%05x) |%03d%%(%05x/%05x) |\n", 162 (int)((dbg_info.snd.sync_buff_pcm_rm*100)/(dbg_info.snd.sync_buff_pcm_len)), 163 (unsigned int)dbg_info.snd.sync_buff_pcm_rm, (unsigned int)dbg_info.snd.sync_buff_pcm_len, 164 (int)((dbg_info.snd.sync_buff_desc_pcm_rm*100)/(dbg_info.snd.sync_buff_desc_pcm_len)), 165 (unsigned int)dbg_info.snd.sync_buff_desc_pcm_rm, (unsigned int)dbg_info.snd.sync_buff_desc_pcm_len, 166 (int)((dbg_info.snd.sync_buff_dd_rm*100)/(dbg_info.snd.sync_buff_dd_len)), 167 (unsigned int)dbg_info.snd.sync_buff_dd_rm, (unsigned int)dbg_info.snd.sync_buff_dd_len, 168 (int)((dbg_info.snd.sync_buff_ddp_rm*100)/(dbg_info.snd.sync_buff_ddp_len)), 169 (unsigned int)dbg_info.snd.sync_buff_ddp_rm, (unsigned int)dbg_info.snd.sync_buff_ddp_len ); 170 if (len_max <= len) 171 goto out; 172 len += sprintf(&buffer[len],"+-----+------------------+------------------+------------------+------------------+\n"); 173 if (len_max <= len) 174 goto out; 175 len += sprintf(&buffer[len],"|DMA |%03d%%(%05x/%05x) | |%03d%%(%05x/%05x) |%03d%%(%05x/%05x) |\n", 176 (int)((dbg_info.snd.dma_buff_pcm_rm*100)/(dbg_info.snd.dma_buff_pcm_len)), 177 (unsigned int)dbg_info.snd.dma_buff_pcm_rm, (unsigned int)dbg_info.snd.dma_buff_pcm_len, 178 (int)((dbg_info.snd.dma_buff_dd_rm*100)/(dbg_info.snd.dma_buff_dd_len)), 179 (unsigned int)dbg_info.snd.dma_buff_dd_rm, (unsigned int)dbg_info.snd.dma_buff_dd_len, 180 (int)((dbg_info.snd.dma_buff_ddp_rm*100)/(dbg_info.snd.dma_buff_ddp_len)), 181 (unsigned int)dbg_info.snd.dma_buff_ddp_rm, (unsigned int)dbg_info.snd.dma_buff_ddp_len ); 182 if (len_max <= len) 183 goto out; 184 185 len += sprintf(&buffer[len],"+-----+------------------+------------------+------------------+------------------+\n\n"); 186 if (len_max <= len) 187 goto out; 188 } 189 190 out: 191 return len; 192 } 193 194 static int audio_show_debug_info(void) 195 { 196 struct audio_dbg_info dbg_info; 197 198 if(!audio_deca_dev || !audio_snd_dev) 199 { 200 return -EUNATCH; 201 } 202 203 if (RET_SUCCESS == deca_io_control(audio_deca_dev, DECA_GET_DBG_INFO, (UINT32)(&dbg_info))) 204 { 205 printk( "\ndesc enable : %s\n", (1==dbg_info.snd.ad_en)?"yes":"no"); 206 printk( "deca state : %s(%d)\n", audio_state(dbg_info.deca.state), (int)dbg_info.deca.state); 207 printk( "deca sub state : %s(%d)\n", audio_sub_state(dbg_info.deca.sub_state), (int)dbg_info.deca.sub_state); 208 printk( "snd state : %s(%d)\n", audio_state(dbg_info.snd.state), (int)dbg_info.snd.state); 209 printk( "snd sub state : %s(%d)\n", audio_sub_state(dbg_info.snd.sub_state), (int)dbg_info.snd.sub_state); 210 211 printk( "+-----+------------------+------------------+------------------+------------------+\n"); 212 printk( "|BUFF |PCM(HEX BYTE) |DESC(HEX BYTE) |DD(HEX BYTE) |DDP(HEX BYTE) |\n"); 213 214 /* deca buff info */ 215 printk( "+-----+------------------+------------------+------------------+------------------+\n"); 216 printk( "|BS |%03d%%(%05x/%05x) |%03d%%(%05x/%05x) | | |\n", 217 (int)((dbg_info.deca.prog_bs_buff_rm*100)/(dbg_info.deca.prog_bs_buff_len)), 218 (unsigned int)dbg_info.deca.prog_bs_buff_rm, (unsigned int)dbg_info.deca.prog_bs_buff_len, 219 (int)((dbg_info.deca.desc_bs_buff_rm*100)/(dbg_info.deca.desc_bs_buff_len)), 220 (unsigned int)dbg_info.deca.desc_bs_buff_rm, (unsigned int)dbg_info.deca.desc_bs_buff_len); 221 printk( "+-----+------------------+------------------+------------------+------------------+\n"); 222 printk( "|CB |%03d%%(%05x/%05x) |%03d%%(%05x/%05x) | | |\n", 223 (int)((dbg_info.deca.prog_cb_buff_rm*100)/(dbg_info.deca.prog_cb_buff_len)), 224 (unsigned int)dbg_info.deca.prog_cb_buff_rm, (unsigned int)dbg_info.deca.prog_cb_buff_len, 225 (int)((dbg_info.deca.desc_cb_buff_rm*100)/(dbg_info.deca.desc_cb_buff_len)), 226 (unsigned int)dbg_info.deca.desc_cb_buff_rm, (unsigned int)dbg_info.deca.desc_cb_buff_len); 227 228 /* snd buff info */ 229 printk( "+-----+------------------+------------------+------------------+------------------+\n"); 230 printk( "|SYNC |%03d%%(%05x/%05x) |%03d%%(%05x/%05x) |%03d%%(%05x/%05x) |%03d%%(%05x/%05x) |\n", 231 (int)((dbg_info.snd.sync_buff_pcm_rm*100)/(dbg_info.snd.sync_buff_pcm_len)), 232 (unsigned int)dbg_info.snd.sync_buff_pcm_rm, (unsigned int)dbg_info.snd.sync_buff_pcm_len, 233 (int)((dbg_info.snd.sync_buff_desc_pcm_rm*100)/(dbg_info.snd.sync_buff_desc_pcm_len)), 234 (unsigned int)dbg_info.snd.sync_buff_desc_pcm_rm, (unsigned int)dbg_info.snd.sync_buff_desc_pcm_len, 235 (int)((dbg_info.snd.sync_buff_dd_rm*100)/(dbg_info.snd.sync_buff_dd_len)), 236 (unsigned int)dbg_info.snd.sync_buff_dd_rm, (unsigned int)dbg_info.snd.sync_buff_dd_len, 237 (int)((dbg_info.snd.sync_buff_ddp_rm*100)/(dbg_info.snd.sync_buff_ddp_len)), 238 (unsigned int)dbg_info.snd.sync_buff_ddp_rm, (unsigned int)dbg_info.snd.sync_buff_ddp_len ); 239 printk( "+-----+------------------+------------------+------------------+------------------+\n"); 240 printk( "|DMA |%03d%%(%05x/%05x) | |%03d%%(%05x/%05x) |%03d%%(%05x/%05x) |\n", 241 (int)((dbg_info.snd.dma_buff_pcm_rm*100)/(dbg_info.snd.dma_buff_pcm_len)), 242 (unsigned int)dbg_info.snd.dma_buff_pcm_rm, (unsigned int)dbg_info.snd.dma_buff_pcm_len, 243 (int)((dbg_info.snd.dma_buff_dd_rm*100)/(dbg_info.snd.dma_buff_dd_len)), 244 (unsigned int)dbg_info.snd.dma_buff_dd_rm, (unsigned int)dbg_info.snd.dma_buff_dd_len, 245 (int)((dbg_info.snd.dma_buff_ddp_rm*100)/(dbg_info.snd.dma_buff_ddp_len)), 246 (unsigned int)dbg_info.snd.dma_buff_ddp_rm, (unsigned int)dbg_info.snd.dma_buff_ddp_len ); 247 248 printk( "+-----+------------------+------------------+------------------+------------------+\n\n"); 249 } 250 251 return 0; 252 } 253 254 /*Process debug info*/ 255 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) 256 static ssize_t audio_dbginfo_procfile_read(struct file *file, char __user *ubuf, size_t size, loff_t *ppos) 257 { 258 int len = 0; 259 ssize_t ret_len = 0; 260 261 if(audio_info_buffer) 262 { 263 memset(audio_info_buffer, 0, MAX_BUF_RD_LEN); 264 len = audio_read_debug_info(audio_info_buffer); 265 ret_len = simple_read_from_buffer(ubuf, size, ppos, audio_info_buffer, len); 266 } 267 268 return ret_len; 269 } 270 271 272 static ssize_t audio_dbginfo_procfile_write(struct file *file, const char __user * buffer, size_t count, loff_t *ppos) 273 { 274 char buf[MAX_BUF_WT_LEN] = {0}; 275 char *eq_ch = NULL; 276 char *endp = NULL; 277 unsigned long value = 0; 278 279 if ((0>=count) || (MAX_BUF_WT_LEN<count)) 280 return 0; 281 282 if (copy_from_user(buf, buffer, count)) 283 return -EFAULT; 284 285 eq_ch = strstr(buf, "="); 286 if (NULL == eq_ch) 287 { 288 printk(KERN_ERR "param error: incorrect value: \"%s\"\n", buf); 289 return -EINVAL; 290 } 291 292 value = simple_strtoul((char *)(eq_ch+1), &endp, 0); 293 if ((eq_ch+1) == endp || value >= INT_MAX) 294 { 295 printk(KERN_ERR "param error: incorrect value: \"%s\"\n", (eq_ch+1)); 296 return -EINVAL; 297 } 298 299 switch(*buf) 300 { 301 case 'a': 302 { 303 if (strstr(buf, "ad_en")) 304 { 305 if (0==value || 1==value) 306 { 307 if (RET_SUCCESS != snd_io_control(audio_snd_dev, SND_SET_AD_DYNAMIC_EN, (UINT32)value)) 308 { 309 printk("\033[40;31m%s->%s.%u, set ad_en(%d) fail!\033[0m\n", __FILE__, __FUNCTION__, __LINE__, (int)value); 310 return -EFAULT; 311 } 312 } 313 else 314 { 315 printk(KERN_ERR "param error: incorrect value: \"%d\"\n", (int)value); 316 return -EINVAL; 317 } 318 } 319 else 320 { 321 printk(KERN_ERR "param error: incorrect value: \"%s\"\n", buf); 322 return -EINVAL; 323 } 324 break; 325 } 326 case 'm': 327 { 328 if (strstr(buf, "monitor")) 329 { 330 if (0==value || 1==value) 331 { 332 g_dbg_show_en = value; 333 if (g_dbg_show_en) 334 { 335 if (mutex_lock_interruptible(&audio_dbg_mutex)) 336 { 337 return(-ERESTARTSYS); 338 } 339 wake_up_interruptible(&audio_dbg_wq); 340 mutex_unlock(&audio_dbg_mutex); 341 } 342 } 343 else 344 { 345 printk(KERN_ERR "param error: incorrect value: \"%d\"\n", (int)value); 346 return -EINVAL; 347 } 348 } 349 else 350 { 351 printk(KERN_ERR "param error: incorrect value: \"%s\"\n", buf); 352 return -EINVAL; 353 } 354 break; 355 } 356 case 'i': 357 { 358 if (strstr(buf, "interval")) 359 { 360 if (0<value && 100>value) 361 { 362 g_dbg_show_interval = value; 363 } 364 else 365 { 366 printk(KERN_ERR "param error: incorrect value: \"%d\"\n", (int)value); 367 return -EINVAL; 368 } 369 } 370 else 371 { 372 printk(KERN_ERR "param error: incorrect value: \"%s\"\n", buf); 373 return -EINVAL; 374 } 375 break; 376 } 377 default: 378 printk(KERN_ERR "param error: incorrect value: \"%s\"\n", buf); 379 return -EINVAL; 380 } 381 382 383 #if 0 /* Modified by William.Zeng on 2016-10-14 18:57 */ 384 if ((1 != sscanf(buf, "ad_en=%d", &ad_en)) && (0==ad_en || 1==ad_en)) 385 { 386 return 0; 387 } 388 if (RET_SUCCESS != snd_io_control(audio_snd_dev, SND_SET_AD_DYNAMIC_EN, (enum adec_desc_channel_enable)ad_en)) 389 { 390 printk("\033[40;31m%s->%s.%u, set ad_en(%d) fail!\033[0m\n", __FILE__, __FUNCTION__, __LINE__, ad_en); 391 return 0; 392 } 393 printk("\033[40;31m%s->%s.%u, set ad_en(%d) success!\033[0m\n", __FILE__, __FUNCTION__, __LINE__, ad_en); 394 #endif /* #if 0, End of Modified by William.Zeng on 2016-10-14 18:57 */ 395 396 return count; 397 } 398 #else 399 static int audio_dbginfo_procfile_read(char*buffer, char**buffer_localation, off_t offset,int buffer_length,int* eof, void *data ) 400 { 401 int len = 0; 402 len = audio_read_debug_info(buffer); 403 *eof = 1; 404 return len; 405 } 406 407 static int audio_dbginfo_procfile_write(struct file *filp, const char *buffer,unsigned long count,void *data) 408 { 409 char buf[MAX_BUF_WT_LEN] = {0}; 410 char *eq_ch = NULL; 411 char *endp = NULL; 412 unsigned long value = 0; 413 414 if ((0>=count) || (MAX_BUF_WT_LEN<count)) 415 return 0; 416 417 if (copy_from_user(buf, buffer, count)) 418 return -EFAULT; 419 420 eq_ch = strstr(buf, "="); 421 if (NULL == eq_ch) 422 { 423 printk(KERN_ERR "param error: incorrect value: \"%s\"\n", buf); 424 return -EINVAL; 425 } 426 427 value = simple_strtoul((char *)(eq_ch+1), &endp, 0); 428 if ((eq_ch+1) == endp || value >= INT_MAX) 429 { 430 printk(KERN_ERR "param error: incorrect value: \"%s\"\n", (eq_ch+1)); 431 return -EINVAL; 432 } 433 434 switch(*buf) 435 { 436 case 'a': 437 if (strstr(buf, "ad_en")) 438 { 439 if (0==value || 1==value) 440 { 441 if (RET_SUCCESS != snd_io_control(audio_snd_dev, SND_SET_AD_DYNAMIC_EN, (UINT32)value)) 442 { 443 printk("\033[40;31m%s->%s.%u, set ad_en(%d) fail!\033[0m\n", __FILE__, __FUNCTION__, __LINE__, (int)value); 444 return -EFAULT; 445 } 446 } 447 else 448 { 449 printk(KERN_ERR "param error: incorrect value: \"%d\"\n", (int)value); 450 return -EINVAL; 451 } 452 } 453 else 454 { 455 printk(KERN_ERR "param error: incorrect value: \"%s\"\n", buf); 456 return -EINVAL; 457 } 458 break; 459 case 'm': 460 if (strstr(buf, "monitor")) 461 { 462 if (0==value || 1==value) 463 { 464 g_dbg_show_en = value; 465 if (g_dbg_show_en) 466 { 467 if (mutex_lock_interruptible(&audio_dbg_mutex)) 468 { 469 return(-ERESTARTSYS); 470 } 471 wake_up_interruptible(&audio_dbg_wq); 472 mutex_unlock(&audio_dbg_mutex); 473 } 474 } 475 else 476 { 477 printk(KERN_ERR "param error: incorrect value: \"%d\"\n", (int)value); 478 return -EINVAL; 479 } 480 } 481 else 482 { 483 printk(KERN_ERR "param error: incorrect value: \"%s\"\n", buf); 484 return -EINVAL; 485 } 486 break; 487 default: 488 printk(KERN_ERR "param error: incorrect value: \"%s\"\n", buf); 489 return -EINVAL; 490 } 491 492 493 #if 0 /* Modified by William.Zeng on 2016-10-14 18:57 */ 494 if ((1 != sscanf(buf, "ad_en=%d", &ad_en)) && (0==ad_en || 1==ad_en)) 495 { 496 return 0; 497 } 498 if (RET_SUCCESS != snd_io_control(audio_snd_dev, SND_SET_AD_DYNAMIC_EN, (enum adec_desc_channel_enable)ad_en)) 499 { 500 printk("\033[40;31m%s->%s.%u, set ad_en(%d) fail!\033[0m\n", __FILE__, __FUNCTION__, __LINE__, ad_en); 501 return 0; 502 } 503 printk("\033[40;31m%s->%s.%u, set ad_en(%d) success!\033[0m\n", __FILE__, __FUNCTION__, __LINE__, ad_en); 504 #endif /* #if 0, End of Modified by William.Zeng on 2016-10-14 18:57 */ 505 506 return count; 507 } 508 509 510 #endif 511 512 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) 513 static const struct file_operations audio_debuginfo_fops = { 514 .read = audio_dbginfo_procfile_read, 515 .write = audio_dbginfo_procfile_write, 516 .llseek = default_llseek, 517 }; 518 #endif 519 520 static int audio_dbg_show_thread(void *param) 521 { 522 __s32 ret; 523 524 for(;;) 525 { 526 if (mutex_lock_interruptible(&audio_dbg_mutex)) 527 { 528 return(-ERESTARTSYS); 529 } 530 531 /* Wait until we are allowed to show debug info. 532 */ 533 while (g_dbg_show_en == 0) 534 { 535 mutex_unlock(&audio_dbg_mutex); 536 if (wait_event_interruptible(audio_dbg_wq, (1==g_dbg_show_en))) 537 { 538 return(-ERESTARTSYS); 539 } 540 if (mutex_lock_interruptible(&audio_dbg_mutex)) 541 { 542 return(-ERESTARTSYS); 543 } 544 } 545 546 ret = audio_show_debug_info(); 547 548 if (ret < 0) 549 { 550 g_dbg_show_en = 0; 551 printk("\033[40;31m%s->%s.%u, audio_show_debug_info failed!.\033[0m\n", __FILE__, __FUNCTION__, __LINE__); 552 } 553 mutex_unlock(&audio_dbg_mutex); 554 555 msleep(g_dbg_show_interval*1000); 556 } 557 558 return(0); 559 } 560 561 int audio_debug_procfs_init(void) 562 { 563 audio_info_buffer = kmalloc(MAX_BUF_RD_LEN, GFP_KERNEL); 564 if (NULL == audio_info_buffer) 565 { 566 printk("kmall audio_info_buffer %d failed!!\n", MAX_BUF_RD_LEN); 567 return -1; 568 } 569 mutex_init(&audio_dbg_mutex); 570 init_waitqueue_head(&audio_dbg_wq); 571 572 audio_proc_dir = proc_mkdir(AUDIO_DEBUG_PROC_DIR, NULL); 573 if (audio_proc_dir == NULL) { 574 printk("audio_debug_procfs_init create dir audio failed!!\n"); 575 kfree(audio_info_buffer); 576 return -1; 577 } 578 579 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 10, 0)) 580 /*For Debug info*/ 581 audio_proc_dbginfo_file = proc_create(AUDIO_DEBUG_PROC_INFO,0644,audio_proc_dir, &audio_debuginfo_fops); 582 #else 583 /*For Debug info*/ 584 audio_proc_dbginfo_file = create_proc_entry(AUDIO_DEBUG_PROC_INFO,0644,audio_proc_dir); 585 #endif 586 if(audio_proc_dbginfo_file == NULL) 587 { 588 remove_proc_entry(AUDIO_DEBUG_PROC_DIR, NULL); 589 kfree(audio_info_buffer); 590 printk("Error:could not initialize /proc/%s/%s\n", AUDIO_DEBUG_PROC_DIR, AUDIO_DEBUG_PROC_INFO); 591 return -1; 592 } 593 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)) 594 audio_proc_dbginfo_file->read_proc = audio_dbginfo_procfile_read; 595 audio_proc_dbginfo_file->write_proc = audio_dbginfo_procfile_write; 596 #endif 597 598 audio_deca_dev=(struct deca_device*)hld_dev_get_by_type(NULL, HLD_DEV_TYPE_DECA); 599 audio_snd_dev=(struct snd_device*)hld_dev_get_by_type(NULL, HLD_DEV_TYPE_SND); 600 601 audio_dbg_show_thread_ptr = kthread_create(audio_dbg_show_thread, NULL, "audio_dbg"); 602 603 if (IS_ERR(audio_dbg_show_thread_ptr)) 604 { 605 printk("%s,%d\n", __FUNCTION__, __LINE__); 606 remove_proc_entry(AUDIO_DEBUG_PROC_INFO, audio_proc_dir); 607 remove_proc_entry(AUDIO_DEBUG_PROC_DIR, NULL); 608 kfree(audio_info_buffer); 609 return(PTR_ERR(audio_dbg_show_thread_ptr)); 610 } 611 612 wake_up_process(audio_dbg_show_thread_ptr); 613 614 return 0; 615 } 616 617 618 void audio_debug_procfs_exit(void) 619 { 620 remove_proc_entry(AUDIO_DEBUG_PROC_INFO, audio_proc_dir); 621 remove_proc_entry(AUDIO_DEBUG_PROC_DIR, NULL); 622 623 if (audio_info_buffer) 624 kfree(audio_info_buffer); 625 626 return ; 627 }
今天刚好加了一个procfs的目录,用于调试自己的驱动,使用方法如下:
目前支持如下几个命令:
cat /proc/audio/debuginfo --》查看audio信息
echo "ad_en=1" > /proc/audio/debuginfo --》动态打开/关闭audio desc,ad_en参数只能为0或1
echo "monitor=1" > /proc/audio/debuginfo --》wake up内核线程audio_dbg,默认每秒打印一次audio信息,monitor参数只能为0或1
echo "interval=5" > /proc/audio/debuginfo --》设置monitor打印的时间间隔(单位:秒),interval参数范围为[1,100]
audio打印信息如下:(其中表格记录的是audio各个buff的使用情况:剩余数据量百分比(剩余数据量/buff总大小),主要用于debug buff堵住的情况)
# cat /proc/audio/debuginfo desc enable : no deca state : IDLE(2) deca sub state : IDLE(0) snd state : IDLE(2) snd sub state : IDLE(0) +-----+------------------+------------------+------------------+------------------+ |BUFF |PCM(HEX BYTE) |DESC(HEX BYTE) |DD(HEX BYTE) |DDP(HEX BYTE) | +-----+------------------+------------------+------------------+------------------+ |BS |000%(00000/0c800) |000%(00000/0c800) | | | +-----+------------------+------------------+------------------+------------------+ |CB |000%(00000/000c8) |000%(00000/000c8) | | | +-----+------------------+------------------+------------------+------------------+ |SYNC |000%(00000/60300) |000%(00000/60300) |000%(00000/60300) |000%(00000/60300) | +-----+------------------+------------------+------------------+------------------+ |DMA |000%(00000/20100) | |000%(00000/20100) |000%(00000/20100) | +-----+------------------+------------------+------------------+------------------+