serial_dsc21.c

来自「这是一个SIGMA方案的PMP播放器的UCLINUX程序,可播放DVD,VCD,」· C语言 代码 · 共 2,400 行 · 第 1/5 页

C
2,400
字号
/* *  linux/drivers/char/serial_dsc21.c * *  Copyright (C) 2001 * Author: RidgeRun, Inc. *          gmcnutt@ridgerun.com *   *  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*(), *	  supress 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> * * This module exports the following rs232 io functions: * *	int rs_init(void); *//* * Serial driver configuration section.  Here are the various options: * * SERIAL_PARANOIA_CHECK * 		Check the magic number for the dsc21_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//#define SERIAL_DSC21_INLINE inline#define SERIAL_DSC21_INLINE/* Sanity checks */#ifdef MODULE#undef CONFIG_SERIAL_DSC21_CONSOLE#endif#define RS_ISR_PASS_LIMIT 256#ifdef MODVERSIONS#include <linux/modversions.h>#endif#include <linux/module.h>#include <linux/types.h>#include <linux/serial.h>#include <linux/serialP.h>//#include <linux/serial_reg.h>#include <asm/serial.h>#define LOCAL_VERSTRING ""#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/malloc.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_DSC21_CONSOLE#include <linux/console.h>#endif#ifdef CONFIG_MAGIC_SYSRQ#include <linux/sysrq.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>#define SERIAL_DEV_OFFSET	0static DECLARE_TASK_QUEUE(tq_serial);static struct tty_driver serial_driver, callout_driver;static int serial_refcount;/* 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 dsc21_async_struct *IRQ_ports[NR_IRQS];static int IRQ_timeout[NR_IRQS];#ifdef CONFIG_SERIAL_DSC21_CONSOLEstatic struct console sercons;#endif#if defined(CONFIG_SERIAL_DSC21_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)static unsigned long break_pressed; /* break, really ... */#endifstatic void autoconfig(struct serial_state * state);static void change_speed(struct dsc21_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 },	{ "DSC21", 32, UART_CLEAR_FIFO | UART_USE_FIFO },	{ 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))#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];/* * 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_MUTEXstatic DECLARE_MUTEX(tmp_buf_sem);#elsestatic struct semaphore tmp_buf_sem = MUTEX;#endifstatic SERIAL_DSC21_INLINE unsigned int serial_in(struct dsc21_async_struct *info, 					 int offset){	return inw(info->iomem_base + (offset<<info->iomem_reg_shift));}static SERIAL_DSC21_INLINE void serial_out(struct dsc21_async_struct *info, int offset,				  int value){	outw(value, (unsigned long) info->iomem_base +	     (offset<<info->iomem_reg_shift));}static SERIAL_DSC21_INLINE void serial_dsc21_disable_tx_int(struct dsc21_async_struct *info){	info->MSR &= ~UART_MSR_TFTIE;	serial_out(info, UART_MSR, info->MSR);}static SERIAL_DSC21_INLINE void serial_dsc21_disable_rx_int(struct dsc21_async_struct *info){	info->MSR &= ~UART_MSR_RFTIE;	serial_out(info, UART_MSR, info->MSR);}static SERIAL_DSC21_INLINE void serial_dsc21_enable_tx_int(struct dsc21_async_struct *info){	info->MSR |= UART_MSR_TFTIE;	serial_out(info, UART_MSR, info->MSR);}static SERIAL_DSC21_INLINE void serial_dsc21_enable_rx_int(struct dsc21_async_struct *info){	info->MSR |= UART_MSR_RFTIE;	serial_out(info, UART_MSR, info->MSR);}static SERIAL_DSC21_INLINE void serial_dsc21_disable_ints(struct dsc21_async_struct *info,					     u16 *msr){	*msr = info->MSR & UART_MSR_INTS;	info->MSR &= ~UART_MSR_INTS;	serial_out(info, UART_MSR, info->MSR);}static SERIAL_DSC21_INLINE void serial_dsc21_restore_ints(struct dsc21_async_struct *info,					     u16 msr){	info->MSR |= msr & UART_MSR_INTS;	serial_out(info, UART_MSR, info->MSR);}static SERIAL_DSC21_INLINE void serial_dsc21_clear_fifos(struct dsc21_async_struct *info){	serial_out(info, UART_RFCR, 0x8000);	serial_out(info, UART_TFCR, 0x8000);}static SERIAL_DSC21_INLINE void serial_dsc21_disable_breaks(struct dsc21_async_struct *info){	info->LCR &= ~UART_LCR_BOC;	serial_out(info, UART_LCR, info->LCR);}static SERIAL_DSC21_INLINE void serial_dsc21_enable_breaks(struct dsc21_async_struct *info){	info->LCR |= UART_LCR_BOC;	serial_out(info, UART_LCR, info->LCR);}static SERIAL_DSC21_INLINE void serial_dsc21_set_rate(struct dsc21_async_struct *info, u16 rate){	serial_out(info, UART_BRSR, rate);}static SERIAL_DSC21_INLINE void serial_dsc21_set_mode(struct dsc21_async_struct *info,					 u16 mode){	info->MSR &= ~UART_MSR_MODE_BITS;	info->MSR |= mode;	serial_out(info, UART_MSR, info->MSR);}static SERIAL_DSC21_INLINE void serial_dsc21_set_rx_trigger(struct dsc21_async_struct *info,					       u16 val){	serial_out(info, UART_RFCR, val);}static SERIAL_DSC21_INLINE void serial_dsc21_set_tx_trigger(struct dsc21_async_struct *info,					       u16 val){	serial_out(info, UART_TFCR, val);}static SERIAL_DSC21_INLINE void serial_dsc21_out(	struct dsc21_async_struct *info, u8 val){	serial_out(info, UART_DTRR, val);}static SERIAL_DSC21_INLINE u8 serial_dsc21_in(struct dsc21_async_struct *info){	return serial_in(info, UART_DTRR);}static SERIAL_DSC21_INLINE u16 serial_dsc21_status(struct dsc21_async_struct *info){	return serial_in(info, UART_SR);}static SERIAL_DSC21_INLINE u8 serial_dsc21_data_available(struct dsc21_async_struct *info){	return ((serial_in(info, UART_SR) & UART_SR_RFNEF) != 0);}static SERIAL_DSC21_INLINE u8 serial_dsc21_tx_fifo_empty(struct dsc21_async_struct *info){	return ((serial_in(info, UART_SR) & UART_SR_TREF) == 0);}static SERIAL_DSC21_INLINE u8 serial_dsc21_room_in_tx_fifo(	struct dsc21_async_struct *info){	return ((serial_in(info, UART_SR) & UART_SR_TFTI) != 0);}static SERIAL_DSC21_INLINE int serial_paranoia_check(struct dsc21_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 dsc21_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 void rs_stop(struct tty_struct *tty){	struct dsc21_async_struct *info = (struct dsc21_async_struct *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "rs_stop"))		return;	save_flags(flags); cli();	if (info->MSR & UART_MSR_TFTIE) serial_dsc21_disable_tx_int(info);	restore_flags(flags);}static void rs_start(struct tty_struct *tty){	struct dsc21_async_struct *info = (struct dsc21_async_struct *)tty->driver_data;	unsigned long flags;		if (serial_paranoia_check(info, tty->device, "rs_start"))		return;		save_flags(flags); cli();	if (info->xmit.head != info->xmit.tail	    && info->xmit.buf	    && !(info->MSR & UART_MSR_TFTIE))		serial_dsc21_enable_tx_int(info);	restore_flags(flags);}static SERIAL_DSC21_INLINE void rs_sched_event(struct dsc21_async_struct *info,				  int event){	info->event |= 1 << event;	queue_task(&info->tqueue, &tq_serial);	mark_bh(SERIAL_BH);}static SERIAL_DSC21_INLINE void receive_chars(struct dsc21_async_struct *info,				 int *status, struct pt_regs * regs){	struct tty_struct *tty = info->tty;	unsigned char ch;	struct	async_icount *icount;	icount = &info->state->icount;	do {		ch = serial_dsc21_in(info);		if (tty->flip.count < TTY_FLIPBUF_SIZE) {			*tty->flip.char_buf_ptr = ch;			*tty->flip.flag_buf_ptr = 0;			tty->flip.flag_buf_ptr++;			tty->flip.char_buf_ptr++;			tty->flip.count++;						icount->rx++;		}		*status = serial_dsc21_status(info);	} while (*status & UART_SR_RFNEF);#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */	tty_flip_buffer_push(tty);#else	queue_task(&tty->flip.tqueue, &tq_timer);#endif	}static SERIAL_DSC21_INLINE void transmit_chars(struct dsc21_async_struct *info,					       int *intr_done){	int count;	if (info->x_char) {		serial_dsc21_out(info, info->x_char);		info->state->icount.tx++;		info->x_char = 0;		if (intr_done)			*intr_done = 0;		return;	}	if (info->xmit.head == info->xmit.tail	    || info->tty->stopped	    || info->tty->hw_stopped) {		serial_dsc21_disable_tx_int(info);		return;	}

⌨️ 快捷键说明

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