[Драйвер] Анализ последовательного драйвера (3)-последовательный драйвер
[Драйвер] Анализ последовательного драйвера (3)-последовательный драйвер

Введение

В первых двух разделах мы представили структуру драйвера последовательного порта и основную часть tty. В этом разделе мы представляем часть драйвера последовательного порта, которая тесно связана с аппаратным обеспечением.

Драйвер UART частично зависит от аппаратной платформы, тогда как драйвер TTY не имеет никакого отношения к конкретной платформе. Хотя часть UART зависит от платформы, какой бы аппаратной она ни была, идея драйвера одна и та же, и она будет представлена ​​отдельно в модулях ниже.

Ключевые структуры данных

struct uart_driver

struct uart_driverСама структура не содержит в себе лежащего в основеUARTКак работать с оборудованием,Чтода Абстракция всех драйверов последовательных устройствиинкапсуляция。Играет роль подключения драйверов аппаратных устройств.иTTYРоль водителя。Зарегистрированstruct uart_driverнельзя использовать послеUARTоборудование,Также необходимо связать конкретное устройство UART.

uart_driver Представление структуры UART водить машину, это определяетсуществоватьinclude/linux/serial_core.hв файле,Содержание следующее:

Язык кода:javascript
копировать
struct uart_driver {
 struct module  *owner;
 const char  *driver_name;
 const char  *dev_name;
 int    major;
 int    minor;
 int    nr;
 struct console  *cons;

 /*
  * these are private; the low level driver should not
  * touch these; they should be initialised to NULL
  */
 struct uart_state *state;
 struct tty_driver *tty_driver;
};
  • owner:Указатель на модуль владельца этого драйвера,То есть загружается модуль ядра, загружающий драйвер.
  • driver_name:нить,выразить имя водителя.
  • dev_name:нить,выразить имя устройства,То есть имя файла устройства, управляемого драйвером,Такие как ttyS.
  • major:выражатьоборудованиевладелец файлаоборудование Число。
  • minor:выражатьоборудованиевремя файлаоборудование Число。
  • nr:целое число,выразить Количество устройств, которыми управляет этот драйвер.
  • cons:ориентированный struct console указатель типа,выражать Долженпоследовательный портоборудованиеграницаконсоль。

Кроме того, структура также содержит два частных поля указателя:

  • state:ориентированный struct uart_state Указатель типа выражает информацию о внутреннем состоянии драйвера.
  • tty_driver:ориентированный struct tty_driver Указатель на тип, которому соответствует драйвер tty водитель.

struct uart_port

Часто на микросхеме последовательного порта имеется несколько последовательных портов (последовательный порт). ports,Соответствует физическому последовательному порту),Эти последовательные порты имеют одинаковый механизм работы.。LinuxЯдро использует эти последовательные порты какstruct uart_portОписание структуры。struct uart_portиспользуется для описанияUARTпрерывание порта、Адрес памяти ввода-вывода、Размер ФИФО、Тип порта и другая информация.

существовать Linux В ядре каждое устройство последовательного порта соответствует struct uart_port Структура данных, и эта структура данных будет сохранена как атрибут последовательного устройства, существующего в соответствующем узле устройства середина.

Когда приложение обращается к последовательному устройству путем открытия узла устройства, ядро ​​получает соответствующий struct uart_port структуру данных, а затем использовать эту структуру данных для выполнения таких операций, как чтение и запись последовательного порта.

Язык кода:javascript
копировать
struct uart_port {
 spinlock_t  lock;   /* port lock */
 unsigned long  iobase;   /* in/out[bwl] */
 unsigned char __iomem *membase;  /* read/write[bwl] */
 unsigned int  (*serial_in)(struct uart_port *, int);
 void   (*serial_out)(struct uart_port *, int, int);
 void   (*set_termios)(struct uart_port *,
                   struct ktermios *new,
                   struct ktermios *old);
 void   (*set_mctrl)(struct uart_port *, unsigned int);
 int   (*startup)(struct uart_port *port);
 void   (*shutdown)(struct uart_port *port);
 void   (*throttle)(struct uart_port *port);
 void   (*unthrottle)(struct uart_port *port);
 int   (*handle_irq)(struct uart_port *);
 void   (*pm)(struct uart_port *, unsigned int state,
          unsigned int old);
 void   (*handle_break)(struct uart_port *);
 int   (*rs485_config)(struct uart_port *,
      struct serial_rs485 *rs485);
 unsigned int  irq;   /* irq number */
 unsigned long  irqflags;  /* irq flags  */
 unsigned int  uartclk;  /* base uart clock */
 unsigned int  fifosize;  /* tx fifo size */
 unsigned char  x_char;   /* xon/xoff char */
 unsigned char  regshift;  /* reg offset shift */
 unsigned char  iotype;   /* io access style */
 unsigned char  unused1;

 unsigned int  read_status_mask; /* driver specific */
 unsigned int  ignore_status_mask; /* driver specific */
 struct uart_state *state;   /* pointer to parent state */
 struct uart_icount icount;   /* statistics */
 struct console  *cons;   /* struct console, if any */
 /* flags must be updated while holding port mutex */
 upf_t   flags;
 /*
  * Must hold termios_rwsem, port mutex and port lock to change;
  * can hold any one lock to read.
  */
 upstat_t  status;

 int   hw_stopped;  /* sw-assisted CTS flow state */
 unsigned int  mctrl;   /* current modem ctrl settings */
 unsigned int  timeout;  /* character-based timeout */
 unsigned int  type;   /* port type */
 const struct uart_ops *ops;
 unsigned int  custom_divisor;
 unsigned int  line;   /* port index */
 unsigned int  minor;
 resource_size_t  mapbase;  /* for ioremap */
 resource_size_t  mapsize;
 struct device  *dev;   /* parent device */
 unsigned char  hub6;   /* this should be in the 8250 driver */
 unsigned char  suspended;
 unsigned char  irq_wake;
 unsigned char  unused[2];
 struct attribute_group *attr_group;  /* port specific attributes */
 const struct attribute_group **tty_groups; /* all attributes (serial core use only) */
 struct serial_rs485     rs485;
 void   *private_data;  /* generic platform data pointer */
};
  • unsigned long iobase: Указывает базовый адрес существующего пространства ввода-вывода устройства последовательного порта.
  • unsigned char __iomem *membase: Указывает на адрес, отображенный в памяти последовательного устройства.
  • unsigned int (*serial_in)(struct uart_port *, int): Указатель функции, используемый для чтения данных с последовательного устройства.
  • void (*serial_out)(struct uart_port *, int, int): Указатель функции,используется для向последовательный портоборудованиесередина Писать Введите данные。
  • void (*set_termios)(struct uart_port *, struct ktermios *new, struct ktermios *old): Указатель функции, используемый для установки устройства последовательного порта.Параметры терминала。
  • void (*set_mctrl)(struct uart_port *, unsigned int): Указатель функции, используемый для установки устройства последовательного порта. modem управляющий сигнал.
  • int (*startup)(struct uart_port *port): Указатель функции,используется для初始化последовательный портоборудованиеизапускатьпередача инфекции。
  • void (*shutdown)(struct uart_port *port): Указатель функции, используемый для закрытия устройства последовательного порта.
  • void (*throttle)(struct uart_port *port): Указатель функции, используемый для управления потоком передачи последовательного устройства в остановленное состояние.
  • void (*unthrottle)(struct uart_port *port): Указатель функции, используемый для отмены состояния остановки управления потоком передачи устройства последовательного порта.
  • int (*handle_irq)(struct uart_port *): Указатель функции, используемый для обработки прерываний устройств последовательного порта.
  • void (*pm)(struct uart_port *, unsigned int state, unsigned int old): Указатель функции, используемый для управления питанием последовательных устройств.
  • void (*handle_break)(struct uart_port *): Указатель функции, используемый для обработки символа прерывания сигнала прерывания устройства последовательного порта.
  • int (*rs485_config)(struct uart_port *, struct serial_rs485 *rs485): Указатель функции для конфигурации RS485 Параметры последовательной связи.
  • unsigned int irq: Номер прерывания, используемый этим устройством последовательного порта.
  • unsigned long irqflags: Флаг прерывания этого устройства последовательного порта.
  • unsigned int uartclk: Тактовая частота этого последовательного устройства.
  • unsigned int fifosize: Устройство последовательного порта FIFO размер.
  • unsigned char x_char: XON/XOFF характер.
  • unsigned char regshift: Зарегистрируйте смещение.
  • unsigned char iotype: I/O Тип доступа.
  • unsigned char unused1: Неиспользуемая переменная-член.
  • unsigned int read_status_mask: Бит маски, используемый для указания статуса чтения.
  • unsigned int ignore_status_mask: Бит маски, используемый для указания статуса игнорирования.
  • struct uart_state *state: Указатель на структуру состояния устройства последовательного порта.
  • struct uart_icount icount: Используется для хранения статистической информации о последовательном устройстве.
  • struct console *cons: Указатель на консольное устройство, которому принадлежит это последовательное устройство.
  • unsigned int mctrl:Текущее управление модемом(Modem Контроль) настройки. Это значение содержит статус текущего сигнала управления (например, DTR, RTS, DSR, CTS и т. д.). Обычно управляется аппаратно.
  • unsigned int timeout:Тайм-аут на основе символов。Когда персонажпередача инфекцииприезжатьUARTпорт,Если следующий символ не получен в течение указанного времени,Истечет время ожидания и будет отправлено уведомление. Обычно устанавливается водителем.
  • unsigned int type:Тип порта。Это значение обычно используется для идентификацииUARTОсобые свойства фурнитуры(Например, тип чипа、Диапазон скорости передачи данных и т. д.).
  • const struct uart_ops *ops:одинориентированныйstruct структура uart_opsизуказатель。Эта структура содержитUARTСвязанные с драйвером Указатель функции,нравитьсяUARTчитать、Писать、запускать、Хватит ждать ожидания.
  • unsigned int custom_divisor:Пользовательский делитель,Используется для реализации нестандартных скоростей передачи данных. Это значение обычно задается драйвером.
  • unsigned int line:индекс порта,Номер, используемый для идентификации этого порта UART.
  • unsigned int minor:портиз次оборудование Число,Используется для определения местоположения порта UART в системе.
  • resource_size_t mapbase、resource_size_t mapsize:Начальный адрес отображаемой областииразмер.Эти значения обычно задаются драйвером,Используется для сопоставления физического адреса порта UART с виртуальным адресом.
  • struct device *dev:ориентированныйотецоборудованиеизуказатель。в целомда ДолженUARTоборудование所соединятьиз总线控制器оборудование。
  • unsigned char hub6:используется для обозначенияHub6Статус совета。Эта переменная должна Должендасуществовать8250определено в драйвере。
  • unsigned char suspended:используется для обозначения Долженпортда Будет ли приостановлено。
  • unsigned char irq_wake:используется для обозначения Долженпортда Поддерживать ли прерывание пробуждения。
  • unsigned char unused[2]:неиспользованные байты。
  • struct attribute_group *attr_group:ориентированный属性组изуказатель。Группа атрибутов содержитUARTоборудованиеиз属性идействовать,Например, состояние устройства, настройки скорости передачи данных и т. д. ожидание.
  • const struct attribute_group **tty_groups:ориентированныйуказатель数组изуказатель,Этот массив содержит указатели на все группы атрибутов.,Для использования последовательным ядром.
  • struct serial_rs485 rs485:RS485Структура конфигурации,Используется для связи RS485.
  • void *private_data:ориентированный私有数据изуказатель。этотуказательв целомводителемиспользовать,Используется для сохранения данных, относящихся к драйверу.

struct uart_ops

Linux В конечном итоге система вызывает систему для отправки и получения данных. ops функция в . ops да uart_ops类型из Структурауказательпеременная。uartаппаратное обеспечениедействоватьфункциясобирать,Базовый драйвер оборудования должен реализовывать эту структуру.

uart_opsСтруктура Используется для определения интерфейса для драйвера последовательного порта, позволяя верхнему уровню вызывать эти интерфейсы для реализации таких операций, как чтение и запись последовательного порта. Он содержит множество указателей функций, каждый указатель функции соответствует определенной операции последовательного порта.

В ядре Linux драйвер последовательного порта разделен на два уровня: драйвер чипа последовательного порта и serial core слой。Чтосередина,serial core Уровень предоставляет большое количество функциональных интерфейсов для использования драйвером микросхемы последовательного порта верхнего уровня. Определения этих функциональных интерфейсов включают существование. struct uart_ops в структуре.

При написании драйвера микросхемы последовательного порта необходимо реализовать struct uart_ops Каждый функциональный интерфейс определен в структуре так, что serial core вызов слоя.

Например, существование реализовано в драйвере микросхемы uart_start() Функция соответствует struct uart_ops в структуре startup указатель функции.

поэтому,struct uart_ops Структура да является ключом к реализации драйвера последовательного порта. Она определяет все функциональные интерфейсы, которые должен реализовать драйвер, и связана с ними. serial core слои связаны.

Язык кода:javascript
копировать
struct uart_ops {
 unsigned int (*tx_empty)(struct uart_port *);
 void  (*set_mctrl)(struct uart_port *, unsigned int mctrl);
 unsigned int (*get_mctrl)(struct uart_port *);
 void  (*stop_tx)(struct uart_port *);
 void  (*start_tx)(struct uart_port *);
 void  (*throttle)(struct uart_port *);
 void  (*unthrottle)(struct uart_port *);
 void  (*send_xchar)(struct uart_port *, char ch);
 void  (*stop_rx)(struct uart_port *);
 void  (*enable_ms)(struct uart_port *);
 void  (*break_ctl)(struct uart_port *, int ctl);
 int  (*startup)(struct uart_port *);
 void  (*shutdown)(struct uart_port *);
 void  (*flush_buffer)(struct uart_port *);
 void  (*set_termios)(struct uart_port *, struct ktermios *new,
           struct ktermios *old);
 void  (*set_ldisc)(struct uart_port *, struct ktermios *);
 void  (*pm)(struct uart_port *, unsigned int state,
         unsigned int oldstate);
 void  (*wake_peer)(struct uart_port *);

 /*
  * Return a string describing the type of the port
  */
 const char *(*type)(struct uart_port *);

 /*
  * Release IO and memory resources used by the port.
  * This includes iounmap if necessary.
  */
 void  (*release_port)(struct uart_port *);

 /*
  * Request IO and memory resources used by the port.
  * This includes iomapping the port if necessary.
  */
 int  (*request_port)(struct uart_port *);
 void  (*config_port)(struct uart_port *, int);
 int  (*verify_port)(struct uart_port *, struct serial_struct *);
 int  (*ioctl)(struct uart_port *, unsigned int, unsigned long);
#ifdef CONFIG_CONSOLE_POLL
 int  (*poll_init)(struct uart_port *);
 void  (*poll_put_char)(struct uart_port *, unsigned char);
 int  (*poll_get_char)(struct uart_port *);
#endif
};
  • tx_empty():Проверьте буфер отправки последовательного портада Нет пусто,Используется, чтобы определить, может ли да отправлять данные.
  • set_mctrl():Настройте последовательный порт modem управляющие сигналы, такие как RTS、DTR ждать.
  • get_mctrl():Получить последовательный порт modem управляющий сигнал.
  • stop_tx():Остановить токсуществоватьданные отправлены。
  • start_tx():Начать отправку данных。
  • throttle():Ограничить скорость отправки,Уменьшите объем отправляемых данных.
  • unthrottle():Отмена Ограничить скорость отправки。
  • send_xchar():отправить XON или XOFF Символ, используемый для управления потоком.
  • stop_rx():Прекратить получение данных。
  • enable_ms():включить последовательный порт modem Функция определения статуса.
  • break_ctl():отправить break Сигнал.
  • startup():Инициализация оборудования последовательного порта。
  • shutdown():Закройте оборудование последовательного порта。
  • flush_buffer():Очистить буфер последовательного порта。
  • set_termios():Настройте последовательный порт Параметры терминала。
  • set_ldisc():Настройте последовательный порт Правила отраслино。
  • pm():Реализовать последовательный порт power management。
  • wake_peer():используется длябудить Что他休眠状态изпоследовательный порт。

Кроме того, включены некоторые указатели функций для обработки ресурсов ввода-вывода последовательного порта:

  • type():返回描述последовательный порт类型изнить。
  • release_port():释放последовательный портиз IO и ресурсы памяти,включая подъем IO картографированиеждать.
  • request_port():请求последовательный портиз IO и ресурсы памяти,включая IO картографированиеждать.
  • config_port():Настройка параметров последовательного порта。
  • verify_port():Проверьте параметры последовательного портадаправильно или нет。
  • ioctl():实现последовательный портоборудованиеиз ioctl интерфейс.

struct uart_state

uart_state выражать UART статус и с struct uart_port Структуры используются вместе для управления UART порт.

struct uart_port Представление структуры UART информацию об аппаратном обеспечении и операциях порта, в то время как struct uart_state Структура содержит статус программного обеспечения, связанный с портом.

потому что UART Статус может содержать несколько состояний, поэтому несколько состояний можно использовать одновременно. UART статус для управления несколькими UART Портовые операции.

Язык кода:javascript
копировать
struct uart_state {
 struct tty_port  port;

 enum uart_pm_state pm_state;
 struct circ_buf  xmit;

 struct uart_port *uart_port;
};
  • struct tty_port port:выражать tty Информация о статусе порта,Включает буферы приема и отправки.,Информация управления и информация управления потоком и т. д. ожидание.
  • enum uart_pm_state pm_state:выражатьпоследовательный портоборудованиеиз电源管理状态,Можетда UART_PM_STATE_ONUART_PM_STATE_OFF или UART_PM_STATE_UNDEFINED
  • struct circ_buf xmit:выражатьпоследовательный портоборудованиеиз发送缓冲区,Используется для хранения данных для отправки.
  • struct uart_port *uart_port:выражать Долженпоследовательный порт Устройство соответствующее struct uart_port Структура.

Когда приложение записывает данные на последовательное устройство, данные будут храниться в xmit буфер и запускает функцию обработки отправки данных драйвера последовательного порта. Эта функция запустится с xmit Возьмите данные из буфера и передайте uart_port Указатель функции отправляет данные на физический последовательный порт. существуют При отправке данных драйвер также будет в соответствии с Состояние управления потоком последовательного порта выполняет управление потоком данных.

Когда данные будут получены, они будут сохранены в port в буфере приема и запускает функцию обработки приема данных драйвера последовательного порта. Функция-обработчик возьмет данные из буфера приема и передаст их приложению.

После абстрагирования структуры данных последовательное ядро ​​предоставляет удобный программный API базовому драйверу, в основном включающий следующие функции.

Ключевой API

uart_register_driver

uart_register_driverбудет определен и заполненuart driverЗарегистрируйтесь, чтобыkernelсередина,Обычно существование вызывается в интерфейсе инициализации модуля драйвера.

Язык кода:javascript
копировать
int uart_register_driver(struct uart_driver *drv)
{
 struct tty_driver *normal;
 int i, retval;

 BUG_ON(drv->state);
  
 drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
 if (!drv->state)
  goto out;

 normal = alloc_tty_driver(drv->nr);
 if (!normal)
  goto out_kfree;

 drv->tty_driver = normal;

 normal->driver_name = drv->driver_name;
 normal->name  = drv->dev_name;
 normal->major  = drv->major;
 normal->minor_start = drv->minor;
 normal->type  = TTY_DRIVER_TYPE_SERIAL;
 normal->subtype  = SERIAL_TYPE_NORMAL;
 normal->init_termios = tty_std_termios;
 normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
 normal->flags  = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
 normal->driver_state    = drv;
 tty_set_operations(normal, &uart_ops);

 /*
  * Initialise the UART state(s).
  */
 for (i = 0; i < drv->nr; i++) {
  struct uart_state *state = drv->state + i;
  struct tty_port *port = &state->port;

  tty_port_init(port);
  port->ops = &uart_port_ops;
 }

 retval = tty_register_driver(normal);
 if (retval >= 0)
  return retval;

 for (i = 0; i < drv->nr; i++)
  tty_port_destroy(&drv->state[i].port);
 put_tty_driver(normal);
out_kfree:
 kfree(drv->state);
out:
 return -ENOMEM;
}

uart_register_driver()Зарегистрируйте свою работунравиться Вниз:

  1. В соответствии с максимальным количеством устройств, поддерживаемых драйвером, подайте заявку на n uart_state пространство, каждый uart_state У каждого есть один uart_port 。
  2. Затем он выделит tty_driver объект и инициализировать его различные свойства, такие как driver_name,name,major,minor_start и т. д. Эти атрибуты да используются для существования. TTY Создано в подсистеме tty устройство, их значения берутся из uart_driver Значение, указанное в объекте.
  3. Далее он будет существовать tty_driver Средние настройки tty операция, среди которых tty_ops даа структура, которая определяет UART Функция, необходимая для последовательного интерфейса. После того, как эти функциисуществовать устройства последовательного порта зарегистрированы, когда есть данные, входящие и исходящие через последовательный порт, TTY Подсистема будет вызывать ихфункция。tty_set_operations() функцияиспользуется длясуществовать tty_driver Средние настройки tty действовать.
  4. существовать Инициализация завершена tty_driver Наконец, функция пройдет все UART Объекты состояния устройства и инициализировать их. Эти объекты состояния хранятся существующим uart_driver Объект state в поле. каждый UART Объект состояния устройства содержит tty_port Объект, в котором хранится информация об Устройстве последовательного информация о порте, такая как управление потоком, длина слова, четность и т. д. ждать.существовать здесь, tty_port Операция настроена на uart_port_ops,Он содержит конкретную реализацию UART Функция, необходимая для последовательного интерфейса.
  5. наконец-то позвонят tty_register_driver() Функция регистрации в ядре tty водитель и поместите водительское tty_driver Структура и uart_driver Связано со структурой.
  6. Если регистрация не удалась,Функция освободит ранее выделенную память. Если регистрация прошла успешно,Долженфункциявернется 0, в противном случае будет возвращен отрицательный код ошибки.

Подвести итогслово:tty serial coreбазовый уровень драйвераиttyСоединение между слоями должно начинаться сuart_register_driver()серединасоединять,tty_driverдасуществоватьuart_driverПроцесс регистрациисередина构建из。

uart_unregister_driver

uart_unregister_driverдаодинLinuxЯдров Отмена регистрации серийного драйверафункция,Используется для отключения ранее зарегистрированного драйвера от устройства последовательного порта системы.

Язык кода:javascript
копировать
/**
 * uart_unregister_driver - remove a driver from the uart core layer
 * @drv: low level driver structure
 *
 * Remove all references to a driver from the core driver.  The low
 * level driver must have removed all its ports via the
 * uart_remove_one_port() if it registered them with uart_add_one_port().
 * (ie, drv->port == NULL)
 */
void uart_unregister_driver(struct uart_driver *drv)
{
 struct tty_driver *p = drv->tty_driver;
 unsigned int i;
 /*Получаем информацию, связанную с драйвером tty_driver Пример*/
 tty_unregister_driver(p);
    
    /*Отменяем регистрацию драйвера и подключаем его к системе. tty Отключение устройства*/
 put_tty_driver(p);
    
    /*Выпускаем tty_driver Например, если счетчик использования экземпляра в этот момент равен нулю, то есть ни один другой модуль существования не использует этот экземпляр, то он будет полностью выгружен и все ресурсы памяти будут освобождены*/
 for (i = 0; i < drv->nr; i++)
  tty_port_destroy(&drv->state[i].port);
 kfree(drv->state);
 drv->state = NULL;
 drv->tty_driver = NULL;
}

uart_add_one_port

uart_add_one_portиспользуется для ВоляодинUARTпорт добавлен вUART驱动程序из状态表середина,И зарегистрируйте устройство порта TTY.,Позволяет пользовательскому пространству обмениваться данными с UART через это устройство.

Язык кода:javascript
копировать
/**
 * uart_add_one_port - attach a driver-defined port structure
 * @drv: pointer to the uart low level driver structure for this port
 * @uport: uart port structure to use for this port.
 *
 * This allows the driver to register its own uart_port structure
 * with the core driver.  The main purpose is to allow the low
 * level uart drivers to expand uart_port, rather than having yet
 * more levels of structures.
 */
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
{
 struct uart_state *state;
 struct tty_port *port;
 int ret = 0;
 struct device *tty_dev;
 int num_groups;
 
    /*Проверяем, находится ли да в контексте прерывания, если да напрямую возвращает ошибку*/
 BUG_ON(in_interrupt());
    
 /*Проверяем, находится ли добавленный порт да за пределами диапазона, поддерживаемого драйвером, если да, возвращаем EINVAL*/
 if (uport->line >= drv->nr)
  return -EINVAL;
 
    /*Получаем информацию о состоянии (uart_state) и порт (tty_port), соответствующий порту*/
 state = drv->state + uport->line;
 port = &state->port;

 mutex_lock(&port_mutex);
 mutex_lock(&port->mutex);
    
    /*Проверяем, занят ли порт да другими устройствами, если да, возвращаем EINVAL*/
 if (state->uart_port) {
  ret = -EINVAL;
  goto out;
 }

 /* Свяжите порт и таблицу состояния драйвера и выполните соответствующие работы по инициализации, включая статус PM, консоль, спин-блокировку и т. д. */
 state->uart_port = uport;
 uport->state = state;

 state->pm_state = UART_PM_STATE_UNDEFINED;
 uport->cons = drv->cons;
 uport->minor = drv->tty_driver->minor_start + uport->line;

 /*
  * If this port is a console, then the spinlock is already
  * initialised.
  */
 if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
  spin_lock_init(&uport->lock);
  lockdep_set_class(&uport->lock, &port_lock_key);
 }
 if (uport->cons && uport->dev)
  of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
 
    /*Настройте атрибуты порта, такие как скорость передачи данных, биты данных, стоповые биты и т. д.*/
 uart_configure_port(drv, state, uport);

 num_groups = 2;
 if (uport->attr_group)
  num_groups++;
    
 /*Назначаем и устанавливаем группы атрибутов устройства TTY, которые включают в себя общие группы атрибутов устройства TTY и определяемые пользователем группы атрибутов*/
 uport->tty_groups = kcalloc(num_groups, sizeof(*uport->tty_groups),
        GFP_KERNEL);
 if (!uport->tty_groups) {
  ret = -ENOMEM;
  goto out;
 }
 uport->tty_groups[0] = &tty_dev_attr_group;
 if (uport->attr_group)
  uport->tty_groups[1] = uport->attr_group;

 /*Зарегистрируем устройство порта TTY и свяжем его с tty_driverиtty_port*/
 tty_dev = tty_port_register_device_attr(port, drv->tty_driver,
   uport->line, uport->dev, port, uport->tty_groups);
    /*Если регистрация прошла успешно, помечаем устройство как пробуждаемое*/
 if (likely(!IS_ERR(tty_dev))) {
  device_set_wakeup_capable(tty_dev, 1);
 } else {
  dev_err(uport->dev, "Cannot register tty device on line %d\n",
         uport->line);
 }

 /*
  * Ensure UPF_DEAD is not set.
  */
 uport->flags &= ~UPF_DEAD;
 
 out:
 mutex_unlock(&port->mutex);
 mutex_unlock(&port_mutex);

 return ret;
}

uart_remove_one_port

uart_remove_one_portиспользуется дляиз основного драйверасерединаразделение(отключиться)один指定изпортструктура。

Язык кода:javascript
копировать
/**
 * uart_remove_one_port - detach a driver defined port structure
 * @drv: pointer to the uart low level driver structure for this port
 * @uport: uart port structure for this port
 *
 * This unhooks (and hangs up) the specified port structure from the
 * core driver.  No further calls will be made to the low-level code
 * for this port.
 */
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
{
 struct uart_state *state = drv->state + uport->line;
 struct tty_port *port = &state->port;
 struct tty_struct *tty;
 int ret = 0;
    
 /*Проверяем, находится ли текущий да в контексте прерывания*/
 BUG_ON(in_interrupt());
 
    /*Проверяем, равен ли указатель порта uart в структуре состояния uart указателю порта uart, переданному в функцию, если нет, выводим сообщение об ошибке*/
 if (state->uart_port != uport)
  dev_alert(uport->dev, "Removing wrong port: %p != %p\n",
   state->uart_port, uport);
    
 /*Получаем блокировку мьютекса структуры порта tty, которая используется для предотвращения одновременного изменения состояния порта*/
 mutex_lock(&port_mutex);

 /*Получаем блокировку мьютекса структуры порта tty, а затем проверяем, пуст ли указатель порта uart. Если пусто, выразите, что текущий порт уже занят. удалитьсуществовать. В этом случае будет возвращено -EINVAL и мьютекс будет разблокирован. */
 mutex_lock(&port->mutex);
 if (!state->uart_port) {
  mutex_unlock(&port->mutex);
  ret = -EINVAL;
  goto out;
 }
    /*блокировка port->mutex блокировка мьютекса и будет uport->flags установлен на UPF_DEAD, выражать Порт закрыт. Разблокировано позже port->mutex。*/
 uport->flags |= UPF_DEAD;
 mutex_unlock(&port->mutex);

 /*Удалить устройство из уровня tty*/
 tty_unregister_device(drv->tty_driver, uport->line);
    
 /*Получать tty Устройство соответствующее tty структура и использование tty_vhangup() Функция Закрыть это tty Терминал управления устройством. Наконец, используйте tty_kref_put() Функциональный выпуск tty Счетчик ссылок на структуру. */
 tty = tty_port_tty_get(port);
 if (tty) {
  tty_vhangup(port->tty);
  tty_kref_put(tty);
 }

 /*Если этот порт используется как консольный, используйте unregister_console() Функция Отменить консольную регистрацию этого порта*/
 if (uart_console(uport))
  unregister_console(uport->cons);

 /*в соответствии с uport->type значение для освобождения порта IO и ресурсы памяти, если uport->type Значение PORT_UNKNOWN, тогда выражение не имеет соответствующих ресурсов, которые необходимо освободить*/
 if (uport->type != PORT_UNKNOWN)
  uport->ops->release_port(uport);
 kfree(uport->tty_groups);

 /*Воля uport->type ценитьустановлен на PORT_UNKNOWN, выражать Порт больше не существует. В то же время, state->uart_port установлен на NULL,выражать state Соответствующий порт больше не связан с uport связанный. */
 uport->type = PORT_UNKNOWN;

 state->uart_port = NULL;
out:
 mutex_unlock(&port_mutex);

 return ret;
}

uart_write_wakeup

uart_write_wakeupuart_write_wakeupПробуждение последовательного порта верхнего уровня Писатьпроцесс заблокирован данными,Обычно существует функция обработчика прерывания отправки последовательного порта.

Язык кода:javascript
копировать
/*
 * This routine is used by the interrupt handler to schedule processing in
 * the software interrupt portion of the driver.
 */
void uart_write_wakeup(struct uart_port *port)
{
 struct uart_state *state = port->state;
 /*
  * This means you called this function _after_ the port was
  * closed.  No cookie for you.
  */
 BUG_ON(!state);
    /*функцияпросыпаться сstate->portсвязанный терминал。*/
 tty_wakeup(state->port.tty);
}

uart_suspend_port

uart_suspend_portфункция используется для приостановки работы порта для управления питанием. он выполняет ряд операций,В том числе проверка, может ли субустройство да разбудить систему,Прекратить отправку и получение данных,Подождите, пока буфер отправки станет пустым.,закрыть порт,Остановить консоль,и измените состояние управления питанием порта.

Язык кода:javascript
копировать
int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
{
 struct uart_state *state = drv->state + uport->line;
 struct tty_port *port = &state->port;
 struct device *tty_dev;
 struct uart_match match = {uport, drv};
    
 /*Блокируем порт, чтобы гарантировать, что условия гонки не возникнут при выполнении других операций*/
 mutex_lock(&port->mutex);
 
    /*Найти с помощьюuport->dev相关联из子оборудование。он используетmatchСтруктураиserial_match_portфункциячтобы соответствовать субоборудование*/
 tty_dev = device_find_child(uport->dev, &match, serial_match_port);
    /*нравитьсяфрукты找приезжать了子оборудованиеии Долженоборудование Можетбудить系统,тогда будетuport->irqустановлен набудитьсерединаперерыв,и будетuport->irq_wakeустановлен на1. Затем,Отпустите tty_dev и разблокируйте мьютекс порта.,и возвращает 0*/
 if (device_may_wakeup(tty_dev)) {
  if (!enable_irq_wake(uport->irq))
   uport->irq_wake = 1;
  put_device(tty_dev);
  mutex_unlock(&port->mutex);
  return 0;
 }
    /*Если подустройство найдено, но оно не может разбудить систему, отпустите tty_dev*/
 put_device(tty_dev);

 /* Nothing to do if the console is not suspending */
    /*Если консоль не включает приостановку и обновление консоли, перейдите к разблокировке*/
 if (!console_suspend_enabled && uart_console(uport))
  goto unlock;
 
    /*Воляuport->suspendedустановлен на1,выразиться порт завис. */
 uport->suspended = 1;
 
    /* Если порт был инициализирован, выполните некоторые операции, чтобы остановить передачу и закрыть порт. Эти операции включают установку ASYNCB_SUSPENDED и очистку флага ASYNCB_INITIALIZED, остановку отправки и получения данных, ожидание опустошения буфера отправки и закрытие порта. */
 if (port->flags & ASYNC_INITIALIZED) {
  const struct uart_ops *ops = uport->ops;
  int tries;

  set_bit(ASYNCB_SUSPENDED, &port->flags);
  clear_bit(ASYNCB_INITIALIZED, &port->flags);

  spin_lock_irq(&uport->lock);
  ops->stop_tx(uport);
  ops->set_mctrl(uport, 0);
  ops->stop_rx(uport);
  spin_unlock_irq(&uport->lock);

  /*
   * Wait for the transmitter to empty.
   */
  for (tries = 3; !ops->tx_empty(uport) && tries; tries--)
   msleep(10);
  if (!tries)
   dev_err(uport->dev, "%s%d: Unable to drain transmitter\n",
    drv->dev_name,
    drv->tty_driver->name_base + uport->line);

  ops->shutdown(uport);
 }

 /*
  * Disable the console device before suspending.
  */
    /* */
     /*Если консоль отключена, остановите консоль*/
 if (uart_console(uport))
  console_stop(uport->cons);
 /*Вызовите функцию uart_change_pm, чтобы изменить состояние управления питанием порта на UART_PM_STATE_OFF*/
 uart_change_pm(state, UART_PM_STATE_OFF);
unlock:
 mutex_unlock(&port->mutex);

 return 0;
}

uart_resume_port

uart_resume_portэффектдавосстанавливатьсяодинужевешатьизUARTпорт.

Язык кода:javascript
копировать
int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
{
 struct uart_state *state = drv->state + uport->line;
 struct tty_port *port = &state->port;
 struct device *tty_dev;
 struct uart_match match = {uport, drv};
 struct ktermios termios;

 mutex_lock(&port->mutex);
 
    /*Используем device_find_child для поиска структуры с именем match uart_matchсоответствиеuport->devиз子оборудование*/
 tty_dev = device_find_child(uport->dev, &match, serial_match_port);
    
    /*Если устройство найдено, порт не приостановлен и устройство может проснуться, функция отключает пробуждение по IRQ и возвращает 0*/
 if (!uport->suspended && device_may_wakeup(tty_dev)) {
  if (uport->irq_wake) {
   disable_irq_wake(uport->irq);
   uport->irq_wake = 0;
  }
  put_device(tty_dev);
  mutex_unlock(&port->mutex);
  return 0;
 }
    
    /*функция Воляuport->suspendedустановлен на0*/
 put_device(tty_dev);
 uport->suspended = 0;

 /*
  * Re-enable the console device after suspending.
  */
    /*нравитьсяфруктыпортдаконсольпорт,нофункция Воляtermiosструктураустановлен настройки флага консоли*/
 if (uart_console(uport)) {
  /*
   * First try to use the console cflag setting.
   */
  memset(&termios, 0, sizeof(struct ktermios));
  termios.c_cflag = uport->cons->cflag;

  /*
   * If that's unset, use the tty termios setting.
   */
  if (port->tty && termios.c_cflag == 0)
   termios = port->tty->termios;
  /*нравитьсяфрукты启用了консольвешать,Затем функция использует uart_change_pm, чтобы включить состояние управления питанием.,использоватьuport->ops->set_termiosнастраиватьtermios,ииспользоватьconsole_startзапускатьконсоль*/
  if (console_suspend_enabled)
   uart_change_pm(state, UART_PM_STATE_ON);
  uport->ops->set_termios(uport, &termios, NULL);
  if (console_suspend_enabled)
   console_start(uport->cons);
 }

 if (port->flags & ASYNC_SUSPENDED) {
  const struct uart_ops *ops = uport->ops;
  int ret;
 /* Если порт завис, функция использует uart_change_pm для изменения состояния управления питанием на открытие */
  uart_change_pm(state, UART_PM_STATE_ON);
  spin_lock_irq(&uport->lock);
        /*использоватьops->set_mctrlВолялиния управления модемомустановлен на0*/
  ops->set_mctrl(uport, 0);
  spin_unlock_irq(&uport->lock);
  if (console_suspend_enabled || !uart_console(uport)) {
   /* Protected by port mutex for now */
   struct tty_struct *tty = port->tty;
            /*использоватьops->startupзапускатьпорт*/
   ret = ops->startup(uport);
   if (ret == 0) {
            /*нравитьсяфруктыпортуспехзапускать,Затем используйте uart_change_speed, чтобы изменить скорость порта.,использоватьops->start_txзапускатьпередача инфекции,исуществоватьport->flagsСредние настройкиASYNCB_INITIALIZEDКусочек*/    if (tty)
     uart_change_speed(tty, state, NULL);
    spin_lock_irq(&uport->lock);
    ops->set_mctrl(uport, uport->mctrl);
                
    ops->start_tx(uport);
    spin_unlock_irq(&uport->lock);
    set_bit(ASYNCB_INITIALIZED, &port->flags);
   } else {
    /*
     * Failed to resume - maybe hardware went away?
     * Clear the "initialized" flag so we won't try
     * to call the low level drivers shutdown method.
     */
                /*Если порт невозможно восстановить, функция очищает бит ASYNCB_INITIALIZED и вызывает uart_shutdown*/
    uart_shutdown(tty, state);
   }
  }

  clear_bit(ASYNCB_SUSPENDED, &port->flags);
 }

 mutex_unlock(&port->mutex);

 return 0;
}

uart_get_baud_rate

uart_get_baud_rate,Роль функции da соответствует заданным настройкам терминала и области действия.,Получите доступную скорость передачи данных. Если вы не можете получить скорость передачи данных, отвечающую требованиям,Будет использоваться ближайшая возможная скорость передачи данных.

Язык кода:javascript
копировать
/**
 * uart_get_baud_rate - return baud rate for a particular port
 * @port: uart_port structure describing the port in question.
 * @termios: desired termios settings.
 * @old: old termios (or NULL)
 * @min: minimum acceptable baud rate
 * @max: maximum acceptable baud rate
 *
 * Decode the termios structure into a numeric baud rate,
 * taking account of the magic 38400 baud rate (with spd_*
 * flags), and mapping the %B0 rate to 9600 baud.
 *
 * If the new baud rate is invalid, try the old termios setting.
 * If it's still invalid, we try 9600 baud.
 *
 * Update the @termios structure to reflect the baud rate
 * we're actually going to be using. Don't do this for the case
 * where B0 is requested ("hang up").
 */
unsigned int
uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
     struct ktermios *old, unsigned int min, unsigned int max)
{
 unsigned int try;
 unsigned int baud;
 unsigned int altbaud;
 int hung_up = 0;
 upf_t flags = port->flags & UPF_SPD_MASK;
 
 switch (flags) {
 case UPF_SPD_HI:
  altbaud = 57600;
  break;
 case UPF_SPD_VHI:
  altbaud = 115200;
  break;
 case UPF_SPD_SHI:
  altbaud = 230400;
  break;
 case UPF_SPD_WARP:
  altbaud = 460800;
  break;
 default:
  altbaud = 38400;
  break;
 }

 for (try = 0; try < 2; try++) {
  baud = tty_termios_baud_rate(termios);

  /*
   * The spd_hi, spd_vhi, spd_shi, spd_warp kludge...
   * Die! Die! Die!
   */
  if (try == 0 && baud == 38400)
   baud = altbaud;

  /*
   * Special case: B0 rate.
   */
  if (baud == 0) {
   hung_up = 1;
   baud = 9600;
  }

  if (baud >= min && baud <= max)
   return baud;

  /*
   * Oops, the quotient was zero.  Try again with
   * the old baud rate if possible.
   */
  termios->c_cflag &= ~CBAUD;
  if (old) {
   baud = tty_termios_baud_rate(old);
   if (!hung_up)
    tty_termios_encode_baud_rate(termios,
        baud, baud);
   old = NULL;
   continue;
  }

  /*
   * As a last resort, if the range cannot be met then clip to
   * the nearest chip supported rate.
   */
  if (!hung_up) {
   if (baud <= min)
    tty_termios_encode_baud_rate(termios,
       min + 1, min + 1);
   else
    tty_termios_encode_baud_rate(termios,
       max - 1, max - 1);
  }
 }
 /* Should never happen */
 WARN_ON(1);
 return 0;
}

Эта функция делает следующее

  1. в соответствии с UPF_SPD_MASK Бит флага анализирует альтернативную скорость передачи данных. altbaud
  2. Функция дважды попытается получить скорость передачи данных. Впервые функция будет от termios анализирует текущую скорость передачи данных, если она равна 38400,тогда будетскорость передачи данныхустановлен Альтернативная скорость передачи данных altbaud。нравитьсяфруктыскорость передачи данных等于 0(то есть запрос“вешать”),нонастраиватьскорость передачи данных为 9600。нравитьсяфруктыскорость передачи данныхсуществовать min и max В пределах диапазона возвращается скорость передачи данных.
  3. Если скорость передачи данных, полученная впервые, равна 0,тогда функция попытается использовать старые настройки терминала.
  4. Если вы все еще не можете выполнить требования,Функция ограничит скорость передачи данных до ближайшего поддерживаемого значения. Метод резки,нравитьсяфруктыскорость передачи данных小于等于最小值 min,нонастраиватьскорость передачи данных为 min + 1,нетнонастраиватьскорость передачи данных为 max - 1

uart_get_divisor

uart_get_divisor,используется для Рассчитать данныепортиз UART Значение делителя тактовой частоты для достижения заданной скорости передачи данных . Основное да рассчитывается с помощью некоторых основных математических операций. UART Значение делителя часов. Это значение да используется для настройки UART аппаратное обеспечение для достижения указанной скорости передачи данных.

существоватьпоследовательный порт通信середина,Значение делителя тактовой частоты соответствует скорости передачи данных.,То есть, чем меньше значение делителя тактовой частоты, тем,Чем выше скорость передачи данных,Чем выше скорость передачи.

Язык кода:javascript
копировать
/**
 * uart_get_divisor - return uart clock divisor
 * @port: uart_port structure describing the port.
 * @baud: desired baud rate
 *
 * Calculate the uart clock divisor for the port.
 */
unsigned int
uart_get_divisor(struct uart_port *port, unsigned int baud)
{
 unsigned int quot;

 /*
  * Old custom speed handling.
  */
 if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
  quot = port->custom_divisor;
 else
  quot = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);

 return quot;
}

Эта функция делает следующее

  1. Прежде всего соответствии с Заданная скорость передачи данных рассчитывается UART длина тактового цикла period,Продолжительность этого периода проходит 16 * baud рассчитано. Затем измените порт UART тактовая частота, разделенная на period,полученное частное quot Как раз то, что нужно UART Значение делителя часов. используется здесь DIV_ROUND_CLOSEST Макрос, округляющий числа с плавающей запятой до ближайшего целого значения.
  2. Существуют также особые случаи, которые необходимо учитывать при вычислении значений делителя тактовой частоты. Если заданная скорость передачи данных 38400,иипортиз标志Кусочек Значение UPF_SPD_CUST,вам нужно использовать значение пользовательского делителя порта,Вместо значения, рассчитанного по формуле дав. Это связано с тем, что существуют некоторые старые драйверы последовательного порта.,Некоторые специальные скорости передачи данных могут поддерживаться с использованием пользовательских значений делителя.

uart_update_timeout

uart_update_timeoutиспользуется для Настройте последовательный порт FIFO период тайм-аута. FIFO (первым пришел — первым вышел) — это распространенная структура, используемая для кэширования данных в оборудовании последовательного порта. Она может повысить эффективность передачи через последовательный порт. Период ожидания да относится к существованию FIFO Если передача данных отсутствует, сколько времени потребуется для их автоматической очистки? ФИФО. Настройка времени ожидания может повлиять на стабильность и эффективность передачи данных через последовательный порт.

Язык кода:javascript
копировать
/**
 * uart_update_timeout - update per-port FIFO timeout.
 * @port:  uart_port structure describing the port
 * @cflag: termios cflag value
 * @baud:  speed of the port
 *
 * Set the port FIFO timeout value.  The @cflag value should
 * reflect the actual hardware settings.
 */
void
uart_update_timeout(struct uart_port *port, unsigned int cflag,
      unsigned int baud)
{
 unsigned int bits;

 /* byte size and parity */
 switch (cflag & CSIZE) {
 case CS5:
  bits = 7;
  break;
 case CS6:
  bits = 8;
  break;
 case CS7:
  bits = 9;
  break;
 default:
  bits = 10;
  break; /* CS8 */
 }

 if (cflag & CSTOPB)
  bits++;
 if (cflag & PARENB)
  bits++;

 /*
  * The total number of bits to be transmitted in the fifo.
  */
 bits = bits * port->fifosize;

 /*
  * Figure the timeout to send the above number of bits.
  * Add .02 seconds of slop
  */
 port->timeout = (HZ * bits) / baud + HZ/50;
}
  1. в соответствии «Настройки терминала» cflag значение, вычислите количество бит, которое необходимо передать для каждого байта bits。в соответствии с cflag в CSIZE Флаговый бит, определяет количество бит в каждом байте (5, 6, 7 или 8 немного), и в соответствии с CSTOPB и PARENB Бит флага, увеличение количества стоповых битов и битов четности.
  2. Количество бит, которое необходимо передать для каждого байта bits умножить на FIFO размера, чтобы получить общее количество битов, которые необходимо передать.
  3. в соответствии Скорость передачи и общее количество передаваемых бит, рассчитайте таймаут. Разделите общее количество битов, которые необходимо передать, на скорость передачи данных, чтобы получить время, необходимое для передачи данных, плюс некоторое дополнительное время (0,02 секунд) в качестве буфера для получения тайм-аута.
  4. наконец,Таким образом, тайм-аут конфигурации FIFO завершается.

uart_match_port

uart_match_portв соответствии с Атрибуты двух портов сравниваются, чтобы увидеть, являются ли два последовательных порта согласованными.

Язык кода:javascript
копировать
/*
 * Are the two ports equivalent?
 */
int uart_match_port(struct uart_port *port1, struct uart_port *port2)
{
 if (port1->iotype != port2->iotype)
  return 0;

 switch (port1->iotype) {
 case UPIO_PORT:
  return (port1->iobase == port2->iobase);
 case UPIO_HUB6:
  return (port1->iobase == port2->iobase) &&
         (port1->hub6   == port2->hub6);
 case UPIO_MEM:
 case UPIO_MEM32:
 case UPIO_MEM32BE:
 case UPIO_AU:
 case UPIO_TSI:
  return (port1->mapbase == port2->mapbase);
 }
 return 0;
}
  1. в соответствии с Два последовательных порта iotype Свойства сравниваются, если они не равны, два порта не равны, функция возвращает 0。
  2. в соответствии с iotype Если атрибуты различаются, сравните другие атрибуты двух портов. для UPIO_PORT и UPIO_HUB6 типы портов, сравнение их iobase и hub6 Атрибут да одинаков для остальных видов; портов, сравнение их mapbase Атрибут да не равен ожиданию. Если все атрибуты равны, то два порта равны и функция возвращается. 1, иначе возврат 0。

uart_console_write

uart_console_writeиспользуется для Воляконсольинформация Писать Введите последовательный порт。

существуетвстроенная система,Часто необходимо перенаправить вывод консоли на последовательный порт.,для отладкиирегистрация。Долженфункция Осуществленный Воляодиннить Писать Введите последовательный портизоперация, среди которому необходимо преобразовать строку с новой строки в возврат каретки и новую строку.

Язык кода:javascript
копировать
/**
 * uart_console_write - write a console message to a serial port
 * @port: the port to write the message
 * @s: array of characters
 * @count: number of characters in string to write
 * @putchar: function to write character to port
 */
void uart_console_write(struct uart_port *port, const char *s,
   unsigned int count,
   void (*putchar)(struct uart_port *, int))
{
 unsigned int i;

 for (i = 0; i < count; i++, s++) {
  if (*s == '\n')
   putchar(port, '\r');
  putchar(port, *s);
 }
}

Реализация функции в основном проходит все символы в строке.,и записывает каждый символ в последовательный порт. существовать до написания символов,Необходимо определить, является ли символ да символом новой строки. Если далин сломается,Сначала вам необходимо преобразовать его в возврат каретки и перевод строки.,Снова Писать Введите последовательный порт。

Подвести итог

Часть, которая соединяется с нижним слоем, ядром. основнойда Обеспечивает два интерфейса:

1. uart_register_driver (один вызов) 2. uart_add_one_port (вызывается несколько раз)

Через эти два интерфейса чип может подключить свой собственный UART к драйверу UART ядра Linux.

Части, которые производители чипов должны разработать и внедрить самостоятельно:

1. структура uart_drvier (одна) 2. Структура uart_port (несколько) 3. набор операций uart_ops для последовательного порта (может быть один, может быть несколько)

Итак, со структурной точки зрения весь процесс стыковки выглядит следующим образом:

Здесь есть одна вещь, которая требует особого внимания,существуют стыковочная часть нижнего слоя,Kernel определенныйодин Структура Вызов:struct uart_ops

существовать tty слой, правильно tty_driver Во время инициализации (serial_core.c) вызовите:

Язык кода:javascript
копировать
tty_set_operations(normal, &uart_ops);

И его реализация да:

Язык кода:javascript
копировать
void tty_set_operations(struct tty_driver *driver,const struct tty_operations *op)

{
 driver->ops = op;
};
EXPORT_SYMBOL(tty_set_operations);

Ты видел это, да прошел? ****tty_operations *op****,так,существовать tty_driver установлен uart_ops Не то struct uart_ops,И этот файл Serial_core.c определен в файле:

Язык кода:javascript
копировать
static const struct tty_operations uart_ops = {
 .open  = uart_open,
 .close  = uart_close,
 .write  = uart_write,
 .put_char = uart_put_char,
 .flush_chars = uart_flush_chars,
 .write_room = uart_write_room,
 .chars_in_buffer= uart_chars_in_buffer,
 .flush_buffer = uart_flush_buffer,
 .ioctl  = uart_ioctl,
 .throttle = uart_throttle,
 .unthrottle = uart_unthrottle,
 .send_xchar = uart_send_xchar,
 .set_termios = uart_set_termios,
 .set_ldisc = uart_set_ldisc,
 .stop  = uart_stop,
 .start  = uart_start,
 .hangup  = uart_hangup,
 .break_ctl = uart_break_ctl,
 .wait_until_sent= uart_wait_until_sent,
#ifdef CONFIG_PROC_FS
 .proc_show = uart_proc_show,
#endif
 .tiocmget = uart_tiocmget,
 .tiocmset = uart_tiocmset,
 .set_serial = uart_set_info_user,
 .get_serial = uart_get_info_user,
 .get_icount = uart_get_icount,
#ifdef CONFIG_CONSOLE_POLL
 .poll_init = uart_poll_init,
 .poll_get_char = uart_poll_get_char,
 .poll_put_char = uart_poll_put_char,
#endif
};

То же имя,Но да это не та же самая структура,Легко быть ослепленным~~

Ссылка на эту статью

https://blog.csdn.net/zhoutaopower/article/details/99289550

https://www.cnblogs.com/timemachine213/p/14317462.html

https://blog.csdn.net/u011728480/article/details/105676239

boy illustration
Учебное пособие по Jetpack Compose для начинающих, базовые элементы управления и макет
boy illustration
Код js веб-страницы, фон частицы, код спецэффектов
boy illustration
【новый! Суперподробное】Полное руководство по свойствам компонентов Figma.
boy illustration
🎉Обязательно к прочтению новичкам: полное руководство по написанию мини-программ WeChat с использованием программного обеспечения Cursor.
boy illustration
[Забавный проект Docker] VoceChat — еще одно приложение для мгновенного чата (IM)! Может быть встроен в любую веб-страницу!
boy illustration
Как реализовать переход по странице в HTML (html переходит на указанную страницу)
boy illustration
Как решить проблему зависания и низкой скорости при установке зависимостей с помощью npm. Существуют ли доступные источники npm, которые могут решить эту проблему?
boy illustration
Серия From Zero to Fun: Uni-App WeChat Payment Practice WeChat авторизует вход в систему и украшает страницу заказа, создает интерфейс заказа и инициирует запрос заказа
boy illustration
Серия uni-app: uni.navigateЧтобы передать скачок значения
boy illustration
Апплет WeChat настраивает верхнюю панель навигации и адаптируется к различным моделям.
boy illustration
JS-время конвертации
boy illustration
Обеспечьте бесперебойную работу ChromeDriver 125: советы по решению проблемы chromedriver.exe не найдены
boy illustration
Поле комментария, щелчок мышью, специальные эффекты, js-код
boy illustration
Объект массива перемещения объекта JS
boy illustration
Как открыть разрешение на позиционирование апплета WeChat_Как использовать WeChat для определения местонахождения друзей
boy illustration
Я даю вам два набора из 18 простых в использовании фонов холста Power BI, так что вам больше не придется возиться с цветами!
boy illustration
Получить текущее время в js_Как динамически отображать дату и время в js
boy illustration
Вам необходимо изучить сочетания клавиш vsCode для форматирования и организации кода, чтобы вам больше не приходилось настраивать формат вручную.
boy illustration
У ChatGPT большое обновление. Всего за 45 минут пресс-конференция показывает, что OpenAI сделал еще один шаг вперед.
boy illustration
Copilot облачной разработки — упрощение разработки
boy illustration
Микросборка xChatGPT с низким кодом, создание апплета чат-бота с искусственным интеллектом за пять шагов
boy illustration
CUDA Out of Memory: идеальное решение проблемы нехватки памяти CUDA
boy illustration
Анализ кластеризации отдельных ячеек, который должен освоить каждый&MarkerгенетическийВизуализация
boy illustration
vLLM: мощный инструмент для ускорения вывода ИИ
boy illustration
CodeGeeX: мощный инструмент генерации кода искусственного интеллекта, который можно использовать бесплатно в дополнение к второму пилоту.
boy illustration
Машинное обучение Реальный бой LightGBM + настройка параметров случайного поиска: точность 96,67%
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция без кодирования и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
LM Studio для создания локальных больших моделей
boy illustration
Как определить количество слоев и нейронов скрытых слоев нейронной сети?
boy illustration
[Отслеживание целей] Подробное объяснение ByteTrack и детали кода