歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> mini6410 看門狗源碼分析

mini6410 看門狗源碼分析

日期:2017/3/1 10:46:45   编辑:Linux編程

看門狗代碼放在linux/drivers/char/watchdog/s3c2410_wdt.c中分析如下:

  1. /* linux/drivers/char/watchdog/s3c2410_wdt.c
  2. *
  3. * Copyright (c) 2004 Simtec Electronics
  4. * Ben Dooks <[email protected]>
  5. *
  6. * S3C2410 Watchdog Timer Support
  7. *
  8. * Based on, softdog.c by Alan Cox,
  9. * (c) Copyright 1996 Alan Cox <[email protected]>
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  24. */
  25. #include <linux/module.h>
  26. #include <linux/moduleparam.h>
  27. #include <linux/types.h>
  28. #include <linux/timer.h>
  29. #include <linux/miscdevice.h>
  30. #include <linux/watchdog.h>
  31. #include <linux/fs.h>
  32. #include <linux/init.h>
  33. #include <linux/platform_device.h>
  34. #include <linux/interrupt.h>
  35. #include <linux/clk.h>
  36. #include <linux/uaccess.h>
  37. #include <linux/io.h>
  38. #include <linux/cpufreq.h>
  39. #include <linux/slab.h>
  40. #include <mach/map.h>
  41. #undef S3C_VA_WATCHDOG
  42. #define S3C_VA_WATCHDOG (0)
  43. #include <plat/regs-watchdog.h>
  44. #define PFX "s3c2410-wdt: "
  45. #define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
  46. #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)
  47. /*
  48. *nowayout表示決不允許看門狗關閉,為1表示不允許關閉,為0表示允許關閉;
  49. *tmr_margin表示默認的看門狗喂狗時間為15s;
  50. *tmr_atboot表示系統啟動時就使能看門狗,為1表示使能,為0表示關閉;
  51. *soft_noboot表示看門狗工作的方式,看門狗可以作為定時器使用也可作為復位硬件使用,
  52. *soft_noboot為1表示看門狗作為定時器使用,不發送復位信號;
  53. *debug表示是否使用調試模式來調試代碼,該模式中,會打印調試信息。
  54. */
  55. static int nowayout = WATCHDOG_NOWAYOUT;
  56. static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;
  57. static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT;
  58. static int soft_noboot;
  59. static int debug;
  60. module_param(tmr_margin, int, 0);
  61. module_param(tmr_atboot, int, 0);
  62. module_param(nowayout, int, 0);
  63. module_param(soft_noboot, int, 0);
  64. module_param(debug, int, 0);
  65. MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. (default="
  66. __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")");
  67. MODULE_PARM_DESC(tmr_atboot,
  68. "Watchdog is started at boot time if set to 1, default="
  69. __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT));
  70. MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
  71. __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  72. MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, "
  73. "0 to reboot (default 0)");
  74. MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)");
  75. static unsigned long open_lock;
  76. static struct device *wdt_dev; /* platform device attached to */
  77. static struct resource *wdt_mem;
  78. static struct resource *wdt_irq;
  79. static struct clk *wdt_clock;
  80. static void __iomem *wdt_base;
  81. static unsigned int wdt_count;
  82. static char expect_close;
  83. static DEFINE_SPINLOCK(wdt_lock);
  84. /* watchdog control routines */
  85. #define DBG(msg...) do { \
  86. if (debug) \
  87. printk(KERN_INFO msg); \
  88. } while (0)
  89. /* functions */
  90. static void s3c2410wdt_keepalive(void)
  91. {
  92. spin_lock(&wdt_lock);
  93. writel(wdt_count, wdt_base + S3C2410_WTCNT);
  94. spin_unlock(&wdt_lock);
  95. }
  96. static void __s3c2410wdt_stop(void)
  97. {
  98. unsigned long wtcon;
  99. wtcon = readl(wdt_base + S3C2410_WTCON);
  100. wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN);
  101. writel(wtcon, wdt_base + S3C2410_WTCON);
  102. }
  103. static void s3c2410wdt_stop(void)
  104. {
  105. spin_lock(&wdt_lock);
  106. __s3c2410wdt_stop();
  107. spin_unlock(&wdt_lock);
  108. }
  109. static void s3c2410wdt_start(void)
  110. {
  111. unsigned long wtcon;
  112. spin_lock(&wdt_lock);
  113. /*首先停止看門狗*/
  114. __s3c2410wdt_stop();
  115. /*讀看門狗的控制寄存器*/
  116. wtcon = readl(wdt_base + S3C2410_WTCON);
  117. /*使能看門狗,設置時鐘分頻值為128*/
  118. wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128;
  119. /*上邊說過看門狗一個作為一個正常的16位內部定時器也可作為復位硬件*/
  120. if (soft_noboot) {//如果作為內部定時器
  121. wtcon |= S3C2410_WTCON_INTEN;//開中斷使能
  122. wtcon &= ~S3C2410_WTCON_RSTEN;//關閉復位使能
  123. } else {//如果作為復位硬件
  124. wtcon &= ~S3C2410_WTCON_INTEN;//關閉中斷使能
  125. wtcon |= S3C2410_WTCON_RSTEN;//開復位使能
  126. }
  127. DBG("%s: wdt_count=0x%08x, wtcon=%08lx\n",
  128. __func__, wdt_count, wtcon);
  129. /*這裡為什麼要設置WTCNT的值,不是WTDAT中的值自動載入WTCNT嗎?看看datasheet就知道了,看門狗定時器最初
  130. *使能的時候,WTDAT寄存器的值不會自動載入時 間計數器,所以WTCNT寄存器必須在使能它之前設置一個初始值
  131. */
  132. writel(wdt_count, wdt_base + S3C2410_WTDAT);
  133. writel(wdt_count, wdt_base + S3C2410_WTCNT);
  134. writel(wtcon, wdt_base + S3C2410_WTCON);
  135. spin_unlock(&wdt_lock);
  136. }
  137. static inline int s3c2410wdt_is_running(void)
  138. {
  139. return readl(wdt_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE;
  140. }
  141. static int s3c2410wdt_set_heartbeat(int timeout)
  142. {
  143. /*首先獲得看門狗的時鐘*/
  144. unsigned long freq = clk_get_rate(wdt_clock);
  145. unsigned int count;
  146. unsigned int divisor = 1;
  147. unsigned long wtcon;
  148. if (timeout < 1)
  149. return -EINVAL;
  150. freq /= 128;
  151. /*秒數乘以每秒的時間滴答等於計數值*/
  152. count = timeout * freq;
  153. DBG("%s: count=%d, timeout=%d, freq=%lu\n",
  154. __func__, count, timeout, freq);
  155. /* if the count is bigger than the watchdog register,
  156. then work out what we need to do (and if) we can
  157. actually make this value
  158. */
  159. /*計數值不能大於WTCNT的最大范圍,WTCNT是一個16位的計數器,最大值是0x10000*/
  160. if (count >= 0x10000) {
  161. for (divisor = 1; divisor <= 0x100; divisor++) {
  162. if ((count / divisor) < 0x10000)
  163. break;
  164. }
  165. /*未找到返回錯誤*/
  166. if ((count / divisor) >= 0x10000) {
  167. dev_err(wdt_dev, "timeout %d too big\n", timeout);
  168. return -EINVAL;
  169. }
  170. }
  171. /*看門狗的喂狗時間*/
  172. tmr_margin = timeout;
  173. DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n",
  174. __func__, timeout, divisor, count, count/divisor);
  175. count /= divisor;
  176. wdt_count = count;
  177. /* update the pre-scaler */
  178. //讀看門狗的控制寄存器
  179. wtcon = readl(wdt_base + S3C2410_WTCON);
  180. //看門狗控制器高8位清零,也就是預分頻部分清零
  181. wtcon &= ~S3C2410_WTCON_PRESCALE_MASK;
  182. //填入預分頻系數
  183. wtcon |= S3C2410_WTCON_PRESCALE(divisor-1);
  184. //填入計數值
  185. writel(count, wdt_base + S3C2410_WTDAT);
  186. //填入控制寄存器的值
  187. writel(wtcon, wdt_base + S3C2410_WTCON);
  188. return 0;
  189. }
  190. /*
  191. * /dev/watchdog handling
  192. */
  193. static int s3c2410wdt_open(struct inode *inode, struct file *file)
  194. {
  195. /*檢查open_lock的第0位,如果open_lock的第0位為0,則表示test_and_set_bit的返回值為0,
  196. 表示wdt設備沒有被其他進程打開,如果為1,表示被其他進程打開,返回EBUSY*/
  197. if (test_and_set_bit(0, &open_lock))
  198. return -EBUSY;
  199. /*如果決不允許關閉看門狗,增加引用計數*/
  200. if (nowayout)
  201. __module_get(THIS_MODULE);
  202. /*設為不允許關閉*/
  203. expect_close = 0;
  204. /* start the timer */
  205. /*開啟看門狗*/
  206. s3c2410wdt_start();
  207. /*這些寄存器不需要像文件一樣對位置進行尋址*/
  208. return nonseekable_open(inode, file);
  209. }
  210. static int s3c2410wdt_release(struct inode *inode, struct file *file)
  211. {
  212. /*
  213. * Shut off the timer.
  214. * Lock it in if it's a module and we set nowayout
  215. */
  216. if (expect_close == 42)//看門狗為允許關閉狀態
  217. s3c2410wdt_stop();//關閉看門狗
  218. else {
  219. dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n");
  220. s3c2410wdt_keepalive();//否則喂狗
  221. }
  222. expect_close = 0; //設為不允許關閉
  223. clear_bit(0, &open_lock);//將open_lock的第0位設為0,是原子操作
  224. return 0;
  225. }
  226. static ssize_t s3c2410wdt_write(struct file *file, const char __user *data,
  227. size_t len, loff_t *ppos)
  228. {
  229. /*
  230. * Refresh the timer.
  231. */
  232. if (len) {//有數據寫入len不為0
  233. if (!nowayout) {//允許關閉
  234. size_t i;
  235. /* In case it was set long ago */
  236. expect_close = 0; //關閉允許關閉狀態
  237. for (i = 0; i != len; i++) {
  238. char c;
  239. if (get_user(c, data + i))
  240. return -EFAULT;
  241. if (c == 'V')//如果向設備寫入'V',就允許關閉設
  242. expect_close = 42;
  243. }
  244. }
  245. s3c2410wdt_keepalive();
  246. }
  247. return len;
  248. }
  249. #define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)
  250. static const struct watchdog_info s3c2410_wdt_ident = {
  251. .options = OPTIONS,
  252. .firmware_version = 0,
  253. .identity = "S3C2410 Watchdog",
  254. };
  255. static long s3c2410wdt_ioctl(struct file *file, unsigned int cmd,
  256. unsigned long arg)
  257. {
  258. void __user *argp = (void __user *)arg;
  259. int __user *p = argp;
  260. int new_margin;
  261. switch (cmd) {
  262. case WDIOC_GETSUPPORT://獲得看門狗設備的信息
  263. return copy_to_user(argp, &s3c2410_wdt_ident,
  264. sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0;
  265. case WDIOC_GETSTATUS:
  266. case WDIOC_GETBOOTSTATUS:
  267. return put_user(0, p);
  268. case WDIOC_KEEPALIVE://對看門狗進行喂狗
  269. s3c2410wdt_keepalive();
  270. return 0;
  271. case WDIOC_SETTIMEOUT://設置看門狗的超時時間
  272. if (get_user(new_margin, p))
  273. return -EFAULT;
  274. if (s3c2410wdt_set_heartbeat(new_margin))
  275. return -EINVAL;
  276. s3c2410wdt_keepalive();
  277. return put_user(tmr_margin, p);
  278. case WDIOC_GETTIMEOUT:
  279. return put_user(tmr_margin, p);
  280. default:
  281. return -ENOTTY;
  282. }
  283. }
  284. /* kernel interface */
  285. /*
  286. *看門狗驅動作為字符驅動的file_operations結構
  287. */
  288. static const struct file_operations s3c2410wdt_fops = {
  289. .owner = THIS_MODULE,
  290. .llseek = no_llseek,
  291. .write = s3c2410wdt_write,
  292. .unlocked_ioctl = s3c2410wdt_ioctl,
  293. .open = s3c2410wdt_open,
  294. .release = s3c2410wdt_release,
  295. };
  296. static struct miscdevice s3c2410wdt_miscdev = {
  297. .minor = WATCHDOG_MINOR,
  298. .name = "watchdog",
  299. .fops = &s3c2410wdt_fops,
  300. };
  301. /* interrupt handler code */
  302. /*
  303. *如果選擇了看門狗作為內部定時器,則當計數值為0時調用中斷處理函數,中斷處理函數的主要功能就是喂狗
  304. */
  305. static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
  306. {
  307. dev_info(wdt_dev, "watchdog timer expired (irq)\n");
  308. /*中斷處理中調用喂狗*/
  309. s3c2410wdt_keepalive();
  310. return IRQ_HANDLED;
  311. }
  312. #ifdef CONFIG_CPU_FREQ
  313. static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb,
  314. unsigned long val, void *data)
  315. {
  316. int ret;
  317. if (!s3c2410wdt_is_running())
  318. goto done;
  319. if (val == CPUFREQ_PRECHANGE) {
  320. /* To ensure that over the change we don't cause the
  321. * watchdog to trigger, we perform an keep-alive if
  322. * the watchdog is running.
  323. */
  324. s3c2410wdt_keepalive();
  325. } else if (val == CPUFREQ_POSTCHANGE) {
  326. s3c2410wdt_stop();
  327. ret = s3c2410wdt_set_heartbeat(tmr_margin);
  328. if (ret >= 0)
  329. s3c2410wdt_start();
  330. else
  331. goto err;
  332. }
  333. done:
  334. return 0;
  335. err:
  336. dev_err(wdt_dev, "cannot set new value for timeout %d\n", tmr_margin);
  337. return ret;
  338. }
  339. static struct notifier_block s3c2410wdt_cpufreq_transition_nb = {
  340. .notifier_call = s3c2410wdt_cpufreq_transition,
  341. };
  342. static inline int s3c2410wdt_cpufreq_register(void)
  343. {
  344. return cpufreq_register_notifier(&s3c2410wdt_cpufreq_transition_nb,
  345. CPUFREQ_TRANSITION_NOTIFIER);
  346. }
  347. static inline void s3c2410wdt_cpufreq_deregister(void)
  348. {
  349. cpufreq_unregister_notifier(&s3c2410wdt_cpufreq_transition_nb,
  350. CPUFREQ_TRANSITION_NOTIFIER);
  351. }
  352. #else
  353. static inline int s3c2410wdt_cpufreq_register(void)
  354. {
  355. return 0;
  356. }
  357. static inline void s3c2410wdt_cpufreq_deregister(void)
  358. {
  359. }
  360. #endif
  361. /* device interface */
  362. static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
  363. {
  364. struct resource *res;
  365. struct device *dev;
  366. unsigned int wtcon;
  367. int started = 0;
  368. int ret;
  369. int size;
  370. DBG("%s: probe=%p\n", __func__, pdev);
  371. /*平台設備中的設備結構體device*/
  372. dev = &pdev->dev;
  373. wdt_dev = &pdev->dev;
  374. /* get the memory region for the watchdog timer */
  375. /*獲得看門狗的內存資源*/
  376. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  377. /*獲取失敗則推出*/
  378. if (res == NULL) {
  379. dev_err(dev, "no memory resource specified\n");
  380. return -ENOENT;
  381. }
  382. /*內存資源所占的字節數*/
  383. size = resource_size(res);
  384. /*申請一塊IO內存,對應看門狗的3個寄存器*/
  385. wdt_mem = request_mem_region(res->start, size, pdev->name);
  386. if (wdt_mem == NULL) {
  387. dev_err(dev, "failed to get memory region\n");
  388. return -EBUSY;
  389. }
  390. /*獲得虛擬地址*/
  391. wdt_base = ioremap(res->start, size);
  392. if (wdt_base == NULL) {
  393. dev_err(dev, "failed to ioremap() region\n");
  394. ret = -EINVAL;
  395. goto err_req;
  396. }
  397. DBG("probe: mapped wdt_base=%p\n", wdt_base);
  398. /*申請中斷*/
  399. wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
  400. if (wdt_irq == NULL) {
  401. dev_err(dev, "no irq resource specified\n");
  402. ret = -ENOENT;
  403. goto err_map;
  404. }
  405. /*並注冊中斷處理函數*/
  406. ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev);
  407. if (ret != 0) {
  408. dev_err(dev, "failed to install irq (%d)\n", ret);
  409. goto err_map;
  410. }
  411. /*獲得看門狗時鐘*/
  412. wdt_clock = clk_get(&pdev->dev, "watchdog");
  413. if (IS_ERR(wdt_clock)) {
  414. dev_err(dev, "failed to find watchdog clock source\n");
  415. ret = PTR_ERR(wdt_clock);
  416. goto err_irq;
  417. }
  418. /*時鐘使能*/
  419. clk_enable(wdt_clock);
  420. if (s3c2410wdt_cpufreq_register() < 0) {
  421. printk(KERN_ERR PFX "failed to register cpufreq\n");
  422. goto err_clk;
  423. }
  424. /* see if we can actually set the requested timer margin, and if
  425. * not, try the default value */
  426. /*設置看門狗復位時間,如果成功返回0*/
  427. if (s3c2410wdt_set_heartbeat(tmr_margin)) {
  428. /*如果不成功,看門狗的復位時間設置成默認值*/
  429. started = s3c2410wdt_set_heartbeat(
  430. CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
  431. if (started == 0)
  432. dev_info(dev,
  433. "tmr_margin value out of range, default %d used\n",
  434. CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
  435. else
  436. dev_info(dev, "default timer value is out of range, "
  437. "cannot start\n");
  438. }
  439. /*注冊混雜設備*/
  440. ret = misc_register(&s3c2410wdt_miscdev);
  441. if (ret) {
  442. dev_err(dev, "cannot register miscdev on minor=%d (%d)\n",
  443. WATCHDOG_MINOR, ret);
  444. goto err_cpufreq;
  445. }
  446. /*如果開機的時候就啟動看門狗*/
  447. if (tmr_atboot && started == 0) {
  448. dev_info(dev, "starting watchdog timer\n");
  449. s3c2410wdt_start();//啟動看門狗
  450. } else if (!tmr_atboot) {
  451. /* if we're not enabling the watchdog, then ensure it is
  452. * disabled if it has been left running from the bootloader
  453. * or other source */
  454. s3c2410wdt_stop();//關閉看門狗
  455. }
  456. /* print out a statement of readiness */
  457. /*讀出看門狗控制寄存器的值*/
  458. wtcon = readl(wdt_base + S3C2410_WTCON);
  459. /*打印看門狗是否使能,是否允許發出復位信號,是否允許發出中斷信號*/
  460. dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n",
  461. (wtcon & S3C2410_WTCON_ENABLE) ? "" : "in",
  462. (wtcon & S3C2410_WTCON_RSTEN) ? "" : "dis",
  463. (wtcon & S3C2410_WTCON_INTEN) ? "" : "en");
  464. return 0;
  465. err_cpufreq:
  466. s3c2410wdt_cpufreq_deregister();
  467. err_clk:
  468. clk_disable(wdt_clock);
  469. clk_put(wdt_clock);
  470. err_irq:
  471. free_irq(wdt_irq->start, pdev);
  472. err_map:
  473. iounmap(wdt_base);
  474. err_req:
  475. release_resource(wdt_mem);
  476. kfree(wdt_mem);
  477. return ret;
  478. }
  479. static int __devexit s3c2410wdt_remove(struct platform_device *dev)
  480. {
  481. misc_deregister(&s3c2410wdt_miscdev);//注銷混雜設備
  482. s3c2410wdt_cpufreq_deregister();
  483. clk_disable(wdt_clock);//關閉時鐘
  484. clk_put(wdt_clock);//減少時鐘引用計數
  485. wdt_clock = NULL;
  486. free_irq(wdt_irq->start, dev);//釋放中斷號
  487. wdt_irq = NULL;
  488. iounmap(wdt_base);//關閉內存映射
  489. release_resource(wdt_mem);//釋放平台資源
  490. kfree(wdt_mem);//釋放I/O內存
  491. wdt_mem = NULL;
  492. return 0;
  493. }
  494. static void s3c2410wdt_shutdown(struct platform_device *dev)
  495. {
  496. s3c2410wdt_stop();
  497. }
  498. #ifdef CONFIG_PM
  499. static unsigned long wtcon_save;
  500. static unsigned long wtdat_save;
  501. /*
  502. *平台驅動中的電源管理部分
  503. */
  504. static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state)
  505. {
  506. /* Save watchdog state, and turn it off. */
  507. /*只要保存S3C2410_WTDAT就可以了,不需要保存S3C2410_WTCNT,
  508. *S3C2410_WTCNT的值會在系統還原的時候直接賦為S3C2410_WTDAT中的值
  509. */
  510. wtcon_save = readl(wdt_base + S3C2410_WTCON);
  511. wtdat_save = readl(wdt_base + S3C2410_WTDAT);
  512. /* Note that WTCNT doesn't need to be saved. */
  513. s3c2410wdt_stop();
  514. return 0;
  515. }
  516. static int s3c2410wdt_resume(struct platform_device *dev)
  517. {
  518. /* Restore watchdog state. */
  519. writel(wtdat_save, wdt_base + S3C2410_WTDAT);
  520. writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */
  521. writel(wtcon_save, wdt_base + S3C2410_WTCON);
  522. printk(KERN_INFO PFX "watchdog %sabled\n",
  523. (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
  524. return 0;
  525. }
  526. #else
  527. #define s3c2410wdt_suspend NULL
  528. #define s3c2410wdt_resume NULL
  529. #endif /* CONFIG_PM */
  530. /*
  531. *S3C2410的看門狗同時具有多重身份:字符設備,混雜設備,平台設備。
  532. *下面是看門狗驅動作為平台驅動的描述:
  533. */
  534. static struct platform_driver s3c2410wdt_driver = {
  535. .probe = s3c2410wdt_probe,
  536. .remove = __devexit_p(s3c2410wdt_remove),
  537. .shutdown = s3c2410wdt_shutdown,
  538. .suspend = s3c2410wdt_suspend,
  539. .resume = s3c2410wdt_resume,
  540. .driver = {
  541. .owner = THIS_MODULE,
  542. .name = "s3c2410-wdt",
  543. },
  544. };
  545. static char banner[] __initdata =
  546. KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n";
  547. /*
  548. *看門狗驅動作為平台驅動的注冊
  549. */
  550. static int __init watchdog_init(void)
  551. {
  552. printk(banner);
  553. return platform_driver_register(&s3c2410wdt_driver);
  554. }
  555. static void __exit watchdog_exit(void)
  556. {
  557. platform_driver_unregister(&s3c2410wdt_driver);
  558. }
  559. module_init(watchdog_init);
  560. module_exit(watchdog_exit);
  561. MODULE_AUTHOR("Ben Dooks <[email protected]>, "
  562. "Dimitry Andric <[email protected]>");
  563. MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver");
  564. MODULE_LICENSE("GPL");
  565. MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
  566. MODULE_ALIAS("platform:s3c2410-wdt");
Copyright © Linux教程網 All Rights Reserved