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

📄 serial_netarm.c

📁 这是一个SIGMA方案的PMP播放器的UCLINUX程序,可播放DVD,VCD,CD MP3...有很好的参考价值.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * linux/drivers/char/serial_netarm.c * * Copyright (C) 2001  IMMS gGmbH * * This software is provided "AS-IS" and without any express or implied  * warranties or conditions. * * 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 particular file is derived from serial.c by Linus Torvalds and * Theodore Ts'o and from Joe deBlaquiere's serial-netarm.c from * the 2.0.38 Net-Lx kernel. * see linux/drivers/char/serial.c for version history and credits * * 06/01: first working adaption to Net+ARM built-in serial interfaces * * author(s) : Rolf Peukert * */static char *serial_version = "0.2";static char *serial_revdate = "2002-02-27";/* * Serial driver configuration section.  Here are the various options: * * SERIAL_PARANOIA_CHECK * 		Check the magic number for the netarm_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 */#ifdef MODULE#undef CONFIG_SERIAL_NETARM_CONSOLE#endif#define RS_STROBE_TIME (10*HZ)#define RS_ISR_PASS_LIMIT 256/* * End of serial driver configuration section. */#include <linux/module.h>#include <linux/types.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>#include <linux/init.h>#include <asm/uaccess.h>#include <linux/delay.h>#ifdef CONFIG_SERIAL_NETARM_CONSOLE#include <linux/console.h>#endif#ifdef CONFIG_MAGIC_SYSRQ#include <linux/sysrq.h>#endif#ifdef CONFIG_PROC_FS#include <linux/proc_fs.h>#endif#include <asm/system.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/bitops.h>#include <asm/arch/netarm_registers.h>#ifdef SERIAL_NETARM_INLINE#define _INLINE_ inline#else#define _INLINE_#endifstatic char *serial_name = "Net+ARM serial driver";static DECLARE_TASK_QUEUE(tq_serial);static struct tty_driver serial_driver, callout_driver;static int serial_refcount;static struct timer_list serial_timer;/* 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/* Wait until transmitter is ready for another character */#define NAS_TX_WAIT_RDY(registers) while \ ((registers->status_a & NETARM_SER_STATA_TX_RDY) == 0){}/* Device descriptor arrays for our serial ports */static struct netarm_async_struct NAS_ports[NR_NAS_PORTS];static struct serial_state rs_table[NR_NAS_PORTS] = {	SERIAL_PORT_DFNS	/* Defined in serial.h */};#ifdef CONFIG_SERIAL_NETARM_CONSOLEstatic struct console sercons;static int lsr_break_flag;#endif#if defined(CONFIG_SERIAL_NETARM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)static unsigned long break_pressed; /* break, really ... */#endifstatic void autoconfig(struct serial_state * state);static void change_speed(struct netarm_async_struct *info, struct termios *old);static void rs_wait_until_sent(struct tty_struct *tty, int timeout);#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_NAS_PORTS];static struct termios *serial_termios[NR_NAS_PORTS];static struct termios *serial_termios_locked[NR_NAS_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_MUTEXstatic DECLARE_MUTEX(tmp_buf_sem);#elsestatic struct semaphore tmp_buf_sem = MUTEX;#endifstatic inline intserial_paranoia_check(struct netarm_async_struct *info,			kdev_t device, const char *routine){#ifdef SERIAL_PARANOIA_CHECK	static const char *badmagic =		"Warning: bad magic number for netarm serial struct (%s) in %s\n";	static const char *badinfo =		"Warning: null netarm_async_struct for (%s) in %s\n";	if (!info) {		printk(badinfo, kdevname(device), routine);		return 1;	}	if (info->magic != NAS_MAGIC) {		printk(badmagic, kdevname(device), routine);		return 1;	}#endif	return 0;}/* * ------------------------------------------------------------ * rs_stop() and rs_start() * * This routines are called before setting or resetting tty->stopped. * They enable or disable transmitter interrupts, as necessary. * ------------------------------------------------------------ */static voidrs_stop(struct tty_struct *tty){	struct netarm_async_struct *info = (struct netarm_async_struct *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "rs_stop"))		return;		save_flags(flags); cli();	/* disable all interrupt sources */	info->registers->ctrl_a = info->registers->ctrl_a & 0xFFFF0000;	restore_flags(flags);}static voidrs_start(struct tty_struct *tty){	struct netarm_async_struct *info = (struct netarm_async_struct *)tty->driver_data;	unsigned long flags;		if (serial_paranoia_check(info, tty->device, "rs_start"))		return;		save_flags(flags); cli();	/* enable rx interrupts */	info->registers->ctrl_a = info->registers->ctrl_a	                          | NETARM_SER_CTLA_IE_RX_RDY				  | NETARM_SER_CTLA_IE_RX_FULL;	restore_flags(flags);}/* * ---------------------------------------------------------------------- * Mask&Acknowledge functions, needed by arch/armnommu/mach-netarm/irq.c * * These functions save the current status bits in the netarm_async_struc * structure, because the status is cleared by acknowledging the IRQ. * Each function is used for both RX and TX interrupts. * ---------------------------------------------------------------------- */voidnas_mask_ack_serial1_irq( unsigned int irq ){	volatile unsigned long int *mask = 		(volatile unsigned long *)(NETARM_GEN_MODULE_BASE + 		NETARM_GEN_INTR_ENABLE_CLR);	volatile unsigned long int *stat_a =		(volatile unsigned long *)(NETARM_SER_MODULE_BASE +		NETARM_SER_CH1_STATUS_A);		if ((irq == IRQ_SER1_TX) || (irq == IRQ_SER1_RX))	{		NAS_ports[0].SCSRA = *stat_a;	/* save current status */		*mask  	= (1 << irq);		/* set mask bit */		*stat_a	= 0xFFFF;		/* clear all IRQ pending bits */	}}voidnas_mask_ack_serial2_irq( unsigned int irq ){	volatile unsigned long int *mask = 		(volatile unsigned long *)(NETARM_GEN_MODULE_BASE + 		NETARM_GEN_INTR_ENABLE_CLR);	volatile unsigned long int *stat_a =		(volatile unsigned long *)(NETARM_SER_MODULE_BASE +		NETARM_SER_CH2_STATUS_A);	if ((irq == IRQ_SER2_TX) || (irq == IRQ_SER2_RX))	{		NAS_ports[1].SCSRA = *stat_a;	/* save current status */		*mask  	= (1 << irq);		/* set mask bit */		*stat_a	= 0xFFFF;		/* clear all IRQ pending bits */	}}/* Hook interrupts into System */static int nas_interrupts_init(void){  int retval;  retval = request_irq (IRQ_SER1_RX,			nas_rx_interrupt_1,			0,			"NetARM Serial1 Receive",			&NAS_ports[0]);  if (retval != 0) {    printk("nas_interrupts_init: failed to register serial1 rx interrupt (%d)\n", retval);    return retval;  }  retval = request_irq (IRQ_SER2_RX,			nas_rx_interrupt_2,			0,			"NetARM Serial2 Receive",			&NAS_ports[1]);  if (retval != 0) {    printk("nas_interrupts_init: failed to register serial2 rx interrupt (%d)\n", retval);    return retval;  }  return 0;}/* * ---------------------------------------------------------------------- * * Here start the interrupt handling routines.  All of the following * subroutines are declared as inline and are folded into * rs_interrupt().  They were separated out for readability's sake. * * Note: rs_interrupt() is a "fast" interrupt, which means that it * runs with interrupts turned off.  People who may want to modify * rs_interrupt() should try to keep the interrupt handler as fast as * possible.  After you are done making modifications, it is not a bad * idea to do: *  * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c * * and look at the resulting assemble code in serial.s. * * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93 * ----------------------------------------------------------------------- *//* * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver. */static _INLINE_ voidrs_sched_event(struct netarm_async_struct *info, int event){	info->event |= 1 << event;	queue_task(&info->tqueue, &tq_serial);	mark_bh(SERIAL_BH);}static _INLINE_ voidreceive_chars(struct netarm_async_struct *info, int *status, struct pt_regs * p_regs){	struct tty_struct *tty = info->tty;	unsigned int ch_uint;	struct	async_icount *icount;	int	buf_count = 0;	volatile unsigned int *fifo;	volatile unsigned char *fifo_char = NULL;	volatile netarm_serial_channel_t *regs = info->registers ;	icount = &info->state->icount;	fifo = (volatile unsigned int*)&(regs->fifo) ;	do	{	    fifo_char = (unsigned char *)&ch_uint ;	    if (*status & NETARM_SER_STATA_RX_RDY)    	    {      		/* need to read the whole buffer (1 to 4 bytes) */      		ch_uint = *fifo;		/* check the status word to see how many bytes are pending */		buf_count = NETARM_SER_STATA_RXFDB(*status);		switch (buf_count)      		{		    case NETARM_SER_STATA_RXFDB_4BYTES:			buf_count = 4;			break;	      		    case NETARM_SER_STATA_RXFDB_3BYTES:      			buf_count = 3;			break;		    case NETARM_SER_STATA_RXFDB_2BYTES:			buf_count = 2;			break;		    case NETARM_SER_STATA_RXFDB_1BYTES:			buf_count = 1;			break;		    default:			printk("receive_chars: AIEE!! GARBAGE!\n");		}	    }	    else	    {		ch_uint = 0;		buf_count = 0;	    }    	    /* read all available characters from FIFO */	    while ((buf_count-- > 0) && (tty->flip.count < TTY_FLIPBUF_SIZE))	    {		*tty->flip.flag_buf_ptr = 0 ;		/* handle port error conditions */		if (*status & NETARM_SER_STATA_RX_BRK)	    	{		    *tty->flip.flag_buf_ptr = TTY_BREAK ;		    icount->brk++;		/*		 * We do the SysRQ and SAK checking		 * here because otherwise the break		 * may get masked by ignore_status_mask		 * or read_status_mask.		 */#if defined(CONFIG_SERIAL_NETARM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)		if (info->line == sercons.index) {			if (!break_pressed) {				break_pressed = jiffies;				goto ignore_char;			}			break_pressed = 0;		}#endif		    if (info->flags & ASYNC_SAK) do_SAK(tty);		}		else if (*status & NETARM_SER_STATA_RX_PARERR)		{		    *tty->flip.flag_buf_ptr = TTY_PARITY ;		    icount->parity++;		}		else if (*status & NETARM_SER_STATA_RX_FRMERR)		{		    *tty->flip.flag_buf_ptr = TTY_FRAME ;		    icount->frame++;		}		else if (*status & NETARM_SER_STATA_RX_OVERRUN)		{		    *tty->flip.flag_buf_ptr = TTY_OVERRUN ;		    icount->overrun++;		}#ifdef CONFIG_SERIAL_NETARM_CONSOLE		if (info->line == sercons.index)		{		    /* Recover the break flag from console xmit */		    *status |= lsr_break_flag;		    lsr_break_flag = 0;		}#endif		if (*status & (NETARM_SER_STATA_RX_BRK))		{#ifdef SERIAL_DEBUG_INTR		    printk("handling break....");#endif		    *tty->flip.flag_buf_ptr = TTY_BREAK;		}#if defined(CONFIG_SERIAL_NETARM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)		if (break_pressed && info->line == sercons.index)		{		    if (ch != 0 &&			time_before(jiffies, break_pressed + HZ*5))		    {			handle_sysrq(ch, p_regs, NULL, NULL);			break_pressed = 0;			goto ignore_char;		    }		    break_pressed = 0;		}#endif#ifdef SERIAL_DEBUG_INTR		printk("receive_chars: %02x (%02x)", *fifo_char, *status);#endif		*tty->flip.char_buf_ptr = *fifo_char;		tty->flip.count++;

⌨️ 快捷键说明

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