Analysis of S3C2440 driver -- dog driver

Source: Internet
Author: User

This article assumes that you have understood the working principle of the watchdog and have 2440 datasheet in your hand. You can view the registers related to the watchdog at any time. I am only focused on analyzing the driver here. Sorry ~

 

 

I borrowed an online friend ☆& Cold smoke ☆to describe the structure diagram of the dog driver. The summary is still quite in place, here, we assume that the copy is as follows (if you offend the original author, please immediately inform us, immediately delete and apologize). You can follow the structure chart to better understand the slightly complex relationship in the driver.

 

After reading the structure diagram, I must have a general understanding of the composition of the program. Paste the code and analyze it.

 

Watchdog_init & watchdog_exit

Static int _ init watchdog_init (void) <br/>{< br/> printk (banner); <br/> return platform_driver_register (& s3c2410wdt_driver ); <br/>}</P> <p> static void _ exit watchdog_exit (void) <br/>{< br/> platform_driver_unregister (& s3c2410wdt_driver ); <br/>}</P> <p> module_init (watchdog_init); <br/> module_exit (watchdog_exit );

The above two functions are the entire driver's entry and exit, respectively, to complete the registration of the platform device and the cancellation of the platform device action, its operation of the platform device is described by the structure s3c2410wdt_driver, the Code is as follows:

 

Structure: s3c2410wdt_driver

Static struct platform_driver s3c2410wdt_driver ={< br/>. probe = s3c2410wdt_probe, <br/>. remove = _ devexit_p (s3c2410wdt_remove), <br/>. shutdown = s3c2410wdt_shutdown, <br/>. suspend = s3c2410wdt_suspend, <br/>. resume = s3c2410wdt_resume, <br/>. driver ={< br/>. owner = this_module, <br/>. name = "s3c2410-wdt", <br/>}, <br/> };

Corresponding to the diagram at the beginning of the article, the above struct is bound with five functions and some of its own information. The functions implemented by the five functions are as follows.

 

S3c2410wdt_remove

Static int _ devexit s3c2410wdt_remove (struct platform_device * Dev) <br/>{< br/> release_resource (wdt_mem ); // release the acquired watchdog platform device Io resources <br/> kfree (wdt_mem); <br/> wdt_mem = NULL; </P> <p> free_irq (wdt_irq-> Start, Dev); // release interrupt (important) <br/> wdt_irq = NULL; </P> <p> clk_disable (wdt_clock); // release the watchdog clock <br/> clk_put (wdt_clock); <br/> wdt_clock = NULL; </P> <p> iounmap (wdt_base); // release the memory ing address <br/> misc_deregister (& s3c2410wdt_miscdev); // cancel the Hybrid device <br/> return 0; <br/>}

 

S3c2410wdt_shutdown

Static void s3c2410wdt_shutdown (struct platform_device * Dev) <br/>{< br/> s3c2410wdt_stop (); <br/>}</P> <p> static void s3c2410wdt_stop (void) <br/>{< br/> spin_lock (& wdt_lock); // spin lock <br/>__ s3c2410wdt_stop (); <br/> spin_unlock (& wdt_lock ); <br/>}</P> <p> static void _ s3c2410wdt_stop (void) <br/>{< br/> unsigned long wtcon; </P> <p> // you can directly operate the watchdog register, how to assign values and assign values <br/> // read the data manual to learn more! <Br/> wtcon = readl (wdt_base + s3c2410_wtcon); <br/> wtcon & = ~ (S3c2410_wtcon_enable | s3c2410_wtcon_rsten); <br/> writel (wtcon, wdt_base + s3c2410_wtcon); <br/>}

 

S3c2410wdt_suspend

Static int s3c2410wdt_suspend (struct platform_device * Dev, pm_message_t state) <br/>{< br/>/* Save the watchdog status, and then disable it, pause the function */<br/> wtcon_save = readl (wdt_base + s3c2410_wtcon); <br/> wtdat_save = readl (wdt_base + s3c2410_wtdat ); </P> <p>/* Note that wtcnt doesn't need to be saved. */<br/> s3c2410wdt_stop (); </P> <p> return 0; <br/>}

 

S3c2410wdt_resume

Static int s3c2410wdt_resume (struct platform_device * Dev) <br/>{< br/>/* reinstall the watchdog status */</P> <p> writel (wtdat_save, wdt_base + s3c2410_wtdat); <br/> writel (wtdat_save, wdt_base + s3c2410_wtcnt);/* reset count */<br/> writel (wtcon_save, wdt_base + s3c2410_wtcon ); </P> <p> printk (kern_info pfx "watchdog % sabled/N", <br/> (wtcon_save & s3c2410_wtcon_enable )? "EN": "dis"); </P> <p> return 0; <br/>}

 

S3c2410wdt_probe

Static int _ devinit s3c2410wdt_probe (struct platform_device * pdev) <br/>{< br/> struct resource * res; // defines a resource, used to save the obtained watchdog Io resources <br/> struct device * dev; <br/> unsigned int wtcon; <br/> int started = 0; <br/> int ret; <br/> int size; </P> <p> dbg ("% s: Probe = % P/N", _ FUNC __, pdev); </P> <p> Dev = & pdev-> dev; <br/> wdt_dev = & pdev-> dev; </P> <p>/* get the memory region for the watchdog timer */</P> <p> // obtain the watc The I/O port resources used by hdog platform devices. Note that the ioresource_mem flag is <br/> // consistent with the watchdog platform device definition <br/> res = platform_get_resource (pdev, ioresource_mem, 0); <br/> If (RES = NULL) {<br/> dev_err (Dev, "no memory resource specified/N "); <br/> return-enoent; <br/>}</P> <p> size = (res-> end-res-> Start) + 1; </P> <p> // request_mem_region indicates that this physical address is used by itself <br/> wdt_mem = request_mem_region (res-> Start, size, pdev-> name ); <br/> If (wdt_mem = Null) {<br/> dev_err (Dev, "failed to get memory region/N"); <br/> ret =-enoent; <br/> goto err_req; <br/>}</P> <p> // map the watchdog I/O port to the memory virtual address, size is the length of the ing address <br/> wdt_base = ioremap (res-> Start, size); <br/> If (wdt_base = NULL) {<br/> dev_err (Dev, "failed to ioremap () Region/N"); <br/> ret =-einval; <br/> goto err_req; <br/>}</P> <p> dbg ("probe: mapped wdt_base = % P/N", wdt_base ); </P> <p> // obtain the interrupt number. <br/> wdt_irq = Platform_get_resource (pdev, ioresource_irq, 0); <br/> If (wdt_irq = NULL) {<br/> dev_err (Dev, "No IRQ resource specified/N "); <br/> ret =-enoent; <br/> goto err_map; <br/>}</P> <p> // application interruption <br/> ret = request_irq (wdt_irq-> Start, s3c2410wdt_irq, 0, pdev-> name, pdev); <br/> If (Ret! = 0) {<br/> dev_err (Dev, "failed to install IRQ (% d)/n", RET); <br/> goto err_map; <br/>}</P> <p> // apply for a clock <br/> wdt_clock = clk_get (& pdev-> Dev, "Watchdog "); <br/> If (is_err (wdt_clock) {<br/> dev_err (Dev, "failed to find watchdog clock source/N "); <br/> ret = ptr_err (wdt_clock); <br/> goto err_irq; <br/>}</P> <p> // The clk_enable is defined in arch/ARM/plat-s3c/clock. c <br/> clk_enable (wdt_clock); </P> <p> /* See if we can actually set the requested timer margin, and if <br/> * not, try the default value */</P> <p> If (s3c2410wdt_set_heartbeat (tmr_margin )) {<br/> started = s3c2410wdt_set_heartbeat (<br/> config_s3c2410_watchdog_default_time); </P> <p> If (started = 0) <br/> dev_info (Dev, <br/> "tmr_margin value out of range, default % d used/N", <br/> config_s3c2410_watchdog_default_time); <br/> else <br/> Dev _ INFO (Dev, "Default timer value is out of range," <br/> "cannot start/N "); <br/>}</P> <p> // register the wdt device as a miscellaneous device. Note that the struct is s3c2410wdt_miscdev <br/> ret = misc_register (& s3c2410wdt_miscdev ); <br/> If (RET) {<br/> dev_err (Dev, "cannot register miscdev on minor = % d (% d)/n", <br/> watchdog_minor, RET); <br/> goto err_clk; <br/>}</P> <p> If (tmr_atboot & started = 0) {<br/> dev_info (Dev, "Starting watchdog timer/N"); <B R/> s3c2410wdt_start (); <br/>} else if (! Tmr_atboot) {<br/>/* if we're not enabling the watchdog, then ensure it is <br/> * disabled if it has been left running from the bootloader <br/> * or other source */</P> <p> s3c2410wdt_stop (); <br/>}</P> <p>/* print out a Statement of readiness */</P> <p> wtcon = readl (wdt_base + s3c2410_wtcon ); </P> <p> dev_info (Dev, "watchdog % sactive, reset % sabled, IRQ % sabled/N", <br/> (wtcon & s3c2410_wtcon_enable)? "": "In", <br/> (wtcon & s3c2410_wtcon_rsten )? "": "Dis", <br/> (wtcon & s3c2410_wtcon_inten )? "": "En"); </P> <p> return 0; </P> <p> err_clk: <br/> clk_disable (wdt_clock ); <br/> clk_put (wdt_clock); </P> <p> err_irq: <br/> free_irq (wdt_irq-> Start, pdev ); </P> <p> err_map: <br/> iounmap (wdt_base); </P> <p> err_req: <br/> release_resource (wdt_mem ); <br/> kfree (wdt_mem); </P> <p> return ret; <br/>}< br/>

 

Note that when you register wdt as a miscellaneous device, the structure of the parameter is s3c2410wdt_miscdev. The Code is as follows:

Static struct miscdevice s3c2410wdt_miscdev ={< br/>. minor = watchdog_minor, <br/>. name = "Watchdog", <br/>. foPs = & s3c2410wdt_fops, <br/> };

Haha, you should be familiar with this stuff. In some previous column drivers, there are structures that have been touched. Here we focus on. fops, which provides several tool functions.

Static const struct file_operations s3c2410wdt_fops ={< br/>. owner = this_module, <br/>. llseek = no_llseek, <br/>. write = s3c2410wdt_write, <br/>. unlocked_ioctl = s3c2410wdt_ioctl, <br/>. open = s3c2410wdt_open, <br/>. release = s3c2410wdt_release, <br/> };

 

S3c2410wdt_open

Static int s3c2410wdt_open (struct inode * inode, struct file * file) <br/>{< br/> // try to obtain the semaphore (I .e., lock). If the acquisition fails, if other processes are in use at this time, the system returns <br/> If (test_and_set_bit (0, & open_lock) <br/> return-ebusy; </P> <p> // If the config_watchdog_nowayout entry is configured in the kernel, add 1 To the count of the module. <br/> If (nowayout) <br/>__ module_get (this_module); </P> <p> expect_close = 0; </P> <p>/* start the timer */<br/> s3c2410wdt_start (); </P> <p> // indicates that the returned device file cannot be operated by seek. nons Eekable_open is defined in FS. <br/> return nonseekable_open (inode, file); <br/>}</P> <p> static void s3c2410wdt_start (void) <br/>{< br/> // The Entire Function operates the register directly. Hey, I still don't want to explain it. <br/> unsigned long wtcon; </P> <p> spin_lock (& wdt_lock); // try to obtain the spin lock </P> <p >__ s3c2410wdt_stop (); </P> <p> wtcon = readl (wdt_base + s3c2410_wtcon); <br/> wtcon | = s3c2410_wtcon_enable | s3c2410_wtcon_div128; </P> <p> If (soft_noboot) {<br/> wtcon | = s3c2410_wtcon_in Ten; <br/> wtcon & = ~ S3c2410_wtcon_rsten; <br/>} else {<br/> wtcon & = ~ S3c2410_wtcon_inten; <br/> wtcon | = s3c2410_wtcon_rsten; <br/>}</P> <p> dbg ("% s: wdt_count = 0x % 08x, wtcon = % 08lx/N ", <br/> _ FUNC __, wdt_count, wtcon); </P> <p> writel (wdt_count, wdt_base + s3c2410_wtdat ); <br/> writel (wdt_count, wdt_base + s3c2410_wtcnt); <br/> writel (wtcon, wdt_base + s3c2410_wtcon); <br/> spin_unlock (& wdt_lock ); <br/>}< br/>

 

S3c2410wdt_release

Static int s3c2410wdt_release (struct inode * inode, struct file * file) <br/>{< br/>/* <br/> * shut off the timer. <br/> * lock it in if it's a module and we set nowayout <br/> */</P> <p> // if the current operation status is determined to be you can disable the watchdog timer, otherwise, it is in the "Hello dog" status <br/> If (expect_close = 42) <br/> s3c2410wdt_stop (); <br/> else {<br/> dev_err (wdt_dev, "unexpected close, not stopping watchdog/N"); <br/> s3c2410wdt_keepalive (); // feed the dog <br/>}< br/> expect_close = 0; <br/> clear_bit (0, & open_lock); <br/> return 0; <br/>}

 

S3c2410wdt_write

Static ssize_t s3c2410wdt_write (struct file * file, const char _ User * data, <br/> size_t Len, loff_t * PPOs) <br/> {<br/>/* <br/> * refresh the timer. <br/> */<br/> If (LEN) {<br/> If (! Nowayout) {<br/> size_t I; </P> <p>/* in case it was set long ago */<br/> expect_close = 0; </P> <p> for (I = 0; I! = Len; I ++) {<br/> char C; </P> <p> If (get_user (C, Data + I )) <br/> return-efault; <br/> If (C = 'V') // write character V allows the dog to be disabled, however, the premise is that <br/> // config_watchdog_nowayout is not configured <br/> expect_close = 42; <br/>}< br/> s3c2410wdt_keepalive (); // dog feeding <br/>}< br/> return Len; <br/>}< br/>

 

S3c2410wdt_ioctl

 Static long s3c2410wdt_ioctl (struct file * file, unsigned int cmd, <br/> unsigned long Arg) <br/> {<br/> void _ User * argp = (void _ User *) ARG; <br/> int _ User * P = argp; <br/> int new_margin; </P> <p> switch (CMD) {<br/> case wdioc_getsupport: // obtain the support information of the watchdog, wdt_ident is defined above <br/> return copy_to_user (argp, & s3c2410_wdt_ident, <br/> sizeof (s3c2410_wdt_ident ))? -Efault: 0; <br/> case wdioc_getstatus: // obtain the watchdog status <br/> case wdioc_getbootstatus: <br/> return put_user (0, P ); <br/> case wdioc_keepalive: // dog Feed command <br/> s3c2410wdt_keepalive (); <br/> return 0; <br/> case wdioc_settimeout: // set the timer overflow Time Value command (in seconds) <br/> If (get_user (new_margin, p) <br/> return-efault; <br/> If (s3c2410wdt_set_heartbeat (new_margin) <br/> return-einval; <br/> s3c2410wdt_keepalive (); <br/> return put_user (tmr_margin, P ); <br/> case wdioc_gettimeout: // read the timer default overflow Time Value command <br/> return put_user (tmr_margin, P); <br/> default: <br/> return-enotty; <br/>}< br/>

 

So far, the dog driver function has been fully introduced. Some friends may be confused at the beginning, just like me. What kind of device is the dog. Whether it is a platform device, a hybrid device (MISC), or a character device (char. Here, I will extract a piece of explanation from a netizen. The viewpoint is unique and can be explained in a simple way. The excerpt is as follows:

 

I once saw such a passage, saying that a peanut, if we regard it as a character device, when we cook it, it becomes a Hybrid device in the dish, but it always comes from a member hanging on the root of a peanut seedling, so it can exist as an independent device in a peanut seedling, therefore, it can also be defined as a platform device. What does this mean? A character device is a description of its nature, indicating that it is serialized and accessed sequentially (rather than buffered randomly). A hybrid device is a container that stores this character device, that is, this device is lost in a hybrid device that uses the same device number, while a platform device describes a feature or attribute of the device. In other words, this device is an independent module of the platform and is completely an additional attribute.

My personal skills are limited. If you have any questions about this article, please ask the readers to avoid mistakes.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.