免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3066 | 回复: 0
打印 上一主题 下一主题

[驱动] 求助,移植ADC驱动时kernel panic [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-11-15 13:37 |只看该作者 |倒序浏览
昨天移植了ADC驱动,但内核启动过程中会崩掉。

看内核警告应该是 ioremap处出现了空指针(我是这么判断的。。),但我看不出来。
麻烦高手指点一二~感激不尽~

以下是错误信息:
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c0004000
[00000000] *pgd=00000000
Internal error: Oops: 805 [#1]
last sysfs file:
Modules linked in:
CPU: 0    Not tainted  (2.6.32.46 #1
PC is at adc_init+0x78/0xb4
LR is at __arm_ioremap_pfn+0x120/0x138
pc : [<c0019ec0>]    lr : [<c00365bc>]    psr: a0000013
sp : c3823fb0  ip : 00000000  fp : 00000000
r10: 00000000  r9 : 00000000  r8 : 00000000
r7 : 00000000  r6 : 00000000  r5 : c0022680  r4 : c0443d34
r3 : 00000000  r2 : c486e004  r1 : ffffffe0  r0 : c0400384
Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
Control: c000717f  Table: 30004000  DAC: 00000017
Process swapper (pid: 1, stack limit = 0xc3822270)
Stack: (0xc3823fb0 to 0xc3824000)
3fa0:                                     c0019e48 c002f37c c0019e48 00000000
3fc0: c040dbe0 c040dbe0 c00224c4 c0022680 00000000 00000000 00000000 00000000
3fe0: 00000000 c00083fc 00000000 00000000 00000000 c0030868 11cc37dc 33ec33cc
[<c0019ec0>] (adc_init+0x78/0xb4) from [<c002f37c>] (do_one_initcall+0x5c/0x1bc)
[<c002f37c>] (do_one_initcall+0x5c/0x1bc) from [<c00083fc>] (kernel_init+0xa0/0x1)
[<c00083fc>] (kernel_init+0xa0/0x11 from [<c0030868>] (kernel_thread_exit+0x0/0)
Code: ea000007 e2802004 e3a03000 e59f0030 (e5832000)
---[ end trace 0cab6b11a4649c09 ]---

这个是驱动源码:
  1. #include <linux/errno.h>
  2. #include <linux/kernel.h>
  3. #include <linux/module.h>
  4. #include <linux/fs.h>
  5. #include <linux/init.h>
  6. #include <linux/serio.h>
  7. #include <linux/delay.h>
  8. #include <linux/miscdevice.h>
  9. #include <linux/clk.h>
  10. #include <linux/wait.h>
  11. #include <linux/irq.h>
  12. #include <linux/sched.h>
  13. #include <asm/io.h>
  14. #include <asm/irq.h>
  15. #include <asm/uaccess.h>
  16. #include <plat/regs-adc.h>

  17. #define DEVICE_NAME        "adc"

  18. static void __iomem *base_addr;

  19. typedef struct {
  20.         wait_queue_head_t wait;
  21.         int channel;
  22.         int prescale;
  23. }ADC_DEV;

  24. DECLARE_MUTEX(ADC_LOCK);

  25. static ADC_DEV adc_dev;
  26. static volatile int ev_adc = 0;
  27. static int adc_finish=0;
  28. static int owned_adc=0;
  29. static int adc_data;
  30. static struct clk    *adc_clock;

  31. #define ADCCON (base_addr + S3C2410_ADCCON)    //ADC control

  32. #define ADCTSC (base_addr + S3C2410_ADCTSC)    //ADC touch screen control

  33. #define ADCDLY (base_addr + S3C2410_ADCDLY)    //ADC start or Interval Delay

  34. #define ADCDAT0 (base_addr + S3C2410_ADCDAT0)    //ADC conversion data 0

  35. #define ADCDAT1 (base_addr + S3C2410_ADCDAT1)    //ADC conversion data 1

  36. #define ADCUPDN (base_addr + 0x14)    //Stylus Up/Down interrupt status

  37. /* ADCCON寄存器设置 */
  38. #define PRESCALE_DIS (0 << 14)                //预分频禁止
  39. #define PRESCALE_EN (1 << 14)                //预分频使能
  40. #define PRSCVL(x) ((x) << 6)                //预分频系数,0~255之间
  41. #define ADC_INPUT(x) ((x) << 3)                //设置模拟信号输入频道
  42. #define ADC_START (1 << 0)                //通过读取启动ADC
  43. #define ADC_ENDCVT (1 << 15)                //转换结束标志

  44. /* 设置输入频道为ch,预分频系数为prescale,并使能ADC转换 */
  45. static void start_adc(int ch,int prescale)
  46. {
  47.         unsigned int tmp;

  48.         tmp = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT(ch);
  49.         writel(tmp,ADCCON);

  50.         tmp = readl(ADCCON);
  51.         tmp |= ADC_START;
  52.         writel(tmp,ADCCON);
  53. }

  54. static irqreturn_t adc_interrupt(int irq,void *dev_id)
  55. {
  56.         if(owned_adc){       
  57.                 adc_data = readl(ADCDAT0)& 0x3ff;
  58.                 adc_finish = 1 ;
  59.                 wake_up_interruptible(&adc_dev.wait);
  60.         }
  61.         return IRQ_HANDLED;
  62. }

  63. static ssize_t adc_read(struct file *filp,char *buffer , size_t count ,loff_t *ppos)
  64. {
  65.         if(down_trylock(&ADC_LOCK)==0){
  66.                 owned_adc = 1;
  67.                 start_adc(adc_dev.channel,adc_dev.prescale);
  68.                 wait_event_interruptible(adc_dev.wait,adc_finish);
  69.                
  70.                 adc_finish = 0;

  71.                 copy_to_user(buffer,(char *)&adc_data,sizeof(adc_data));
  72.                 owned_adc = 0;

  73.                 up(&ADC_LOCK);
  74.                 return sizeof(adc_data);
  75.         }
  76.         return -EINVAL;
  77. }

  78. static int adc_open(struct inode *inode,struct file *filp)
  79. {
  80.         int ret;
  81.         init_waitqueue_head(&(adc_dev.wait));

  82.         adc_dev.channel = 0;
  83.         adc_dev.prescale = 0xff;

  84.         ret = request_irq(IRQ_ADC,adc_interrupt,IRQF_SHARED,DEVICE_NAME,&adc_dev);
  85.         if(ret){
  86.                 free_irq(IRQ_ADC,&adc_dev);
  87.                 return ret;
  88.         }
  89.         return 0;
  90. }

  91. static int adc_release(struct inode *inode , struct file *filp)
  92. {
  93.         free_irq(IRQ_ADC,&adc_dev);
  94.         return 0;
  95. }

  96. static struct file_operations adc_fops = {
  97.         .owner        =        THIS_MODULE,
  98.         .open         =        adc_open,
  99.         .read        =        adc_read,
  100.         .release=        adc_release,
  101. };

  102. static struct miscdevice adc_misc ={
  103.         .minor        =        MISC_DYNAMIC_MINOR,
  104.         .name        =        DEVICE_NAME,
  105.         .fops        =        &adc_fops,
  106. };

  107. static int __init adc_init(void)
  108. {
  109.         int ret;
  110.         printk("func:%s",__FUNCTION__);
  111.        
  112.         adc_clock = clk_get(NULL,"adc");

  113.         if(!adc_clock){
  114.                 printk(KERN_ERR "failed to get adc clock source \n");
  115.                 return -ENOENT;
  116.         }

  117.         clk_enable(adc_clock);
  118.        
  119.         base_addr = ioremap(S3C2410_PA_ADC,0x20);
  120.         if(base_addr == NULL){
  121.                 printk(KERN_ERR "Failed to remap register block\n");
  122.                 return -ENOMEM;
  123.         }

  124.         writel(ADCTSC,0);
  125.        
  126.         ret = misc_register(&adc_misc);
  127.        
  128.         printk(DEVICE_NAME "\t :initiated!\n");

  129.         return ret;
  130. }

  131. static void __exit adc_exit(void)
  132. {
  133.     free_irq(IRQ_ADC, &adc_dev);
  134.     iounmap(base_addr);

  135.     if (adc_clock) {
  136.         clk_disable(adc_clock);
  137.         clk_put(adc_clock);
  138.         adc_clock = NULL;
  139.     }

  140.     misc_deregister(&adc_misc);
  141. }

  142. EXPORT_SYMBOL(ADC_LOCK);
  143. module_init(adc_init);
  144. module_exit(adc_exit);
  145. MODULE_LICENSE("GPL");
  146. M
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP