The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

Консольные драйверы

Консольные драйверы

Предыдущая  Содержание  Следующая V*D*V

Консоль является устройством, которое показывает сообщения printk(), генерируемые ядром. Если посмотреть на Рисунок 12.5, то можно увидеть, что консольные драйверы лежат в двух ярусах: верхний уровень составляют такие драйверы, как драйвер виртуального терминала, консольный драйвер печати и, например, драйвер консоли USB_UART (обсуждается в ближайшее время), а низкий уровень  - драйверы, которые несут ответственность за дополнительные операции. Следовательно, есть две основных определённых структуры интерфейса, используемые консольными драйверами. Высокоуровневые консольные драйверы вращаются вокруг структуры console, которая определяет такие основные операции, как setup() и write(). Низкоуровневые драйверы сконцентрированы на структуре consw, которая определяет дополнительные операции, такие, как установка свойств курсора, переключение консоли, гашение, изменение размеров и установка информации палитры. Эти структуры определяются в include/linux/console.h следующим образом:

 

1.struct console {
   char name[8];
   void (*write)(struct console *, const char *, unsigned);
   int (*read)(struct console *, char *, unsigned);
   /* ... */
   void (*unblank)(void);
   int (*setup)(struct console *, char *);
   /* ... */
};
 

2.struct consw {
   struct module *owner;
   const char *(*con_startup)(void);
   void (*con_init)(struct vc_data *, int);
   void (*con_deinit)(struct vc_data *);
   void (*con_clear)(struct vc_data *, int, int, int, int);
   void (*con_putc)(struct vc_data *, int, int, int);
   void (*con_putcs)(struct vc_data *,
   const unsigned short *, int, int, int);
   void (*con_cursor)(struct vc_data *, int);
   int (*con_scroll)(struct vc_data *, int, int, int, int);
   /* ... */
};

 

Как вы уже могли догадаться, глядя на Рисунок 12.5, большинство консольных устройств требуют драйверов обоих уровней, работающих в тандеме. Во многих ситуациях драйвером консоли верхнего уровня является vt. В ПК-совместимых системах, консольный драйвер VGA (vgacon) является обычно низкоуровневым консольным драйвером, тогда как на встроенных устройствах низкоуровневым драйвером часто является консольный драйвер кадрового буфер (fbcon). Из-за косвенности, предлагаемой абстракцией кадрового буфера, fbcon, в отличие от других низкоуровневых консольных драйверов, является аппаратно-независимым.

 

Давайте кратко рассмотрим архитектуру обоих уровней консольных драйверов:

 

Драйвер верхнего уровня заполняет структуру console заданными точками входа и регистрирует её в ядре с помощью register_console(). Отмена регистрации осуществляется с использованием unregister_console(). Это драйвер, который взаимодействует с printk(). Входные точки, принадлежащие этому драйверу, вызываются службы связанного низкоуровневого драйвера консоли.
 

Низкоуровневый драйвер консоли заполняет структуру consw заданными точками входа и регистрирует её в ядре с помощью register_con_driver(). Отмена регистрации осуществляется с помощью unregister_con_driver(). Когда система поддерживает несколько драйверов консоли, чтобы зарегистрировать себя, драйвер может вместо этого вызвать take_over_console() и взять на себя обслуживание существующей консоли. give_up_console() выполняет обратное. Для обычных дисплеев низкоуровневые драйверы взаимодействуют с консольным драйвером верхнего уровня vt и символьным (текстовым) драйвером vc_screen, который позволяет получить доступ к памяти консоли.
 

Некоторым простым консолям, таким, построчно-печатающие устройства и USB_UART, обсуждаемые далее, необходим только высокоуровневый драйвер консоли.

 

Драйвер fbcon в ядре 2.6 также поддерживает поворот консоли. Дисплейные панели на КПК и мобильных телефонах обычно монтируются в портретной ориентации, в то время как автомобильные панели и IP телефоны являются примерами систем, где дисплейная панель находится в альбомном режиме. Иногда из-за экономических или других факторов встроенные устройства могут потребовать альбомный LCD, смонтированный в режиме портрета, или наоборот. В таких ситуациях удобна поддержка поворота консоли. Поскольку fbcon аппаратно-независим, реализация поворота консоли также универсальна. Для включения поворота консоли  включите при конфигурации ядра CONFIG_FRAMEBUFFER_CONSOLE_ROTATION и добавьте в командную строчку ядра fbcon=rotate:X, где X равно 0 для нормальной ориентации, 1 для поворота на 90 градусов, 2 для поворота на 180 градусов, и 3 для поворота на 270 градусов.

Пример устройства: Снова сотовый телефон

Чтобы узнать, как писать консольные драйверы, давайте вновь обратимся к сотовому телефону с Linux, который мы использовали в Главе 6. Наша задача в этом разделе заключается в разработке драйвера консоли, который работает в мобильном телефоне поверх USB_UART. Для удобства на Рисунке 12.7 воспроизводится сотовый телефон из Рисунка 6.5 Главы 6. Давайте напишем консольный драйвер, который выдаёт сообщения printk() наружу через USB_UART. Сообщения забираются ПК и отображаются для пользователя с помощью сессии, эмулирующей терминал.

 

Рисунок 12.7. Консоль через USB_UART.

Рисунок 12.7. Консоль через USB_UART.

 

Распечатка 12.3 содержит реализацию консольного драйвера, который работает через USB_UART-ы. Структура usb_uart_port[] и некоторые определения, используемые драйвером USB_UART в Главе 6, также включены в эту распечатку, чтобы создать полноценный драйвер. Действия драйвера объясняют комментарии распечатки.

 

Рисунок 12.5 показывает положение нашего примера консольного драйвера USB_UART в подсистеме видео в Linux. Как вы можете видеть, USB_UART - это простое устройство, которому необходим только высокоуровневый консольный драйвер.

 

Распечатка 12.3. Консоль через USB_UART

 

Код:

#include <linux/console.h>

#include <linux/serial_core.h>

#include <asm/io.h>

 

#define USB_UART_PORTS          2 /* Этот сотовый телефон имеет 2 порта USB_UART */

/* Каждый USB_UART имеет 3-х байтовый набор регистров, состоящий из

   UU_STATUS_REGISTER по смещению 0, UU_READ_DATA_REGISTER по

   смещению 1, и UU_WRITE_DATA_REGISTER по смещению 2, как показано

   Таблице 1 Главы 6, "Драйверы последовательный устройств" */

#define USB_UART1_BASE          0xe8000000 /* Базовый адрес памяти для USB_UART1 */

#define USB_UART2_BASE          0xe9000000 /* Базовый адрес памяти для USB_UART2 */

#define USB_UART_REGISTER_SPACE 0x3

/* Назначение битов регистра состояния */

#define USB_UART_TX_FULL        0x20

#define USB_UART_RX_EMPTY       0x10

#define USB_UART_STATUS         0x0F

 

#define USB_UART1_IRQ           3

#define USB_UART2_IRQ           4

#define USB_UART_CLK_FREQ       16000000

#define USB_UART_FIFO_SIZE      32

 

/* Параметры каждого из поддерживаемых портов USB_UART */

static struct uart_port usb_uart_port[] = {

    {

        .mapbase  = (unsigned int)USB_UART1_BASE,

        .iotype   = UPIO_MEM,           /* Отображённая память */

        .irq      = USB_UART1_IRQ,      /* IRQ */

        .uartclk  = USB_UART_CLK_FREQ,  /* Частота в Гц */

        .fifosize = USB_UART_FIFO_SIZE, /* Размер FIFO */

        .flags    = UPF_BOOT_AUTOCONF,  /* Флаг порта UART */

        .line     = 0,                  /* Номер линии UART */

    },

    {

        .mapbase  = (unsigned int)USB_UART2_BASE,

        .iotype   = UPIO_MEM,           /* Отображённая память */

        .irq      = USB_UART2_IRQ,      /* IRQ */

        .uartclk  = USB_UART_CLK_FREQ,  /* Частота в Гц */

        .fifosize = USB_UART_FIFO_SIZE, /* Размер FIFO */

        .flags    = UPF_BOOT_AUTOCONF,  /* Флаг порта UART */

        .line     = 1,                  /* Номер линии UART */

    }

};

 

/* Запись символа в порт USB_UART */

static void

usb_uart_putc(struct uart_port *port, unsigned char c)

{

    /* Ждём, пока появится место в TX FIFO этого USB_UART.

       Проверяем это опрашивая бит USB_UART_TX_FULL

       регистра состояния */

    while (__raw_readb(port->membase) & USB_UART_TX_FULL);

 

    /* Записываем символ в порт данных */

    __raw_writeb(c, (port->membase+1));

}

 

/* Консольная запись */

static void

usb_uart_console_write(struct console *co, const char *s, u_int count)

{

    int i;

 

    /* Пишем каждый символ */

    for (i = 0; i < count; i++, s++) {

        usb_uart_putc(&usb_uart_port[co->index], *s);

    }

}

 

/* Получение параметров коммуникации */

static void __init

usb_uart_console_get_options(struct uart_port *port,

                    int *baud, int *parity, int *bits)

{

    /* Читаем текущие настройки (возможно, установленные через bootloader)

       или возвращаем настройки по умолчанию для чётности, числа бит данных

       и скорости передачи */

    *parity = 'n';

    *bits = 8;

    *baud = 115200;

}

 

/* Установка параметров консоли для коммуникации */

static int __init

usb_uart_console_setup(struct console *co, char *options)

{

    struct uart_port *port;

    int baud, bits, parity, flow;

 

    /* Проверяем номер порта и получаем индекс

       соответствующей структуры */

    if (co->index == -1 || co->index >= USB_UART_PORTS) {

        co->index = 0;

    }

    port = &usb_uart_port[co->index];

 

    /* Используем функции, предоставляемые уровнем serial для обработки параметров */

    if (options) {

        uart_parse_options(options, &baud, &parity, &bits, &flow);

    } else {

        usb_uart_console_get_options(port, &baud, &parity, &bits);

    }

    return uart_set_options(port, co, baud, parity, bits, flow);

}

 

/* Заполняем структуру консоли */

static struct console usb_uart_console = {

    .name   = "ttyUU",                /* Имя консоли */

    .write  = usb_uart_console_write, /* Как делать printk в консоли */

    .device = uart_console_device,    /* Предоставлена ядром serial */

    .setup  = usb_uart_console_setup, /* Как настроить консоль */

    .flags  = CON_PRINTBUFFER,        /* Флаг по умолчанию */

    .index  = -1,                     /* Инициализация в неправильное значение */

};

 

/* Инициализация консоли */

static int __init

usb_uart_console_init(void)

{

/* ... */

/* Регистрация этой консоли */

register_console(&usb_uart_console);

return 0;

}

 

console_initcall(usb_uart_console_init); /* Метка инициализации консоли */

 

После того, как драйвер будет собран как часть ядра, вы сможете активировать его с помощью добавления в командную строку ядра console=ttyUUX (где X равен 0 или 1).

Логотип при загрузке

Популярной функцией, предлагаемой подсистемой кадрового буфера является отображение при загрузке логотипа. Для отображения логотипа при конфигурации ядра включите CONFIG_LOGO и выберите доступный логотип. Вы также можете добавить своё изображение логотипа в каталог drivers/video/logo/.

 

Широко используемым форматом изображения для логотипа загрузки является CLUT224, который поддерживает 224 цветов. Работа в таком формате похожа на псевдо-палитры, описанные в разделе "Цветовые режимы". Изображение в CLUT224 является файлом языка Си, содержащим две структуры:

 

CLUT (Color Look Up Table, Справочная таблица цветов), которая является символьным массивом из 224 наборов RGB (тем самым имеет размер 224*3 байт). Каждый 3-х байтовый элемент CLUT представляет собой комбинацию красного, зеленого и синего цветов.
 

Массив данных, каждый байт которого является индексом в CLUT. Индексы имеют значения от 32 до 255 (поддерживая тем самым 224 цветов). Индекс 32 относится к первому элементу в CLUT. Код работы с логотипом (в drivers/video/fbmem.c) создаёт пиксельные данные кадрового буфера из наборов CLUT, соответствующих каждому индексу в массиве данных. Визуальное отображение информации осуществляется с использованием метода низкоуровневого драйвера кадрового буфера fb_imageblit(), как рассказывалось в разделе "Методы ускорения".

 

Другими поддерживаемыми форматами логотипа являются 16-ти цветный vga16 и черно-белый mono. Скрипты для конвертации стандартных файлов в Переносимую пиксельную карту, Portable Pixel Map (PPM)  доступны на верхнем уровне каталога scripts/.

 

Если устройство кадрового буфера также является консолью, под логотипом прокручиваются сообщения при загрузке. Вы можете предпочесть отключить консольные сообщения на системе, готовой к поставке (добавив в командную строку ядра console=/dev/null), и показывать в качестве загрузочного логотипа собственно подготовленное изображение "заставка" в формата CLUT224.

Предыдущая  Содержание  Следующая