/*
* uart Открытый анализ
*
* вопрос: Когда приложение вызывает функцию открытого системного вызова, как оно открывает последовательный порт?
*
* */
/*Samsung.c Функция входа в функциональный модуль
*Это общедоступный интерфейс, эта функция будет вызываться независимо от 2440/6410.
* */
static int __init s3c24xx_serial_modinit(void)
{
int ret;
ret = uart_register_driver(&s3c24xx_uart_drv);
if (ret < 0) {
printk(KERN_ERR "failed to register UART driver\n");
return -1;
}
return 0;
}
int uart_register_driver(struct uart_driver *drv)
{
/*Игнорировать нерелевантный код**/
struct tty_driver *normal;
normal = alloc_tty_driver(drv->nr);
if (!normal)
goto out_kfree;
/* Ставим нормальный назначен на tty_driver*/ драйвера uart
drv->tty_driver = normal;
/*Настройка обычных операций*/
tty_set_operations(normal, &uart_ops);
/*Регистрируем драйвер tty*/
tty_register_driver(normal);
}
int tty_register_driver(struct tty_driver *driver)
{
/*Назначаем основной номер устройства*/
if (!driver->major) {
error = alloc_chrdev_region(&dev, driver->minor_start,
driver->num, driver->name);
if (!error) {
driver->major = MAJOR(dev);
driver->minor_start = MINOR(dev);
}
} else {
dev = MKDEV(driver->major, driver->minor_start);
error = register_chrdev_region(dev, driver->num, driver->name);
/*Инициализируем символьное устройство, регистрируем символьное устройство*/
cdev_init(&driver->cdev, &tty_fops);
driver->cdev.owner = driver->owner;
error = cdev_add(&driver->cdev, dev, driver->num);
}
/*
* Когда приложение вызывает системный вызов open, sys_open вызывает функцию open в символьном файле file_operations.
* То есть функция открытия в tty_fops
* */
static int tty_open(struct inode *inode, struct file *filp)
{
/*Сначала определяем, является ли открытое устройство:
*MAJOR = 5, MINOR = 0
*MAJOR = 5, MINOR = 1
*MAJOR = 4, MINOR = 0
* Фактически устройство 2440_Serial0 открыто.
*
* MAJOR = 204 MINOR = 64
* */
if (device == MKDEV(TTYAUX_MAJOR, 0)) {
tty = get_current_tty();
if (!tty) {
tty_unlock();
mutex_unlock(&tty_mutex);
return -ENXIO;
}
driver = tty_driver_kref_get(tty->driver);
index = tty->index;
filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
/* noctty = 1; */
/* FIXME: Should we take a driver reference ? */
tty_kref_put(tty);
goto got_driver;
}
#ifdef CONFIG_VT
if (device == MKDEV(TTY_MAJOR, 0)) {
extern struct tty_driver *console_driver;
driver = tty_driver_kref_get(console_driver);
index = fg_console;
noctty = 1;
goto got_driver;
}
#endif
if (device == MKDEV(TTYAUX_MAJOR, 1)) {
struct tty_driver *console_driver = console_device(&index);
if (console_driver) {
driver = tty_driver_kref_get(console_driver);
if (driver) {
/* Don't let /dev/console block */
filp->f_flags |= O_NONBLOCK;
noctty = 1;
goto got_driver;
}
}
tty_unlock();
mutex_unlock(&tty_mutex);
return -ENODEV;
}
/*Если приведенное выше суждение неверно, выполните это предложение*/
driver = get_tty_driver(device, &index);
if (!driver) {
tty_unlock();
mutex_unlock(&tty_mutex);
return -ENODEV;
}
/*Если tty существует, повторно инициализируем структуру tty_struct, если она не существует*/
if (tty) {
retval = tty_reopen(tty);
if (retval)
tty = ERR_PTR(retval);
} else
/*Эта функция в основном выделяет tty, а затем инициализирует tty.
* Затем сохраните tty_struct в массиве tty_struct[] tty_driver.
* в соответствии сtty_struct->index*/
tty = tty_init_dev(driver, index, 0);
/*Затем он позвонитtty->ops->open。 Фактически, эта открытая функция
* Функция uart_open в uart_opsz
*
* */
if (tty->ops->open)
retval = tty->ops->open(tty, filp);
}
/* Найдите tty_driver, соответствующий устройству, по номеру устройства и сохраните индекс в индекс.
*
* **/
static struct tty_driver *get_tty_driver(dev_t device, int *index)
{
struct tty_driver *p;
list_for_each_entry(p, &tty_drivers, tty_drivers) {
dev_t base = MKDEV(p->major, p->minor_start);
if (device < base || device >= base + p->num)
continue;
*index = device - base;
return tty_driver_kref_get(p);
}
return NULL;
}
/*Важные утверждения при инициализации tty
*
* 1. Свяжите tty с дисциплиной линии через номер индекса N_TTY. будущее
* Членом ldisc в tty_struct будет tty_ldisc_N_TTY.
* 2. Установите для ops в tty_struct значение ops в tty_driver. И операции в tty_driver
* Это через tty_set_operations(normal, &uart_ops);установить в。 Это uart_ops
* */
void initialize_tty_struct(struct tty_struct *tty,
struct tty_driver *driver, int idx)
{
tty_ldisc_init(tty);
tty->driver = driver;
tty->ops = driver->ops;
tty->index = idx;
}
/*
* Найдите uart_state, сохраненный в tty_driver.
* Фактически, uart_state сохраняется в uart_driver во время инициализации.
*
* Затем вызовите uart_start для инициализации последовательного порта. port
*
* */
static int uart_open(struct tty_struct *tty, struct file *filp)
{
/*
* We take the semaphore inside uart_get to guarantee that we won't
* be re-entered while allocating the state structure, or while we
* request any IRQs that the driver may need. This also has the nice
* side-effect that it delays the action of uart_hangup, so we can
* guarantee that state->port.tty will always contain something
* reasonable.
*/
state = uart_get(drv, line);
if (IS_ERR(state)) {
retval = PTR_ERR(state);
goto fail;
}
port = &state->port;
/*
* Once we set tty->driver_data here, we are guaranteed that
* uart_close() will decrement the driver module use count.
* Any failures from here onwards should not touch the count.
*/
tty->driver_data = state;
state->uart_port->state = state;
tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
tty->alt_speed = 0;
tty_port_tty_set(port, tty);
/*
* Start up the serial port.
*/
retval = uart_startup(tty, state, 0);
}
static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw)
{
/*Самое главное предложение - позвонитьops->startup. То есть инициализировать операции в uart_port. Это s3c24xx_serial_ops*/
uport->ops->startup(uport);
}
/*
* Эта функция предназначена для открытия прерываний rx и tx, а затем разрешения прерываний.
* Тогда просто ждите, пока произойдет прерывание. Затем перейдите к обработчику прерывания, чтобы обработать прерывание.
*/
static int s3c24xx_serial_startup(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
int ret;
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);
return ret;
}
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);
goto err;
}
ourport->tx_claimed = 1;
dbg("s3c24xx_serial_startup ok\n");
/* the port reset code should have done the correct
* register setup for the port controls */
return ret;
}
Подведите итог:
Основная функция открытия В ядре создается и инициализируется tty_struct для описания конкретного соответствующего аппаратного устройства. Например, tty_struct используется для описания uart0 на s3c24xx, а затем находится uart_port.
Метод запуска в ops инициализирует оборудование uart.
Наиболее важные шаги в конкретном процессе инициализации tty_struct следующие:
1. Инициализируйте операции tty-struct,Просто измените opsназначен в tty_driver. наtty_struct
2. Инициализируйте набор операций дисциплины линии tty.
3. Инициализируйте uart_state в tty_struct. uart_state содержит информацию uart_port. Этот шаг выполняется с помощью метода open в ops на шаге 1.
4. В соответствии с uart_state, найденным на шаге 3, найдите метод запуска в операциях uart_port для инициализации оборудования uart.