串口 (四) linux串口之驱动代码

early console 之 early printk

需要平台侧实现 printch

early console 之 earlycon

//驱动需要实现的代码   
  static void pl011_putc(struct uart_port *port, int c)                            
  {                                                                                
      while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) // 寄存器在平台相关侧定义,基址有上层传入                 
          ;                                                                        
      writeb(c, port->membase + UART01x_DR);                                       
      while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)                  
          ;                                                                        
  }                                                                                
                                                                                   
  static void pl011_early_write(struct console *con, const char *s, unsigned n)    
  {                                                                                
      struct earlycon_device *dev = con->data;                                     
                                                                                   
      uart_console_write(&dev->port, s, n, pl011_putc);                            
  }                                                                                
                                                                                   
  static int __init pl011_early_console_setup(struct earlycon_device *device,      
                          const char *opt)                                         
  {                                                                                
      if (!device->port.membase)                                                   
          return -ENODEV;                                                          
                                                                                       
      device->con->write = pl011_early_write;                                          
      return 0;                                                                        
  }                                            
// 可见,提供给kernel 的只是一个函数,这个函数的第一个参数是个 earlycon_device 的句柄.
//of_setup_earlycon
	// 地址 波特率 iotype 已经从dts众解析且被传入 early_console_dev
	//setup(&early_console_dev, NULL); // 该 setup 就是 pl011_early_console_setup.
	//register_console(early_console_dev.con);
  EARLYCON_DECLARE(pl011, pl011_early_console_setup);                                  
  OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);

// 具体使用的时候会使用 printk ---> early_console_dev->con->write ---> pl011_putc
	

console

console 一般用 console_initcall 声明,并在声明函数中 register_console
还可以 在 串口注册的时候 uart_add_one_port ---> register_console

  • console_initcall
  #ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE                                             
                                                                                   
  static struct console s3c24xx_serial_console;                                    
                                                                                       
  static int __init s3c24xx_serial_console_init(void)                                  
  {                                                                                    
      register_console(&s3c24xx_serial_console);                                       
      return 0;                                                                        
  }                                                                                    
  console_initcall(s3c24xx_serial_console_init);                                       
                                                                                       
  #define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console                               
  #else                                                                                
  #define S3C24XX_SERIAL_CONSOLE NULL                                                  
  #endif 

static struct console s3c24xx_serial_console = {                                 
  .name       = S3C24XX_SERIAL_NAME,                                           
  .device     = uart_console_device,                                           
  .flags      = CON_PRINTBUFFER,                                               
  .index      = -1,                                                            
  .write      = s3c24xx_serial_console_write,                                  
  .setup      = s3c24xx_serial_console_setup,                                  
  .data       = &s3c24xx_uart_drv,                                             
};
  • uart_add_one_port
  控制台也可以在 使用 uart_add_one_port(&amba_reg, &uap->port); 的 时候注册
  static struct uart_driver amba_reg = {                                           
      .owner          = THIS_MODULE,                                               
      .driver_name        = "ttyAMA",                                              
      .dev_name       = "ttyAMA",                                                  
      .major          = SERIAL_AMBA_MAJOR,                                         
      .minor          = SERIAL_AMBA_MINOR,                                         
      .nr         = UART_NR,                                                       
      .cons           = AMBA_CONSOLE,                                              
  };

 #define AMBA_CONSOLE    (&amba_console)


   static struct console amba_console = {                                           
      .name       = "ttyAMA",                                                      
      .write      = pl011_console_write,                                           
      .device     = uart_console_device,                                           
      .setup      = pl011_console_setup,                                           
      .flags      = CON_PRINTBUFFER,                                               
      .index      = -1,                                                            
      .data       = &amba_reg,                                                     
  };  


probe
	uart_add_one_port(&amba_reg, &uap->port);
		register_console

串口注册设备 /dev/ttyXXX

  static struct uart_ops s3c24xx_serial_ops = {                                    
      .pm     = s3c24xx_serial_pm,                                                 
      .tx_empty   = s3c24xx_serial_tx_empty,                                       
      .get_mctrl  = s3c24xx_serial_get_mctrl,                                      
      .set_mctrl  = s3c24xx_serial_set_mctrl,                                      
      .stop_tx    = s3c24xx_serial_stop_tx,                                        
      .start_tx   = s3c24xx_serial_start_tx,                                       
      .stop_rx    = s3c24xx_serial_stop_rx,                                        
      .break_ctl  = s3c24xx_serial_break_ctl,                                      
      .startup    = s3c24xx_serial_startup,                                        
      .shutdown   = s3c24xx_serial_shutdown,                                       
      .set_termios    = s3c24xx_serial_set_termios,                                
      .type       = s3c24xx_serial_type,                                           
      .release_port   = s3c24xx_serial_release_port,                               
      .request_port   = s3c24xx_serial_request_port,                               
      .config_port    = s3c24xx_serial_config_port,                                
      .verify_port    = s3c24xx_serial_verify_port,                                
  #if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)       
      .poll_get_char = s3c24xx_serial_get_poll_char,                               
      .poll_put_char = s3c24xx_serial_put_poll_char,                               
  #endif                                                                           
  };

// 发
  s3c24xx_serial_start_tx
  	s3c24xx_serial_start_next_tx
      s3c24xx_serial_start_tx_pio
      s3c24xx_serial_start_tx_dma
        wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
// 收
	s3c64xx_serial_handle_irq
		s3c24xx_serial_rx_chars
			s3c24xx_serial_rx_chars_dma
				uart_rx_drain_fifo
					rd_regb(port, S3C2410_URXH);
			s3c24xx_serial_rx_chars_pio
				rd_regb(port, S3C2410_URXH);
// 注册

  static struct uart_driver s3c24xx_uart_drv = { // 1.                                   
      .owner      = THIS_MODULE,                                                       
      .driver_name    = "s3c2410_serial",                                              
      .nr     = CONFIG_SERIAL_SAMSUNG_UARTS,                                           
      .cons       = S3C24XX_SERIAL_CONSOLE,                                            
      .dev_name   = S3C24XX_SERIAL_NAME,                                               
      .major      = S3C24XX_SERIAL_MAJOR,                                              
      .minor      = S3C24XX_SERIAL_MINOR,                                              
  };

s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = { // 2.
  [0] = {
      	.port = { // struct uart_port
      		.ops        = &s3c24xx_serial_ops,
};

probe
    uart_register_driver(&s3c24xx_uart_drv); // 1.
    ourport = &s3c24xx_serial_ports[index];
    uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); //2.

你可能感兴趣的:(驱动)