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

📄 serial_s3c44b0.c

📁 32位arm芯片选择,要:ARM 公司以及ARM 芯片的现状和发展
💻 C
字号:
/* *  linux/drivers/serial/serial_s3c440b.c * *  Driver for S3C44B0 serial ports * *  Copyright (c) 2005  JieZheng (caolingzi@netease.com) * * *  Based on drivers/char/serial_s3c4510b.c *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. * * 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 program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * */#include <linux/config.h>    /*---><linux/autoconfig.h> (inlcude .config)*/#include <linux/kernel.h>  /* printk() */#include <linux/sched.h>   /* struct task_struct *current */#include <linux/major.h>   /* TTY_MAJOR  is 4 */#include <linux/init.h>    /* module_init(), module_exit(), __init, __exit */#include <linux/slab.h>    /* kmalloc(); */#include <linux/module.h> /* it must be included by a module source */#include <linux/types.h>    /* MAJOR(), MINOR() */#include <linux/spinlock.h>  #include <linux/string.h>    /* string operations */#include <linux/fcntl.h>     /* Macro file operation define */#include <linux/ioport.h>#include <linux/prtace.h>  /* structs and defines to help the user use the ptrace system call. */#include <linux/mm.h>     /* memory operations */#include <linux/errno.h>#include <linux/interrupt.h>           /* struct irqaction{}; */#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/circ_buf.h>#include <linux/serial.h>#include <linux/console.h>#include <linux/sysrq.h>#include <linux/serial_core.h>#include <asm/system.h>#include <asm/io.h>#include <asm/mach/irq.h>#include <asm/uaccess.h>#include <asm/bitops.h>#include <asm/arch/system.h>  /* S3C44B0 head file  */#include <asm/arch/irq.h>        /* S3C44B0 irq head file */#include <asm/irq.h>#define SERIAL_S3C44B0_NAME	 "Samsung S3C44B0 Internal UART"#define UART_NR	2static void led_set(int){}static void led_clr(int){}static void __xmit_char(struct uart_port *port, const char ch) {	while(!(SYSREG_GET(S3C44B0X_UTRSTAT0) & 0x2));	SYSREG_SETB(S3C44B0X_UTXH0, ch);	if (ch == '\n'){		while(!(SYSREG_GET(S3C44B0X_UTRSTAT0) & 0x2));		SYSREG_SETB(S3C44B0X_UTXH0, '\r');	}			}static void __xmit_string(struct uart_port *port, const char *p, int len){        while( len-- > 0) {                __xmit_char( port, *p++);        }}static void __s3c44b0_stop_tx(struct uart_port *port, unsigned int tty_stop){	/*SYSREG_AND_SET(port->iobase+4, 0xfffffff3);*/}static void __s3c44b0_tx_chars(struct uart_port *port){	struct circ_buf *xmit = &port->info->xmit;        int count;         _DPRINTK("called with info = 0x%08x", (unsigned int) port);        if ( port->x_char) {                __xmit_char( port, port->x_char);                port->icount.tx++;                port->x_char = 0;                return;        }        if (uart_circ_empty( xmit) || uart_tx_stopped( port)) {                __s3c44b0_stop_tx( port, 0);                return;        }        count = port->fifosize >> 1;        do {                __xmit_char( port, xmit->buf[xmit->tail]);                xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);                port->icount.tx++;                if (uart_circ_empty(xmit))                        break;        } while (--count > 0);        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)                uart_write_wakeup( port);        if (uart_circ_empty(xmit))                __s3c44b0_stop_tx( port, 0);}static void __s3c44b0_rx_char(struct uart_port *port){		struct tty_struct *tty = port->info->tty;	unsigned int ch;	UART_STAT status;	if (tty->flip.count >= TTY_FLIPBUF_SIZE) {		tty->flip.work.func((void *)tty);		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {			printk(KERN_WARNING "TTY_DONT_FLIP set\n");			return;		}	}	ch = SYSREG_GET(port->iobase+0x24) & 0xFF;	*tty->flip.char_buf_ptr = ch;	*tty->flip.flag_buf_ptr = TTY_NORMAL;	port->icount.rx++;	/*	 * Note that the error handling code is	 * out of the main execution path	 */		tty->flip.flag_buf_ptr++;		tty->flip.char_buf_ptr++;		tty->flip.count++;		tty_flip_buffer_push(tty);}static void __s3c44b0_start_tx(struct uart_port *port, unsigned int tty_start){	__s3c44b0_tx_chars(port);}static void __s3c44b0_send_xchar(struct uart_port *port, char ch){        _DPRINTK("called with port = 0x%08x", (unsigned int) port);}static void __s3c44b0_stop_rx(struct uart_port *port){ 	     /* disable_irq(S3C44B0X_INTERRUPT_UTX0); */}static irqreturn_t __s3c44b0_rx_int(int irq, void *dev_id, struct pt_regs *regs){      _DPRINTK("called with irq = 0x%08x", irq);        struct uart_port *port = dev_id;        led_set(2);        __s3c44b0_rx_char( port);        led_clr(2);        return IRQ_HANDLED;}static irqreturn_t __s3c44b0_tx_int(int irq, void *dev_id, struct pt_regs *regs){      _DPRINTK("called with irq = 0x%08x", irq);        struct uart_port *port = dev_id;        led_set(1);        __s3c44b0_start_tx( port, 0);        led_clr(1);        return IRQ_HANDLED;}static void __s3c44b0_enable_ms(struct uart_port *port){	  _DPRINTK("called with port = 0x%08x", (unsigned int) port);}static unsigned int __s3c44b0_tx_empty(struct uart_port *port){	return 0;}static unsigned int __s3c44b0_get_mctrl(struct uart_port *port){	return 0;}static void __s3c44b0_set_mctrl(struct uart_port *port, unsigned int mctrl){}static void __s3c44b0_break_ctl(struct uart_port *port, int break_state){}static void __s3c44b0_init(struct uart_port *port){		SYSREG_SET(port->iobase, 0x03);	SYSREG_SET(port->iobase+4, 0x0309);	SYSREG_SET(port->iobase+8, 0x01);	SYSREG_SET(port->iobase+28, 0x22);}static struct irqaction __rx_irqaction[UART_NR] = {        {                .name		= "serial0_rx",                .flags		=  SA_INTERRUPT,                .handler 	= __s3c44b0_rx_int,        },        {                .name		= "serial1_rx",                .flags		=  SA_INTERRUPT,                .handler 	= __s3c44b0_rx_int,        },};static struct irqaction __tx_irqaction[UART_NR] = {        {                .name		= "serial0_tx",                .flags		=  SA_INTERRUPT,                .handler 	= __s3c44b0_tx_int,        },        {                .name		= "serial1_tx",                .flags		=  SA_INTERRUPT,                .handler 	= __s3c44b0_tx_int,        },};static int __s3c44b0_startup(struct uart_port *port){	/* this is the first time this port is opened */	/* do any hardware initialization needed here */	   int status;        __s3c44b0_init(port);        /*         * Allocate the IRQs for TX and RX         */        __tx_irqaction[port->line].dev_id = (void *)port;        __rx_irqaction[port->line].dev_id = (void *)port;        status = setup_irq( port->irq, &__tx_irqaction[port->line]);        if ( status) {                printk( KERN_ERR "Unabled to hook interrupt for serial %d TX\n", port->line);                return status;        }        status = setup_irq( port->irq+1, &__rx_irqaction[port->line]);        if ( status) {                printk( KERN_ERR "Unabled to hook interrupt for serial %d RX\n", port->line);                return status;        }        /*         * Finally, enable interrupts         */        spin_lock_irq( &port->lock);	if(port->line == 0)			SYSREG_AND_SET(S3C44B0X_INTMSK, 0xfffffff7);	else if(port->line == 1)		SYSREG_AND_SET(S3C44B0X_INTMSK, 0xfffffffb);	else		printk(KERN_ERR "Unmask interrupt for none serial port\n");        spin_unlock_irq( &port->lock);        return 0;}static void __s3c44b0_shutdown(struct uart_port *port){	/* The port is being closed by the last user. */	/* Do any hardware specific stuff here */      spin_lock_irq( &port->lock);      if(port->line == 0)			SYSREG_AND_SET(S3C44B0X_INTMSK, 0xfffffff7);	else if(port->line == 1)		SYSREG_AND_SET(S3C44B0X_INTMSK, 0xfffffffb);	else		printk(KERN_ERR "mask interrupt for none serial port\n");       spin_unlock_irq( &port->lock);}static void __s3c44b0_set_termios(struct uart_port *port, struct termios *termios, struct termios *old){        uart_update_timeout(port, termios->c_cflag, 115200);}static void __s3c44b0_pm(struct uart_port *port, unsigned int state, unsigned int oldstate){		}static int __s3c44b0_set_wake(struct uart_port *port, unsigned int state){        return 0;}static const char *__s3c44b0_type(struct uart_port *port){	return SERIAL_S3C44B0_NAME;}static void __s3c44b0_release_port(struct uart_port *port){}static int __s3c44b0_request_port(struct uart_port *port){	return 0;}static void __s3c44b0_config_port(struct uart_port *port, int flags){}static int __s3c44b0_verify_port(struct uart_port *port, struct serial_struct *ser){	return 0;}static struct uart_ops __s3c44b0_ops = {	.tx_empty	= __s3c44b0_tx_empty,	.set_mctrl	= __s3c44b0_set_mctrl,	.get_mctrl	= __s3c44b0_get_mctrl,	.stop_tx		= __s3c44b0_stop_tx,	.start_tx		= __s3c44b0_start_tx,	.send_xchar:  = __s3c44b0_send_xchar,	.stop_rx		= __s3c44b0_stop_rx,	.enable_ms	= __s3c44b0_enable_ms,	.break_ctl	= __s3c44b0_break_ctl,	.startup		= __s3c44b0_startup,	.shutdown	= __s3c44b0_shutdown,	.set_termios   = __s3c44b0_set_termios,       .pm             	= __s3c44b0_pm,       .set_wake       = __s3c44b0_set_wake,	.type		= __s3c44b0_type,	.release_port	= __s3c44b0_release_port,	.request_port	= __s3c44b0_request_port,	.config_port	= __s3c44b0_config_port,	.verify_port	= __s3c44b0_verify_port,};static struct uart_port __s3c44b0_ports[UART_NR] = {		  {                .iobase            	= S3C44B0X_ULCON0,                       .line                   	= 0,										/* port index */                .irq                    	= S3C44B0X_INTERRUPT_UTX0,		/* irq number */                .fifosize               = 1,										/* tx fifo size  */                .ops                    = &__s3c44b0_ops,						                .ignore_status_mask   = 0x0000000F,						/* ? */	                .type                   = PORT_S3C44B0,        },        {                .iobase                = S3C44B0X_ULCON1,                .line                    = 1,                .irq                     =  S3C44B0X_INTERRUPT_UTX1,                    .fifosize               = 1,                .ops                    = &__s3c44b0_ops,                .ignore_status_mask    = 0x0000000F,                .type                   = PORT_S3C44B0,        }};#ifdef CONFIG_SERIAL_S3C44B0_CONSOLE/************** console driver *****************/static void __s3c44b0_console_write(struct console *co, const char *s, u_int count){	struct uart_port *port = &__s3c44b0_ports[co->index];	__xmit_string( port, s, count);}static int __init __s3c44b0_console_setup(struct console *co, char *options){	struct uart_port *port;	int baud = 115200;	int bits = 8;	int parity = 'n';	int flow = 0;	/*	 * Check whether an invalid uart number has been specified, and	 * if so, search for the first available port that does have	 * console support.	 */	port = uart_get_console(__s3c44b0_ports, UART_NR, co);//	_DPRINTK("using port = 0x%08x", (unsigned int) port);	if (options)		uart_parse_options(options, &baud, &parity, &bits, &flow);	__s3c44b0_init(port, baud);	return uart_set_options(port, co, baud, parity, bits, flow);}extern struct uart_driver __s3c44b0_driver;static struct uart_console __s3c44b0_console = {				.name		= "ttyS",			       .write          	= __s3c44b0_console_write,        			.device         	= uart_console_device,			       .setup          	= __s3c44b0_console_setup,			       .flags          	= CON_PRINTBUFFER,			       .index          	= -1,			       .data           	= &__s3c44b0_driver,};static int __init __s3c44b0_console_init(void){	register_console(&__s3c44b0_console);	return 0;}console_initcall(__s3c44b0_console_init);#endif /* CONFIG_SERIAL_S3C44B0_CONSOLE */static struct uart_driver __s3c44b0_driver = {				.owner		= THIS_MODULE,				.driver_name	= SERIAL_S3C44B0_NAME,				.dev_name	= "ttyS",				.major		= TTY_MAJOR,				.minor		= 68,				.nr			= UART_NR,#ifdef CONFIG_SERIAL_S3C44B0_CONSOLE        			.cons:            &__s3c44b0_console,#endif				};static int __init __s3c44b0_serial_init(void){        int    status, i;/*      _DPRINTK("initializing driver with drv = 0x%08x", (unsigned int) &__s3c44b0_driver); */        status = uart_register_driver( &__s3c44b0_driver);        if ( status) {                _DPRINTK("uart_register_driver() returned %d", status);        }        for ( i = 0; i < UART_NR; i++) {                status = uart_add_one_port( &__s3c44b0_driver, &__s3c44b0_ports[i]);                if ( status) {                        _DPRINTK("uart_add_one_port(%d) returned %d", i, status);                }        }        return 0;}module_init(__s3c44b0_serial_init);

⌨️ 快捷键说明

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