The serial port driver is implemented by the Tty_driver architecture. A function in an application is to manipulate the hardware, first passing through a TTY, and then reaching the driver after a level call. This article first describes the entire process of opening the device's open function in the application.
First in the serial port initialization will first register a serial port driver, the function prototype is
int uart_register_driver (struct uart_driver *drv)
The function that registers the TTY driver is called in this function
int tty_register_driver (struct tty_driver *driver)
{
...
Cdev_init (&driver->cdev, &tty_fops);
...
}
From this code can be seen that the serial port is essentially a character device. Using Soucesight to backtrack the parameter tty_fops, you can find out the function call relationship table of the application and the TTY schema file_operations
static const struct file_operations tty_fops = {. Llseek = No_llseek,. Read = Tty_read,. Write = Tty_write,. Poll = Tty_poll,. Unlocked_ioctl = Tty_ioctl,. Compat_ioctl = Tty_compat_ioctl, .open = Tty_open, . Release = Tty_release,. Fasync = Tty_fasync,};
You can see that the open function in the application is actually the Tty_open function in the TTY schema, and view the function
Static int tty_open (structstruct file *filp)
{
struct Tty_struct *tty = NULL;
int Noctty, retval;
struct Tty_driver *driver;
int index;
dev_t device = inode->i_rdev;
unsigned saved_flags = filp->f_flags;
...
if (Tty->ops->open)
...
}
This call to the open function in Tty->ops, which is the struct tty_operations type, is actually the UART_OPS structure
Static Const struct tty_operations uart_ops = { . Open = uart_open, ...};
We can see that the Uart_open function is called again.
Static int uart_open (structstruct file *filp)
{
...
retval = Uart_startup (TTY, State, 0);
...
}
static int Uart_startup (struct tty_struct *tty, struct uart_state *state, int INIT_HW) { struct Uart_port * Uport = State->uart_port; struct tty_port *port = &state-> long page; int retval = 0 ; ... retval = Uport->ops->startup (Uport); ...}
After the layer call to here, called to the uport structure of the function, Uport for the struct uart_port type, each uart_port corresponding to a serial device, that is, this has been called to the underlying driver of the startup function. Initialize the Uart_port with an array when the serial port is initialized
Static structS3c24xx_uart_port S3c24xx_serial_ports[config_serial_samsung_uarts] = { [0] ={. Port= { .Lock= __spin_lock_unlocked (s3c24xx_serial_ports[0].port.Lock),. Iotype=Upio_mem,. IRQ=irq_s3cuart_rx0,. UARTCLK=0,. Fifosize= -, . OPS = & s3c24xx_serial_ops, . Flags=upf_boot_autoconf,. Line=0, } }, ...}
Function Action Set
Static structUart_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,. Enable_ms=S3c24xx_serial_enable_ms,. 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,};
So, retval = Uport->ops->startup (uport); Here we finally call the S3c24xx_serial_startup function, the truth has basically surfaced. The open function in the application is called through the TTY schema, and finally to the S3c24xx_serial_startup function in the samsung.c driver file.
Static intS3c24xx_serial_startup (structUart_port *Port) { structS3c24xx_uart_port *ourport =To_ourport (port); intret; DBG ("s3c24xx_serial_startup:port=%p (%08lx,%p) \ n", Port->mapbase, port->membase); rx_enabled (port) = 1; ret = Request_irq (OURPORT->RX_IRQ, S3c24xx_serial_rx_chars, 0, S3c24xx_serial_portname (port), ourport); if(Ret! =0) {PRINTK (Kern_err"cannot get IRQ%d\n", ourport->RX_IRQ); returnret; } ourport->rx_claimed =1; DBG ("requesting TX irq...\n"); tx_enabled (port) = 1; ret = Request_irq (OURPORT->TX_IRQ, S3c24xx_serial_tx_chars, 0, S3c24xx_serial_portname (port), ourport); if(ret) {PRINTK (Kern_err"cannot get IRQ%d\n", ourport->TX_IRQ); Gotoerr; } ourport->tx_claimed =1; DBG ("S3c24xx_serial_startup ok\n"); /*The port reset code should has the do the correct * register setup for the port controls*/ returnret; Err:s3c24xx_serial_shutdown (port); returnRet
This function mainly does four things, the code has been highlighted:
1. Open the Receive Enable
2, registration data receive interrupt
3. Turn on Send to enable
4, registration data transmission interruption
At this point, the Linux serial driver to open the device implementation has been analyzed. If you have questions or suggestions, please note.
Linux Serial driver Analysis--turn on the device