色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > S3C2440驅(qū)動簡析——串口驅(qū)動

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

          作者: 時間:2016-11-21 來源:網(wǎng)絡(luò) 收藏
          對于驅(qū)動的學(xué)習(xí)停歇了幾乎一周的時間,期間忙于補習(xí)Linux應(yīng)用編程和搜索驅(qū)動、內(nèi)核相關(guān)書籍,以便之后更進一步地學(xué)習(xí)。在之前友善提供的驅(qū)動例程里面,涉及的知識面非常有限,需要研究更多的驅(qū)動源碼,了解更多的驅(qū)動知識,是當(dāng)務(wù)之急。研究別人代碼的同時,當(dāng)然不忘自己也要動手練習(xí)。以下貼出串口驅(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);//把設(shè)置過的ucon寫回串口控制寄存器
          41. return0;
          42. }
          43. staticints3c2440_serial_getsource(structuart_port*port,
          44. structs3c24xx_uart_clksrc*clk)
          45. {//設(shè)置時鐘源和對應(yīng)預(yù)分頻值
          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. {//重設(shè)串口
          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);//重新設(shè)置寄存器UCON
          95. wr_regl(port,S3C2410_ULCON,cfg->ulcon);//重新設(shè)置寄存器ULCON
          96. //resetbothfifos//
          97. wr_regl(port,S3C2410_UFCON,cfg->ufcon|S3C2410_UFCON_RESETBOTH);//重啟fifo
          98. wr_regl(port,S3C2410_UFCON,cfg->ufcon);//重新設(shè)定寄存器UFCON
          99. return0;
          100. }
          101. staticstructs3c24xx_uart_infos3c2440_uart_inf={//串口設(shè)備環(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={//注冊串口設(shè)備
          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);//注銷串口設(shè)備
          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://cafeforensic.com/article/201611/319506.htm

          幾個問題需要我們注意:

          1.設(shè)備如何注冊、注銷

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

          注冊:

          [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.幾個非常重要的結(jié)構(gòu)體

          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 :提供串口設(shè)備環(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 :設(shè)備的信息

          [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 :設(shè)備注冊用

          [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ù)進行注冊)本串口所使用的是一個設(shè)備用 Platform_device 表示,驅(qū)動用 Platform_driver 進行注冊的機制。而后者是在內(nèi)核2.6版本所提出來的新事物,其優(yōu)勢在于platform機制將設(shè)備本身的資源注冊進內(nèi)核,由內(nèi)核統(tǒng)一管理,在驅(qū)動程序中使用這些資源時通過 platform device 提供的標(biāo)準(zhǔn)接口進行申請并使用。這樣提高了驅(qū)動和資源管理的獨立性,并且擁有較好的可移植性和安全性(這些標(biāo)準(zhǔn)接口是安全的)。關(guān)于這兩種機制更深入的分析,請看以下鏈接:http://blog.csdn.net/jarvis_xian/archive/2011/05/23/6440649.aspx




          評論


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

          關(guān)閉