在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,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) > 設計應用 > S3C2440驅(qū)動簡析——串口驅(qū)動

            S3C2440驅(qū)動簡析——串口驅(qū)動

            作者: 時間:2016-11-21 來源:網(wǎng)絡 收藏
            對于驅(qū)動的學習停歇了幾乎一周的時間,期間忙于補習Linux應用編程和搜索驅(qū)動、內(nèi)核相關書籍,以便之后更進一步地學習。在之前友善提供的驅(qū)動例程里面,涉及的知識面非常有限,需要研究更多的驅(qū)動源碼,了解更多的驅(qū)動知識,是當務之急。研究別人代碼的同時,當然不忘自己也要動手練習。以下貼出串口驅(qū)動程序,并在程序里附上簡要注釋。
            [c-sharp]view plaincopy
            1. // linux/drivers/serial/s3c2440.c
            2. *
            3. *DriverforSamsungS3C2440andS3C2442SoConboardUARTs.
            4. *
            5. *BenDooks,Copyright(c)2003-2005,2008SimtecElectronics
            6. *http://armlinux.simtec.co.uk/
            7. *
            8. *Thisprogramisfreesoftware;youcanredistributeitand/ormodify
            9. *itunderthetermsoftheGNUGeneralPublicLicenseversion2as
            10. *publishedbytheFreeSoftwareFoundation.
            11. //
            12. #include"linux/module.h"
            13. #include"linux/ioport.h"
            14. #include"linux/io.h"
            15. #include"linux/platform_device.h"
            16. #include"linux/init.h"
            17. #include"linux/serial_core.h"
            18. #include"linux/serial.h"
            19. #include"asm/irq.h"
            20. #include"mach/hardware.h"
            21. #include"plat/regs-serial.h"
            22. #include"mach/regs-gpio.h"
            23. #include"samsung.h"
            24. staticints3c2440_serial_setsource(structuart_port*port,
            25. structs3c24xx_uart_clksrc*clk)
            26. {//本函數(shù)選定串口端口和時鐘源
            27. unsignedlongucon=rd_regl(port,S3C2410_UCON);//讀取寄存器UCON
            28. // todo-properfclk<>nonfclkswitch.//
            29. ucon&=~S3C2440_UCON_CLKMASK;//#defineS3C2440_UCON_CLKMASK(3<<10)
            30. if(strcmp(clk->name,"uclk")==0)//選擇時鐘源
            31. ucon|=S3C2440_UCON_UCLK;
            32. elseif(strcmp(clk->name,"pclk")==0)
            33. ucon|=S3C2440_UCON_PCLK;
            34. elseif(strcmp(clk->name,"fclk")==0)
            35. ucon|=S3C2440_UCON_FCLK;
            36. else{
            37. printk(KERN_ERR"unknownclocksource%s/n",clk->name);
            38. return-EINVAL;
            39. }
            40. wr_regl(port,S3C2410_UCON,ucon);//把設置過的ucon寫回串口控制寄存器
            41. return0;
            42. }
            43. staticints3c2440_serial_getsource(structuart_port*port,
            44. structs3c24xx_uart_clksrc*clk)
            45. {//設置時鐘源和對應預分頻值
            46. unsignedlongucon=rd_regl(port,S3C2410_UCON);
            47. unsignedlongucon0,ucon1,ucon2;
            48. switch(ucon&S3C2440_UCON_CLKMASK){
            49. caseS3C2440_UCON_UCLK:
            50. clk->divisor=1;
            51. clk->name="uclk";
            52. break;
            53. caseS3C2440_UCON_PCLK:
            54. caseS3C2440_UCON_PCLK2:
            55. clk->divisor=1;
            56. clk->name="pclk";
            57. break;
            58. caseS3C2440_UCON_FCLK:
            59. //thefunofcalculatingtheuartdivisorson
            60. *thes3c2440//
            61. ucon0=__raw_readl(S3C24XX_VA_UART0+S3C2410_UCON);
            62. ucon1=__raw_readl(S3C24XX_VA_UART1+S3C2410_UCON);
            63. ucon2=__raw_readl(S3C24XX_VA_UART2+S3C2410_UCON);
            64. printk("ucons:lx,lx,lx/n",ucon0,ucon1,ucon2);
            65. ucon0&=S3C2440_UCON0_DIVMASK;
            66. ucon1&=S3C2440_UCON1_DIVMASK;
            67. ucon2&=S3C2440_UCON2_DIVMASK;
            68. if(ucon0!=0){
            69. clk->divisor=ucon0>>S3C2440_UCON_DIVSHIFT;
            70. clk->divisor+=6;
            71. }elseif(ucon1!=0){
            72. clk->divisor=ucon1>>S3C2440_UCON_DIVSHIFT;
            73. clk->divisor+=21;
            74. }elseif(ucon2!=0){
            75. clk->divisor=ucon2>>S3C2440_UCON_DIVSHIFT;
            76. clk->divisor+=36;
            77. }else{
            78. //manualcalims44,seemstobe9//
            79. clk->divisor=9;
            80. }
            81. clk->name="fclk";
            82. break;
            83. }
            84. return0;
            85. }
            86. staticints3c2440_serial_resetport(structuart_port*port,
            87. structs3c2410_uartcfg*cfg)
            88. {//重設串口
            89. unsignedlongucon=rd_regl(port,S3C2410_UCON);
            90. dbg("s3c2440_serial_resetport:port=%p(lx),cfg=%p/n",
            91. port,port->mapbase,cfg);
            92. //ensurewedontchangetheclocksettings...//
            93. ucon&=(S3C2440_UCON0_DIVMASK|(3<<10));
            94. wr_regl(port,S3C2410_UCON,ucon|cfg->ucon);//重新設置寄存器UCON
            95. wr_regl(port,S3C2410_ULCON,cfg->ulcon);//重新設置寄存器ULCON
            96. //resetbothfifos//
            97. wr_regl(port,S3C2410_UFCON,cfg->ufcon|S3C2410_UFCON_RESETBOTH);//重啟fifo
            98. wr_regl(port,S3C2410_UFCON,cfg->ufcon);//重新設定寄存器UFCON
            99. return0;
            100. }
            101. staticstructs3c24xx_uart_infos3c2440_uart_inf={//串口設備環(huán)境信息和提供的操作函數(shù)
            102. .name="SamsungS3C2440UART",
            103. .type=PORT_S3C2440,
            104. .fifosize=64,
            105. .rx_fifomask=S3C2440_UFSTAT_RXMASK,
            106. .rx_fifoshift=S3C2440_UFSTAT_RXSHIFT,
            107. .rx_fifofull=S3C2440_UFSTAT_RXFULL,
            108. .tx_fifofull=S3C2440_UFSTAT_TXFULL,
            109. .tx_fifomask=S3C2440_UFSTAT_TXMASK,
            110. .tx_fifoshift=S3C2440_UFSTAT_TXSHIFT,
            111. .get_clksrc=s3c2440_serial_getsource,
            112. .set_clksrc=s3c2440_serial_setsource,
            113. .reset_port=s3c2440_serial_resetport,
            114. };
            115. //devicemanagement//
            116. staticints3c2440_serial_probe(structplatform_device*dev)
            117. {//完成串口的添加
            118. dbg("s3c2440_serial_probe:dev=%p/n",dev);
            119. returns3c24xx_serial_probe(dev,&s3c2440_uart_inf);
            120. }
            121. staticstructplatform_drivers3c2440_serial_driver={//注冊串口設備
            122. .probe=s3c2440_serial_probe,
            123. .remove=__devexit_p(s3c24xx_serial_remove),
            124. .driver={
            125. .name="s3c2440-uart",
            126. .owner=THIS_MODULE,
            127. },
            128. };
            129. s3c24xx_console_init(&s3c2440_serial_driver,&s3c2440_uart_inf);
            130. staticint__inits3c2440_serial_init(void)
            131. {//初始化模塊
            132. returns3c24xx_serial_init(&s3c2440_serial_driver,&s3c2440_uart_inf);
            133. }
            134. staticvoid__exits3c2440_serial_exit(void)
            135. {//退出模塊
            136. platform_driver_unregister(&s3c2440_serial_driver);//注銷串口設備
            137. }
            138. module_init(s3c2440_serial_init);
            139. module_exit(s3c2440_serial_exit);
            140. MODULE_DESCRIPTION("SamsungS3C2440,S3C2442SoCSerialportdriver");
            141. MODULE_AUTHOR("BenDooks");
            142. MODULE_LICENSE("GPLv2");
            143. MODULE_ALIAS("platform:s3c2440-uart");

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

            幾個問題需要我們注意:

            1.設備如何注冊、注銷

            串口驅(qū)動被作為一個單獨的模塊被加載進內(nèi)核,在模塊的加載和卸載函數(shù)中,只需注冊和注銷一個platform_driver結構體。

            注冊:

            [c-sharp]view plaincopy
            1. staticstructplatform_drivers3c2440_serial_driver={
            2. .probe=s3c2440_serial_probe,
            3. .remove=__devexit_p(s3c24xx_serial_remove),
            4. .driver={
            5. .name="s3c2440-uart",
            6. .owner=THIS_MODULE,
            7. },
            8. };

            注銷:

            [c-sharp]view plaincopy
            1. platform_driver_unregister(&s3c2440_serial_driver);

            2.幾個非常重要的結構體

            s3c2410_uartcfg :保存ucon ulcon ufcon三個串口寄存器的值

            [c-sharp]view plaincopy
            1. structs3c2410_uartcfg{
            2. unsignedcharhwport;//hardwareportnumber//
            3. unsignedcharunused;
            4. unsignedshortflags;
            5. upf_tuart_flags; //defaultuartflags //
            6. unsignedinthas_fracval;
            7. unsignedlongucon;//valueofuconforport//
            8. unsignedlongulcon;//valueofulconforport//
            9. unsignedlongufcon;//valueofufconforport//
            10. structs3c24xx_uart_clksrc*clocks;
            11. unsignedintclocks_size;
            12. };

            s3c24xx_uart_info :提供串口設備環(huán)境信息,并提供三個函數(shù)的接口

            [c-sharp]view plaincopy
            1. structs3c24xx_uart_info{
            2. char*name;
            3. unsignedinttype;
            4. unsignedintfifosize;
            5. unsignedlongrx_fifomask;
            6. unsignedlongrx_fifoshift;
            7. unsignedlongrx_fifofull;
            8. unsignedlongtx_fifomask;
            9. unsignedlongtx_fifoshift;
            10. unsignedlongtx_fifofull;
            11. //uartportfeatures//
            12. unsignedinthas_divslot:1;
            13. //clocksourcecontrol//
            14. int(*get_clksrc)(structuart_port*,structs3c24xx_uart_clksrc*clk);
            15. int(*set_clksrc)(structuart_port*,structs3c24xx_uart_clksrc*clk);
            16. //uartcontrols//
            17. int(*reset_port)(structuart_port*,structs3c2410_uartcfg*);
            18. };

            platform_device :設備的信息

            [c-sharp]view plaincopy
            1. structplatform_device{
            2. constchar*name;
            3. intid;
            4. structdevicedev;
            5. u32num_resources;
            6. structresource*resource;
            7. conststructplatform_device_id*id_entry;
            8. //archspecificadditions//
            9. structpdev_archdataarchdata;
            10. };

            platform_driver :設備注冊用

            [c-sharp]view plaincopy
            1. structplatform_driver{
            2. int(*probe)(structplatform_device*);
            3. int(*remove)(structplatform_device*);
            4. void(*shutdown)(structplatform_device*);
            5. int(*suspend)(structplatform_device*,pm_message_tstate);
            6. int(*resume)(structplatform_device*);
            7. structdevice_driverdriver;
            8. conststructplatform_device_id*id_table;
            9. };

            3.讀寫寄存器的宏定義

            (1)讀寄存器

            unsigned long ucon = rd_regl(port, S3C2410_UCON);

            #define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))

            static unsigned char __raw_readb(unsigned int ptr)

            {

            return *((volatile unsigned char *)ptr);

            }

            #define portaddr(port, reg) ((port)->membase + (reg))

            (2)寫寄存器

            wr_regl(port, S3C2410_UCON, ucon);

            #define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))

            #define portaddr(port, reg) ((port)->membase + (reg))

            #define __raw_writel(v,p)(*(unsigned long *)(p) = (v))

            4.函數(shù)的注冊方式

            細心的朋友可能會發(fā)現(xiàn),我們之前一直使用的是傳統(tǒng)的 device driver 機制(通過 driver_register 函數(shù)進行注冊)本串口所使用的是一個設備用 Platform_device 表示,驅(qū)動用 Platform_driver 進行注冊的機制。而后者是在內(nèi)核2.6版本所提出來的新事物,其優(yōu)勢在于platform機制將設備本身的資源注冊進內(nèi)核,由內(nèi)核統(tǒng)一管理,在驅(qū)動程序中使用這些資源時通過 platform device 提供的標準接口進行申請并使用。這樣提高了驅(qū)動和資源管理的獨立性,并且擁有較好的可移植性和安全性(這些標準接口是安全的)。關于這兩種機制更深入的分析,請看以下鏈接:http://blog.csdn.net/jarvis_xian/archive/2011/05/23/6440649.aspx




            評論


            技術專區(qū)

            關閉