linux终端设备处理代码,Linux终端设备驱动

由于UFSTATn寄存器中的Tx FIFO数据数和Rx FIFO数据数分别占据[7:4]和[3:0]位,因此定义S3C2410_UFSTAT_TXSHIFT和S3C2410_UFSTAT_RXSHIFT分别为4和0,代码清单14.20给出了UFSTATn寄存器的位掩码等信息。代码清单14.20 S3C2410 UART UFSTATn寄存器的位掩码1 #define S3C2410_UFSTAT_TXFULL   (1<<9)

2 #define S3C2410_UFSTAT_RXFULL   (1<<8)

3 #define S3C2410_UFSTAT_TXMASK   (15<<4)

4 #define S3C2410_UFSTAT_TXSHIFT   (4)

5 #define S3C2410_UFSTAT_RXMASK   (15<<0)

6 #define S3C2410_UFSTAT_RXSHIFT   (0)

UTXHn(UART Transmit Buffer Register)和URXHn(UART Receive Buffer Register)分别是UART发送和接收数据寄存器,这2个寄存器存放着发送和接收的数据。UTRSTATn(UART TX/RX Status Register)寄存器反映了发送和接收的状态,通过这个寄存器,驱动程序可以判断URXHn中是否有数据接收到或UTXHn是否为空,这个寄存器主要在非FIFO模式时使用。UMCONn(UART Modem Control Register)用于S3C2410 UART的modem控制,设置是否使用RTS流控,若采用流控,可选择自动流控(Auto Flow Control,AFC)或由软件控制RTS信号的“高”或“低”电平。14.7.2 S3C2410串口驱动数据结构S3C2410串口驱动中uart_driver结构体实例的定义如代码清单14.21,设备名为“s3c2410_serial”,驱动名为“ttySAC”。代码清单14.21 S3C2410串口驱动uart_driver结构体1  #define S3C24XX_SERIAL_NAME "ttySAC"

2  #define S3C24XX_SERIAL_DEVFS    "tts/"

3  #define S3C24XX_SERIAL_MAJOR 204

4  #define S3C24XX_SERIAL_MINOR 64

5

6  static struct uart_driver s3c24xx_uart_drv =

7  {

8   .owner  = THIS_MODULE,

9   .dev_name = "s3c2410_serial",

10  .nr  = 3,

11  .cons  = S3C24XX_SERIAL_CONSOLE,

12  .driver_name = S3C24XX_SERIAL_NAME,

13  .devfs_name = S3C24XX_SERIAL_DEVFS,

14  .major  = S3C24XX_SERIAL_MAJOR,

15  .minor  = S3C24XX_SERIAL_MINOR,

16 };

S3C2410串口驱动中定义了结构体s3c24xx_uart_port,该结构体中封装了uart_port结构体及一些针对S3C2410 UART的附加信息,代码清单14.22给出了s3c24xx_uart_port结构体及其实例s3c24xx_serial_ports[]数组。代码清单14.22 S3C2410串口驱动s3c24xx_uart_port结构体1  struct s3c24xx_uart_port

2  {

3   unsigned char   rx_claimed;

4   unsigned char   tx_claimed;

5

6   struct s3c24xx_uart_info *info;

7   struct s3c24xx_uart_clksrc *clksrc;

8   struct clk   *clk;

9   struct clk   *baudclk;

10  struct uart_port  port;

11 };

12

13 static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {

14  [0] = {

15   .port = {

16    .lock  = SPIN_LOCK_UNLOCKED,

17    .iotype  = UPIO_MEM,

18    .irq  = IRQ_S3CUART_RX0,

19    .uartclk = 0,

20    .fifosize = 16,

21    .ops  = &s3c24xx_serial_ops,

22    .flags  = UPF_BOOT_AUTOCONF,

23    .line  = 0,//端口索引:0

24   }

25  },

26  [1] = {

27   .port = {

28    .lock  = SPIN_LOCK_UNLOCKED,

29    .iotype  = UPIO_MEM,

30    .irq  = IRQ_S3CUART_RX1,

31    .uartclk = 0,

32    .fifosize = 16,

33    .ops  = &s3c24xx_serial_ops,

34    .flags  = UPF_BOOT_AUTOCONF,

35    .line  = 1, //端口索引:1

36   }

37  },

38 #if NR_PORTS > 2

39

40  [2] = {

41   .port = {

42    .lock  = SPIN_LOCK_UNLOCKED,

43    .iotype  = UPIO_MEM,

44    .irq  = IRQ_S3CUART_RX2,

45    .uartclk = 0,

46    .fifosize = 16,

47    .ops  = &s3c24xx_serial_ops,

48    .flags  = UPF_BOOT_AUTOCONF,

49    .line  = 2, //端口索引:2

50   }

51  }

52 #endif

53 };

S3C2410串口驱动中uart_ops结构体实例的定义如代码清单14.23,将一系列s3c24xx_serial_函数赋值给了uart_ops结构体的成员。代码清单14.23 S3C2410串口驱动uart_ops结构体1  static struct uart_ops s3c24xx_serial_ops =

2  {

3   .pm  = s3c24xx_serial_pm,

4   .tx_empty = s3c24xx_serial_tx_empty,//发送缓冲区空5   .get_mctrl = s3c24xx_serial_get_mctrl,//得到modem控制设置6   .set_mctrl = s3c24xx_serial_set_mctrl, //设置modem控制(MCR)7   .stop_tx = s3c24xx_serial_stop_tx, //停止接收字符8   .start_tx = s3c24xx_serial_start_tx,//开始传输字符9   .stop_rx = s3c24xx_serial_stop_rx, //停止接收字符10  .enable_ms = s3c24xx_serial_enable_ms,// modem状态中断使能11  .break_ctl = s3c24xx_serial_break_ctl,//控制break信号的传输12  .startup = s3c24xx_serial_startup,//启动端口13  .shutdown = s3c24xx_serial_shutdown,//禁用端口14  .set_termios = s3c24xx_serial_set_termios,//改变端口参数15  .type  = s3c24xx_serial_type,//返回描述特定端口的常量字符串指针16  .release_port = s3c24xx_serial_release_port,//释放端口占用的内存及IO资源17  .request_port = s3c24xx_serial_request_port,//申请端口所需的内存和IO资源18  .config_port = s3c24xx_serial_config_port,//执行端口所需的自动配置步骤19  .verify_port = s3c24xx_serial_verify_port,//验证新的串行端口信息20 };

set_mctrl()函数的原型为:void (*set_mctrl)(struct uart_port *port, u_int mctrl);它将参数port所对应的调制解调器控制线的值设为参数mctrl的值。get_mctrl()函数的原型为:unsigned int (*get_mctrl)(struct uart_port *port);该函数返回调制解调器控制输入的现有状态,这些状态信息包括:TIOCM_CD(CD信号状态)、TIOCM_CTS(CTS信号状态)、TIOCM_DSR(DSR信号状态)、TIOCM_RI(RI信号状态)等。如果信号被置为有效,则对应位将被置位。端口启动函数startup()的原型为:int (*startup)(struct uart_port *port, struct uart_info *info);该函数申请所有中断资源,初始化底层驱动状态,并开启端口为可接收数据的状态。shutdown()函数完成与startup()函数的作用相反,其原型:void (*shutdown)(struct uart_port *port, struct uart_info *info);这个函数禁用端口,释放所有的中断资源。回过头来看s3c24xx_uart_port结构体,其中的s3c24xx_uart_info成员(代码清单14.22第6行)是一些针对S3C2410 UART的信息,其定义如代码清单14.24。代码清单14.24 S3C2410串口驱动s3c24xx_uart_info结构体1  static struct s3c24xx_uart_info s3c2410_uart_inf =

2  {

3   .name  = "Samsung S3C2410 UART",

4   .type  = PORT_S3C2410,

5   .fifosize = 16,

6   .rx_fifomask = S3C2410_UFSTAT_RXMASK,

7   .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT,

8   .rx_fifofull = S3C2410_UFSTAT_RXFULL,

9   .tx_fifofull = S3C2410_UFSTAT_TXFULL,

10  .tx_fifomask = S3C2410_UFSTAT_TXMASK,

11  .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT,

12  .get_clksrc = s3c2410_serial_getsource,

13  .set_clksrc = s3c2410_serial_setsource,

14  .reset_port = s3c2410_serial_resetport,

15 };在S3C2410串口驱动中,针对UART的设置(UCONn、ULCONn、UFCONn寄存器等)被封装到s3c2410_uartcfg结构体中,其定义如代码清单14.25。代码清单14.25 S3C2410串口驱动s3c2410_uartcfg结构体1  struct s3c2410_uartcfg

2  {

3    unsigned char hwport; /*硬件端口号*/

4    unsigned char unused;

5    unsigned short flags;

6    unsigned long uart_flags; /*缺省的uart标志*/

7

8    unsigned long ucon; /*端口的ucon值*/

9    unsigned long ulcon; /*端口的ulcon值*/

10   unsigned long ufcon; /*端口的ufcon值*/

11

12   struct s3c24xx_uart_clksrc *clocks;

13   unsigned int clocks_size;

14 };

14.7.3 S3C2410串口驱动初始化与释放在S3C2410串口驱动的模块加载函数中会调用uart_register_driver()注册s3c24xx_uart_drv这个uart_driver,同时经过s3c2410_serial_init()→s3c24xx_serial_init()→platform_driver_register()的调用导致s3c24xx_serial_probe()被执行,而s3c24xx_serial_probe()函数中会调用s3c24xx_serial_init_port()初始化UART端口并调用uart_add_one_port()添加端口,整个过程的对应代码如 清单14.26。代码清单14.26 S3C2410串口驱动初始化过程1   static int __init s3c24xx_serial_modinit(void)

2   {

3    int ret;

4     //注册uart_driver

5    ret = uart_register_driver(&s3c24xx_uart_drv);

6    if (ret < 0) {

7     printk(KERN_ERR "failed to register UART driver\n");

8     return -1;

9    }

10    //初始化s3c2410的串口11   s3c2410_serial_init();

12

13   return 0;

14  }

15

16  static inline int s3c2410_serial_init(void)

17  {

18   return s3c24xx_serial_init(&s3c2410_serial_drv, &s3c2410_uart_inf);

19  }

20

21  static int s3c24xx_serial_init(struct platform_driver *drv,

22            struct s3c24xx_uart_info *info)

23  {

24   dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);

25   return platform_driver_register(drv);//注册平台驱动26  }

27

28  //平台驱动probe()函数29  static int s3c24xx_serial_probe(struct platform_device *dev,

30      struct s3c24xx_uart_info *info)

31  {

32   struct s3c24xx_uart_port *ourport;

33   int ret;

34

35   dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);

36

37   ourport = &s3c24xx_serial_ports[probe_index];

38   probe_index++;

39

40   dbg("%s: initialising port %p...\n", __FUNCTION__, ourport);

41    //初始化uart端口42   ret = s3c24xx_serial_init_port(ourport, info, dev);

43   if (ret < 0)

44    goto probe_err;

45

46   dbg("%s: adding port\n", __FUNCTION__);

47   //添加uart_port

48   uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);

49   platform_set_drvdata(dev, &ourport->port);

50

51   return 0;

52

53   probe_err:

54   return ret;

55  }

56  //42行调用的s3c24xx_serial_init_port()函数57  static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,

58          struct s3c24xx_uart_info *info,

59          struct platform_device *platdev)

60  {

61   struct uart_port *port = &ourport->port;

62   struct s3c2410_uartcfg *cfg;

63   struct resource *res;

64

65   dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);

66

67   if (platdev == NULL)

68    return -ENODEV;

69

70   cfg = s3c24xx_dev_to_cfg(&platdev->dev);

71

72   if (port->mapbase != 0)

73    return 0;

74

75   if (cfg->hwport > 3)

76    return -EINVAL;

77

78   /*为端口设置info成员*/

79   port->dev = &platdev->dev;

80   ourport->info = info;

81

82   /*初始化fifosize */

83   ourport->port.fifosize = info->fifosize;

84

85   dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);

86

87   port->uartclk = 1;

88    /*如果使用流控*/

89   if (cfg->uart_flags & UPF_CONS_FLOW) {

90    dbg("s3c24xx_serial_init_port: enabling flow control\n");

91    port->flags |= UPF_CONS_FLOW;

92   }

93

94   /*利用平台资源中记录的信息初始化uart端口的基地址、中断号*/

95   res = platform_get_resource(platdev, IORESOURCE_MEM, 0);

96   if (res == NULL) {

97    printk(KERN_ERR "failed to find memory resource for uart\n");

98    return -EINVAL;

99   }

100

101  dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);

102

103  port->mapbase = res->start;

104  port->membase = S3C24XX_VA_UART+(res->start - S3C24XX_PA_UART);

105  port->irq = platform_get_irq(platdev, 0);

106

107  ourport->clk = clk_get(&platdev->dev, "uart");

108

109  dbg("port: map=%08x, mem=%08x, irq=%d, clock=%ld\n",

110      port->mapbase, port->membase, port->irq, port->uartclk);

111

112  /*复位fifo并设置uart */

113  s3c24xx_serial_resetport(port, cfg);

114  return 0;

115 }

116 //113行调用的s3c24xx_serial_resetport()函数117 static inline int s3c24xx_serial_resetport(struct uart_port * port,

118         struct s3c2410_uartcfg *cfg)

119 {

120  struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);

121

122  return (info->reset_port)(port, cfg);

123 }

124 //122行调用的info->reset_port()函数125 static int s3c2410_serial_resetport(struct uart_port *port,

126         struct s3c2410_uartcfg *cfg)

127 {

128  dbg("s3c2410_serial_resetport: port=%p (%08lx), cfg=%p\n",

129      port, port->mapbase, cfg);

130

131  wr_regl(port, S3C2410_UCON,  cfg->ucon);

132  wr_regl(port, S3C2410_ULCON, cfg->ulcon);

133

134  /*复位2个fifo */

135  wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);

136  wr_regl(port, S3C2410_UFCON, cfg->ufcon);

137

138  return 0;

139 }在S3C2410串口驱动模块被卸载时,它会最终调用uart_remove_one_port()释放uart_port并调用uart_unregister_driver()注销uart_driver,如代码清单14.27所示。代码清单14.27 S3C2410串口驱动释放过程1  static void __exit s3c24xx_serial_modexit(void)

2  {

3   s3c2410_serial_exit();

4    //注销uart_driver

5   uart_unregister_driver(&s3c24xx_uart_drv);

6  }

7

8  static inline void s3c2410_serial_exit(void)

9  {

10  //注销平台驱动11  platform_driver_unregister(&s3c2410_serial_drv);

12 }

13

14 static int s3c24xx_serial_remove(struct platform_device *dev)

15 {

16  struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);

17

18  //移除uart端口19  if (port)

20   uart_remove_one_port(&s3c24xx_uart_drv, port);

21

22  return 0;

23 }上述代码中对S3C24xx_serial_remove()的调用发生在platform_driver_unregister()之后,由于S3C2410的UART是集成于SoC芯片内部的一个独立的硬件单元,因此也被作为1个平台设备而定义。14.7.4 S3C2410串口数据收发S3C2410串口驱动uart_ops结构体的startup ()成员函数s3c24xx_serial_startup()用于启动端口,申请端口的发送、接收中断,使能端口的发送和接收,其实现如代码清单14.28。代码清单14.28 S3C2410串口驱动startup ()函数1  static int s3c24xx_serial_startup(struct uart_port *port)

2  {

3   struct s3c24xx_uart_port *ourport = to_ourport(port);

4   int ret;

5

6   dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",

7       port->mapbase, port->membase);

8

9   rx_enabled(port) = 1;//置接收使能状态为1

10   //申请接收中断11  ret = request_irq(RX_IRQ(port),

12      s3c24xx_serial_rx_chars, 0,

13      s3c24xx_serial_portname(port), ourport);

14

15  if (ret != 0) {

16   printk(KERN_ERR "cannot get irq %d\n", RX_IRQ(port));

17   return ret;

18  }

19

20  ourport->rx_claimed = 1;

21

22  dbg("requesting tx irq...\n");

23

24  tx_enabled(port) = 1;//置发送使能状态为1

25   //申请发送中断26  ret = request_irq(TX_IRQ(port),

27      s3c24xx_serial_tx_chars, 0,

28      s3c24xx_serial_portname(port), ourport);

29

30  if (ret) {

31   printk(KERN_ERR "cannot get irq %d\n", TX_IRQ(port));

32   goto err;

33  }

34

35  ourport->tx_claimed = 1;

36

37  dbg("s3c24xx_serial_startup ok\n");

38

39  /*端口复位代码应该已经为端口控制设置了正确的寄存器*/

40

41  return ret;

42

43  err:

44  s3c24xx_serial_shutdown(port);

45  return ret;

46 }

s3c24xx_serial_startup()的“反函数”为s3c24xx_serial_shutdown(),其释放中断,禁止发送和接收,实现如代码清单14.29。代码清单14.29 S3C2410串口驱动shutdown ()函数1  static void s3c24xx_serial_shutdown(struct uart_port *port)

2  {

3   struct s3c24xx_uart_port *ourport = to_ourport(port);

4

5   if (ourport->tx_claimed) {

6    free_irq(TX_IRQ(port), ourport);

7    tx_enabled(port) = 0; //置发送使能状态为0

8    ourport->tx_claimed = 0;

9   }

10

11  if (ourport->rx_claimed) {

12   free_irq(RX_IRQ(port), ourport);

13   ourport->rx_claimed = 0;

14   rx_enabled(port) = 0; //置接收使能状态为1

15  }

16 }

S3C2410串口驱动uart_ops结构体的tx_empty()成员函数s3c24xx_serial_tx_empty()用于判断发送缓冲区是否为空,其实现 如代码清单14.30,当使能FIFO模式的时候,判断UFSTATn寄存器,否则判断UTRSTATn寄存器的相应位。代码清单14.30 S3C2410串口驱动tx_empty()函数1  /*检查发送缓冲区/FIFO是否为空*/

2  static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)

3  {

4    //fifo模式,检查UFSTATn寄存器5    struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);

6    unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);

7    unsigned long ufcon = rd_regl(port, S3C2410_UFCON);

8

9    if (ufcon &S3C2410_UFCON_FIFOMODE)

10   {

11     if ((ufstat &info->tx_fifomask) != 0 ||  //Tx fifo数据数非0

12     (ufstat &info->tx_fifofull))   // Tx fifo满13       return 0;   //0:非空14

15     return 1; //1:空16   }

17

18   return s3c24xx_serial_txempty_nofifo(port);

19 }

20

21 static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)

22 {

23   //非fifo模式,检查UTRSTATn寄存器24   return (rd_regl(port, S3C2410_UTRSTAT) &S3C2410_UTRSTAT_TXE);

25 }

S3C2410串口驱动uart_ops结构体的start_tx ()成员函数s3c24xx_serial_start_tx()用于启动发送,而stop_rx()成员函数s3c24xx_serial_stop_rx()用于停止发送,代码清单14.31给出了这2个函数的实现。代码清单14.31 S3C2410串口驱动start_tx ()、stop_rx()函数1  static void s3c24xx_serial_start_tx(struct uart_port *port)

2  {

3   if (!tx_enabled(port)) {//如果端口发送未使能4    if (port->flags & UPF_CONS_FLOW)

5     s3c24xx_serial_rx_disable(port);

6

7    enable_irq(TX_IRQ(port));//使能发送中断8    tx_enabled(port) = 1;//置端口发送使能状态为1

9   }

10 }

11

12 static void s3c24xx_serial_stop_tx(struct uart_port *port)

13 {

14  if (tx_enabled(port)) {//如果端口发送已使能15   disable_irq(TX_IRQ(port));//禁止发送中断16   tx_enabled(port) = 0;//置端口发送使能状态为0

17   if (port->flags & UPF_CONS_FLOW)

18    s3c24xx_serial_rx_enable(port);

19  }

20 }

S3C2410串口驱动uart_ops结构体的stop_rx ()成员函数s3c24xx_serial_stop_rx ()用于停止接收,代码清单14.32给出了这个函数的实现。注意uart_ops中没有start_rx()成员,因为接收并不是由“我方”启动,而是 由“它方”的发送触发“我方”的接收中断,“我方”再被动响应。代码清单14.32 S3C2410串口驱动stop_rx ()函数1  static void s3c24xx_serial_stop_rx(struct uart_port *port)

2  {

3   if (rx_enabled(port)) {//如果接收为使能4    dbg("s3c24xx_serial_stop_rx: port=%p\n", port);

5    disable_irq(RX_IRQ(port));//禁止接收中断6    rx_enabled(port) = 0;//置接收使能状态为0

7   }

8  }在S3C2410串口驱动中,与数据收发关系最密切的函数不是上述uart_ops成员函数,而是s3c24xx_serial_startup()为发送和接收中断注册 的中断处理函数s3c24xx_serial_rx_chars()和s3c24xx_serial_tx_chars()。s3c24xx_serial_rx_chars ()读取URXHn寄存器以获得接收到的字符,并调用uart_insert_char()将该字符添加了tty设备的flip缓冲区中,当接收到64个 字符或者不再能接受到字符后,调用tty_flip_buffer_push()函数向上层“推”tty设备的flip缓冲,其实现如代码清单14.33。代码清单14.33 S3C2410串口驱动接收中断处理函数1  static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id, struct

2    pt_regs *regs)

3  {

4    struct s3c24xx_uart_port *ourport = dev_id;

5    struct uart_port *port = &ourport->port; //获得uart_port

6    struct tty_struct *tty = port->info->tty; //获得tty_struct

7    unsigned int ufcon, ch, flag, ufstat, uerstat;

8    int max_count = 64;

9

10   while (max_count-- > 0)

11   {

12     ufcon = rd_regl(port, S3C2410_UFCON);

13     ufstat = rd_regl(port, S3C2410_UFSTAT);

14     //如果接收到0个字符15     if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)

16       break;

17

18     uerstat = rd_regl(port, S3C2410_UERSTAT);

19     ch = rd_regb(port, S3C2410_URXH); //读出字符20

21     if (port->flags &UPF_CONS_FLOW)

22     {

23       int txe = s3c24xx_serial_txempty_nofifo(port);

24

25       if (rx_enabled(port)) //如果端口为使能接收状态26       {

27         if (!txe) //如果发送缓冲区为空28         {

29           rx_enabled(port) = 0; //置端口为使能接收状态为0

30           continue;

31         }

32       }

33       else   //端口为禁止接收状态34       {

35         if (txe)  //如果发送缓冲区非空36         {

37           ufcon |= S3C2410_UFCON_RESETRX;

38           wr_regl(port, S3C2410_UFCON, ufcon);

39           rx_enabled(port) = 1;//置端口为使能接收状态为1

40           goto out;

41         }

42         continue;

43       }

44     }

45

46     /*将接收到的字符写入buffer */

47     flag = TTY_NORMAL;

48     port->icount.rx++;

49

50     if (unlikely(uerstat &S3C2410_UERSTAT_ANY))

51     {

52       dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n", ch, uerstat);

53

54        if (uerstat &S3C2410_UERSTAT_BREAK)

55       {

56         dbg("break!\n");

57         port->icount.brk++;

58         if (uart_handle_break(port))

59           goto ignore_char;

60       }

61

62       if (uerstat &S3C2410_UERSTAT_FRAME)

63         port->icount.frame++;

64       if (uerstat &S3C2410_UERSTAT_OVERRUN)

65         port->icount.overrun++;

66

67       uerstat &= port->read_status_mask;

68

69       if (uerstat &S3C2410_UERSTAT_BREAK)

70         flag = TTY_BREAK;

71       else if (uerstat &S3C2410_UERSTAT_PARITY)

72         flag = TTY_PARITY;

73       else if (uerstat &(S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_OVERRUN))

74         flag = TTY_FRAME;

75     }

76

77     if (uart_handle_sysrq_char(port, ch, regs)) //处理sysrq字符78       goto ignore_char;

79     //插入字符到tty设备的flip缓冲80     uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag);

81

82     ignore_char: continue;

83   }

84   tty_flip_buffer_push(tty);  //刷新tty设备的flip缓冲85

86   out: return IRQ_HANDLED;

87 }上述代码第80行的uart_insert_char()函数是串口核心层对tty_insert_flip_char()的封装,它作为内联函数被定义于serial_core.h文件中。如代码清单14.34,s3c24xx_serial_tx_chars()读取uart_info中环形缓冲区中的字符,写入调用UTXHn寄存器。代码清单14.34 S3C2410串口驱动发送中断处理函数1  static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id, struct pt_regs

2    *regs)

3  {

4    struct s3c24xx_uart_port *ourport = id;

5    struct uart_port *port = &ourport->port;

6    struct circ_buf *xmit = &port->info->xmit;  //得到环形缓冲区7    int count = 256;   //最多1次发256个字符8

9    if (port->x_char) //如果定义了xchar,发送10   {

11     wr_regb(port, S3C2410_UTXH, port->x_char);

12     port->icount.tx++;

13     port->x_char = 0;

14     goto out;

15   }

16

17   /*如果没有更多的字符需要发送,或者uart Tx停止,则停止uart并退出*/

18   if (uart_circ_empty(xmit) || uart_tx_stopped(port))

19   {

20     s3c24xx_serial_stop_tx(port);

21     goto out;

22   }

23

24   /*尝试把环行buffer中的数据发空*/

25   while (!uart_circ_empty(xmit) && count-- > 0)

26   {

27     if (rd_regl(port, S3C2410_UFSTAT) &ourport->info->tx_fifofull)

28       break;

29

30     wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);

31     xmit->tail = (xmit->tail + 1) &(UART_XMIT_SIZE - 1);

32     port->icount.tx++;

33   }

34   /*如果环形缓冲区中剩余的字符少于WAKEUP_CHARS,唤醒上层*/

35   if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)

36     uart_write_wakeup(port);

37

38   if (uart_circ_empty(xmit)) //如果发送环形buffer为空39     s3c24xx_serial_stop_tx(port); //停止发送40

41   out: return IRQ_HANDLED;

42 }上述代码第35行的宏WAKEUP_CHARS的含义为:当发送环形缓冲区中的字符数小于该数时,驱动将请求上层向下传递更多的数据,uart_write_wakeup()完成此目的。uart_circ_chars_pending()、uart_circ_empty()是定义于serial_core.h中的宏,分别返回环形缓冲区剩余的字符数以及判断缓冲区是否为空。14.7.5 S3C2410串口线路设置S3C2410串口驱动uart_ops结构体的set_termios()成员函数用于改变端口的参数设置,包括波特率、字长、停止位、奇偶校验等,它会根据传递给它 的port、termios参数成员的值设置S3C2410 UART的ULCONn、UCONn、UMCONn等寄存器,其实现如代码清单14.35。代码清单14.35 S3C2410串口驱动set_termios()函数1   static void s3c24xx_serial_set_termios(struct uart_port *port,

2              struct termios *termios,

3              struct termios *old)

4   {

5    struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);

6    struct s3c24xx_uart_port *ourport = to_ourport(port);

7    struct s3c24xx_uart_clksrc *clksrc = NULL;

8    struct clk *clk = NULL;

9    unsigned long flags;

10   unsigned int baud, quot;

11   unsigned int ulcon;

12   unsigned int umcon;

13

14   /*不支持modem控制信号线*/

15   termios->c_cflag &= ~(HUPCL | CMSPAR);

16   termios->c_cflag |= CLOCAL;

17

18   /*请求内核计算分频以便产生对应的波特率*/

19   baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);

20

21   if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)

22    quot = port->custom_divisor;

23   else

24    quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);

25

26   /*检查以确定是否需要改变时钟源*/

27   if (ourport->clksrc != clksrc || ourport->baudclk != clk) {

28    s3c24xx_serial_setsource(port, clksrc);

29

30    if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {

31     clk_disable(ourport->baudclk);

32     ourport->baudclk  = NULL;

33    }

34

35    clk_enable(clk);

36

37    ourport->clksrc = clksrc;

38    ourport->baudclk = clk;

39   }

40

41    /*设置字长*/

42   switch (termios->c_cflag & CSIZE) {

43   case CS5:

44    dbg("config: 5bits/char\n");

45    ulcon = S3C2410_LCON_CS5;

46    break;

47   case CS6:

48    dbg("config: 6bits/char\n");

49    ulcon = S3C2410_LCON_CS6;

50    break;

51   case CS7:

52    dbg("config: 7bits/char\n");

53    ulcon = S3C2410_LCON_CS7;

54    break;

55   case CS8:

56   default:

57    dbg("config: 8bits/char\n");

58    ulcon = S3C2410_LCON_CS8;

59    break;

60   }

61

62   /*保留以前的lcon IR设置*/

63   ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);

64

65   if (termios->c_cflag & CSTOPB)

66    ulcon |= S3C2410_LCON_STOPB;

67    /*设置是否采用RTS、CTS自动流空*/

68   umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0;

69

70   if (termios->c_cflag & PARENB) {

71    if (termios->c_cflag & PARODD)

72     ulcon |= S3C2410_LCON_PODD;//计校验73    else

74     ulcon |= S3C2410_LCON_PEVEN;//偶校验75   } else {

76    ulcon |= S3C2410_LCON_PNONE;//无校验77   }

78

79   spin_lock_irqsave(&port->lock, flags);

80

81   dbg("setting ulcon to %08x, brddiv to %d\n", ulcon, quot);

82

83   wr_regl(port, S3C2410_ULCON, ulcon);

84   wr_regl(port, S3C2410_UBRDIV, quot);

85   wr_regl(port, S3C2410_UMCON, umcon);

86

87   dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",

88       rd_regl(port, S3C2410_ULCON),

89       rd_regl(port, S3C2410_UCON),

90       rd_regl(port, S3C2410_UFCON));

91

92   /*更新端口的超时*/

93   uart_update_timeout(port, termios->c_cflag, baud);

94

95   /*我们对什么字符状态状态标志感兴趣?*/

96   port->read_status_mask = S3C2410_UERSTAT_OVERRUN;

97   if (termios->c_iflag & INPCK)

98    port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;

99

100  /*我们要忽略什么字符状态标志?*/

101  port->ignore_status_mask = 0;

102  if (termios->c_iflag & IGNPAR)

103   port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;

104  if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)

105   port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;

106

107  /*如果CREAD未设置,忽略所用字符*/

108  if ((termios->c_cflag & CREAD) == 0)

109   port->ignore_status_mask |= RXSTAT_DUMMY_READ;

110

111  spin_unlock_irqrestore(&port->lock, flags);

112 }由于S3C2410集成UART并不包含完整的Modem控制信号线,因此其uart_ops结构体的get_mctrl()、set_mctrl()成员 函数的实现非常简单,如代码清单14.36,get_mctrl()返回DSR一直有效,而CTS则根据UMSTATn寄存器的内容获得,set_mctrl()目前为空。代码清单14.36 S3C2410串口驱动get_mctrl()和set_mctrl()函数1  static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)

2  {

3   unsigned int umstat = rd_regb(port,S3C2410_UMSTAT);

4

5   if (umstat & S3C2410_UMSTAT_CTS)//CTS信号有效(低电平)6    return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;

7   else

8    return TIOCM_CAR | TIOCM_DSR;

9  }

10

11 static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)

12 {

13  /* todo:可能移除AFC,并手工进行CTS */

14 }

14.8总结TTY设备驱动的主体工作围绕tty_driver这个结构体的成员函数展开,主要应实现其中的数据发送和接收流程以及tty设备线路设置接口函数。针对串口,内核实现了串口核心层,这个层实现了串口设备通用的tty_driver。因此,串口设备驱动的主体工作从tty_driver转移到了uart_driver。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值