蛻變成蝶~Linux設備驅動之watchdog設備驅動

  看門狗(watchdog )分硬件看門狗和軟件看門狗。硬件看門狗是利用一個定時器 電路,其定時輸出鏈接到電路的復位端,程序在必定時間範圍內對定時器清零 (俗稱 「喂狗」),若是程序出現故障,不在定時週期內復位看門狗,就使得看門狗定時器溢出產生復位信號 並重啓系統。軟件看門狗原理上同樣,只是將硬件電路上的定時器用處理器的內部定 時器代替。html

1 看門狗的三個寄存器node

1.1 watchdog原理app

  S3C2410內部集成了watchdog,提供3 個寄存器對watchdog 進行操做,這3 個寄存器分別爲WTCON (watchdog 控制寄存器)、WTDAT (watchdog 數據寄存器)和WTCNT(watchdog 記數寄存器) S3c2440的看門狗的原理框圖以下:函數

  能夠看到,看門狗定時器的頻率由PCLK提供,其預分頻器最大取值爲255+1;另外,經過MUX,能夠進一步下降頻率。定時器採用遞減模式,一旦到0,則能夠觸發看門狗中斷以及RESET復位信號。 看門狗定時器的頻率的計算公式以下:ui

t_watchdog = 1/[PCLK/(Prescaler value + 1)/Division_factor]

1.2 開啓S3C2410 的看門狗 spa

void enable watchdog () 
     { 
               
       rWTCON = WTCON DIV64 | WTCON RSTEN;//64分頻、開啓復位信號 
       rWTDAT = 0x8000;//計數目標 
                
       rWTCON |= WTCON ENABLE;//開啓看門狗 
      } 

1.3 S3C2410 的看門狗 「喂狗」orm

void feed dog () 
{
    rWTCNT=0x8000; 
} 

1.4 看門狗的使用例程 htm

void main () 

     { 
   
       init system (); 

       ... 
           
       enable watchdog ();//啓動看門狗 

       ... 

       while (1) 

       { 

          ... 

            
         feed dog (); //喂狗 

      } 

    } 

2 watchdog中的數據結blog

  有一類設備被稱爲 「平臺設備」,一般 SoC 系統中集成的獨立的外設單元都被看成平臺設備處理內存

2.1 platform_device 結構體

struct platform device 

     { 

       const char  * name;//設備名 

       u32      id; 

       struct device dev; 
           
       u32      num resources;//設備所使用各種資源數量 

       struct resource * resource;//資源 

     }; 

2.2 S3C2410 中的平臺設備

struct platform device *s3c24xx uart devs[];
struct platform device s3c device usb; //USB 控制器 
                 
       struct platform device s3c device lcd; //LCD 控制器 
                     
       struct platform device s3c device wdt; //看門狗 
                                                       2 
                      
       struct platform device s3c device i2c; //I C 控制器 
                     
       struct platform device s3c device iis; //IIS 
                  
       struct platform device s3c device rtc; //實時鐘 
        ... 

      /*SMDK2410開發板使用的平臺設備*/ 

                        
      static struct platform device *smdk2410 devices[]  initdata = 

      { 
       
         &s3c device usb, //USB 
            
         &s3c device lcd, //LCD 
              
         &s3c device wdt, //看門狗 
                              
         &s3c device i2c, //I C
             
         &s3c device iis,  //IIS 

      }; 

2.3 S3C2410 看門狗的platform_device 結構體

struct platform device s3c device wdt = 

      { 

        .name = "s3c2410-wdt",  //設備名 

        .id =  - 1, . 
  
       num resources = ARRAY SIZE (s3c wdt resource),  //資源數量 
                 
        .resource = s3c wdt resource,  //看門狗所使用資源 

      }; 

2.4 int platform_add_devices()函數

int platform add devices(struct platform device **devs, int num) 

      { 

        int i, ret = 0; 

        for (i = 0; i < num; i++) 

         { 
ret = platform device register(devs[i]);/*註冊平臺設備*/ 

          if (ret) /*註冊失敗*/ 

          { 

           while (--i >= 0) 
   
              platform device unregister(devs[i]);/*註銷已經註冊的平臺設備 */ 

           break; 

         } 

        } 

       return ret; 

     } 

2.5 platform_driver 結構體 

struct platform driver 
      { 
                                       
        int (*probe)(struct platform device *);//探測 
                                
        int (*remove)(struct platform device *);//移除 
                                    
       void (*shutdown)(struct platform device *);//關閉 
                                   
        int (*suspend)(struct platform device *, pm message t state);// 掛起 
                   
        int (*resume)(struct platform device *);//恢復 
           
        struct device driver driver; 

       }; 

2.6 S3C2410 看門狗的platform_driver 結構體 

static struct platform driver s3c2410wdt driver = 

      { 
                         
       .probe      = s3c2410wdt probe,//S3C2410看門狗探測 

                                 
       .remove     = s3c2410wdt remove,// S3C2410看門狗移除 

                                 
       .shutdown   = s3c2410wdt shutdown,//S3C2410看門狗關閉 

                                 
       .suspend    = s3c2410wdt suspend,//S3C2410看門狗掛起 

                          
        .resume     = s3c2410wdt resume, //S3C2410看門狗恢復 

        .driver     = { 

                    
            .owner  = THIS MODULE, 

           .name   = "s3c2410-wdt",//設備名 

      }, 
};

2.7 S3C2410 看門狗所用資源 

static struct resource s3c wdt resource[] = 

       { 

         [0] = 

        { 

          .start = S3C24XX PA WATCHDOG,     //看門狗I/O 內存開始位置 

         .end = S3C24XX PA WATCHDOG + S3C24XX SZ WATCHDOG - 1, 

              //看門狗I/O 內存結束位置 

          .flags = IORESOURCE MEM,  //I/O 內存資源 

        } , 

        [1] = 

       { 

         .start = IRQ WDT, //看門狗開始IRQ 號 

         .end = IRQ WDT, //看門狗結束IRQ 號 

         .flags = IORESOURCE IRQ,  //IRQ 資源 

        } 

      }; 

2.8 S3C2410 看門狗驅動的miscdevice 結構體 

 static struct miscdevice s3c2410wdt miscdev = 
 { 
                     
        .minor      = WATCHDOG MINOR,//次設備號 

        .name       = "watchdog", 

       .fops       = &s3c2410wdt fops,//文件操做結構體 

}; 

2.9 S3C2410 看門狗驅動的文件操做結構體

static struct file operations s3c2410wdt fops = 
{ 
            
        .owner      = THIS MODULE, 
       
        .llseek     = no llseek,    //seek 
                      
        .write      = s3c2410wdt write,     //寫函數 
                            
        .ioctl      = s3c2410wdt ioctl, //ioctl 函數 
                      
        .open       = s3c2410wdt open,  //打開函數 
                     
        .release    = s3c2410wdt release,//釋放函數 

}; 

3 加載和卸載函數 

  驅動模塊的加載和卸載函數分別 用 platform_driver_register() 和 platform_driver_ unregister()註冊和註銷platform_driver

3.1 S3C2410 看門狗驅動

static int     __init watchdog__init (void) 
      { 
       printk (banner); 
        
        return   platform driver register(&s3c2410wdt driver);//       注 冊platform driver 
      } 
      
      static void     exit watchdog exit (void) 
       { 
platform driver unregister (&s3c2410wdt driver);//          注  銷 platform driver 
     } 

4 探測和移除函數 

4.1 探測函數

static int s3c2410wdt probe (struct platform device *pdev) 
      { 
        struct resource *res; 
        int started = 0; 
        int ret; 
        int size; 
     
        DBG ("%s: probe=%p\n", _ _FUNCTION_ _, pdev); 
      
       /* 得到看門狗的內存區域 */ 
      
                     
       res = platform get resource (pdev, IORESOURCE MEM, 0); 
       if (res == NULL) 
        { 
                
        printk(KERN INFO PFX "failed to get memory region resouce\n"); 
         return  - ENOENT; 
        } 
      
       size = (res->end - res->start) + 1; 
       //申請I/O 內存 
          
       wdt mem = request mem region (res->start, size, pdev->name); 
            
       if (wdt mem == NULL) 
        { 
            
         printk(KERN INFO PFX "failed to get memory region\n"); 
         return  - ENOENT; 
        } 
      
          
       wdt base = ioremap (res->start, size); //設備內存->虛擬地址 
              
       if (wdt base == 0) 
        { 
                   
         printk(KERN INFO PFX "failed to ioremap () region\n"); 
         return  - EINVAL; 
        } 
      
                           
       DBG ("probe: mapped wdt base=%p\n", wdt base); 
      
       /* 得到看門狗的中斷 */ 
      
                   
       res = platform get resource (pdev, IORESOURCE IRQ, 0); 
       if (res == NULL) 
{ 
                  
         printk(KERN INFO PFX "failed to get irq resource\n"); 
         return  - ENOENT; 
        } 
       //申請中斷 
              
         ret = request irq (res->start, s3c2410wdt irq, 0, pdev->name, 
pdev); 
       if (ret != 0) 
        { 
             
         printk(KERN INFO PFX "failed to install irq (%d)\n", ret); 
         return ret; 
        } 
      
           
       wdt clock = clk get (&pdev->dev, "watchdog"); //得到看門狗時鐘源 
         
       if (wdt clock == NULL) 
        { 
                  
         printk(KERN INFO PFX "failed to find watchdog clock source\n"); 
         return  - ENOENT; 
        } 
      
          
       clk enable (wdt clock); 
      
       /* 看看是否能設置定時器的超時時間爲指望的值,若是不能,使用缺省值 */ 
      
                       
       if (s3c2410wdt set heartbeat (tmr margin)) 
        { 
                              
         started = s3c2410wdt set heartbeat ( 
                 
             CONFIG S3C2410 WATCHDOG DEFAULT TIME); 
         if (started == 0) 
         { 
                      
           printk (KERN INFO PFX "tmr margin value out of range, default 
%d 
                             
             used\n",CONFIG S3C2410 WATCHDOG DEFAULT TIME); 
         } 
         else 
         { 
                     
           printk (KERN INFO PFX 
             "default timer value is out of range, cannot start\n"); 
         } 
        } 
      
      //註冊miscdevice 
                    
       ret = misc register(&s3c2410wdt miscdev); 
       if (ret) 
        { 
                      
         printk(KERN ERR PFX "cannot registermiscdev on minor=%d (%d)\n", 
                     
           WATCHDOG MINOR, ret); 
         return ret; 
        } 
      
              
       if (tmr atboot && started == 0) 
        { 
                    
         printk(KERN INFO PFX "Starting Watchdog Timer\n"); 
                
        s3c2410wdt start (); 
        } 
      
       return 0; 
     } 

4.2 探測函數 

static int s3c2410wdt remove (struct platform device *dev) 

      { 
   
        if (wdt mem != NULL) 

        { 
       
          release resource (wdt mem); //釋放資源 

                    
          kfree (wdt mem);//釋放內存 

 
          wdt mem = NULL; 

       } 

      //釋放中斷 

            
   if (wdt irq != NULL) 

       { 

       
         free irq (wdt irq->start, dev); 

      
         wdt irq = NULL; 
} 

       //禁止時鐘源 


       if (wdt clock != NULL) 

       { 

         clk disable (wdt clock); 

         clk put (wdt clock); 

         wdt clock = NULL; 

        } 
    misc deregister(&s3c2410wdt miscdev);//註銷miscdevice 

       return 0; 

    } 

5 掛起和恢復函數

5.1 掛起函數

static   int  s3c2410wdt suspend (struct    platform device   *dev, 

pm message t state) 
      { 
        /* 保存看門狗狀態,中止它 */ 
           
       wtcon save = readl (wdt base + S3C2410 WTCON); 
          
       wtdat save = readl (wdt base + S3C2410 WTDAT); 
      
             
        s3c2410wdt stop (); 
      
        return 0; 
     } 

5.2 恢復函數

static int s3c2410wdt resume (struct platform device *dev) 
      { 
        /* 恢復看門狗狀態 */ 
               
        writel (wtdat save, wdt base + S3C2410 WTDAT); 
                 
        writel (wtdat save, wdt base + S3C2410 WTCNT); 
                
        writel (wtcon save, wdt base + S3C2410 WTCON); 
      
                  
        printk (KERN INFO PFX "watchdog %sabled\n", (wtcon save 
                
          &S3C2410 WTCON ENABLE)? "en" : "dis"); 
     
       return 0; 
     } 

6 打開和釋放函數 

6.1 打開函數

static int s3c2410wdt open (struct inode *inode, struct file *file) 
      { 
              
        if (down trylock (&open lock))  //得到打開鎖 
          return  - EBUSY; 
     
        if (nowayout) 
        { 
        
            module get (THIS MODULE); 
        } 
       else 
        { 
                
         allow close = CLOSE STATE ALLOW; 
        } 
      
       /* 啓動看門狗 */ 
                   
       s3c2410wdt start (); 
                         
       return nonseekable open (inode, file); 
     } 

6.2 釋放函數

static int s3c2410wdt release (struct inode *inode,struct file *file) 
      { 
        /* 中止看門狗 */ 
                
        if (allow close == CLOSE STATE ALLOW) 
        { 
                
          s3c2410wdt stop (); 
       } 
        else 
        { 
                
              printk (KERN CRIT  PFX  "Unexpected  close,  not  stopping 
watchdog!\n"); 
           
         s3c2410wdt keepalive (); 
        } 
      
            
       allow close = CLOSE STATE NOT; 
             
       up (&open lock);  //釋放打開鎖 
       return 0; 
     } 

7 啓停watchdog函數和寫函數

7.1 啓停看門狗函數

/*中止看門狗*/ 
                           
       static int s3c2410wdt stop (void) 
       { 
        unsigned long wtcon; 
      
               
        wtcon = readl(wdt base + S3C2410 WTCON); 
        //中止看門狗,禁止復位 
                       
        wtcon &= ~ (S3C2410 WTCON ENABLE | S3C2410 WTCON RSTEN); 
                       
        writel (wtcon, wdt base + S3C2410 WTCON); 
      
        return 0; 
      } 
      
      /*開啓看門狗*/ 
                   
      static int s3c2410wdt start (void) 
      { 
        unsigned long wtcon; 
      
            
        s3c2410wdt stop (); 
      
                       
        wtcon = readl(wdt base + S3C2410 WTCON); 
        //使能看門狗,128 分頻 
                     
        wtcon |= S3C2410 WTCON ENABLE | S3C2410 WTCON DIV128; 
      
              
        if (soft noboot) 
        { 
                       
         wtcon |= S3C2410 WTCON INTEN; //使能中斷 
                         
         wtcon &= ~S3C2410 WTCON RSTEN; //禁止復位 
        } 
        else 
        { 
                        
         wtcon &= ~S3C2410 WTCON INTEN; //禁止中斷 
                     
         wtcon |= S3C2410 WTCON RSTEN; //使能復位 
        } 
      
                  
        DBG ("%s: wdt count=0x%08x, wtcon=%08lx\n",        FUNCTION    , 
           
          wdt count, wtcon); 
                  
        writel (wdt count, wdt base + S3C2410 WTDAT); 
               
        writel (wdt count, wdt base + S3C2410 WTCNT); 
                   
        writel (wtcon, wdt base + S3C2410 WTCON); 
      
        return 0; 
      } 

7.2 寫函數

static ssize t s3c2410wdt write (struct file *file, const char      user *data, 
       
        size t len, loff t *ppos) 
       { 
        /* 刷新看門狗 */ 
        if (len) 
         { 
          if (!nowayout) 
{ 

            size t i; 
             
           allow close = CLOSE STATE NOT; 
           for (i = 0; i != len; i++) 
           { 
             char c; 
                 
             if (get user(c, data + i))//用戶空間->內核空間 
               return  - EFAULT; 
             if (c == 'V ')  //若是寫入了'V ' ,容許關閉 
               
               allow close = CLOSE STATE ALLOW; 
           } 
         } 
            
         s3c2410wdt keepalive (); 
        } 
       return len; 
     } 

  版權全部,轉載請註明轉載地址:http://www.cnblogs.com/lihuidashen/p/4501953.html

相關文章
相關標籤/搜索