Re: Digging through old vendor code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 13 Jan 2008 11:28:06 -0500, linux@xxxxxxxxxxx <linux@xxxxxxxxxxx> wrote:
> > Heh. Maybe you could just use the rename logic?
> >
> > [How-to snipped]
>
> Clever idea, but I think the real problem was to figure out what VERSION
> of the file was the base; i.e. to look through history.
>
> Still, it should be possible to adapt the technique...
>
> #!/bin/sh
>
> # List of files we are looking to copy from
> SRC="drivers/serial/"
> # Temporary work directory
> DST=/tmp/work
> git-clone -l -n -s . $DST
> { cd $DST; git-symbolic-ref HEAD refs/heads/DELETEME; }
> for i in `git-rev-list v2.6.20..v2.6.24-rc6 -- $SRC`; do
>         j=`git-describe $i`
>         git-archive --prefix="$j/" $i -- $SRC | tar xf - -C $DST
>         # This is abusing the index, but it saves space...
>         { cd $DST; git add $j; rm -rf $j; }
> done
>
> # And  now proceed as per Linus's idea...
> # Except we have it all in the index; no need
> # to actually make a commit...
>
> cd $DST
> cp $target_file $DST
> { cd $DST; git-diff-files -M...; }

I tried this using -M1%, it returned 53,575 files. Same thing for 10%.

The files don't seem to be in order by similarity, the first match
returned is not a good one.

I attached the file if anyone wants to play with it. I'm 90% certain
it was copied from amba-pl010.c in 2.6.15.


>
>
> Maybe a real git wizard will show me how to insert the index entries
> directly without ever doing anything as pedestrian as extracting, hashing,
> and then deleting the files, but it's still not that bad.
>
> And it's kind of a neat example of using the index as a staging area
> for a commit.
>
> (Exercise for the reader: the above gets a complete copy of every file in
> the directory for every commit in qhich ANY file in the directory changed.
> Better would be to do the git-rev-list per-file, so you only add unique
> file versions.  This requires an outer loop over file names and a more
> careful pathname specification to git add in the inner loop.)
>


-- 
Jon Smirl
jonsmirl@xxxxxxxxx
/*
 *  linux/drivers/serial/cs93xx.c
 *
 *  Driver for EP93xx serial ports
 *
 *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o,
 *  Deep Blue Solutions Ltd.
 *
 *  Copyright 1999 ARM Limited
 *  Copyright (C) 2000 Deep Blue Solutions Ltd.
 *  Copyright (c) 2003 Cirrus Logic, Inc.
 *
 * 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
 *
 *  $Id: linux-2.6.21.5-ep9x.patch,v 1.8 2008/01/04 13:28:07 baustin Exp $
 *
 * The EP93xx serial ports are AMBA, but at different addresses from the
 * integrator.
 * This is a generic driver for ARM AMBA-type serial ports.  They
 * have a lot of 16550-like features, but are not register compatable.
 * Note that although they do have CTS, DCD and DSR inputs, they do
 * not have an RI input, nor do they have DTR or RTS outputs.  If
 * required, these have to be supplied via some other means (eg, GPIO)
 * and hooked into this driver.
 */
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/spinlock.h>
//#include <linux/device.h>
#include <linux/platform_device.h>

#include <asm/hardware.h>
#include <asm/io.h>
//#include <asm/irqs.h>

#if defined(CONFIG_SERIAL_EP93XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif


#include <linux/serial_core.h>
#include <linux/amba/bus.h>
#include <linux/amba/serial.h>



#if defined(CONFIG_ARCH_EP9301) || defined(CONFIG_ARCH_EP9302)
#ifdef CONFIG_EP93XX_IRDA
#define UART_NR		1
#else
#define UART_NR		2
#endif
#else
#ifdef CONFIG_EP93XX_IRDA
#define UART_NR		2
#else
#define UART_NR		3
#endif
#endif

#define SERIAL_EP93XX_MAJOR	204
#define SERIAL_EP93XX_MINOR	16
#define SERIAL_EP93XX_NR	UART_NR

#define EP93XX_ISR_PASS_LIMIT	256

/*
 * Access macros for the AMBA UARTs
 */
#define UART_GET_INT_STATUS(p)	((readl((p)->membase + UARTIIR)) & 0xff)
#define UART_PUT_ICR(p, c)	writel((c), (p)->membase + UARTICR)
#define UART_GET_FR(p)		((readl((p)->membase + UARTFR)) & 0xff)
#define UART_GET_CHAR(p)	((readl((p)->membase + UARTDR)) & 0xff)
#define UART_PUT_CHAR(p, c)	writel((c), (p)->membase + UARTDR)
#define UART_GET_RSR(p)		((readl((p)->membase + UARTRSR)) & 0xff)
#define UART_PUT_RSR(p, c)	writel((c), (p)->membase + UARTRSR)
#define UART_GET_CR(p)		((readl((p)->membase + UARTCR)) & 0xff)
#define UART_PUT_CR(p,c)	writel((c), (p)->membase + UARTCR)
#define UART_GET_LCRL(p)	((readl((p)->membase + UARTCR_L)) & 0xff)
#define UART_PUT_LCRL(p,c)	writel((c), (p)->membase + UARTCR_L)
#define UART_GET_LCRM(p)	((readl((p)->membase + UARTCR_M)) & 0xff)
#define UART_PUT_LCRM(p,c)	writel((c), (p)->membase + UARTCR_M)
#define UART_GET_LCRH(p)	((readl((p)->membase + UARTCR_H)) & 0xff)
#define UART_PUT_LCRH(p,c)	writel((c), (p)->membase + UARTCR_H)
#define UART_RX_DATA(s)		(((s) & UARTFR_RXFE) == 0)
#define UART_TX_READY(s)	(((s) & UARTFR_TXFF) == 0)
#define UART_TX_EMPTY(p)	((UART_GET_FR(p) & UARTFR_TMSK) == 0)

#define UART_GET_MCR(p)		readl((p)->membase + UARTMCR)
#define UART_PUT_MCR(c, p)	writel((c), (p)->membase + UARTMCR)
#define UART_CLEAR_ECR(p)	writel( 0, (p)->membase + UARTECR)

#define UART_DUMMY_RSR_RX	256
#define UART_PORT_SIZE		65536

/*
 * We wrap our port structure around the generic uart_port.
 */
struct uart_ep93xx_port {
	struct uart_port	port;
	unsigned int		old_status;
};


static void
ep93xxuart_enable_clocks(struct uart_port *port)
{
	unsigned int uiSysDevCfg;

	/*
	 * Enable the clocks to this UART in CSC_syscon
	 * - Read DEVCFG
	 * - OR in the correct uart enable bit
	 * - Set the lock register
	 * - Write back to DEVCFG
	 */
	uiSysDevCfg = inl(SYSCON_DEVCFG);

	switch ((unsigned long)port->membase) {
	case UART1_BASE:
		uiSysDevCfg |= SYSCON_DEVCFG_U1EN;
		break;

	case UART2_BASE:
		uiSysDevCfg |= SYSCON_DEVCFG_U2EN;
		break;

	case UART3_BASE:
		uiSysDevCfg |= SYSCON_DEVCFG_U3EN;
		break;
	}

	SysconSetLocked( SYSCON_DEVCFG, uiSysDevCfg );
}

static void
ep93xxuart_disable_clocks(struct uart_port *port)
{
	unsigned int uiSysDevCfg;

	/*
	 * Disable the clocks to this UART in CSC_syscon
	 * - Read DEVCFG
	 * - AND to clear the correct uart enable bit
	 * - Set the lock register
	 * - Write back to DEVCFG
	 */
	uiSysDevCfg = inl(SYSCON_DEVCFG);

	switch ((unsigned long)port->membase) {
	case UART1_BASE:
		uiSysDevCfg &= ~((unsigned int)SYSCON_DEVCFG_U1EN);
		break;

	case UART2_BASE:
		uiSysDevCfg &= ~((unsigned int)SYSCON_DEVCFG_U2EN);
		break;

	case UART3_BASE:
		uiSysDevCfg &= ~((unsigned int)SYSCON_DEVCFG_U3EN);
		break;
	}

	SysconSetLocked( SYSCON_DEVCFG, uiSysDevCfg );
}

#if 1
static int
ep93xxuart_is_port_enabled(struct uart_port *port)
{
	unsigned int uiSysDevCfg;

	uiSysDevCfg = inl(SYSCON_DEVCFG);

	switch ((unsigned long)port->membase) {
	case UART1_BASE:
		uiSysDevCfg &= (unsigned int)SYSCON_DEVCFG_U1EN;
		break;

	case UART2_BASE:
		uiSysDevCfg &= (unsigned int)SYSCON_DEVCFG_U2EN;
		break;

	case UART3_BASE:
		uiSysDevCfg &= (unsigned int)SYSCON_DEVCFG_U3EN;
		break;
	}

	return( uiSysDevCfg != 0 );
}
#endif

static void
ep93xxuart_stop_tx(struct uart_port *port)
{
	unsigned int cr;

	cr = UART_GET_CR(port);
	cr &= ~UARTCR_TIE;
	UART_PUT_CR(port, cr);
}

static void
ep93xxuart_start_tx(struct uart_port *port)
{
	unsigned int cr;

	cr = UART_GET_CR(port);
	cr |= UARTCR_TIE;
	UART_PUT_CR(port, cr);
}

static void
ep93xxuart_stop_rx(struct uart_port *port)
{
	unsigned int cr;

	cr = UART_GET_CR(port);
	cr &= ~(UARTCR_RIE | UARTCR_RTIE);
	UART_PUT_CR(port, cr);
}

static void
ep93xxuart_enable_ms(struct uart_port *port)
{
	unsigned int cr;

	cr = UART_GET_CR(port);
	cr |= UARTCR_MSIE;
	UART_PUT_CR(port, cr);
}

static void
#ifdef SUPPORT_SYSRQ
ep93xxuart_rx_chars(struct uart_port *port, struct pt_regs *regs)
#else
ep93xxuart_rx_chars(struct uart_port *port)
#endif
{
	struct tty_struct *tty = port->info->tty;
	unsigned int status, ch, flag, rsr, max_count = 256;

if(((unsigned long)port->membase)==UART2_BASE)
{
printk("ep93 UART2 ep93xxuart_rx_chars\n");
}

	flag = 0;
	status = UART_GET_FR(port);
	while (UART_RX_DATA(status) && max_count--) {
		//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 = UART_GET_CHAR(port);

		//*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
		 */
		rsr = UART_GET_RSR(port) | UART_DUMMY_RSR_RX;
		UART_PUT_RSR(port, 0);
		if (rsr & UARTRSR_ANY) {
			if (rsr & UARTRSR_BE) {
				rsr &= ~(UARTRSR_FE | UARTRSR_PE);
				port->icount.brk++;
				if (uart_handle_break(port))
					goto ignore_char;
			} else if (rsr & UARTRSR_PE)
				port->icount.parity++;
			else if (rsr & UARTRSR_FE)
				port->icount.frame++;
			if (rsr & UARTRSR_OE)
				port->icount.overrun++;

			rsr &= port->read_status_mask;

			if (rsr & UARTRSR_BE)
				//*tty->flip.flag_buf_ptr = TTY_BREAK;
				flag = TTY_BREAK;
			else if (rsr & UARTRSR_PE)
				//*tty->flip.flag_buf_ptr = TTY_PARITY;
				flag = TTY_PARITY;
			else if (rsr & UARTRSR_FE)
				//*tty->flip.flag_buf_ptr = TTY_FRAME;
				flag = TTY_FRAME;
		}

		if (uart_handle_sysrq_char(port, ch))
			goto ignore_char;

		//if ((rsr & port->ignore_status_mask) == 0) {
		//	tty->flip.flag_buf_ptr++;
		//	tty->flip.char_buf_ptr++;
		//	tty->flip.count++;
		//}
		//if ((rsr & UARTRSR_OE) &&
		//   tty->flip.count < TTY_FLIPBUF_SIZE) {
			/*
			 * Overrun is special, since it's reported
			 * immediately, and doesn't affect the current
			 * character
			 */
		//	*tty->flip.char_buf_ptr++ = 0;
		//	*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
		//	tty->flip.count++;
		//}

		uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag);

	ignore_char:
		status = UART_GET_FR(port);
	}
	tty_flip_buffer_push(tty);
	return;
}

static void
ep93xxuart_tx_chars(struct uart_port *port)
{
	struct circ_buf *xmit = &port->info->xmit;
	int count;

	if (port->x_char) {
		UART_PUT_CHAR(port, port->x_char);
		port->icount.tx++;
		port->x_char = 0;
		return;
	}
	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
		ep93xxuart_stop_tx(port);
		return;
	}

	count = port->fifosize >> 1;
	do {
		UART_PUT_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))
		ep93xxuart_stop_tx(port);
}

static void
ep93xxuart_modem_status(struct uart_port *port)
{
	struct uart_ep93xx_port *uap = (struct uart_ep93xx_port *)port;
	unsigned int status, delta;

	UART_PUT_ICR(port, 0);

	status = UART_GET_FR(port) & UARTFR_MODEM_ANY;

	delta = status ^ uap->old_status;
	uap->old_status = status;

	if (!delta)
		return;

	if (delta & UARTFR_DCD)
		uart_handle_dcd_change(port, status & UARTFR_DCD);

	if (delta & UARTFR_DSR)
		port->icount.dsr++;

	if (delta & UARTFR_CTS)
		uart_handle_cts_change(port, status & UARTFR_CTS);

	wake_up_interruptible(&port->info->delta_msr_wait);
}

static irqreturn_t
ep93xxuart_int(int irq, void *dev_id)
{
	struct uart_port *port = dev_id;
	unsigned int status, pass_counter = EP93XX_ISR_PASS_LIMIT;


if(((unsigned long)port->membase)==UART2_BASE)
{
printk("ep93 UART2 ep93xxuart_int\n");
}


	spin_lock(&port->lock);

	status = UART_GET_INT_STATUS(port);
if(((unsigned long)port->membase)==UART2_BASE)
{
printk("status=%x\n",status);
}
	do {
		if (status & (UARTIIR_RTIS | UARTIIR_RIS))
#ifdef SUPPORT_SYSRQ
			ep93xxuart_rx_chars(port, regs);
#else
			ep93xxuart_rx_chars(port);
#endif
		if (status & UARTIIR_TIS)
			ep93xxuart_tx_chars(port);
		if (status & UARTIIR_MIS)
			ep93xxuart_modem_status(port);

		if (pass_counter-- == 0)
			break;

		status = UART_GET_INT_STATUS(port);
	} while (status & (UARTIIR_RTIS | UARTIIR_RIS | UARTIIR_TIS));

	spin_unlock(&port->lock);

	return IRQ_HANDLED;
}

static unsigned int
ep93xxuart_tx_empty(struct uart_port *port)
{
	return UART_GET_FR(port) & UARTFR_BUSY ? 0 : TIOCSER_TEMT;
}

static unsigned int
ep93xxuart_get_mctrl(struct uart_port *port)
{
	unsigned int result = 0;
	unsigned int status;

	status = UART_GET_FR(port);
	if (status & UARTFR_DCD)
		result |= TIOCM_CAR;
	if (status & UARTFR_DSR)
		result |= TIOCM_DSR;
	if (status & UARTFR_CTS)
		result |= TIOCM_CTS;

	return result;
}

static void
ep93xxuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
	unsigned int ctrl = 0;

	ctrl = UART_GET_MCR(port);

#define BIT93(tiocmbit, uartbit)		\
	if (mctrl & tiocmbit)		\
		ctrl |= uartbit;	\
	else				\
		ctrl &= ~uartbit

	BIT93(TIOCM_RTS, UARTMCR_RTS);
	BIT93(TIOCM_DTR, UARTMCR_DTR);
	BIT93(TIOCM_OUT1, UARTMCR_OUT1);
	BIT93(TIOCM_OUT2, UARTMCR_OUT2);
	BIT93(TIOCM_LOOP, UARTMCR_LOOP);
#undef BIT93

	UART_PUT_MCR(ctrl, port);
}

static void
ep93xxuart_break_ctl(struct uart_port *port, int break_state)
{
	unsigned long flags;
	unsigned int lcr_h;

	spin_lock_irqsave(&port->lock, flags);
	lcr_h = UART_GET_LCRH(port);
	if (break_state == -1)
		lcr_h |= UARTLCR_H_BRK;
	else
		lcr_h &= ~UARTLCR_H_BRK;
	UART_PUT_LCRH(port, lcr_h);
	spin_unlock_irqrestore(&port->lock, flags);
}

static int
ep93xxuart_startup(struct uart_port *port)
{
	struct uart_ep93xx_port *uap = (struct uart_ep93xx_port *)port;
	int retval = -EINVAL;
	char *name = 0;

	/*
	 * Enable the clocks for this port.
	 */
	ep93xxuart_enable_clocks(port);

	/*
	 * Get the name of this port (used only for resource allocations).
	 */
	switch ((unsigned long)port->membase) {
	case UART1_BASE:
		name = "ttyAM0";
		break;
	case UART2_BASE:
		name = "ttyAM1";
		break;
	case UART3_BASE:
		name = "ttyAM2";
		break;
	}
printk("EP93XX UART--%s irq=%d\n",name,port->irq);
	/*
	 * Allocate the IRQ
	 */
	retval = request_irq(port->irq, ep93xxuart_int, 0 , name, port);
printk("irq is ok %d\n",retval);
	if (retval) {
		ep93xxuart_disable_clocks(port);
		return retval;
	}

	/*
	 * Allocate the memory region.
	 */
	if(request_mem_region(port->mapbase, UART_PORT_SIZE, name) == NULL) {
		printk("mem region fail\n");
		free_irq(port->irq, port);
		ep93xxuart_disable_clocks(port);
		return 1;
	}

	/*
	 * initialise the old status of the modem signals
	 */
	uap->old_status = UART_GET_FR(port) & UARTFR_MODEM_ANY;

printk("old status %x\n",uap->old_status);
	/*
	 * Finally, enable interrupts
	 */
	spin_lock_irq(&port->lock);
	UART_PUT_CR(port, UARTCR_UARTEN | UARTCR_RIE | UARTCR_RTIE|0x2);
	spin_unlock_irq(&port->lock);
	
	{
	unsigned int cr;

	cr = UART_GET_CR(port);
	printk("cr=%x\n",cr);
	}
	/*
	 * Success.
	 */
	return 0;
}

static void
ep93xxuart_shutdown(struct uart_port *port)
{
	/*
	 * disable all interrupts, disable the port
	 */
	UART_PUT_CR(port, 0);

	/*
	 * disable break condition and fifos
	 */
	UART_PUT_LCRH(port, UART_GET_LCRH(port) &
		      ~(UARTLCR_H_BRK | UARTLCR_H_FEN));

	/*
	 * Free the interrupt
	 */
	free_irq(port->irq, port);

	/*
	 * Release the memory region.
	 */
	release_mem_region(port->mapbase, UART_PORT_SIZE);

	/*
	 * Disable the clock.
	 */
	ep93xxuart_disable_clocks( port );
}

static void
ep93xxuart_set_termios(struct uart_port *port, struct ktermios *termios,
		       struct ktermios *old)
{
	unsigned int lcr_h, baud, quot;
	unsigned long flags;

	/*
	 * Ask the core to calculate the divisor for us.
	 */
	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
	quot = uart_get_divisor(port, baud) - 1;
	
	/* byte size and parity */
	switch (termios->c_cflag & CSIZE) {
	case CS5:
		lcr_h = UARTLCR_H_WLEN_5;
		break;
	case CS6:
		lcr_h = UARTLCR_H_WLEN_6;
		break;
	case CS7:
		lcr_h = UARTLCR_H_WLEN_7;
		break;
	default: // CS8
		lcr_h = UARTLCR_H_WLEN_8;
		break;
	}
	if (termios->c_cflag & CSTOPB)
		lcr_h |= UARTLCR_H_STP2;
	if (termios->c_cflag & PARENB) {
		lcr_h |= UARTLCR_H_PEN;
		if (!(termios->c_cflag & PARODD))
			lcr_h |= UARTLCR_H_EPS;
	}
	if (port->fifosize > 1)
		lcr_h |= UARTLCR_H_FEN;

	spin_lock_irqsave(&port->lock, flags);

	/*
	 * Update the per-port timeout.
	 */
	uart_update_timeout(port, termios->c_cflag, baud);

	port->read_status_mask = UARTRSR_OE;
	if (termios->c_iflag & INPCK)
		port->read_status_mask |= UARTRSR_FE | UARTRSR_PE;
	if (termios->c_iflag & (BRKINT | PARMRK))
		port->read_status_mask |= UARTRSR_BE;

	/*
	 * Characters to ignore
	 */
	port->ignore_status_mask = 0;
	if (termios->c_iflag & IGNPAR)
		port->ignore_status_mask |= UARTRSR_FE | UARTRSR_PE;
	if (termios->c_iflag & IGNBRK) {
		port->ignore_status_mask |= UARTRSR_BE;
		/*
		 * If we're ignoring parity and break indicators,
		 * ignore overruns too (for real raw support).
		 */
		if (termios->c_iflag & IGNPAR)
			port->ignore_status_mask |= UARTRSR_OE;
	}

	/*
	 * Ignore all characters if CREAD is not set.
	 */
	if ((termios->c_cflag & CREAD) == 0)
		port->ignore_status_mask |= UART_DUMMY_RSR_RX;

	if (UART_ENABLE_MS(port, termios->c_cflag))
		ep93xxuart_enable_ms(port);

	UART_PUT_LCRL(port, quot & 0xff);
	UART_PUT_LCRM(port, (quot >> 8) & 0xff);
	UART_PUT_LCRH(port, lcr_h);

	spin_unlock_irqrestore(&port->lock, flags);
}

static const char *
ep93xxuart_type(struct uart_port *port)
{
	return port->type == PORT_AMBA ? "EP93XX" : NULL;
}

/*
 * Release the memory region(s) being used by 'port'
 */
static void
ep93xxuart_release_port(struct uart_port *port)
{
}

/*
 * Request the memory region(s) being used by 'port'
 */
static int
ep93xxuart_request_port(struct uart_port *port)
{
	return 0;
}

/*
 * Configure/autoconfigure the port.
 */
static void
ep93xxuart_config_port(struct uart_port *port, int flags)
{
	if (flags & UART_CONFIG_TYPE)
		port->type = PORT_AMBA;
}

/*
 * verify the new serial_struct (for TIOCSSERIAL).
 */
static int
ep93xxuart_verify_port(struct uart_port *port, struct serial_struct *ser)
{
	int ret = 0;
	if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
		ret = -EINVAL;
	if (ser->irq < 0 || ser->irq >= NR_IRQS)
		ret = -EINVAL;
	if (ser->baud_base < 9600)
		ret = -EINVAL;
	return ret;
}

static struct uart_ops ep93xx_pops = {
	.tx_empty	= ep93xxuart_tx_empty,
	.set_mctrl	= ep93xxuart_set_mctrl,
	.get_mctrl	= ep93xxuart_get_mctrl,
	.stop_tx	= ep93xxuart_stop_tx,
	.start_tx	= ep93xxuart_start_tx,
	.stop_rx	= ep93xxuart_stop_rx,
	.enable_ms	= ep93xxuart_enable_ms,
	.break_ctl	= ep93xxuart_break_ctl,
	.startup	= ep93xxuart_startup,
	.shutdown	= ep93xxuart_shutdown,
	.set_termios	= ep93xxuart_set_termios,
	.type		= ep93xxuart_type,
	.release_port	= ep93xxuart_release_port,
	.request_port	= ep93xxuart_request_port,
	.config_port	= ep93xxuart_config_port,
	.verify_port	= ep93xxuart_verify_port,
};

static struct uart_ep93xx_port ep93xx_ports[UART_NR] = {
	{
		.port	= {
			.membase	= (void *)UART1_BASE,
			.mapbase	= /*HwRegToPhys(UART1_BASE)*/UART1_BASE_VIRT,
			.iotype		= UPIO_MEM,
			.irq		= IRQ_EP93XX_UART1,
			.uartclk	= 14745600,
			.fifosize	= 16,
			.ops		= &ep93xx_pops,
			.flags		= UPF_BOOT_AUTOCONF,
			.line		= 0,
		},
	},
#if !defined(CONFIG_EP93XX_IRDA)
	{
		.port	= {
			.membase	= (void *)UART2_BASE,
			.mapbase	= /*HwRegToPhys(UART2_BASE)*/UART2_BASE_VIRT,
			.iotype		= UPIO_MEM,
			.irq		= IRQ_EP93XX_UART2,
			.uartclk	= 14745600,
			.fifosize	= 16,
			.ops		= &ep93xx_pops,
			.flags		= UPF_BOOT_AUTOCONF,
			.line		= 1,
		},
	},
#endif
#if !defined(CONFIG_ARCH_EP9301) && !defined(CONFIG_ARCH_EP9302)
	{
		.port	= {
			.membase	= (void *)UART3_BASE,
			.mapbase	= /*HwRegToPhys(UART3_BASE)*/UART3_BASE_VIRT,
			.iotype		= UPIO_MEM,
			.irq		= IRQ_EP93XX_UART3,
			.uartclk	= 14745600,
			.fifosize	= 16,
			.ops		= &ep93xx_pops,
			.flags		= UPF_BOOT_AUTOCONF,
#if !defined(CONFIG_EP93XX_IRDA)
			.line		= 2,
#else
			.line		= 1,
#endif
		},
	}
#endif
};

#ifdef CONFIG_SERIAL_EP93XX_CONSOLE

static void
ep93xxuart_console_write_char(struct uart_port *port, char ch)
{
	unsigned int status;

	do {
		status = UART_GET_FR(port);
	} while (!UART_TX_READY(status));
	UART_PUT_CHAR(port, ch);
}

static void
ep93xxuart_console_write(struct console *co, const char *s, unsigned int count)
{
	struct uart_port *port = &ep93xx_ports[co->index].port;
	unsigned int status, old_cr, old_power;
	int i;

	old_power = ep93xxuart_is_port_enabled(port);
	if (!old_power)
		ep93xxuart_enable_clocks(port);

	/*
	 * First save the CR then disable the interrupts
	 */
	old_cr = UART_GET_CR(port);
	UART_PUT_CR(port, UARTCR_UARTEN);

	/*
	 * Now, do each character
	 */
	for (i = 0; i < count; i++) {
		ep93xxuart_console_write_char(port, s[i]);
		if (s[i] == '\n')
			ep93xxuart_console_write_char(port, '\r');
	}

	/*
	 * Finally, wait for transmitter to become empty
	 * and restore the TCR
	 */
	do {
		status = UART_GET_FR(port);
	} while (status & UARTFR_BUSY);
	UART_PUT_CR(port, old_cr);

	if (!old_power)
		ep93xxuart_disable_clocks(port);
}

static void __init
ep93xxuart_console_get_options(struct uart_port *port, int *baud, int *parity,
			       int *bits)
{
	if (UART_GET_CR(port) & UARTCR_UARTEN) {
		unsigned int lcr_h, lcr_m, lcr_l;

		lcr_h = UART_GET_LCRH(port);

		*parity = 'n';
		if (lcr_h & UARTLCR_H_PEN) {
			if (lcr_h & UARTLCR_H_EPS)
				*parity = 'e';
			else
				*parity = 'o';
		}

		if ((lcr_h & 0x60) == UARTLCR_H_WLEN_7)
			*bits = 7;
		else
			*bits = 8;

		lcr_m = UART_GET_LCRM(port);
		lcr_l = UART_GET_LCRL(port);

		*baud = port->uartclk / (16 * ((lcr_m * 256) + lcr_l + 1));
	}
}

static int __init
ep93xxuart_console_setup(struct console *co, char *options)
{
	struct uart_port *port;
	int baud = 57600;
	int bits = 8;
	int parity = 'n';
	int flow = 'n';

	/*
	 * Check whether an invalid uart number has been specified, and
	 * if so, search for the first available port that does have
	 * console support.
	 */
	if (co->index >= UART_NR)
		co->index = 0;
	port = &ep93xx_ports[co->index].port;

	if (options)
		uart_parse_options(options, &baud, &parity, &bits, &flow);
	else
		ep93xxuart_console_get_options(port, &baud, &parity, &bits);

	return uart_set_options(port, co, baud, parity, bits, flow);
}

static struct console ep93xx_console;
#define EP93XX_CONSOLE	&ep93xx_console
#else
#define EP93XX_CONSOLE	NULL
#endif

static struct uart_driver ep93xx_reg = {
	.driver_name		= "ttyAM",
	.dev_name		= "ttyAM",
	.major			= SERIAL_EP93XX_MAJOR,
	.minor			= SERIAL_EP93XX_MINOR,
	.nr			= UART_NR,
	.cons			= EP93XX_CONSOLE,
};


/*
 * The 'index' element of this field selects which UART to use for
 * console.  For ep93xx, valid values are 0, 1, and 2.  If you set
 * it to -1, then uart_get_console will search for the first UART
 * which is the same as setting it to 0.
 */
static struct console ep93xx_console = {
	.name		= "ttyAM",
	.write		= ep93xxuart_console_write,
	.device		= uart_console_device,
	.setup		= ep93xxuart_console_setup,
	.flags		= CON_PRINTBUFFER,
	.index		= -1,
	.data		= &ep93xx_reg,
};

static int __init
ep93xxuart_console_init(void)
{
	register_console(&ep93xx_console);
	return 0;
}
console_initcall(ep93xxuart_console_init);

static struct resource uarts[UART_NR] = {
	[0] = {
		.name		= "uart1",
		.start		= /*HwRegToPhys(UART1_BASE)*/UART1_BASE_VIRT,
		.end		= /*HwRegToPhys(UART1_BASE)*/UART1_BASE_VIRT + 0x0000ffff,
	},
#if !defined(CONFIG_EP93XX_IRDA)
	[1] = {
		.name		= "uart2",
		.start		= /*HwRegToPhys(UART2_BASE)*/UART2_BASE_VIRT,
		.end		= /*HwRegToPhys(UART2_BASE)*/UART2_BASE_VIRT + 0x0000ffff,
	},
#endif
#if !defined(CONFIG_ARCH_EP9301) && !defined(CONFIG_ARCH_EP9302)
	[2] = {
		.name		= "uart3",
		.start		= /*HwRegToPhys(UART3_BASE)*/UART3_BASE_VIRT,
		.end		= /*HwRegToPhys(UART3_BASE)*/UART3_BASE_VIRT + 0x0000ffff,
	},
#endif
};

static int __init
ep93xxuart_init(void)
{
	int ret, i;

	ret = uart_register_driver(&ep93xx_reg);
	if (ret == 0) {
		for (i = 0; i < UART_NR; i++) {
			request_resource(&iomem_resource, &uarts[i]);
			uart_add_one_port(&ep93xx_reg, &ep93xx_ports[i].port);
		}
	}
	return ret;
}

static void __exit ep93xxuart_exit(void)
{
	int i;

	for (i = 0; i < UART_NR; i++)
		uart_remove_one_port(&ep93xx_reg, &ep93xx_ports[i].port);
	uart_unregister_driver(&ep93xx_reg);
}

module_init(ep93xxuart_init);
module_exit(ep93xxuart_exit);

MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd/Cirrus Logic, Inc.");
MODULE_DESCRIPTION("EP93xx ARM serial port driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV(SERIAL_EP93XX_MAJOR, SERIAL_EP93XX_MINOR);

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux