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

📄 mx21_16c2552.c

📁 arm926e的mx21处理器的串口驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:

	/*
	 * Set the check interval to be 1/5 of the estimated time to
	 * send a single character, and make it at least 1.  The check
	 * interval should also be less than the timeout.
	 *
	 * Note: we have to use pretty tight timings here to satisfy
	 * the NIST-PCTS.
	 */
	char_time = (info->timeout - HZ/50) / info->port->fifosize;
	char_time = char_time / 5;
	if (char_time == 0)
		char_time = 1;
	if (timeout && timeout < char_time)
		char_time = timeout;
	/*
	 * If the transmitter hasn't cleared in twice the approximate
	 * amount of time to send the entire FIFO, it probably won't
	 * ever clear.  This assumes the UART isn't doing flow
	 * control, which is currently the case.  Hence, if it ever
	 * takes longer than info->timeout, this is probably due to a
	 * UART bug of some kind.  So, we clamp the timeout parameter at
	 * 2*info->timeout.
	 */
	if (!timeout || timeout > 2 * info->timeout)
		timeout = 2 * info->timeout;

	expire = jiffies + timeout;
#if DEBUG
	printk("ambauart_wait_until_sent(%d), jiff=%lu, expire=%lu...\n",
	       MINOR(tty->device) - tty->driver.minor_start, jiffies,
	       expire);
#endif
	while (UART_GET_FR(info->port) & AMBA_UARTFR_BUSY) {
		set_current_state(TASK_INTERRUPTIBLE);
		schedule_timeout(char_time);
		if (signal_pending(current))
			break;
		if (timeout && time_after(jiffies, expire))
			break;
		status = UART_GET_FR(info->port);
	}
	set_current_state(TASK_RUNNING);
}

static void ambauart_hangup(struct tty_struct *tty)
{
	struct amba_info *info = tty->driver_data;
	struct amba_state *state = info->state;

	ambauart_flush_buffer(tty);
	if (info->flags & ASYNC_CLOSING)
		return;
	ambauart_shutdown(info);
	info->event = 0;
	state->count = 0;
	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
	info->tty = NULL;
	wake_up_interruptible(&info->open_wait);
}

static int block_til_ready(struct tty_struct *tty, struct file *filp,
			   struct amba_info *info)
{
	DECLARE_WAITQUEUE(wait, current);
	struct amba_state *state = info->state;
	unsigned long flags;
	int do_clocal = 0, extra_count = 0, retval;

	/*
	 * If the device is in the middle of being closed, then block
	 * until it's done, and then try again.
	 */
	if (tty_hung_up_p(filp) ||
	    (info->flags & ASYNC_CLOSING)) {
		if (info->flags & ASYNC_CLOSING)
			interruptible_sleep_on(&info->close_wait);
		return (info->flags & ASYNC_HUP_NOTIFY) ?
			-EAGAIN : -ERESTARTSYS;
	}

	/*
	 * If this is a callout device, then just make sure the normal
	 * device isn't being used.
	 */
	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
		if (info->flags & ASYNC_NORMAL_ACTIVE)
			return -EBUSY;
		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
		    (info->session != current->session))
			return -EBUSY;
		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
		    (info->pgrp != current->pgrp))
			return -EBUSY;
		info->flags |= ASYNC_CALLOUT_ACTIVE;
		return 0;
	}

	/*
	 * If non-blocking mode is set, or the port is not enabled,
	 * then make the check up front and then exit.
	 */
	if ((filp->f_flags & O_NONBLOCK) ||
	    (tty->flags & (1 << TTY_IO_ERROR))) {
		if (info->flags & ASYNC_CALLOUT_ACTIVE)
			return -EBUSY;
		info->flags |= ASYNC_NORMAL_ACTIVE;
		return 0;
	}

	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
		if (state->normal_termios.c_cflag & CLOCAL)
			do_clocal = 1;
	} else {
		if (tty->termios->c_cflag & CLOCAL)
			do_clocal = 1;
	}

	/*
	 * Block waiting for the carrier detect and the line to become
	 * free (i.e., not in use by the callout).  While we are in
	 * this loop, state->count is dropped by one, so that
	 * rs_close() knows when to free things.  We restore it upon
	 * exit, either normal or abnormal.
	 */
	retval = 0;
	add_wait_queue(&info->open_wait, &wait);
	save_flags(flags); cli();
	if (!tty_hung_up_p(filp)) {
		extra_count = 1;
		state->count--;
	}
	restore_flags(flags);
	info->blocked_open++;
	while (1) {
		save_flags(flags); cli();
		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
		    (tty->termios->c_cflag & CBAUD)) {
			info->mctrl = TIOCM_DTR | TIOCM_RTS;
			info->port->set_mctrl(info->port, info->mctrl);
		}
		restore_flags(flags);
		set_current_state(TASK_INTERRUPTIBLE);
		if (tty_hung_up_p(filp) ||
		    !(info->flags & ASYNC_INITIALIZED)) {
			if (info->flags & ASYNC_HUP_NOTIFY)
				retval = -EAGAIN;
			else
				retval = -ERESTARTSYS;
			break;
		}
		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
		    !(info->flags & ASYNC_CLOSING) &&
		    (do_clocal || (UART_GET_FR(info->port) & AMBA_UARTFR_DCD)))
			break;
		if (signal_pending(current)) {
			retval = -ERESTARTSYS;
			break;
		}
		schedule();
	}
	set_current_state(TASK_RUNNING);
	remove_wait_queue(&info->open_wait, &wait);
	if (extra_count)
		state->count++;
	info->blocked_open--;
	if (retval)
		return retval;
	info->flags |= ASYNC_NORMAL_ACTIVE;
	return 0;
}

static struct amba_info *ambauart_get(int line)
{
	struct amba_info *info;
	struct amba_state *state = amba_state + line;

	state->count++;
	if (state->info)
		return state->info;
	info = kmalloc(sizeof(struct amba_info), GFP_KERNEL);
	if (info) {
		memset(info, 0, sizeof(struct amba_info));
		init_waitqueue_head(&info->open_wait);
		init_waitqueue_head(&info->close_wait);
		init_waitqueue_head(&info->delta_msr_wait);
		info->flags = state->flags;
		info->state = state;
		info->port  = amba_ports + line;
		tasklet_init(&info->tlet, ambauart_tasklet_action,
			     (unsigned long)info);
	}
	if (state->info) {
		kfree(info);
		return state->info;
	}
	state->info = info;
	return info;
}

static int ambauart_open(struct tty_struct *tty, struct file *filp)
{
	struct amba_info *info;
	int retval, line = MINOR(tty->device) - tty->driver.minor_start;

#if DEBUG
	printk("ambauart_open(%d) called\n", line);
#endif

	MOD_INC_USE_COUNT;
	if (line >= SERIAL_AMBA_NR) {
		MOD_DEC_USE_COUNT;
		return -ENODEV;
	}

	info = ambauart_get(line);
	if (!info)
		return -ENOMEM;

	tty->driver_data = info;
	info->tty = tty;
	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;

	/*
	 * Make sure we have the temporary buffer allocated
	 */
	if (!tmp_buf) {
		unsigned long page = get_zeroed_page(GFP_KERNEL);
		if (tmp_buf)
			free_page(page);
		else if (!page) {
			MOD_DEC_USE_COUNT;
			return -ENOMEM;
		}
		tmp_buf = (u_char *)page;
	}

	/*
	 * If the port is in the middle of closing, bail out now.
	 */
	if (tty_hung_up_p(filp) ||
	    (info->flags & ASYNC_CLOSING)) {
		if (info->flags & ASYNC_CLOSING)
			interruptible_sleep_on(&info->close_wait);
		MOD_DEC_USE_COUNT;
		return -EAGAIN;
	}

//#ifdef CONFIG_SERIAL_AMBA_CONSOLE
#ifdef CONFIG_MX1_EXT_UART
	/*
	 * Copy across the serial console cflag setting
	 */
	if (ambauart_cons.cflag && ambauart_cons.index == line) {
		tty->termios->c_cflag = ambauart_cons.cflag;
		ambauart_cons.cflag = 0;
	}
#endif

	/*
	 * Start up the serial port
	 */
	retval = ambauart_startup(info);
	if (retval) {
		MOD_DEC_USE_COUNT;
		return retval;
	}

	retval = block_til_ready(tty, filp, info);
	if (retval) {
		MOD_DEC_USE_COUNT;
		return retval;
	}

	if ((info->state->count == 1) &&
	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
			*tty->termios = info->state->normal_termios;
		else
			*tty->termios = info->state->callout_termios;
		ambauart_change_speed(info, NULL);
	}
	info->session = current->session;
	info->pgrp = current->pgrp;
	return 0;
}

int __init ambauart_init(void)
{
	int i;

	ambanormal_driver.magic = TTY_DRIVER_MAGIC;
	ambanormal_driver.driver_name = "serial_amba";
	ambanormal_driver.name = SERIAL_AMBA_NAME;
	ambanormal_driver.major = SERIAL_AMBA_MAJOR;
	ambanormal_driver.minor_start = SERIAL_AMBA_MINOR;
	ambanormal_driver.num = SERIAL_AMBA_NR;
	ambanormal_driver.type = TTY_DRIVER_TYPE_SERIAL;
	ambanormal_driver.subtype = SERIAL_TYPE_NORMAL;
	ambanormal_driver.init_termios = tty_std_termios;
	ambanormal_driver.init_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
	ambanormal_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
	ambanormal_driver.refcount = &ambauart_refcount;
	ambanormal_driver.table = ambauart_table;
	ambanormal_driver.termios = ambauart_termios;
	ambanormal_driver.termios_locked = ambauart_termios_locked;

	ambanormal_driver.open = ambauart_open;
	ambanormal_driver.close = ambauart_close;
	ambanormal_driver.write = ambauart_write;
	ambanormal_driver.put_char = ambauart_put_char;
	ambanormal_driver.flush_chars = ambauart_flush_chars;
	ambanormal_driver.write_room = ambauart_write_room;
	ambanormal_driver.chars_in_buffer = ambauart_chars_in_buffer;
	ambanormal_driver.flush_buffer	= ambauart_flush_buffer;
	ambanormal_driver.ioctl = ambauart_ioctl;
	ambanormal_driver.throttle = ambauart_throttle;
	ambanormal_driver.unthrottle = ambauart_unthrottle;
	ambanormal_driver.send_xchar = ambauart_send_xchar;
	ambanormal_driver.set_termios = ambauart_set_termios;
	ambanormal_driver.stop = ambauart_stop;
	ambanormal_driver.start = ambauart_start;
	ambanormal_driver.hangup = ambauart_hangup;
	ambanormal_driver.break_ctl = ambauart_break_ctl;
	ambanormal_driver.wait_until_sent = ambauart_wait_until_sent;
	ambanormal_driver.read_proc = NULL;

	/*
	 * The callout device is just like the normal device except for
	 * the major number and the subtype code.
	 */
	ambacallout_driver = ambanormal_driver;
	ambacallout_driver.name = CALLOUT_AMBA_NAME;
	ambacallout_driver.major = CALLOUT_AMBA_MAJOR;
	ambacallout_driver.subtype = SERIAL_TYPE_CALLOUT;
	ambacallout_driver.read_proc = NULL;
	ambacallout_driver.proc_entry = NULL;

	if (tty_register_driver(&ambanormal_driver))
		panic("Couldn't register AMBA serial driver\n");
	if (tty_register_driver(&ambacallout_driver))
		panic("Couldn't register AMBA callout driver\n");

	for (i = 0; i < SERIAL_AMBA_NR; i++) {
		struct amba_state *state = amba_state + i;
		state->line		= i;
		state->close_delay	= 5 * HZ / 10;
		state->closing_wait	= 30 * HZ;
		state->callout_termios	= ambacallout_driver.init_termios;
		state->normal_termios	= ambanormal_driver.init_termios;
	}

	return 0;
}

static int st16c2552_gpio_init(void)
{
	
	/* 
	 * PC17-SAP_RXD : RESET
	 * PC18-SAP_TXD : PORTA_INT
	*/
	_reg_GPIO_GIUS(GPIOC) |= 0x00060000;
	_reg_GPIO_OCR2(GPIOC) |= 0x0000003C; 
	
	
	_reg_GPIO_DDIR(GPIOC) &= ~(0x00040000);
	_reg_GPIO_DDIR(GPIOC) |= 0x00020000;
	
	_reg_GPIO_IMR(GPIOC)  &= ~(0x00040000);
	_reg_GPIO_ICR1(GPIOC) &= 0xffffffcf;
	
	return 0;
	
}

static int st16c2552_gpio_enable_inter(void)
{

	_reg_GPIO_IMR(GPIOC) |= 0x00040000;	

	return 0;
}

static int st16c2552_gpio_disable_inter(void)
{

	_reg_GPIO_IMR(GPIOC) &= ~(0x00040000);

	return 0;
}

static int st16c2552_reset(void)
{
	int i;
	
	_reg_GPIO_DR(GPIOC) |= 0x00020000;
	for(i=0;i<10000;i++);
	_reg_GPIO_DR(GPIOC) &= ~0x00020000;
	
	return 0;
}

int __exit st16c2552_cleanup(void)
{
	/*Do some cleanup work*/
	free_irq(8,"mx21_16c2552");

	//tasklet_kill(&ambauart_tasklet_action);

    
	if (tty_unregister_driver(&ambanormal_driver))
		panic("Couldn't unregister AMBA serial driver\n");
	if (tty_unregister_driver(&ambacallout_driver))
		panic("Couldn't unregister AMBA callout driver\n");
		
	return 0;
}


int init_module(void)
{
	u8 a[2];
	_reg_WEIM_CSL(CS1) = 0x11118301;   //buswidth=8
	
	st16c2552_gpio_init();
	st16c2552_reset();
	
	st16c2552_gpio_enable_inter();
		
	//IO_WRITE(MX21_EXT_UART_BASE+UART16C2552_LCR,0x80);
	//IO_WRITE(MX21_EXT_UART_BASE+UART16C2552_DLL,0x80);
	//IO_WRITE(MX21_EXT_UART_BASE+UART16C2552_DLM,0x10);
	//a[0] = IO_READ(MX21_EXT_UART_BASE+UART16C2552_DLL);
	//a[1] = IO_READ(MX21_EXT_UART_BASE+UART16C2552_DLM);
	//printk("dll=%x,  dlm=%x\n",a[0],a[1]);
	
	return ambauart_init();
}

void cleanup_module(void)
{
	_reg_WEIM_CSL(CS1) = 0x11118501;   //buswidth=16
	st16c2552_cleanup();
}

MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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