在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > ARM-Linux驅(qū)動--Watch Dog Timer(看門狗)驅(qū)動分析

            ARM-Linux驅(qū)動--Watch Dog Timer(看門狗)驅(qū)動分析

            作者: 時間:2016-11-20 來源:網(wǎng)絡(luò) 收藏
            硬件平臺:FL2440

            內(nèi)核版本:2.6.28

            本文引用地址:http://www.biyoush.com/article/201611/318869.htm

            主機平臺:Ubuntu 11,04

            內(nèi)核版本:2.6.39

            1、看門狗驅(qū)動的原理

            下圖是看門狗驅(qū)動的原理圖

            可以看出,PCLK是系統(tǒng)時鐘,經(jīng)過8位的預(yù)分頻,然后再被分頻(16、32、64、128)然后產(chǎn)生計數(shù)脈沖,進(jìn)行計數(shù),當(dāng)計數(shù)器WTCNT加到0或減到0,然后產(chǎn)生中斷,或引起系統(tǒng)復(fù)位。所以要隔一段時間,重置WTCNT的值,防止WTCNT減到0,稱之“喂狗”。

            2、驅(qū)動分析

            下面是自己的驅(qū)動分析,如有理解錯誤,請指正

            注,為了盡量是驅(qū)動容易理解,這個驅(qū)動暫時將有關(guān)電源管理的功能刪除了,等理解透徹再完善

            1. #include
            2. #include
            3. #include
            4. #include
            5. #include
            6. #include
            7. #include
            8. #include
            9. #include
            10. #includeinterrupt.h>
            11. #include
            12. #include
            13. #include
            14. #include
            15. #include
            16. #undefS3C_VA_WATCHDOG
            17. #defineS3C_VA_WATCHDOG(0)
            18. #include
            19. #definePFX"s3c2410-wdt:"
            20. #defineCONFIG_S3C2410_WATCHDOG_ATBOOT(0)
            21. #defineCONFIG_S3C2410_WATCHDOG_DEFAULT_TIME(15)
            22. staticintnowayout=WATCHDOG_NOWAYOUT;
            23. staticinttmr_margin=CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;
            24. staticinttmr_atboot=CONFIG_S3C2410_WATCHDOG_ATBOOT;
            25. staticintsoft_noboot=1;//設(shè)置默認(rèn)為執(zhí)行中斷
            26. staticintdebug;
            27. staticintcount;//用于計數(shù),控制LED燈的亮滅
            28. module_param(tmr_margin,int,0);
            29. module_param(tmr_atboot,int,0);
            30. module_param(nowayout,int,0);
            31. module_param(soft_noboot,int,0);
            32. module_param(debug,int,0);
            33. MODULE_PARM_DESC(tmr_margin,"Watchdogtmr_margininseconds.default="
            34. __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME)")");
            35. MODULE_PARM_DESC(tmr_atboot,
            36. "Watchdogisstartedatboottimeifsetto1,default="
            37. __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT));
            38. MODULE_PARM_DESC(nowayout,"Watchdogcannotbestoppedoncestarted(default="
            39. __MODULE_STRING(WATCHDOG_NOWAYOUT)")");
            40. MODULE_PARM_DESC(soft_noboot,"Watchdogaction,setto1toignorereboots,0to
            41. reboot(defaultdependsonONLY_TESTING)");
            42. MODULE_PARM_DESC(debug,"Watchdogdebug,setto>1fordebug,(default0)");
            43. typedefenumclose_state
            44. {
            45. CLOSE_STATE_NOT,
            46. CLOSE_STATE_ALLOW=0x4021
            47. }close_state_t;
            48. staticunsignedlongopen_lock;
            49. staticstructdevice*wdt_dev;/*platformdeviceattachedto*/
            50. staticstructresource*wdt_mem;//用來保存IO端口占用的內(nèi)存資源
            51. staticstructresource*wdt_irq;//保存wdt中斷號
            52. staticstructclk*wdt_clock;//保存從平臺獲取的watchdog時鐘
            53. staticvoid__iomem*wdt_base;//經(jīng)過ioremap后的內(nèi)存基地址
            54. staticunsignedintwdt_count;//保存向WTCNT寫的計數(shù)值
            55. staticclose_state_tallow_close;
            56. staticDEFINE_SPINLOCK(wdt_lock);//定義一個自旋鎖,用于資源的互斥訪問
            57. /*watchdogcontrolroutines*/
            58. #defineDBG(msg...)do{
            59. if(debug)
            60. printk(KERN_INFOmsg);
            61. }while(0)
            62. /*functions*/
            63. //喂狗函數(shù),實際上是將wdt_count寫入WTCNT寄存器
            64. staticvoids3c2410wdt_keepalive(void)
            65. {
            66. spin_lock(&wdt_lock);//給資源上鎖
            67. writel(wdt_count,wdt_base+S3C2410_WTCNT);//寫WTCNT寄存器
            68. spin_unlock(&wdt_lock);//解鎖資源,下同
            69. }
            70. staticvoid__s3c2410wdt_stop(void)
            71. {
            72. unsignedlongwtcon;
            73. wtcon=readl(wdt_base+S3C2410_WTCON);
            74. wtcon&=~(S3C2410_WTCON_ENABLE|S3C2410_WTCON_RSTEN);
            75. writel(wtcon,wdt_base+S3C2410_WTCON);//設(shè)備看門狗使能無效、復(fù)位功能無效
            76. }
            77. //停止watchdog計時
            78. staticvoids3c2410wdt_stop(void)
            79. {
            80. spin_lock(&wdt_lock);
            81. __s3c2410wdt_stop();
            82. spin_unlock(&wdt_lock);
            83. }
            84. //啟動watchdog計時
            85. staticvoids3c2410wdt_start(void)
            86. {
            87. unsignedlongwtcon;
            88. spin_lock(&wdt_lock);
            89. __s3c2410wdt_stop();
            90. wtcon=readl(wdt_base+S3C2410_WTCON);
            91. wtcon|=S3C2410_WTCON_ENABLE|S3C2410_WTCON_DIV128;//看門狗定時器使能、時鐘除數(shù)因子128
            92. if(soft_noboot)//使用參數(shù)soft_noboot來選擇看門狗到時是重啟還是執(zhí)行中斷函數(shù)
            93. {
            94. wtcon|=S3C2410_WTCON_INTEN;//中斷使能
            95. wtcon&=~S3C2410_WTCON_RSTEN;//復(fù)位功能無效
            96. }
            97. else
            98. {
            99. wtcon&=~S3C2410_WTCON_INTEN;//中斷不使能
            100. wtcon|=S3C2410_WTCON_RSTEN;//復(fù)位功能有效
            101. }
            102. writel(wdt_count,wdt_base+S3C2410_WTDAT);//將wdt_count寫入WTDAT
            103. writel(wdt_count,wdt_base+S3C2410_WTCNT);//將wdt_count寫入WTCNT
            104. writel(wtcon,wdt_base+S3C2410_WTCON);//設(shè)置WTCON
            105. spin_unlock(&wdt_lock);
            106. }
            107. //設(shè)置WatchDog周期timeout
            108. staticints3c2410wdt_set_heartbeat(inttimeout)
            109. {
            110. unsignedintfreq=clk_get_rate(wdt_clock);
            111. unsignedintcount;
            112. unsignedintdivisor=1;
            113. unsignedlongwtcon;
            114. if(timeout<1)
            115. return-EINVAL;
            116. freq/=128;
            117. count=timeout*freq;
            118. /*ifthecountisbiggerthanthewatchdogregister,
            119. thenworkoutwhatweneedtodo(andif)wecan
            120. actuallymakethisvalue
            121. */
            122. //如果計時的時間過大,則適當(dāng)加大預(yù)分頻值
            123. if(count>=0x10000)
            124. {
            125. for(divisor=1;divisor<=0x100;divisor++)
            126. {
            127. if((count/divisor)<0x10000)
            128. break;
            129. }
            130. //若預(yù)分頻最大仍不能滿足計時周期,則報錯
            131. if((count/divisor)>=0x10000)
            132. {
            133. dev_err(wdt_dev,"timeout%dtoobign",timeout);
            134. return-EINVAL;
            135. }
            136. }
            137. tmr_margin=timeout;
            138. count/=divisor;
            139. wdt_count=count;
            140. /*updatethepre-scaler*/
            141. wtcon=readl(wdt_base+S3C2410_WTCON);
            142. wtcon&=~S3C2410_WTCON_PRESCALE_MASK;
            143. wtcon|=S3C2410_WTCON_PRESCALE(divisor-1);
            144. writel(count,wdt_base+S3C2410_WTDAT);//是指WTDAT寄存器
            145. writel(wtcon,wdt_base+S3C2410_WTCON);//設(shè)置預(yù)分頻值
            146. return0;
            147. }
            148. /*
            149. */dev/watchdoghandling
            150. */
            151. staticints3c2410wdt_open(structinode*inode,structfile*file)
            152. {
            153. if(test_and_set_bit(0,&open_lock))//測試并設(shè)置open_lock第0位為1
            154. return-EBUSY;
            155. if(nowayout)
            156. __module_get(THIS_MODULE);
            157. allow_close=CLOSE_STATE_NOT;
            158. /*startthetimer*/
            159. s3c2410wdt_start();//啟動watchdog
            160. returnnonseekable_open(inode,file);
            161. }
            162. staticints3c2410wdt_release(structinode*inode,structfile*file)
            163. {
            164. /*
            165. *Shutoffthetimer.
            166. *Lockitinifitsamoduleandwesetnowayout
            167. */
            168. if(allow_close==CLOSE_STATE_ALLOW)
            169. s3c2410wdt_stop();
            170. else
            171. {
            172. dev_err(wdt_dev,"Unexpectedclose,notstoppingwatchdogn");
            173. s3c2410wdt_keepalive();
            174. }
            175. allow_close=CLOSE_STATE_NOT;
            176. clear_bit(0,&open_lock);//清楚open_lock第0位
            177. return0;
            178. }
            179. staticssize_ts3c2410wdt_write(structfile*file,constchar__user*data,
            180. size_tlen,loff_t*ppos)
            181. {
            182. /*
            183. *Refreshthetimer.
            184. */
            185. if(len)
            186. {
            187. if(!nowayout)
            188. {
            189. size_ti;
            190. /*Incaseitwassetlongago*/
            191. allow_close=CLOSE_STATE_NOT;
            192. for(i=0;i!=len;i++)
            193. {
            194. charc;
            195. if(get_user(c,data+i))//從用戶空間copy數(shù)據(jù)
            196. return-EFAULT;
            197. if(c==V)//當(dāng)輸入V時,關(guān)閉watchdog
            198. allow_close=CLOSE_STATE_ALLOW;
            199. }
            200. }
            201. //注意:這里要手動喂狗一次?!
            202. s3c2410wdt_keepalive();//由于將allow_close設(shè)置成CLOSE_STATE_ALLOW后,當(dāng)release時無法再次喂狗
            203. }
            204. returnlen;
            205. }
            206. #defineOPTIONSWDIOF_SETTIMEOUT|WDIOF_KEEPALIVEPING|WDIOF_MAGICCLOSE
            207. staticconststructwatchdog_infos3c2410_wdt_ident=
            208. {
            209. .options=OPTIONS,
            210. .firmware_version=0,
            211. .identity="S3C2410Watchdog",
            212. };
            213. //IO控制接口函數(shù)
            214. staticlongs3c2410wdt_ioctl(structfile*file,unsignedintcmd,
            215. unsignedlongarg)
            216. {
            217. void__user*argp=(void__user*)arg;
            218. int__user*p=argp;
            219. intnew_margin;
            220. switch(cmd){
            221. caseWDIOC_GETSUPPORT:
            222. returncopy_to_user(argp,&s3c2410_wdt_ident,
            223. sizeof(s3c2410_wdt_ident))?-EFAULT:0;
            224. caseWDIOC_GETSTATUS:
            225. caseWDIOC_GETBOOTSTATUS:
            226. returnput_user(0,p);
            227. caseWDIOC_KEEPALIVE:
            228. s3c2410wdt_keepalive();
            229. return0;
            230. caseWDIOC_SETTIMEOUT:
            231. if(get_user(new_margin,p))
            232. return-EFAULT;
            233. if(s3c2410wdt_set_heartbeat(new_margin))
            234. return-EINVAL;
            235. s3c2410wdt_keepalive();
            236. returnput_user(tmr_margin,p);
            237. caseWDIOC_GETTIMEOUT:
            238. returnput_user(tmr_margin,p);
            239. default:
            240. return-ENOTTY;
            241. }
            242. }
            243. /*kernelinterface*/
            244. //文件操作結(jié)構(gòu)體
            245. staticconststructfile_operationss3c2410wdt_fops=
            246. {
            247. .owner=THIS_MODULE,
            248. .llseek=no_llseek,//屏蔽seek操作
            249. .write=s3c2410wdt_write,//寫方法
            250. .unlocked_ioctl=s3c2410wdt_ioctl,//控制方法
            251. .open=s3c2410wdt_open,//代開設(shè)備方法
            252. .release=s3c2410wdt_release,//關(guān)閉設(shè)備方法
            253. };
            254. staticstructmiscdevices3c2410wdt_miscdev=
            255. {
            256. .minor=WATCHDOG_MINOR,
            257. .name="watchdog",
            258. .fops=&s3c2410wdt_fops,
            259. };
            260. /*interrupthandlercode*/
            261. staticirqreturn_ts3c2410wdt_irq(intirqno,void*param)
            262. {
            263. //dev_info(wdt_dev,"watchdogtimerexpired(irq)n");
            264. s3c2410_gpio_setpin(S3C2410_GPB10,(count++)%2);
            265. s3c2410wdt_keepalive();
            266. returnIRQ_HANDLED;
            267. }
            268. /*deviceinterface*/
            269. //注冊設(shè)備時執(zhí)行
            270. staticints3c2410wdt_probe(structplatform_device*pdev)
            271. {
            272. structresource*res;
            273. structdevice*dev;
            274. unsignedintwtcon;
            275. intstarted=0;
            276. intret;
            277. intsize;
            278. dev=&pdev->dev;
            279. wdt_dev=&pdev->dev;
            280. /*getthememoryregionforthewatchdogtimer*/
            281. //獲取IO端口資源,這里IORESOURCE_MEM和平臺設(shè)備中資源的定義一致
            282. res=platform_get_resource(pdev,IORESOURCE_MEM,0);
            283. if(res==NULL){
            284. dev_err(dev,"nomemoryresourcespecifiedn");
            285. return-ENOENT;
            286. }
            287. size=(res->end-res->start)+1;
            288. //申請內(nèi)存空間
            289. wdt_mem=request_mem_region(res->start,size,pdev->name);
            290. if(wdt_mem==NULL){
            291. dev_err(dev,"failedtogetmemoryregionn");
            292. ret=-ENOENT;
            293. gotoerr_req;
            294. }
            295. //地址映射,wdt_base為基地址
            296. wdt_base=ioremap(res->start,size);
            297. if(wdt_base==NULL){
            298. dev_err(dev,"failedtoioremap()regionn");
            299. ret=-EINVAL;
            300. gotoerr_req;
            301. }
            302. DBG("probe:mappedwdt_base=%pn",wdt_base);
            303. //從平臺設(shè)備中獲取中斷號
            304. wdt_irq=platform_get_resource(pdev,IORESOURCE_IRQ,0);
            305. if(wdt_irq==NULL){
            306. dev_err(dev,"noirqresourcespecifiedn");
            307. ret=-ENOENT;
            308. gotoerr_map;
            309. }
            310. //注冊中斷,中斷處理函數(shù)s3c2410wdt_irq()
            311. ret=request_irq(wdt_irq->start,s3c2410wdt_irq,0,pdev->name,pdev);
            312. if(ret!=0){
            313. dev_err(dev,"failedtoinstallirq(%d)n",ret);
            314. gotoerr_map;
            315. }
            316. //獲取系統(tǒng)時鐘
            317. wdt_clock=clk_get(&pdev->dev,"watchdog");
            318. if(IS_ERR(wdt_clock)){
            319. dev_err(dev,"failedtofindwatchdogclocksourcen");
            320. ret=PTR_ERR(wdt_clock);
            321. gotoerr_irq;
            322. }
            323. //使能時鐘
            324. clk_enable(wdt_clock);
            325. /*seeifwecanactuallysettherequestedtimermargin,andif
            326. *not,trythedefaultvalue*/
            327. if(s3c2410wdt_set_heartbeat(tmr_margin))
            328. {//這里第一次設(shè)置計時周期為tmr_margin,如果設(shè)置不成功,則重新設(shè)置為默認(rèn)值
            329. started=s3c2410wdt_set_heartbeat(
            330. CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
            331. if(started==0)
            332. dev_info(dev,
            333. "tmr_marginvalueoutofrange,default%dusedn",
            334. CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
            335. else
            336. dev_info(dev,"defaulttimervalueisoutofrange,cannotstartn");
            337. }
            338. //注冊設(shè)備
            339. ret=misc_register(&s3c2410wdt_miscdev);
            340. if(ret)
            341. {
            342. dev_err(dev,"cannotregistermiscdevonminor=%d(%d)n",
            343. WATCHDOG_MINOR,ret);
            344. gotoerr_clk;
            345. }
            346. if(tmr_atboot&&started==0)
            347. {
            348. dev_info(dev,"startingwatchdogtimern");
            349. s3c2410wdt_start();//啟動看門狗
            350. }
            351. elseif(!tmr_atboot)
            352. {
            353. /*ifwerenotenablingthewatchdog,thenensureitis
            354. *disabledifithasbeenleftrunningfromthebootloader
            355. *orothersource*/
            356. s3c2410wdt_stop();
            357. }
            358. /*printoutastatementofreadiness*/
            359. wtcon=readl(wdt_base+S3C2410_WTCON);
            360. dev_info(dev,"watchdog%sactive,reset%sabled,irq%sabledn",
            361. (wtcon&S3C2410_WTCON_ENABLE)?"":"in",
            362. (wtcon&S3C2410_WTCON_RSTEN)?"":"dis",
            363. (wtcon&S3C2410_WTCON_INTEN)?"":"en");
            364. //設(shè)置GPB10端口為輸出端口,用于點亮LED10
            365. s3c2410_gpio_cfgpin(S3C2410_GPB10,S3C2410_GPB10_OUTP);
            366. return0;
            367. //出錯跳轉(zhuǎn)表,異常處理
            368. err_clk:
            369. clk_disable(wdt_clock);
            370. clk_put(wdt_clock);
            371. err_irq:
            372. free_irq(wdt_irq->start,pdev);
            373. err_map:
            374. iounmap(wdt_base);
            375. err_req:
            376. release_resource(wdt_mem);
            377. kfree(wdt_mem);
            378. returnret;
            379. }
            380. //設(shè)備移除函數(shù),釋放資源和映射
            381. staticints3c2410wdt_remove(structplatform_device*dev)
            382. {
            383. release_resource(wdt_mem);
            384. kfree(wdt_mem);
            385. wdt_mem=NULL;
            386. free_irq(wdt_irq->start,dev);
            387. wdt_irq=NULL;
            388. clk_disable(wdt_clock);
            389. clk_put(wdt_clock);
            390. wdt_clock=NULL;
            391. iounmap(wdt_base);
            392. misc_deregister(&s3c2410wdt_miscdev);
            393. return0;
            394. }
            395. //關(guān)閉看門狗
            396. staticvoids3c2410wdt_shutdown(structplatform_device*dev)
            397. {
            398. s3c2410wdt_stop();
            399. }
            400. //定義平臺設(shè)備驅(qū)動
            401. staticstructplatform_drivers3c2410wdt_driver={
            402. .probe=s3c2410wdt_probe,
            403. .remove=s3c2410wdt_remove,
            404. .shutdown=s3c2410wdt_shutdown,
            405. .driver={
            406. .owner=THIS_MODULE,
            407. .name="s3c2410-wdt",//該名稱參照內(nèi)核源碼中該資源的名稱,兩者必須一致
            408. },
            409. };
            410. staticcharbanner[]__initdata=
            411. KERN_INFO"S3C2410WatchdogTimer,(c)2004SimtecElectronicsn";
            412. //驅(qū)動安裝時執(zhí)行
            413. staticint__initwatchdog_init(void)
            414. {
            415. printk(banner);
            416. returnplatform_driver_register(&s3c2410wdt_driver);//注冊設(shè)備
            417. }
            418. //驅(qū)動移除是執(zhí)行
            419. staticvoid__exitwatchdog_exit(void)
            420. {
            421. platform_driver_unregister(&s3c2410wdt_driver);//移除設(shè)備
            422. }
            423. module_init(watchdog_init);
            424. module_exit(watchdog_exit);
            425. MODULE_AUTHOR("YanMing");
            426. MODULE_DESCRIPTION("S3C2410WatchdogDeviceDriver");
            427. MODULE_LICENSE("GPL");
            428. MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);

            設(shè)置默認(rèn)不是重啟機器,而是執(zhí)行中斷函數(shù),當(dāng)不喂狗,計數(shù)器減到0,點亮LED,然后喂狗,重新計數(shù)。


            關(guān)鍵詞: ARMLinux驅(qū)動看門

            評論


            技術(shù)專區(qū)

            關(guān)閉