在文件/u-boot-2013.07 / arch / arm / include / asm / arch / s3c24x0.h中定义了有关UART寄存器的结构体,如下所示:
/* UART (see manual chapter 11) */
struct s3c24x0_uart {
u32 ulcon; /* ULCON:线路控制寄存器 */
u32 ucon; /* UCON:控制寄存器 */
u32 ufcon; /* UFCON:FIFO控制寄存器 */
u32 umcon; /* UMCON:MODEM控制寄存器 */
u32 utrstat; /* UTRSTAT:收发状态寄存器 */
u32 uerstat; /* UERSTAT:错误状态寄存器 */
u32 ufstat; /* UFSTAT:FIFO状态寄存器 */
u32 umstat; /* UMSTAT:MODEM状态寄存器 */
#ifdef __BIG_ENDIAN
u8 res1[3];
u8 utxh;
u8 res2[3];
u8 urxh;
#else /* Little Endian */
u8 utxh; /* UTXH:发送缓冲寄存器 */
u8 res1[3];
u8 urxh; /* URXH:接收缓冲寄存器 */
u8 res2[3];
#endif
u32 ubrdiv; /* UBRDIV:波特率分频寄存器 */
};
在设置寄存器时首先通过在/u-boot-2013.07 / arch / arm / include / asm / arch / s3c2440.h中定义的函数获取UART寄存器的首地址,如下所示:
static inline struct s3c24x0_uart
*s3c24x0_get_base_uart(enum s3c24x0_uarts_nr n)
{
return (struct s3c24x0_uart *)(S3C24X0_UART_BASE + (n * 0x4000));
}
/* 注:首地址获取后,根据结构体存储空间的分配,便可以知道UART所有相关的寄存器地址 */
文件一:/u-boot-2013.07 / include / serial.h
#ifndef __SERIAL_H__
#define __SERIAL_H__
#include <post.h>
struct serial_device {
/* enough bytes to match alignment of following func pointer */
char name[16];
int (*start)(void);
int (*stop)(void);
void (*setbrg)(void); /* 为串口设置波特率*/
int (*getc)(void); /* 通过串口获得一个字符 */
int (*tstc)(void);
void (*putc)(const char c); /* 通过串口输出字符c */
void (*puts)(const char *s); /* 通过串口输出字符串s */
#if CONFIG_POST & CONFIG_SYS_POST_UART
void (*loop)(int);
#endif
struct serial_device *next;
};
void default_serial_puts(const char *s);
extern struct serial_device serial_smc_device;
extern struct serial_device serial_scc_device;
extern struct serial_device *default_serial_console(void);
#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
defined(CONFIG_405EX) || defined(CONFIG_440) || \
defined(CONFIG_MB86R0x) || defined(CONFIG_MPC5xxx) || \
defined(CONFIG_MPC83xx) || defined(CONFIG_MPC85xx) || \
defined(CONFIG_MPC86xx) || defined(CONFIG_SYS_SC520) || \
defined(CONFIG_TEGRA) || defined(CONFIG_SYS_COREBOOT) || \
defined(CONFIG_MICROBLAZE)
extern struct serial_device serial0_device;
extern struct serial_device serial1_device;
#endif
extern struct serial_device eserial1_device;
extern struct serial_device eserial2_device;
extern void serial_register(struct serial_device *);
extern void serial_initialize(void);
extern void serial_stdio_init(void);
extern int serial_assign(const char *name);
extern void serial_reinit_all(void);
/* For usbtty */
#ifdef CONFIG_USB_TTY
extern int usbtty_getc(void);
extern void usbtty_putc(const char c);
extern void usbtty_puts(const char *str);
extern int usbtty_tstc(void);
#else
/* stubs */
#define usbtty_getc() 0
#define usbtty_putc(a)
#define usbtty_puts(a)
#define usbtty_tstc() 0
#endif /* CONFIG_USB_TTY */
#if defined(CONFIG_MPC512X)
extern struct stdio_dev *open_port(int num, int baudrate);
extern int close_port(int num);
extern int write_port(struct stdio_dev *port, char *buf);
extern int read_port(struct stdio_dev *port, char *buf, int size);
#endif
#endif
文件二: /u-boot-2013.07 / drivers / serial / serial.c
#include <common.h>
#include <environment.h>
#include <serial.h>
#include <stdio_dev.h>
#include <post.h>
#include <linux/compiler.h>
#include <errno.h>
DECLARE_GLOBAL_DATA_PTR;
static struct serial_device *serial_devices;
static struct serial_device *serial_current;
/*
* Table with supported baudrates (defined in config_xyz.h)
*/
static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
/**
* serial_null() - Void registration routine of a serial driver
*
* This routine implements a void registration routine of a serial
* driver. The registration routine of a particular driver is aliased
* to this empty function in case the driver is not compiled into
* U-Boot.
*/
static void serial_null(void)
{
}
/**
* on_baudrate() - Update the actual baudrate when the env var changes
*
* This will check for a valid baudrate and only apply it if valid.
*/
static int on_baudrate(const char *name, const char *value, enum env_op op,
int flags)
{
int i;
int baudrate;
switch (op) {
case env_op_create:
case env_op_overwrite:
/*
* Switch to new baudrate if new baudrate is supported
*/
baudrate = simple_strtoul(value, NULL, 10);
/* Not actually changing */
if (gd->baudrate == baudrate)
return 0;
for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) {
if (baudrate == baudrate_table[i])
break;
}
if (i == ARRAY_SIZE(baudrate_table)) {
if ((flags & H_FORCE) == 0)
printf("## Baudrate %d bps not supported\n",
baudrate);
return 1;
}
if ((flags & H_INTERACTIVE) != 0) {
printf("## Switch baudrate to %d"
" bps and press ENTER ...\n", baudrate);
udelay(50000);
}
gd->baudrate = baudrate;
#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
gd->bd->bi_baudrate = baudrate;
#endif
serial_setbrg();
udelay(50000);
if ((flags & H_INTERACTIVE) != 0)
while (1) {
if (getc() == '\r')
break;
}
return 0;
case env_op_delete:
printf("## Baudrate may not be deleted\n");
return 1;
default:
return 0;
}
}
U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);
/**
* serial_initfunc() - Forward declare of driver registration routine
* @name: Name of the real driver registration routine.
*
* This macro expands onto forward declaration of a driver registration
* routine, which is then used below in serial_initialize() function.
* The declaration is made weak and aliases to serial_null() so in case
* the driver is not compiled in, the function is still declared and can
* be used, but aliases to serial_null() and thus is optimized away.
*/
#define serial_initfunc(name) \
void name(void) \
__attribute__((weak, alias("serial_null")));
serial_initfunc(mpc8xx_serial_initialize);
serial_initfunc(ns16550_serial_initialize);
serial_initfunc(pxa_serial_initialize);
serial_initfunc(s3c24xx_serial_initialize);
serial_initfunc(s5p_serial_initialize);
serial_initfunc(zynq_serial_initalize);
serial_initfunc(bfin_serial_initialize);
serial_initfunc(bfin_jtag_initialize);
serial_initfunc(mpc512x_serial_initialize);
serial_initfunc(uartlite_serial_initialize);
serial_initfunc(au1x00_serial_initialize);
serial_initfunc(asc_serial_initialize);
serial_initfunc(jz_serial_initialize);
serial_initfunc(mpc5xx_serial_initialize);
serial_initfunc(mpc8260_scc_serial_initialize);
serial_initfunc(mpc8260_smc_serial_initialize);
serial_initfunc(mpc85xx_serial_initialize);
serial_initfunc(iop480_serial_initialize);
serial_initfunc(leon2_serial_initialize);
serial_initfunc(leon3_serial_initialize);
serial_initfunc(marvell_serial_initialize);
serial_initfunc(amirix_serial_initialize);
serial_initfunc(bmw_serial_initialize);
serial_initfunc(cogent_serial_initialize);
serial_initfunc(cpci750_serial_initialize);
serial_initfunc(evb64260_serial_initialize);
serial_initfunc(ml2_serial_initialize);
serial_initfunc(sconsole_serial_initialize);
serial_initfunc(p3mx_serial_initialize);
serial_initfunc(altera_jtag_serial_initialize);
serial_initfunc(altera_serial_initialize);
serial_initfunc(atmel_serial_initialize);
serial_initfunc(lpc32xx_serial_initialize);
serial_initfunc(mcf_serial_initialize);
serial_initfunc(oc_serial_initialize);
serial_initfunc(sandbox_serial_initialize);
serial_initfunc(clps7111_serial_initialize);
serial_initfunc(imx_serial_initialize);
serial_initfunc(ixp_serial_initialize);
serial_initfunc(ks8695_serial_initialize);
serial_initfunc(lh7a40x_serial_initialize);
serial_initfunc(max3100_serial_initialize);
serial_initfunc(mxc_serial_initialize);
serial_initfunc(pl01x_serial_initialize);
serial_initfunc(s3c44b0_serial_initialize);
serial_initfunc(sa1100_serial_initialize);
serial_initfunc(sh_serial_initialize);
/**
* serial_register() - Register serial driver with serial driver core
* @dev: Pointer to the serial driver structure
*
* This function registers the serial driver supplied via @dev with
* serial driver core, thus making U-Boot aware of it and making it
* available for U-Boot to use. On platforms that still require manual
* relocation of constant variables, relocation of the supplied structure
* is performed.
*/
void serial_register(struct serial_device *dev)
{
#ifdef CONFIG_NEEDS_MANUAL_RELOC
if (dev->start)
dev->start += gd->reloc_off;
if (dev->stop)
dev->stop += gd->reloc_off;
if (dev->setbrg)
dev->setbrg += gd->reloc_off;
if (dev->getc)
dev->getc += gd->reloc_off;
if (dev->tstc)
dev->tstc += gd->reloc_off;
if (dev->putc)
dev->putc += gd->reloc_off;
if (dev->puts)
dev->puts += gd->reloc_off;
#endif
dev->next = serial_devices;
serial_devices = dev;
}
/**
* serial_initialize() - Register all compiled-in serial port drivers
*
* This function registers all serial port drivers that are compiled
* into the U-Boot binary with the serial core, thus making them
* available to U-Boot to use. Lastly, this function assigns a default
* serial port to the serial core. That serial port is then used as a
* default output.
*/
void serial_initialize(void)
{
mpc8xx_serial_initialize();
ns16550_serial_initialize();
pxa_serial_initialize();
s3c24xx_serial_initialize();
s5p_serial_initialize();
mpc512x_serial_initialize();
bfin_serial_initialize();
bfin_jtag_initialize();
uartlite_serial_initialize();
zynq_serial_initalize();
au1x00_serial_initialize();
asc_serial_initialize();
jz_serial_initialize();
mpc5xx_serial_initialize();
mpc8260_scc_serial_initialize();
mpc8260_smc_serial_initialize();
mpc85xx_serial_initialize();
iop480_serial_initialize();
leon2_serial_initialize();
leon3_serial_initialize();
marvell_serial_initialize();
amirix_serial_initialize();
bmw_serial_initialize();
cogent_serial_initialize();
cpci750_serial_initialize();
evb64260_serial_initialize();
ml2_serial_initialize();
sconsole_serial_initialize();
p3mx_serial_initialize();
altera_jtag_serial_initialize();
altera_serial_initialize();
atmel_serial_initialize();
lpc32xx_serial_initialize();
mcf_serial_initialize();
oc_serial_initialize();
sandbox_serial_initialize();
clps7111_serial_initialize();
imx_serial_initialize();
ixp_serial_initialize();
ks8695_serial_initialize();
lh7a40x_serial_initialize();
max3100_serial_initialize();
mxc_serial_initialize();
pl01x_serial_initialize();
s3c44b0_serial_initialize();
sa1100_serial_initialize();
sh_serial_initialize();
serial_assign(default_serial_console()->name);
}
/**
* serial_stdio_init() - Register serial ports with STDIO core
*
* This function generates a proxy driver for each serial port driver.
* These proxy drivers then register with the STDIO core, making the
* serial drivers available as STDIO devices.
*/
void serial_stdio_init(void)
{
struct stdio_dev dev;
struct serial_device *s = serial_devices;
while (s) {
memset(&dev, 0, sizeof(dev));
strcpy(dev.name, s->name);
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
dev.start = s->start;
dev.stop = s->stop;
dev.putc = s->putc;
dev.puts = s->puts;
dev.getc = s->getc;
dev.tstc = s->tstc;
stdio_register(&dev);
s = s->next;
}
}
/**
* serial_assign() - Select the serial output device by name
* @name: Name of the serial driver to be used as default output
*
* This function configures the serial output multiplexing by
* selecting which serial device will be used as default. In case
* the STDIO "serial" device is selected as stdin/stdout/stderr,
* the serial device previously configured by this function will be
* used for the particular operation.
*
* Returns 0 on success, negative on error.
*/
int serial_assign(const char *name)
{
struct serial_device *s;
for (s = serial_devices; s; s = s->next) {
if (strcmp(s->name, name))
continue;
serial_current = s;
return 0;
}
return -EINVAL;
}
/**
* serial_reinit_all() - Reinitialize all compiled-in serial ports
*
* This function reinitializes all serial ports that are compiled
* into U-Boot by calling their serial_start() functions.
*/
void serial_reinit_all(void)
{
struct serial_device *s;
for (s = serial_devices; s; s = s->next)
s->start();
}
/**
* get_current() - 返回指向当前所选择的串口的指针
*
* 该函数返回指向当前所选择串口的指针
* 当前所选择的串口可以通过函数serial_assign()来改变
* 为了避免该函数在代码复制前或在任何串口被配置前调用,该函数调
* 用default_serial_console()来确定串口。否则,已配置的串口被返回。
* 成功时返回指向当前所选择串口的指针,失败时返回NULL
*/
static struct serial_device *get_current(void)
{
struct serial_device *dev;
if (!(gd->flags & GD_FLG_RELOC)) /* 这两种情况下使用默认值*/
dev = default_serial_console();
else if (!serial_current)
dev = default_serial_console();
else
dev = serial_current; /* 否则设为当前所选择的串口 */
/* We must have a console device */
if (!dev) {
#ifdef CONFIG_SPL_BUILD
puts("Cannot find console\n");
hang();
#else
panic("Cannot find console\n");
#endif
}
return dev; /* 返回指向所选择串口的指针 */
}
/**
* serial_init() - Initialize currently selected serial port
*
* This function initializes the currently selected serial port. This
* usually involves setting up the registers of that particular port,
* enabling clock and such. This function uses the get_current() call
* to determine which port is selected.
*
* Returns 0 on success, negative on error.
*/
int serial_init(void)
{
return get_current()->start();
}
/**
* serial_setbrg() - 为当前所选择的串口设置波特率
*
* 该函数用于为当前所选择的串口设置波特率,从串口驱动内的全局数据中检索波特率,
* 该函数通过调用get_current()来确定选择了哪个串口。
* Returns 0 on success, negative on error.
*/
void serial_setbrg(void)
{
get_current()->setbrg();
}
/**
* serial_getc() - 从当前所选择的串口中读取一个字符
*
* This function retrieves a character from currently selected serial
* port. In case there is no character waiting on the serial port,
* this function will block and wait for the character to appear.
* 该函数从当前所选择的串口中获取一个字符。该函数通过调用get_current()来确定选择了哪个串口。
* 成功时返回字符,否则返回负值。
*/
int serial_getc(void)
{
return get_current()->getc();
}
/**
* serial_tstc() - Test if data is available on currently selected serial port
*
* This function tests if one or more characters are available on
* currently selected serial port. This function never blocks. This
* function uses the get_current() call to determine which port is
* selected.
*
* Returns positive if character is available, zero otherwise.
*/
int serial_tstc(void)
{
return get_current()->tstc();
}
/**
* serial_putc() - Output character via currently selected serial port
* @c: Single character to be output from the serial port.
*
* This function outputs a character via currently selected serial
* port. This character is passed to the serial port driver responsible
* for controlling the hardware. The hardware may still be in process
* of transmitting another character, therefore this function may block
* for a short amount of time. This function uses the get_current()
* call to determine which port is selected.
* 该函数通过当前所选择的串口输出一个字符。该字符被传给负责控制硬件的串口驱动。
* 该硬件可能仍需发送另外一个字符,所以要等待一小段时间。
* 该函数通过get_current()确定选择哪一个串口。
*/
void serial_putc(const char c)
{
get_current()->putc(c);
}
/**
* serial_puts() - 通过当前所选择的串口输出字符串
* @s: Zero-terminated string to be output from the serial port.
*
* This function outputs a zero-terminated string via currently
* selected serial port. This function behaves as an accelerator
* in case the hardware can queue multiple characters for transfer.
* The whole string that is to be output is available to the function
* implementing the hardware manipulation. Transmitting the whole
* string may take some time, thus this function may block for some
* amount of time. This function uses the get_current() call to
* determine which port is selected.
*/
void serial_puts(const char *s)
{
get_current()->puts(s);
}
/**
* default_serial_puts() - 通过循环调用serial_putc()来输出字符串
* @s: Zero-terminated string to be output from the serial port.
*
* This function outputs a zero-terminated string by calling serial_putc()
* in a loop. Most drivers do not support queueing more than one byte for
* transfer, thus this function precisely implements their serial_puts().
*
* To optimize the number of get_current() calls, this function only
* calls get_current() once and then directly accesses the putc() call
* of the &struct serial_device .
*/
void default_serial_puts(const char *s)
{
struct serial_device *dev = get_current();
while (*s)
dev->putc(*s++);
}
#if CONFIG_POST & CONFIG_SYS_POST_UART
static const int bauds[] = CONFIG_SYS_BAUDRATE_TABLE;
/**
* uart_post_test() - 用POST来测试当前所选择的串口
* @flags: POST framework flags
*
* Do a loopback test of the currently selected serial port. This
* function is only useful in the context of the POST testing framwork.
* The serial port is firstly configured into loopback mode and then
* characters are sent through it.
*
* Returns 0 on success, value otherwise.
*/
/* Mark weak until post/cpu/.../uart.c migrate over */
__weak
int uart_post_test(int flags)
{
unsigned char c;
int ret, saved_baud, b;
struct serial_device *saved_dev, *s;
bd_t *bd = gd->bd;
/* Save current serial state */
ret = 0;
saved_dev = serial_current;
saved_baud = bd->bi_baudrate;
for (s = serial_devices; s; s = s->next) {
/* If this driver doesn't support loop back, skip it */
if (!s->loop)
continue;
/* Test the next device */
serial_current = s;
ret = serial_init();
if (ret)
goto done;
/* Consume anything that happens to be queued */
while (serial_tstc())
serial_getc();
/* Enable loop back */
s->loop(1);
/* Test every available baud rate */
for (b = 0; b < ARRAY_SIZE(bauds); ++b) {
bd->bi_baudrate = bauds[b];
serial_setbrg();
/*
* Stick to printable chars to avoid issues:
* - terminal corruption
* - serial program reacting to sequences and sending
* back random extra data
* - most serial drivers add in extra chars (like \r\n)
*/
for (c = 0x20; c < 0x7f; ++c) {
/* Send it out */
serial_putc(c);
/* Make sure it's the same one */
ret = (c != serial_getc());
if (ret) {
s->loop(0);
goto done;
}
/* Clean up the output in case it was sent */
serial_putc('\b');
ret = ('\b' != serial_getc());
if (ret) {
s->loop(0);
goto done;
}
}
}
/* Disable loop back */
s->loop(0);
/* XXX: There is no serial_stop() !? */
if (s->stop)
s->stop();
}
done:
/* Restore previous serial state */
serial_current = saved_dev;
bd->bi_baudrate = saved_baud;
serial_reinit_all();
serial_setbrg();
return ret;
}
#endif
文件二: /u-boot-2013.07 / drivers / serial / serial_s3c24x0.c
#include <common.h>
#include <linux/compiler.h>
#include <asm/arch/s3c24x0_cpu.h>
DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_SERIAL1
#define UART_NR S3C24X0_UART0
#elif defined(CONFIG_SERIAL2)
#define UART_NR S3C24X0_UART1
#elif defined(CONFIG_SERIAL3)
#define UART_NR S3C24X0_UART2
#else
#error "Bad: you didn't configure serial ..."
#endif
#include <asm/io.h>
#include <serial.h>
/* Multi serial device functions */
#define DECLARE_S3C_SERIAL_FUNCTIONS(port) \
int s3serial##port##_init(void) \
{ \
return serial_init_dev(port); \
} \
void s3serial##port##_setbrg(void) \
{ \
serial_setbrg_dev(port); \
} \
int s3serial##port##_getc(void) \
{ \
return serial_getc_dev(port); \
} \
int s3serial##port##_tstc(void) \
{ \
return serial_tstc_dev(port); \
} \
void s3serial##port##_putc(const char c) \
{ \
serial_putc_dev(port, c); \
} \
void s3serial##port##_puts(const char *s) \
{ \
serial_puts_dev(port, s); \
}
#define INIT_S3C_SERIAL_STRUCTURE(port, __name) { \
.name = __name, \
.start = s3serial##port##_init, \
.stop = NULL, \
.setbrg = s3serial##port##_setbrg, \
.getc = s3serial##port##_getc, \
.tstc = s3serial##port##_tstc, \
.putc = s3serial##port##_putc, \
.puts = s3serial##port##_puts, \
}
#ifdef CONFIG_HWFLOW
static int hwflow;
#endif
/* 设置指定串口硬件的UART波特率分频寄存器 */
void _serial_setbrg(const int dev_index)
{
/* 获取UART所有寄存器的地址 */
struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
unsigned int reg = 0;
int i;
/* 根据UART时钟频率和波特率计算波特率分频值,UBRDIV=(int)(UART时钟频率/16/波特率)- 1 */
reg = get_PCLK() / (16 * gd->baudrate) - 1;
writel(reg, &uart->ubrdiv); /* 设置UBRDIV */
for (i = 0; i < 100; i++)
/* Delay */ ;
}
static inline void serial_setbrg_dev(unsigned int dev_index)
{
_serial_setbrg(dev_index);
}
/*
* 初始化串口:8位数据位,1位停止位,无起始位,无校验位,波特率
*/
static int serial_init_dev(const int dev_index)
{
struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index); /* 获取UART所有寄存器的地址 */
#ifdef CONFIG_HWFLOW
hwflow = 0; /* turned off by default */
#endif
/* FIFO enable, Tx/Rx FIFO clear */
writel(0x07, &uart->ufcon); /* 设置UFCON = 0X07 */
writel(0x0, &uart->umcon); /* 设置UMCON = 0X0 */
/* Normal,No parity,1 stop,8 bit */
writel(0x3, &uart->ulcon); /* 设置ULCON = 0X3 */
/*
* tx=level,rx=edge,disable timeout int.,enable rx error int.,
* normal,interrupt or polling
*/
writel(0x245, &uart->ucon); /* 设置UCON = 0X245 */
#ifdef CONFIG_HWFLOW
writel(0x1, &uart->umcon); /* rts up,设置UMCON = 0X1 */
#endif
/* FIXME: This is sooooooooooooooooooo ugly */
#if defined(CONFIG_ARCH_GTA02_v1) || defined(CONFIG_ARCH_GTA02_v2)
/* we need auto hw flow control on the gsm and gps port */
if (dev_index == 0 || dev_index == 1)
writel(0x10, &uart->umcon); /* 设置UMCON = 0X10 */
#endif
_serial_setbrg(dev_index); /* 设置UBRDIV */
return (0);
}
/*
* 通过串口读一个字节。成功时返回所读字节,否则返回0.
*/
int _serial_getc(const int dev_index)
{
struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);/* 获取UART所有寄存器的地址 */
while (!(readl(&uart->utrstat) & 0x1))
/* 通过查询法循环等待待接收的字符到达接收移位寄存器中 */ ;
return readb(&uart->urxh) & 0xff; /* 读取并返回URXH中的一字节内容 */
}
/* 通过指定的串口接收一个字节 */
static inline int serial_getc_dev(unsigned int dev_index)
{
return _serial_getc(dev_index);
}
#ifdef CONFIG_HWFLOW
int hwflow_onoff(int on)
{
switch (on) {
case 0:
default:
break; /* return current */
case 1:
hwflow = 1; /* turn on */
break;
case -1:
hwflow = 0; /* turn off */
break;
}
return hwflow;
}
#endif
#ifdef CONFIG_MODEM_SUPPORT
static int be_quiet = 0;
void disable_putc(void)
{
be_quiet = 1;
}
void enable_putc(void)
{
be_quiet = 0;
}
#endif
/*
* 通过串口输出一个字节.
*/
void _serial_putc(const char c, const int dev_index)
{
struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);/* 获取UART所有寄存器的地址 */
#ifdef CONFIG_MODEM_SUPPORT
if (be_quiet)
return;
#endif
while (!(readl(&uart->utrstat) & 0x2))
/* wait for room in the tx FIFO */ ;
#ifdef CONFIG_HWFLOW
while (hwflow && !(readl(&uart->umstat) & 0x1))
/* Wait for CTS up */ ;
#endif
writeb(c, &uart->utxh); /* 通过向UTXH中中写一字节内容以便自动通过串口输出 */
/* If \n, also do \r */
if (c == '\n')
serial_putc('\r');
}
/* 通过指定的串口硬件输出一个字节 */
static inline void serial_putc_dev(unsigned int dev_index, const char c)
{
_serial_putc(c, dev_index);
}
/*
* 检测接收移位寄存器中是否收到一个字节
*/
int _serial_tstc(const int dev_index)
{
struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);/* 获取UART所有寄存器的地址 */
return readl(&uart->utrstat) & 0x1; /*读取并返回UTRSTAT[0]即接收缓冲区状态:1为接收到数据,0为未收到*/
}
static inline int serial_tstc_dev(unsigned int dev_index)
{
return _serial_tstc(dev_index);
}
/* 通过指定的串口硬件来输出字符串 */
void _serial_puts(const char *s, const int dev_index)
{
while (*s) {
_serial_putc(*s++, dev_index);
}
}
static inline void serial_puts_dev(int dev_index, const char *s)
{
_serial_puts(s, dev_index);
}
DECLARE_S3C_SERIAL_FUNCTIONS(0);
struct serial_device s3c24xx_serial0_device =
INIT_S3C_SERIAL_STRUCTURE(0, "s3ser0");
DECLARE_S3C_SERIAL_FUNCTIONS(1);
struct serial_device s3c24xx_serial1_device =
INIT_S3C_SERIAL_STRUCTURE(1, "s3ser1");
DECLARE_S3C_SERIAL_FUNCTIONS(2);
struct serial_device s3c24xx_serial2_device =
INIT_S3C_SERIAL_STRUCTURE(2, "s3ser2");
__weak struct serial_device *default_serial_console(void)
{
#if defined(CONFIG_SERIAL1)
return &s3c24xx_serial0_device;
#elif defined(CONFIG_SERIAL2)
return &s3c24xx_serial1_device;
#elif defined(CONFIG_SERIAL3)
return &s3c24xx_serial2_device;
#else
#error "CONFIG_SERIAL? missing."
#endif
}
void s3c24xx_serial_initialize(void)
{
serial_register(&s3c24xx_serial0_device); /* 注册串口硬件:UART0 */
serial_register(&s3c24xx_serial1_device); /* 注册串口硬件:UART1 */
serial_register(&s3c24xx_serial2_device); /* 注册串口硬件:UART2 */
}