您的位置 首页 厂商

S3C2440驱动简析——串口驱动

对于驱动的学习停歇了几乎一周的时间,期间忙于补习Linux应用编程和搜索驱动、内核相关书籍,以便之后更进一步地学习。在之前友善提供的驱

关于驱动的学习停歇了简直一周的时刻,期间忙于补习Linux运用编程和查找驱动、内核相关书本,以便之后更进一步地学习。在之前友善供给的驱动例程里边,触及的常识面十分有限,需求研讨更多的驱动源码,了解更多的驱动常识,是燃眉之急。研讨他人代码的一起,当然不忘自己也要着手操练。以下贴出串口驱动程序,并在程序里附上扼要注释。

[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. {//本函数选定串口端口和时钟源
  27. unsignedlongucon=rd_regl(port,S3C2410_UCON);//读取寄存器UCON
  28. // todoproperfclk<>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={//串口设备环境信息和供给的操作函数
  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”);

几个问题需求咱们留意:

1.设备怎么注册、刊出

串口驱动被作为一个独自的模块被加载进内核,在模块的加载和卸载函数中,只需注册和刊出一个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 :供给串口设备环境信息,并供给三个函数的接口

[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.函数的注册方法

仔细的朋友可能会发现,咱们之前一向运用的是传统的 device driver 机制(经过 driver_register 函数进行注册)本串口所运用的是一个设备用 Platform_device 表明,驱动用 Platform_driver 进行注册的机制。而后者是在内核2.6版别所提出来的新事物,其优势在于platform机制将设备自身的资源注册进内核,由内核统一管理,在驱动程序中运用这些资源时经过 platform device 供给的标准接口进行请求并运用。这样提高了驱动和资源管理的独立性,而且具有较好的可移植性和安全性(这些标准接口是安全的)。关于这两种机制更深化的剖析,请看以下链接:http://blog.csdn.net/jarvis_xian/archive/2011/05/23/6440649.aspx

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/changshang/263429.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部