📄 serial_44b0.c
字号:
/*
* linux/drivers/char/serial_44b0.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997,
* 1998, 1999 Theodore Ts'o
*
* Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now
* much more extensible to support other serial cards based on the
* 16450/16550A UART's. Added support for the AST FourPort and the
* Accent Async board.
*
* set_serial_info fixed to set the flags, custom divisor, and uart
* type fields. Fix suggested by Michael K. Johnson 12/12/92.
*
* 11/95: TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis <ah@doc.ic.ac.uk>
*
* 03/96: Modularised by Angelo Haritsis <ah@doc.ic.ac.uk>
*
* rs_set_termios fixed to look also for changes of the input
* flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK.
* Bernd Anh鋟pl 05/17/96.
*
* 1/97: Extended dumb serial ports are a config option now.
* Saves 4k. Michael A. Griffith <grif@acm.org>
*
* 8/97: Fix bug in rs_set_termios with RTS
* Stanislav V. Voronyi <stas@uanet.kharkov.ua>
*
* 3/98: Change the IRQ detection, use of probe_irq_o*(),
* suppress TIOCSERGWILD and TIOCSERSWILD
* Etienne Lorrain <etienne.lorrain@ibm.net>
*
* 4/98: Added changes to support the ARM architecture proposed by
* Russell King
*
* 5/99: Updated to include support for the XR16C850 and ST16C654
* uarts. Stuart MacDonald <stuartm@connecttech.com>
*
* 8/99: Generalized PCI support added. Theodore Ts'o
*
* 3/00: Rid circular buffer of redundant xmit_cnt. Fix a
* few races on freeing buffers too.
* Alan Modra <alan@linuxcare.com>
*
* 5/00: Support for the RSA-DV II/S card added.
* Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
*
* 6/00: Remove old-style timer, use timer_list
* Andrew Morton <andrewm@uow.edu.au>
*
* 7/00: Support Timedia/Sunix/Exsys PCI cards
*
* 7/00: fix some returns on failure not using MOD_DEC_USE_COUNT.
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* 10/00: add in optional software flow control for serial console.
* Kanoj Sarcar <kanoj@sgi.com> (Modified by Theodore Ts'o)
*
* 09/02: modify by wesley king for s3c44b0's serial console.
* Qin Wei <king@micetek.com.cn>
*
* 01/03: modify by wesley king for s3c44b0's serial console, support ev44b0ii.
* Qin Wei <king@micetek.com.cn>
*
*/
static char *serial_version = "1.10";
static char *serial_revdate = "2003-01-15";
/*
* Serial driver configuration section. Here are the various options:
*
* CONFIG_HUB6
* Enables support for the venerable Bell Technologies
* HUB6 card.
*
* CONFIG_SERIAL_MANY_PORTS
* Enables support for ports beyond the standard, stupid
* COM 1/2/3/4.
*
* CONFIG_SERIAL_MULTIPORT
* Enables support for special multiport board support.
*
* CONFIG_SERIAL_SHARE_IRQ
* Enables support for multiple serial ports on one IRQ
*
* CONFIG_SERIAL_DETECT_IRQ
* Enable the autodetection of IRQ on standart ports
*
* SERIAL_PARANOIA_CHECK
* Check the magic number for the async_structure where
* ever possible.
*/
#include <linux/config.h>
#include <linux/version.h>
#undef SERIAL_PARANOIA_CHECK
#define CONFIG_SERIAL_NOPAUSE_IO
#define SERIAL_DO_RESTART
/* Set of debugging defines */
#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_FLOW
#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
#undef SERIAL_DEBUG_PCI
#undef SERIAL_DEBUG_AUTOCONF
/* Sanity checks */
// Qinwei : for using polling mode to send char on serial port
//#define UARTPOLLING
#undef UARTPOLLING
#ifdef UARTPOLLING
#define RS_STROBE_TIME 10*HZ
#else
#define RS_STROBE_TIME 10
#endif
#define RS_ISR_PASS_LIMIT 256
#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
#define SERIAL_INLINE
#endif
/*
* End of serial driver configuration section.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <taihe/skjconst.h>
#include <taihe/skj83977.h>
#ifdef LOCAL_HEADERS
#include "serial_local.h"
#else
#include <linux/serial.h>
#include <linux/serialP.h>
//#include <linux/serial_reg.h>
#include <asm/serial.h>
#define LOCAL_VERSTRING ""
#endif
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/slab.h>
#if (LINUX_VERSION_CODE >= 131343)
#include <linux/init.h>
#endif
#if (LINUX_VERSION_CODE >= 131336)
#include <asm/uaccess.h>
#endif
#include <linux/delay.h>
#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
#include <linux/console.h>
#endif
#ifdef CONFIG_MAGIC_SYSRQ
#include <linux/sysrq.h>
#endif
#ifdef CONFIG_LEDMAN
#include <linux/ledman.h>
#endif
/*
* All of the compatibilty code so we can compile serial.c against
* older kernels is hidden in serial_compat.h
*/
#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */
#include "serial_compat.h"
#endif
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#ifdef CONFIG_MAC_SERIAL
#define SERIAL_DEV_OFFSET 2
#else
#define SERIAL_DEV_OFFSET 0
#endif
#ifdef SERIAL_INLINE
#define _INLINE_ inline
#else
#define _INLINE_
#endif
#define RdURXH2() (*(volatile unsigned char *)ADDR_SERIAL_A)
#define RdURXH3() (*(volatile unsigned char *)ADDR_SERIAL_B)
#define WrUTXH2(ch) (*(volatile unsigned char *)ADDR_SERIAL_A)=(unsigned char)(ch)
#define WrUTXH3(ch) (*(volatile unsigned char *)ADDR_SERIAL_B)=(unsigned char)(ch)
#define rEXTINTPND (0x01D20054)
#define EX_UART_GCR_RX_INT 0x01
#define EX_UART_GCR_TX_INT 0x04
#define EX_UART_LCR 3
#define EX_UART_LSR 5
#define EX_UART_BDR 0
#define EX_UART_GCR 1
#define EX_UART_TX 0
#define EX_UART_RX 0
static char *serial_name = "EV44B0II Serial driver";
extern unsigned int dwCpuClk;
extern unsigned int dwTestBaud;
static DECLARE_TASK_QUEUE(tq_serial);
static struct tty_driver serial_driver, callout_driver;
static int serial_refcount;
static struct timer_list serial_timer;
_INLINE_ void disable_uart_tx_interrupt(int line);
_INLINE_ void disable_uart_rx_interrupt(int line);
_INLINE_ void enable_uart_tx_interrupt(int line);
_INLINE_ void enable_uart_rx_interrupt(int line);
static _INLINE_ void wait_for_xmitr(struct async_struct *info);
static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done);
/* serial subtype definitions */
#ifndef SERIAL_TYPE_NORMAL
#define SERIAL_TYPE_NORMAL 1
#define SERIAL_TYPE_CALLOUT 2
#endif
/* number of characters left in xmit buffer before we ask for more */
#define WAKEUP_CHARS 256
/*
* IRQ_timeout - How long the timeout should be for each IRQ
* should be after the IRQ has been active.
*/
static struct async_struct *IRQ_ports[NR_IRQS];
static int IRQ_timeout[NR_IRQS];
#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
static struct console sercons;
static int lsr_break_flag;
#endif
#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
static unsigned long break_pressed; /* break, really ... */
#endif
static unsigned detect_uart_irq (struct serial_state * state);
static void autoconfig(struct serial_state * state);
static void change_speed(struct async_struct *info, struct termios *old);
static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
/*
* Here we define the default xmit fifo size used for each type of
* UART
*/
static struct serial_uart_config uart_config[] = {
{ "unknown", 1, 0 },
{ "8250", 1, 0 },
{ "16450", 1, 0 },
{ "16550", 1, 0 },
{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
{ "cirrus", 1, 0 }, // usurped by cyclades.c
{ "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
UART_STARTECH },
{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
{ "Startech", 1, 0}, // usurped by cyclades.c
{ "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO},
{ "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO |
UART_STARTECH },
{ "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO |
UART_STARTECH },
{ "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO },
{ "S3C44B0", 1, 0}, /* Samsung S3C44B0 uart support */
{ 0, 0}
};
static struct serial_state rs_table[RS_TABLE_SIZE] = {
SERIAL_PORT_DFNS // Defined in serial.h
};
#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))
#ifndef PREPARE_FUNC
#define PREPARE_FUNC(dev) (dev->prepare)
#define ACTIVATE_FUNC(dev) (dev->activate)
#define DEACTIVATE_FUNC(dev) (dev->deactivate)
#endif
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
static struct tty_struct *serial_table[NR_PORTS];
static struct termios *serial_termios[NR_PORTS];
static struct termios *serial_termios_locked[NR_PORTS];
#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
#else
#define DBG_CNT(s)
#endif
/*
* tmp_buf is used as a temporary buffer by serial_write. We need to
* lock it in case the copy_from_user blocks while swapping in a page,
* and some other program tries to do a serial write at the same time.
* Since the lock will only come under contention when the system is
* swapping and available memory is low, it makes sense to share one
* buffer across all the serial ports, since it significantly saves
* memory if large numbers of serial ports are open.
*/
static unsigned char *tmp_buf;
#ifdef DECLARE_MUTEX
static DECLARE_MUTEX(tmp_buf_sem);
#else
static struct semaphore tmp_buf_sem = MUTEX;
#endif
static _INLINE_ int serial_paranoia_check(struct async_struct *info,
kdev_t device, const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
static const char *badmagic =
"Warning: bad magic number for serial struct (%s) in %s\n";
static const char *badinfo =
"Warning: null async_struct for (%s) in %s\n";
if (!info) {
printk(badinfo, kdevname(device), routine);
return 1;
}
if (info->magic != SERIAL_MAGIC) {
printk(badmagic, kdevname(device), routine);
return 1;
}
#endif
return 0;
}
static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
{
// return CSR_READ(info->port + offset);
if(info->line==0||info->line==1)
{
return CSR_READ(info->port + offset);
}
/*else */
/*{ */
/*return (CSR_READ(GetOutAddr(GetInterAddr(info->port)+offset)));*/
/*} */
}
static _INLINE_ void serial_out(struct async_struct *info, int offset,
int value)
{
if(info->line==0||info->line==1)
{
CSR_WRITE(info->port+offset, value);
}
/*else */
/*{ */
/*CSR_WRITE(GetOutAddr(GetInterAddr(info->port)+offset),value);*/
/*} */
}
static _INLINE_ unsigned int uart_in(struct async_struct *info, int offset)
{
switch(info->line)
{
case 0:
return RdURXH0();
case 1:
return RdURXH1();
case 2:
return RdURXH2();
default:
return RdURXH3();
}
}
static _INLINE_ void uart_out(struct async_struct *info, int offset,
int value)
{
switch(info->line)
{
case 0:
WrUTXH0(value);
break;
case 1:
WrUTXH1(value);
break;
default:
break;
/*case 2: */
/*WrUTXH2(value);*/
/*break; */
/*default: */
/*WrUTXH3(value);*/
}
}
/*
* We used to support using pause I/O for certain machines. We
* haven't supported this for a while, but just in case it's badly
* needed for certain old 386 machines, I've left these #define's
* in....
*/
#define serial_inp(info, offset) serial_in(info, offset)
#define serial_outp(info, offset, value) serial_out(info, offset, value)
unsigned int baudrate_div(unsigned int baudrate)
{
dwTestBaud=((unsigned int)((float)dwCpuClk/16/baudrate + 0.5)) -1 ;
return dwTestBaud;
}
/*
* ------------------------------------------------------------
* rs_stop() and rs_start()
*
* This routines are called before setting or resetting tty->stopped.
* They enable or disable transmitter interrupts, as necessary.
* ------------------------------------------------------------
*/
static void rs_stop(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -