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

📄 serial_s3c44b0x.c

📁 S3C44B0x串行口驱动,支持两个UART口
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (info->blocked_open) {		if (info->close_delay) {			current->state = TASK_INTERRUPTIBLE;/*			current->timeout = jiffies + info->close_delay;  */			schedule_timeout(info->close_delay);		}		wake_up_interruptible(&info->open_wait);	}	info->flags &= ~(S_NORMAL_ACTIVE | S_CALLOUT_ACTIVE | S_CLOSING);	wake_up_interruptible(&info->close_wait);	restore_flags(flags);}/* * rs_hangup() --- called by tty_hangup() when a hangup is signaled. */static void rs_hangup(struct tty_struct *tty){	struct s3c44b0x_serial *info = (struct s3c44b0x_serial *) tty->driver_data;		if (serial_paranoia_check(info, tty->device, "rs_hangup"))		return;		rs_flush_buffer(tty);	shutdown(info);	info->event = 0;	info->count = 0;	info->flags &= ~(S_NORMAL_ACTIVE | S_CALLOUT_ACTIVE);	info->tty = 0;	wake_up_interruptible(&info->open_wait);}/* * ------------------------------------------------------------ * rs_open() and friends * ------------------------------------------------------------ */static int block_til_ready(struct tty_struct *tty, struct file *filp,			   struct s3c44b0x_serial *info){	unsigned long flags;	DECLARE_WAITQUEUE(wait, current);	int retval;	int do_clocal = 0;	/*	 * If the device is in the middle of being closed, then block	 * until it's done, and then try again.	 */	if (info->flags & S_CLOSING) {		interruptible_sleep_on(&info->close_wait);#ifdef SERIAL_DO_RESTART		if (info->flags & S_HUP_NOTIFY)			return -EAGAIN;		else			return -ERESTARTSYS;#else		return -EAGAIN;#endif	}	/*	 * 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 & S_NORMAL_ACTIVE)			return -EBUSY;		if ((info->flags & S_CALLOUT_ACTIVE) &&			(info->flags & S_SESSION_LOCKOUT) &&			(info->session != current->session)) return -EBUSY;		if ((info->flags & S_CALLOUT_ACTIVE) &&			(info->flags & S_PGRP_LOCKOUT) &&			(info->pgrp != current->pgrp)) return -EBUSY;		info->flags |= S_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 & S_CALLOUT_ACTIVE)			return -EBUSY;		info->flags |= S_NORMAL_ACTIVE;		return 0;	}	if (info->flags & S_CALLOUT_ACTIVE) {		if (info->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, info->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);#ifdef SERIAL_DEBUG_OPEN	printk("block_til_ready before block: ttyS%d, count = %d\n",		   info->line, info->count);#endif	info->count--;	info->blocked_open++;	while (1) {		save_flags(flags);		cli();		if (!(info->flags & S_CALLOUT_ACTIVE))			set_dtr(info, 1);		restore_flags(flags);		current->state = TASK_INTERRUPTIBLE;		if (tty_hung_up_p(filp) || !(info->flags & S_INITIALIZED)) {#ifdef SERIAL_DO_RESTART			if (info->flags & S_HUP_NOTIFY)				retval = -EAGAIN;			else				retval = -ERESTARTSYS;#else			retval = -EAGAIN;#endif			break;		}		if (!(info->flags & S_CALLOUT_ACTIVE) &&			!(info->flags & S_CLOSING) && do_clocal)			break;		if (signal_pending(current)) {/*		if (current->signal & ~current->blocked) {  */			retval = -ERESTARTSYS;			break;		}#ifdef SERIAL_DEBUG_OPEN		printk("block_til_ready blocking: ttyS%d, count = %d\n",			   info->line, info->count);#endif		schedule();	}	current->state = TASK_RUNNING;	remove_wait_queue(&info->open_wait, &wait);	if (!tty_hung_up_p(filp))		info->count++;	info->blocked_open--;#ifdef SERIAL_DEBUG_OPEN	printk("block_til_ready after blocking: ttyS%d, count = %d\n",		   info->line, info->count);#endif	if (retval)		return retval;	info->flags |= S_NORMAL_ACTIVE;	return 0;}/* * This routine is called whenever a serial port is opened.  It * enables interrupts for a serial port, linking in its S structure into * the IRQ chain.   It also performs the serial-specific * initialization for the tty structure. */int rs_open(struct tty_struct *tty, struct file *filp){	struct s3c44b0x_serial *info;	int retval, line;	line = MINOR(tty->device) - tty->driver.minor_start;	/* check if line is sane */	if (line < 0 || line >= USART_CNT)		return -ENODEV;	info = &s3c44b0x_info[line];	if (serial_paranoia_check(info, tty->device, "rs_open"))		return -ENODEV;#ifdef SERIAL_DEBUG_OPEN	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,		info->count);#endif	info->count++;	tty->driver_data = info;	info->tty = tty;	/*	 * Start up serial port	 */	retval = startup(info);	if (retval)		return retval;		/* enable interrupts */	set_ints_mode(info, 1);	retval = block_til_ready(tty, filp, info);	if (retval) {#ifdef SERIAL_DEBUG_OPEN		printk("rs_open returning after block_til_ready with %d\n",			   retval);#endif		return retval;	}	if ((info->count == 1) && (info->flags & S_SPLIT_TERMIOS)) {		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)			*tty->termios = info->normal_termios;		else			*tty->termios = info->callout_termios;		change_speed(info);	}	info->session = current->session;	info->pgrp = current->pgrp;#ifdef SERIAL_DEBUG_OPEN	printk("rs_open ttyS%d successful...\n", info->line);#endif	return 0;}static struct irqaction irq_uartTx0 =	{ rs_s3c44b0x_interruptTxa,  0, 0, "S3C44B0X_UART_TX0",  NULL, NULL };static struct irqaction irq_uartTx1 =	{ rs_s3c44b0x_interruptTxb,  0, 0, "S3C44B0X_UART_TX1",  NULL, NULL };static struct irqaction irq_uartRx0 =	{ rs_s3c44b0x_interruptRxa,  0, 0, "S3C44B0X_UART_RX0",  NULL, NULL };static struct irqaction irq_uartRx1 =	{ rs_s3c44b0x_interruptRxb,  0, 0, "S3C44B0X_UART_RX1",  NULL, NULL };static struct irqaction irq_uartErr =	{ rs_s3c44b0x_interruptErr, 0, 0, "S3C44B0X_UART_ERR", NULL, NULL };	extern int setup_arm_irq(int, struct irqaction *);static void interrupts_init(void){	setup_arm_irq(S3C44B0X_INTERRUPT_UTX0,  &irq_uartTx0);	setup_arm_irq(S3C44B0X_INTERRUPT_UTX1,  &irq_uartTx1);	setup_arm_irq(S3C44B0X_INTERRUPT_URX0,  &irq_uartRx0);	setup_arm_irq(S3C44B0X_INTERRUPT_URX1,  &irq_uartRx1);	setup_arm_irq(S3C44B0X_INTERRUPT_UERR, &irq_uartErr);}static void show_serial_version(void){	printk("Samsung S3C44B0X UART driver version 0.6 \	<michael.frommberger@sympat.de>\n");}/* rs_init inits the driver */static int __init rs_s3c44b0x_init(void){	int flags, i, pconf;	struct s3c44b0x_serial *info;	/* Configurate the port as uart */	pconf = inl(S3C44B0X_PCONF);	pconf &= ~(0x3f << 13);	pconf |= (0x12 << 13); /* enable TxD1 */	outl(pconf, S3C44B0X_PCONF);		/* Setup base handler, and timer table. */	init_bh(SERIAL_BH, do_serial_bh);		show_serial_version();		/* Initialize the tty_driver structure */		/* set the tty_struct pointers to NULL to let the layer */	/* above allocate the structs. */	for (i=0; i < USART_CNT; i++)		serial_table[i] = NULL;		memset(&serial_driver, 0, sizeof(struct tty_driver));		serial_driver.magic = TTY_DRIVER_MAGIC;	serial_driver.name = "ttyS";	serial_driver.driver_name = "S3C44B0X";	serial_driver.major = TTY_MAJOR;	serial_driver.minor_start = 64;	serial_driver.num = USART_CNT;	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;	serial_driver.subtype = SERIAL_TYPE_NORMAL;	serial_driver.init_termios = tty_std_termios;	serial_driver.init_termios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;	serial_driver.init_termios.c_cflag |= B115200;	/* set the tty-layer to raw-mode */	serial_driver.init_termios.c_cflag &= ~(CSIZE|PARENB);	serial_driver.init_termios.c_cflag |= CS8;	serial_driver.init_termios.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);	serial_driver.init_termios.c_oflag &= ~OPOST;	serial_driver.init_termios.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP	                                   |INLCR|IGNCR|ICRNL|IXON);	serial_driver.flags = TTY_DRIVER_REAL_RAW;	serial_driver.refcount = &serial_refcount;	serial_driver.table = serial_table;	serial_driver.termios = serial_termios;	serial_driver.termios_locked = serial_termios_locked;	serial_driver.open = rs_open;	serial_driver.close = rs_close;	serial_driver.write = rs_write;	serial_driver.flush_chars = rs_flush_chars;	serial_driver.write_room = rs_write_room;	serial_driver.chars_in_buffer = rs_chars_in_buffer;	serial_driver.flush_buffer = rs_flush_buffer;	serial_driver.ioctl = rs_ioctl;	serial_driver.throttle = rs_throttle;	serial_driver.unthrottle = rs_unthrottle;	serial_driver.set_termios = rs_set_termios;	serial_driver.stop = rs_stop;	serial_driver.start = rs_start;	serial_driver.hangup = rs_hangup;		/*	 * The callout device is just like normal device except for	 * major number and the subtype code.	 */	callout_driver = serial_driver;	callout_driver.name = "cua";	callout_driver.major = TTYAUX_MAJOR;	callout_driver.subtype = SERIAL_TYPE_CALLOUT;		if (tty_register_driver(&serial_driver))		panic("Couldn't register serial driver\n");	if (tty_register_driver(&callout_driver))		panic("Couldn't register callout driver\n");		save_flags(flags);	cli();	for (i = 0; i < USART_CNT; i++) {		info = &s3c44b0x_info[i];		info->uart_offset = (i) ? 0 : S3C44B0X_UART1_OFFSET;		info->magic = SERIAL_MAGIC;		info->tty = 0;		info->irqmask = (i) ? (S3C44B0X_INTERRUPT_UTX0 || 		                       S3C44B0X_INTERRUPT_URX0 || 		                       S3C44B0X_INTERRUPT_UERR) :				       (S3C44B0X_INTERRUPT_UTX1 || 		                        S3C44B0X_INTERRUPT_URX1 || 		                        S3C44B0X_INTERRUPT_UERR);		info->irq = (i) ? S3C44B0X_INTERRUPT_UTX0 : 		 		  S3C44B0X_INTERRUPT_UTX1;		info->irq_rx = (i) ? S3C44B0X_INTERRUPT_URX0 :				     S3C44B0X_INTERRUPT_URX1;		info->port = (i) ? 1 : 2;		info->line = i;#if defined(CONFIG_CONSOLE_NULL) || !defined(CONFIG_SERIAL_S3C44B0X_CONSOLE)		info->is_cons = 0;#elif !defined(CONFIG_CONSOLE_NULL) && defined(CONFIG_SERIAL_S3C44B0X_CONSOLE)		if (i == console_number)			info->is_cons = 1;#endif		set_ints_mode(info, 0);		/* info->custom_divisor = 16; */ /* unused? */		info->custom_divisor = 0;		info->close_delay = 50;		info->closing_wait = 3000;		info->cts_state = 1;		info->x_char = 0;		info->event = 0;		info->count = 0;		info->blocked_open = 0;		info->tqueue.routine = do_softint;		info->tqueue.data = info;		info->tqueue_hangup.routine = do_serial_hangup;		info->tqueue_hangup.data = info;		info->callout_termios = callout_driver.init_termios;		info->normal_termios = serial_driver.init_termios;		/* set default modes */		info->ser_mode  = SERIAL_MODE_DEFAULT;									init_waitqueue_head(&info->open_wait);		init_waitqueue_head(&info->close_wait);				printk("%s%d (irq = %d)", serial_driver.name, info->line,			   info->irq);		printk(" is a builtin Samsung S3C44B0X UART\n");	}		interrupts_init();	restore_flags(flags);	return 0;}module_init(rs_s3c44b0x_init);/* * ------------------------------------------------------------ * Serial console driver * ------------------------------------------------------------ */#ifdef CONFIG_SERIAL_S3C44B0X_CONSOLEstatic kdev_t s3c44b0x_console_device(struct console *);static int    s3c44b0x_console_setup(struct console *, char *);static void   s3c44b0x_console_write (struct console *, const char *, unsigned int );static int    s3c44b0x_console_initialized = 0;static struct console s3c44b0x_driver = {	name:		"ttyS",	write:		s3c44b0x_console_write,	device:		s3c44b0x_console_device,	setup:		s3c44b0x_console_setup,	flags:		CON_PRINTBUFFER,	index:		-1,};/* static void init_console(struct s3c44b0x_serial *info) */static int s3c44b0x_console_setup(struct console *c, char *p){	struct s3c44b0x_serial *info = &s3c44b0x_info[console_number];	char ucon = 0;	char ulcon = 0;	int pconf;	unsigned cflag = 0;		memset(info, 0, sizeof(struct s3c44b0x_serial));	info->use_ints = 0;	info->cts_state = 1;	info->is_cons = 1;/*	info->usart->cr = 0; *//*	info->usart->cr = (U_IRQ_TMODE | U_IRQ_RMODE | U_WL8); */	info->line = console_number;	info->baud = 115200;	info->port = (console_number) ? 1 : 2;	info->uart_offset = (console_number) ? 0 : S3C44B0X_UART1_OFFSET;	info->ser_mode  = SERIAL_MODE_DEFAULT;	fifo_init(info);		/* set initial baudrate */	uart_speed(info, cflag);		/* Configurate the port as uart */	pconf = inl(S3C44B0X_PCONF);	pconf &= ~(0x3f << 13);	pconf |= (0x12 << 13); /* enable TxD1 */	outl(pconf, S3C44B0X_PCONF);		/* rx/tx setup */	ucon |= S3C44B0X_UCON_RX_MODE_INT_POLL;   /* receive mode: IRQ or polling */	ucon |= S3C44B0X_UCON_TX_MODE_INT_POLL;   /* transmit mode: IRQ or polling */	outb(ucon, S3C44B0X_UCON0 + info->uart_offset);		/* set line control register */	ulcon |= S3C44B0X_ULCON_WORDLN_8;	ulcon |= S3C44B0X_ULCON_STOPB_1;	ulcon |= S3C44B0X_ULCON_PAR_NO;	outb(ulcon, S3C44B0X_ULCON0 + info->uart_offset);	rx_enable(info);	tx_enable(info);		s3c44b0x_console_initialized = 1;		return 0;}static kdev_t s3c44b0x_console_device(struct console *c){	return MKDEV(TTY_MAJOR, 64 + c->index);}static void s3c44b0x_console_write (struct console *co, const char *str,			   unsigned int count){#if defined(CONFIG_CONSOLE_NULL)	return;#else	struct s3c44b0x_serial *info = &s3c44b0x_info[console_number];		if (!s3c44b0x_console_initialized)		printk ("WARNING: Console used unintialized\n");		while (count--) {		if  (*str == '\n')			rs_put_char(info,'\r');        	rs_put_char(info, *str++ );	}#endif}void __init s3c44b0x_console_init(void){	register_console(&s3c44b0x_driver);}#endif /* CONFIG_SERIAL_S3C44B0X_CONSOLE *//* * Local variables: *  c-indent-level: 8 *  c-basic-offset: 8 *  tab-width: 8 * End: */

⌨️ 快捷键说明

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