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

📄 sh-sci.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id: sh-sci.c,v 1.40 2000/04/15 06:57:29 gniibe Exp $ * *  linux/drivers/char/sh-sci.c * *  SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO) *  Copyright (C) 1999, 2000  Niibe Yutaka *  Copyright (C) 2000  Sugioka Toshinobu *  Modified to support multiple serial ports. Stuart Menefy (May 2000). * * TTY code is based on sx.c (Specialix SX driver) by: * *   (C) 1998 R.E.Wolff@BitWizard.nl * */#include <linux/config.h>#include <linux/module.h>#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/serial.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>#include <linux/init.h>#include <linux/delay.h>#ifdef CONFIG_SERIAL_CONSOLE#include <linux/console.h>#endif#include <asm/system.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/bitops.h>#include <linux/generic_serial.h>#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB#include <asm/sh_bios.h>#endif#include "sh-sci.h"#ifdef CONFIG_SERIAL_CONSOLEstatic struct console sercons;static struct sci_port* sercons_port=0;static int sercons_baud;#endif/* Function prototypes */static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag);#ifndef SCI_ONLYstatic void sci_init_pins_scif(struct sci_port* port, unsigned int cflag);#if defined(__sh3__)static void sci_init_pins_irda(struct sci_port* port, unsigned int cflag);#endif#endifstatic void sci_disable_tx_interrupts(void *ptr);static void sci_enable_tx_interrupts(void *ptr);static void sci_disable_rx_interrupts(void *ptr);static void sci_enable_rx_interrupts(void *ptr);static int  sci_get_CD(void *ptr);static void sci_shutdown_port(void *ptr);static int sci_set_real_termios(void *ptr);static void sci_hungup(void *ptr);static void sci_close(void *ptr);static int sci_chars_in_buffer(void *ptr);static int sci_init_drivers(void);static struct tty_driver sci_driver, sci_callout_driver;static struct sci_port sci_ports[SCI_NPORTS] = SCI_INIT;static struct tty_struct *sci_table[SCI_NPORTS] = { NULL, };static struct termios *sci_termios[SCI_NPORTS];static struct termios *sci_termios_locked[SCI_NPORTS];int sci_refcount;int sci_debug = 0;#ifdef MODULEMODULE_PARM(sci_debug, "i");#endif#define dprintk(x...) do { if (sci_debug) printk(x); } while(0)static void put_char(struct sci_port *port, char c){	unsigned long flags;	unsigned short status;	save_and_cli(flags);	do		status = sci_in(port, SCxSR);	while (!(status & SCxSR_TDxE(port)));  	sci_out(port, SCxTDR, c);	sci_in(port, SCxSR);            /* Dummy read */	sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));	restore_flags(flags);}#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUBstatic void handle_error(struct sci_port *port){				/* Clear error flags */	sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));}static int get_char(struct sci_port *port){	unsigned long flags;	unsigned short status;	int c;	save_and_cli(flags);        do {		status = sci_in(port, SCxSR);		if (status & SCxSR_ERRORS(port)) {			handle_error(port);			continue;		}	} while (!(status & SCxSR_RDxF(port)));	c = sci_in(port, SCxRDR);	sci_in(port, SCxSR);            /* Dummy read */	sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));	restore_flags(flags);	return c;}/* Taken from sh-stub.c of GDB 4.18 */static const char hexchars[] = "0123456789abcdef";static __inline__ char highhex(int  x){	return hexchars[(x >> 4) & 0xf];}static __inline__ char lowhex(int  x){	return hexchars[x & 0xf];}#endif/* * Send the packet in buffer.  The host gets one chance to read it. * This routine does not wait for a positive acknowledge. */static void put_string(struct sci_port *port,				  const char *buffer, int count){	int i;	const unsigned char *p = buffer;#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB	int checksum;    	/* This call only does a trap the first time it is	 * called, and so is safe to do here unconditionally	 */	if (sh_bios_in_gdb_mode()) {	    /*  $<packet info>#<checksum>. */	    do {		unsigned char c;		put_char(port, '$');		put_char(port, 'O'); /* 'O'utput to console */		checksum = 'O';		for (i=0; i<count; i++) { /* Don't use run length encoding */			int h, l;			c = *p++;			h = highhex(c);			l = lowhex(c);			put_char(port, h);			put_char(port, l);			checksum += h + l;		}		put_char(port, '#');		put_char(port, highhex(checksum));		put_char(port, lowhex(checksum));	    } while  (get_char(port) != '+');	} else#endif	for (i=0; i<count; i++) {		if (*p == 10)			put_char(port, '\r');		put_char(port, *p++);	}}static struct real_driver sci_real_driver = {	sci_disable_tx_interrupts,	sci_enable_tx_interrupts,	sci_disable_rx_interrupts,	sci_enable_rx_interrupts,	sci_get_CD,	sci_shutdown_port,	sci_set_real_termios,	sci_chars_in_buffer,	sci_close,	sci_hungup,	NULL};#if defined(SCI_ONLY) || defined(SCI_AND_SCIF)static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag){}#endif#if defined(SCIF_ONLY) || defined(SCI_AND_SCIF)#if defined(__sh3__)/* For SH7707, SH7709, SH7709A, SH7729 */static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag){	unsigned int fcr_val = 0;	{		unsigned short data;		/* We need to set SCPCR to enable RTS/CTS */		data = ctrl_inw(SCPCR);		/* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/		ctrl_outw(data&0x0fcf, SCPCR);	}	if (cflag & CRTSCTS)		fcr_val |= SCFCR_MCE;	else {		unsigned short data;		/* We need to set SCPCR to enable RTS/CTS */		data = ctrl_inw(SCPCR);		/* Clear out SCP7MD1,0, SCP4MD1,0,		   Set SCP6MD1,0 = {01} (output)  */		ctrl_outw((data&0x0fcf)|0x1000, SCPCR);		data = ctrl_inb(SCPDR);		/* Set /RTS2 (bit6) = 0 */		ctrl_outb(data&0xbf, SCPDR);	}	sci_out(port, SCFCR, fcr_val);}static void sci_init_pins_irda(struct sci_port* port, unsigned int cflag){	unsigned int fcr_val = 0;	if (cflag & CRTSCTS)		fcr_val |= SCFCR_MCE;	sci_out(port, SCFCR, fcr_val);}#else/* For SH7750 */static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag){	unsigned int fcr_val = 0;	if (cflag & CRTSCTS) {		fcr_val |= SCFCR_MCE;	} else {		ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */	}	sci_out(port, SCFCR, fcr_val);}#endif#endif /* SCIF_ONLY || SCI_AND_SCIF */static void sci_setsignals(struct sci_port *port, int dtr, int rts){	/* This routine is used for seting signals of: DTR, DCD, CTS/RTS */	/* We use SCIF's hardware for CTS/RTS, so don't need any for that. */	/* If you have signals for DTR and DCD, please implement here. */	;}static int sci_getsignals(struct sci_port *port){	/* This routine is used for geting signals of: DTR, DCD, DSR, RI,	   and CTS/RTS */	return TIOCM_DTR|TIOCM_RTS|TIOCM_DSR;/*	(((o_stat & OP_DTR)?TIOCM_DTR:0) |	 ((o_stat & OP_RTS)?TIOCM_RTS:0) |	 ((i_stat & IP_CTS)?TIOCM_CTS:0) |	 ((i_stat & IP_DCD)?TIOCM_CAR:0) |	 ((i_stat & IP_DSR)?TIOCM_DSR:0) |	 ((i_stat & IP_RI) ?TIOCM_RNG:0)*/}static void sci_set_baud(struct sci_port *port, int baud){	int t;	switch (baud) {	case 0:		t = -1;		break;	case 2400:		t = BPS_2400;		break;	case 4800:		t = BPS_4800;		break;	case 9600:		t = BPS_9600;		break;	case 19200:		t = BPS_19200;		break;	case 38400:		t = BPS_38400;		break;	case 57600:		t = BPS_57600;		break;	default:		printk(KERN_INFO "sci: unsupported baud rate: %d, using 115200 instead.\n", baud);	case 115200:		t = BPS_115200;		break;	}	if (t > 0) {		sci_setsignals (port, 1, -1);		if(t >= 256) {			sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);			t >>= 2;		} else {			sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3);		}		sci_out(port, SCBRR, t);		udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */	} else {		sci_setsignals (port, 0, -1);	}}static void sci_set_termios_cflag(struct sci_port *port, int cflag, int baud){	unsigned int status;	unsigned int smr_val;	do		status = sci_in(port, SCxSR);	while (!(status & SCxSR_TEND(port)));	sci_out(port, SCSCR, 0x00);	/* TE=0, RE=0, CKE1=0 */	if (port->type == PORT_SCIF) {		sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);	}	smr_val = sci_in(port, SCSMR) & 3;	if ((cflag & CSIZE) == CS7)		smr_val |= 0x40;	if (cflag & PARENB)		smr_val |= 0x20;	if (cflag & PARODD)		smr_val |= 0x10;	if (cflag & CSTOPB)		smr_val |= 0x08;	sci_out(port, SCSMR, smr_val);	sci_set_baud(port, baud);	port->init_pins(port, cflag);	sci_out(port, SCSCR, SCSCR_INIT(port));}static int sci_set_real_termios(void *ptr){	struct sci_port *port = ptr;	if (port->old_cflag != port->gs.tty->termios->c_cflag) {		port->old_cflag = port->gs.tty->termios->c_cflag;		sci_set_termios_cflag(port, port->old_cflag, port->gs.baud);		sci_enable_rx_interrupts(port);	}	/* Tell line discipline whether we will do input cooking */	if (I_OTHER(port->gs.tty))		clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);	else		set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);/* Tell line discipline whether we will do output cooking. * If OPOST is set and no other output flags are set then we can do output * processing.  Even if only *one* other flag in the O_OTHER group is set * we do cooking in software. */	if (O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty))		set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);	else		clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);	return 0;}/* ********************************************************************** * *                   the interrupt related routines                       * * ********************************************************************** *//* * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver. */

⌨️ 快捷键说明

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