⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial.c

📁 Simple Operating Systems (简称SOS)是一个可以运行在X86平台上(包括QEMU
💻 C
字号:
/* Copyright (C) 2000  David Decotigny, The KOS Team   This program is free software; you can redistribute it and/or   modify it under the terms of the GNU General Public License   as published by the Free Software Foundation; either version 2   of the License, or (at your option) any later version.      This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.      You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,   USA. */#include <sos/errno.h>#include <hwcore/ioports.h>#include <sos/klibc.h>#include <hwcore/irq.h>#include <drivers/devices.h>#include "tty.h"#define SERIAL_BAUDRATE_MAX 115200/* Default parameters */#ifndef DEBUG_SERIAL_PORT# define DEBUG_SERIAL_PORT 0#endif#ifndef DEBUG_SERIAL_SPEED# define DEBUG_SERIAL_SPEED 9600#endif/* The offsets of UART registers.  */#define UART_TX         0#define UART_RX         0#define UART_DLL        0#define UART_IER        1#define UART_DLH        1#define UART_IIR        2#define UART_FCR        2#define UART_LCR        3#define UART_MCR        4#define UART_LSR        5#define UART_MSR        6#define UART_SR         7/* For LSR bits.  */#define UART_DATA_READY         0x01#define UART_EMPTY_TRANSMITTER  0x20/* The type of parity.  */#define UART_NO_PARITY          0x00#define UART_ODD_PARITY         0x08#define UART_EVEN_PARITY        0x18/* The type of word length.  */#define UART_5BITS_WORD 0x00#define UART_6BITS_WORD 0x01#define UART_7BITS_WORD 0x02#define UART_8BITS_WORD 0x03/* The type of the length of stop bit.  */#define UART_1_STOP_BIT         0x00#define UART_2_STOP_BITS        0x04/* the switch of DLAB.  */#define UART_DLAB               0x80/* Enable the FIFO.  */#define UART_ENABLE_FIFO        0xC7/* Turn on DTR, RTS, and OUT2.  */#define UART_ENABLE_MODEM       0x0Bstatic struct{  unsigned short iobase;  unsigned short is_enabled;  struct tty_device *tty;} _serial_config [] = { { 0x3f8, FALSE },                        { 0x2f8, FALSE },                        { 0x3e8, FALSE },                        { 0x2e8, FALSE } };#define SERIAL_PORT_MAX 4#define serial_inb inb#define serial_outb(port,val) outb(val,port)inline static intserial_isready (unsigned short port){  unsigned char status;  status = serial_inb (port + UART_LSR);  return (status & UART_DATA_READY) ? : -1;}static charserial_getchar (unsigned short unit){  if(unit >= SERIAL_PORT_MAX     || _serial_config[unit].is_enabled == FALSE)    return -1;  /* Wait until data is ready.  */  while ((serial_inb (_serial_config[unit].iobase + UART_LSR)          & UART_DATA_READY) == 0)    ;  /* Read and return the data.  */  return serial_inb (_serial_config[unit].iobase + UART_RX);}/* 0 on success */static intserial_putchar (unsigned short port, char c){  /* Perhaps a timeout is necessary.  */  int timeout = 10000;  /* Wait until the transmitter holding register is empty.  */  while ((serial_inb (port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)    if (--timeout == 0)      /* There is something wrong. But what can I do?  */      return -1;  serial_outb (port + UART_TX, c);  return 0;}static char serial_printk_buf[1024];inline static int serial_prints(unsigned short unit, const char *str){  const char *c;  unsigned short port;  if(unit >= SERIAL_PORT_MAX     || _serial_config[unit].is_enabled == FALSE)    return -1;  port = _serial_config[unit].iobase;  for (c = str; *c != '\0'; c++)    serial_putchar(port, *c);  return (int) (c-str);}int sos_serial_printf(unsigned short unit, const char *format, ...){  va_list args;  int len;  va_start(args, format);  len=vsnprintf(serial_printk_buf,sizeof(serial_printk_buf),format,args);  return serial_prints(unit, serial_printk_buf);}static void serial_irq_handler (int irq_level){  unsigned char chr;  if (irq_level == SOS_IRQ_COM1)    {      char c[2];      chr = serial_inb (_serial_config[0].iobase + UART_RX);      /* Little hacks to get it to work with Qemu serial port	 emulation. */      if (chr == '\r')	chr = '\n';      else if (chr == 127)	chr = '\b';      /* Build a null-terminated string */      c[0] = chr;      c[1] = '\0';      tty_add_chars (_serial_config[0].tty, c);    }}static sos_ret_t sos_serial_putchar (char c){  sos_ret_t ret;  int i;  /* The serial port doesn't understand '\b', but requires ANSI     commands instead. So we emulate '\b' by outputing "\e[D \e[D"     which basically goes backward one character, prints a space and     goes backward one character again. */  if (c == '\b')    {      const char *str = "\e[D \e[D";      for (i = 0; i < strlen(str); i++)	{	  ret = serial_putchar (_serial_config[0].iobase, str[i]);	  if (ret != SOS_OK)	    return ret;	}      return SOS_OK;    }  return serial_putchar (_serial_config[0].iobase, c);}/* OK On success */sos_ret_t sos_serial_subsystem_setup (sos_bool_t enable){  unsigned short div = 0;  unsigned char status = 0;  unsigned short serial_port;  unsigned short unit = 0;  unsigned int speed = 115200;  int word_len = UART_8BITS_WORD;  int parity = UART_NO_PARITY;  int stop_bit_len = UART_1_STOP_BIT;  if (unit >= SERIAL_PORT_MAX)    return -1;  serial_port = _serial_config[unit].iobase;  /* Turn off the interrupt.  */  serial_outb (serial_port + UART_IER, 0);  /* Set DLAB.  */  serial_outb (serial_port + UART_LCR, UART_DLAB);  /* Set the baud rate.  */  if (speed > SERIAL_BAUDRATE_MAX)    return -1;  div = SERIAL_BAUDRATE_MAX / speed;  serial_outb (serial_port + UART_DLL, div & 0xFF);  serial_outb (serial_port + UART_DLH, div >> 8);  /* Set the line status.  */  status |= parity | word_len | stop_bit_len;  serial_outb (serial_port + UART_LCR, status);  /* Enable the FIFO.  */  serial_outb (serial_port + UART_FCR, UART_ENABLE_FIFO);  /* Turn on DTR, RTS, and OUT2.  */  serial_outb (serial_port + UART_MCR, UART_ENABLE_MODEM);  /* Drain the input buffer.  */  while (serial_isready (serial_port) != -1)    (void) serial_getchar (unit);  _serial_config[unit].is_enabled = TRUE;  return SOS_OK;}/* Cannot be placed in sos_serial_subsystem_init() because when it   gets called, the IRQ handling subsystem is not yet initialized */sos_ret_t sos_ttyS0_subsystem_setup (void){  sos_ret_t ret;  /* FIXME */  ret = tty_create (SOS_CHARDEV_SERIAL_MINOR, sos_serial_putchar,		    & _serial_config[0].tty);  if (SOS_OK != ret)    return ret;  sos_irq_set_routine (SOS_IRQ_COM1, serial_irq_handler);  /* Enable interrupts */  serial_outb (_serial_config[0].iobase + UART_IER, 1);  return SOS_OK;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -