亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 1143 | 回復: 0
打印 上一主題 下一主題

linux設備驅動歸納總結(十一):簡單的看門狗驅動 [復制鏈接]

論壇徽章:
0
跳轉到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2011-02-09 10:20 |只看該作者 |倒序瀏覽
linux設備驅動歸納總結(十一):寫個簡單的看門狗驅動


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

設備驅動的歸納已經差不多了,趁著知識點還沒有遺忘,寫點代碼鞏固一下,來個簡單的看門狗驅動——靜態(tài)平臺類的雜設備看門狗驅動,有定時和重啟兩個基本功能。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


一、S3C2440中的看門狗——具體請看s3c2440文檔


看門狗應該可以算是S3C2440中最簡單的一個設備的,僅僅只有三個寄存器需要配置。S3C2440中的看門狗有兩種功能(只能二選一):

1、復位功能,在指定時間內,如果沒有執(zhí)行喂狗操作。指定時間到達后會執(zhí)行系統(tǒng)重啟操作。

2、定時功能,每隔指定的時間,看門狗就會往處理器發(fā)送中斷,執(zhí)行中斷處理函數(shù)。


接下來就要看看控制看門狗的三個寄存器:

1、控制寄存器——WTCON

首先要看看分頻系數(shù)Prescaler value[15:8]和時鐘分頻Clock select[4:3]。看門狗的時鐘頻率就是通過這兩個值分頻得出的:

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

每個(1/t_watchdog)秒,看門狗計數(shù)器減一。

Watchdog timer[5]是看門狗的是能控制位,初始化時必須將此為置一,不然看門狗無法操作。

Interrupt generation[2]是控制中斷的產生,如果你使用看門狗來執(zhí)行定時功能,置一代表使能看門狗產生中斷,反之不產生中斷。

Reset enable/disable[0]用控制看門狗是否復位,如果置一,代表當時間到達后系統(tǒng)重啟。


2、數(shù)據(jù)寄存器WTDAT和計數(shù)寄存器WTCNT


這兩個都是用于存放16位數(shù)據(jù)的寄存器。

1、如果是復位模式,從WTCON[5]置一開始,每隔(1/t_watchdog)秒,WTCNT中的值減一,直到WTCNT0,系統(tǒng)就會復位。在WTCNT還沒有為0前,可以重新往WTCNT中賦值,這樣WTCNT就會從新的數(shù)值開始減一,這就是所謂的喂狗操作,重復地在WTCNT0前喂狗,就可以讓系統(tǒng)不復位。

2、如果是定時模式, 從WTCON[5]置一開始,每隔(1/t_watchdog)秒,WTCNT中的值減一,直到WTCNT0,看門狗往處理器發(fā)送中斷信號,并自動將WTDAT賦值給WTCNT,讓WTCNT重新開始減一。這樣的重復操作就實現(xiàn)了看門狗的定時。

注意:不管是哪一種模式,一開始時看門狗都不會將WTDAT的值賦給WTCNT,都是直接以WTCNT的值開始計數(shù)。所以,在是能看門狗之前,必須先設備WTCNT的值,指定時間長短。


接下來的程序我需要的時間間隔是1秒,所以,Prescaler value[15:8]我賦值為99,Clock select[4:3]我賦值為128。S3C2440中的PCLK定義為50000000,通過公式可以計算出:

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

所以,看門狗的計數(shù)間隔是(1/3906.25)秒,1秒需要計數(shù)大約3906


看門狗介紹完畢,接著就開始寫驅動了,在寫驅動前貼張之前我介紹過的圖,我寫驅動的步驟:

接在來我就會按這個順序來寫個簡單的看門狗驅動,實現(xiàn)看門狗的兩種功能,定時和復位。


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


二、第一個看門狗程序,代碼路徑11th_wdt/1st。


寫驅動前先要寫一些基本的操作代碼,檢驗一下該設備是否能正常工作。


第一個看門狗程序做了三步,簡單實現(xiàn)了看門狗的復位操作:

1、定義了一個維護看門狗數(shù)據(jù)的結構體:

9 struct _wdt_t {

10      unsigned long phys, virt; //存放物理地址和對應的虛擬地址

11     unsigned long wtcon, wtdat, wtcnt; //存放寄存器

12     unsigned long reg;

13

14     void (*init_reset)(struct _wdt_t *); //操作看門狗的函數(shù)指針

15 };

2、實現(xiàn)了看門狗的復位操作:

19 static void s3c_wdt_init_reset(struct _wdt_t *wdt)

20 {

21     iowrite32((int)(WDT_1S * 10), wdt->wtdat); //其實這個不設置也可以

22     iowrite32((int)(WDT_1S * 10), wdt->wtcnt); //設置10秒后系統(tǒng)復位

23     iowrite32(0x6339, wdt->wtcon); //設置wtcon寄存器為0x6339,使能了看門狗和復位功能

24 }

3、封裝了設備的初始化和注銷函數(shù):

26 int init_wdt_device(struct _wdt_t *wdt)

27 {

28     int ret = 0;

29     //ioremap

30     wdt->phys = 0x53000000;

31     wdt->virt = (unsigned long)ioremap(wdt->phys, 0x0c);

32      wdt->wtcon = wdt->virt + 0x0;

33      wdt->wtdat = wdt->virt + 0x4;

34      wdt->wtcnt = wdt->virt + 0x8;

35

36     //function

37      wdt->init_reset = s3c_wdt_init_reset;

38     return ret;

39 }

40

41 void destroy_wdt_device(struct _wdt_t *wdt)

42 {

43     iounmap((void *)wdt->virt);

44 }

寫完后編譯,效果就是加載模塊后十秒系統(tǒng)重啟,看門狗的復位功能驗證成功。


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


三、第二個看門狗程序,代碼路徑11th_wdt/2nd。


第一個看門狗程序實現(xiàn)了復位操作,接下來我就要在原來代碼的基礎上加上看門狗的定時功能。很簡單,只貼上就三個函數(shù),其他細節(jié)請看源代碼:

1、初始化看門狗,設置為定時功能,每隔一秒產生一次中斷:

29 static void s3c_wdt_init_interrupt(struct _wdt_t *wdt)

30 {

31     iowrite32((int)(WDT_1S), wdt->wtdat);

32     iowrite32((int)(WDT_1S), wdt->wtcnt);

33     iowrite32(0x6338, wdt->wtcon);

34 }

2、初始話后還不能產生中斷,還需要實現(xiàn)開啟和關閉中斷操作,其實就是設置寄存器的一位:

36 static void s3c_wdt_start(struct _wdt_t *wdt)

37 {

38      wdt->reg = ioread32(wdt->wtcon);

39      wdt->reg |= (1 << 2);

40     iowrite32(wdt->reg, wdt->wtcon);

41 }

42

43 static void s3c_wdt_stop(struct _wdt_t *wdt)

44 {

45     wdt->reg = ioread32(wdt->wtcon);

46     wdt->reg &= (1 << 2);

47     iowrite32(wdt->reg, wdt->wtcon);

48 }


既然是產生了中斷,就要注冊中斷和實現(xiàn)中斷處理函數(shù),中斷的注冊操作應該放在設備初始化函數(shù)中:

50 irqreturn_t wdt_irq_handler(int irqno, void *dev_id)

51 {

52     printk("wang wang wang ...\n");

53     return IRQ_HANDLED;

54 }

55

56 int init_wdt_device(struct _wdt_t *wdt)

57 {

58     int ret = 0;

59     //ioremap

60     wdt->phys = 0x53000000;

61     wdt->virt = (unsigned long)ioremap(wdt->phys, 0x0c);

62     wdt->wtcon = wdt->virt + 0x0;

63     wdt->wtdat = wdt->virt + 0x4;

64     wdt->wtcnt = wdt->virt + 0x8;

65

66     //irq

67     ret = request_irq(IRQ_S3C2440_WDT, wdt_irq_handler, IRQF_TRIGGER_NONE,

68                                         "s3c2440_wdt-irq", NULL);

69     if(ret){

70         printk("request wdt-irq failed!\n");

71         goto err;

72     }

73

74     //function

75     wdt->init_reset = s3c_wdt_init_reset;

76     wdt->init_interrupt = s3c_wdt_init_interrupt;

77     wdt->start = s3c_wdt_start;

78     wdt->stop = s3c_wdt_stop;

79

80     return ret;

81

82 err:

83     iounmap((void *)wdt->virt);

84     return ret;

85 }

86

87 void destroy_wdt_device(struct _wdt_t *wdt)

88 {

89     free_irq(IRQ_S3C2440_WDT, NULL);

90     iounmap((void *)wdt->virt);

91 }

寫完后編譯,效果就是加載模塊后每隔一秒打印出一句話,看門狗的定時功能驗證成功。


注意:一般是不能加載成功的,運行命令”cat /proc/interrupt”就知道,系統(tǒng)中本身就注冊了一個看門狗中斷,為了能夠執(zhí)行成功,方法有兩個:(之前介紹過的兩男共享一妞)

1、干掉系統(tǒng)中的看門狗中斷:

方法:配置內核時不要選上看門狗設備。

2、修改內核源代碼,添加共享標記。

我這里使用的是第一種解決方法。


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


四、第三個看門狗程序,代碼路徑11th_wdt/3rd。


上面已經實現(xiàn)了圖上的三步:定義面向對象結構體,實現(xiàn)基本的硬件操作函數(shù)、定義設備的初始化和注銷函數(shù)。

接下來就將它修改成靜態(tài)平臺類驅動。方法很簡單,將之前放在wdt_init的操作放在probe函數(shù)中,配對成功后自動調用,將之前放在wdt_exit的操作放在remove函數(shù)中。

貼上部分代碼:

97 static int s3c_wdt_probe(struct platform_device *pdev)

98 {

99       printk("[%s]\n", __FUNCTION__);

100     my_wdt.phys = pdev->resource[0].start;

101     my_wdt.irqno = pdev->resource[1].start;

102     init_wdt_device(&my_wdt);

103     my_wdt.init_interrupt(&my_wdt);

104     my_wdt.start(&my_wdt);

105     return 0;

106 }

107

108 static int s3c_wdt_remove(struct platform_device *pdev)

109 {

110     printk("[%s]\n", __FUNCTION__);

111     my_wdt.stop(&my_wdt);

112     destroy_wdt_device(&my_wdt);

113     return 0;

114 }

115

116 static struct platform_driver wdt_pdrv = {

117     .probe = s3c_wdt_probe,

118     .remove = s3c_wdt_remove,

119     .driver = {

120         .name = "s3c_wdt_xb",

121     },

122 };

123

124 static int __init wdt_init(void)

125 {

126     platform_driver_register(&wdt_pdrv);

127     printk("hello wdt!\n");

128     return 0;

129 }

130

131 static void __exit wdt_exit(void)

132 {

133     platform_driver_unregister(&wdt_pdrv);

134     printk("bye wdt!\n");

135 }

136

137 module_init(wdt_init);

138 module_exit(wdt_exit);


既然說是靜態(tài)平臺類驅動,那就是需要修改內核代碼,方法在linux設備驅動歸納總結(九):1.platform設備驅動有介紹,在三處文件添加代碼:

1、arch/arm/mach-s3c2440/mach-mini2440.c

250 static struct platform_device *mini2440_devices[] __initdata = {

251     &s3c_device_usb,

252     &s3c_device_rtc,

253     &s3c_device_lcd,

254     &s3c_device_wdt,

255     &s3c_device_led,

256     &s3c_device_wdt_xb, //這是我新加的

257     &s3c_device_i2c0,

258     &s3c_device_iis,

259     &s3c_device_dm9k,

260     &net_device_cs8900,

261     &s3c24xx_uda134x,

262 };

2、arch/arm/plat-s3c24xx/devs.c

379 /* Watchdog xiaobai*/

380

381 static struct resource s3c_wdt_xb_resource[] = {

382     [0] = {

383         .start = 0x53000000,

384         .end = 0x530000ff,

385         .flags = IORESOURCE_MEM,

386     },

387     [1] = {

388         .start = IRQ_S3C2440_WDT,

389         .end = IRQ_S3C2440_WDT,

390         .flags = IORESOURCE_IRQ,

391     }

392 };

393

394 struct platform_device s3c_device_wdt_xb = {

395     .name = "s3c_wdt_xb",

396     .id = -1,

397     .num_resources = ARRAY_SIZE(s3c_wdt_xb_resource),

398     .resource = s3c_wdt_xb_resource,

399 };

400

401 EXPORT_SYMBOL(s3c_device_wdt_xb);

3、arch/arm/plat-s3c/include/plat/devs.h

27 extern struct platform_device s3c_device_dm9k;

28 extern struct platform_device net_device_cs8900;

29 extern struct platform_device s3c_device_fb;

30 extern struct platform_device s3c_device_usb;

31 extern struct platform_device s3c_device_lcd;

32 extern struct platform_device s3c_device_wdt;

33 extern struct platform_device s3c_device_led;

34 extern struct platform_device s3c_device_wdt_xb; //這是我添加的

35 extern struct platform_device s3c_device_i2c0;

36 extern struct platform_device s3c_device_i2c1;

37 extern struct platform_device s3c_device_iis;


修改后重新編譯內核,加載模塊后,內核會自動調用probe函數(shù),具體效果就是每隔一秒打印一句話。


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


五、第四個看門狗程序,代碼路徑11th_wdt/4th。


接下來就要注冊雜設備類驅動,并且提供ioctl命令給用戶空間控制看門狗。


先要在頭文件中實現(xiàn)幾個命令:

/*11th_wdt/4th/ioctl_wdt.h*/

1 #ifndef _WDT_H

2 #define _WDT_H

3

4 #define MAGIC 'x'

5 #define WDT_RESET _IO(MAGIC, 0) //產生一個數(shù)字

6 #define WDT_INTERRUPT _IO(MAGIC, 1)

7 #define WDT_START _IO(MAGIC, 2)

8 #define WDT_STOP _IO(MAGIC, 3)

9

10 #endif /* _WDT_H */

再看看ioctl的實現(xiàn),很簡單,四個命令對應四個不同的操作:

112 int s3c_wdt_ioctl (struct inode *node, struct file *filp,

113 unsigned int cmd, unsigned long args)

114 {

115     switch(cmd){

116         case WDT_RESET:

117             my_wdt.init_reset(&my_wdt);

118             break;

119         case WDT_INTERRUPT:

120             my_wdt.init_interrupt(&my_wdt);

121             break;

122         case WDT_START:

123             my_wdt.start(&my_wdt);

124             break;

125         case WDT_STOP:

126             my_wdt.stop(&my_wdt);

127             break;

128         default:

129             printk("unknow ioctl cmd!\n");

130             return - EINVAL;

131     }

132     return 0;

133 }

134

135 static struct file_operations wdt_fops = {

136     .ioctl = s3c_wdt_ioctl,

137 };

接著是實現(xiàn)雜設備類驅動:

139 /*******************

140 * misc class *

141 *******************/

142

143 static struct miscdevice wdt_misc = {

144     .name = "s3c_wdt",

145     .fops = &wdt_fops,

146 };

147

148 /*******************

149 * platform總線操作*

150 *******************/

151 static int s3c_wdt_probe(struct platform_device *pdev)

152 {

153     printk("[%s]\n", __FUNCTION__);

154     my_wdt.phys = pdev->resource[0].start;

155     my_wdt.irqno = pdev->resource[1].start;

156

157     init_wdt_device(&my_wdt);

158     misc_register(&wdt_misc);

159     return 0;

160 }

161

162 static int s3c_wdt_remove(struct platform_device *pdev)

163 {

164     printk("[%s]\n", __FUNCTION__);

165     misc_deregister(&wdt_misc);

166     destroy_wdt_device(&my_wdt);

167     return 0;

168 }

最后就可以寫個應用程序驗證一下了:

/*11th_wdt/4th/app.c */

8 #include "ioctl_wdt.h"

9

10 int main(int argc, char *argv[])

11 {

12     int fd;

13

14     fd = open("/dev/s3c_wdt", O_RDWR);

15     if(fd < 0)

16         perror("open");

17

18     printf("./app [func]\n");

19     printf("func : reset interrupt start stop\n");

20     printf("[%s]\n", argv[1]);

21

22     if(!strncasecmp("reset", argv[1], 5))

23         ioctl(fd, WDT_RESET);

24     if(!strncasecmp("interrupt", argv[1], 9))

25         ioctl(fd, WDT_INTERRUPT);

26     if(!strncasecmp("start", argv[1], 5))

27         ioctl(fd, WDT_START);

28     if(!strncasecmp("stop", argv[1], 4))

29         ioctl(fd, WDT_STOP);

30

31     return 0;

32 }

編譯后驗證一下,可以使用./app reset啟動復位功能,也可以./app interrupt & ./app start啟動定時功能。


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


六、第五個看門狗程序,代碼路徑11th_wdt/5th。


看門狗的驅動就基本完成了,最后還有個功能要補充,喂狗,直接上代碼:

65 static void s3c_wdt_feed(struct _wdt_t *wdt)

66 {

67     iowrite32((int)(WDT_1S * 10), wdt->wtcnt);

68 }

然后稍稍修改一下其他代碼就可以了。

編譯后運行,執(zhí)行./app reset后,只要在10秒內執(zhí)行./app feed,系統(tǒng)就不會重啟。


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


七、總結


簡單的看門狗驅動基本上就完成了,當然還有很多需要完善的地方,如設定定時的時間等。具體包含了以下知識點:

1、字符設備的方法;

2、io內存——ioremap;

3、中斷注冊;

4、platform設備驅動;

5、雜設備驅動;


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

源代碼: 11th_wdt.rar  

您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復

  

北京盛拓優(yōu)訊信息技術有限公司. 版權所有 京ICP備16024965號-6 北京市公安局海淀分局網監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關心和支持過ChinaUnix的朋友們 轉載本站內容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP