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

📄 serial.c

📁 In the ffuart.tar.gz it has one file. The serial.c is the source codes of the FFUART as a console
💻 C
📖 第 1 页 / 共 5 页
字号:
	change_speed(info, 0);	info->flags |= ASYNC_INITIALIZED;	restore_flags(flags);	return 0;	errout:	restore_flags(flags);	return retval;}/* * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */static void shutdown(struct async_struct * info){	unsigned long	flags;	struct serial_state *state;	int		retval;	if (!(info->flags & ASYNC_INITIALIZED))		return;	state = info->state;#ifdef SERIAL_DEBUG_OPEN	printk("Shutting down serial port %d (irq %d)....", info->line,	       state->irq);#endif		save_flags(flags); cli(); /* Disable interrupts */	/*	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq	 * here so the queue might never be waken up	 */	wake_up_interruptible(&info->delta_msr_wait);		/*	 * First unlink the serial port from the IRQ chain...	 */	if (info->next_port)		info->next_port->prev_port = info->prev_port;	if (info->prev_port)		info->prev_port->next_port = info->next_port;	else		IRQ_ports[state->irq] = info->next_port;	figure_IRQ_timeout(state->irq);		/*	 * Free the IRQ, if necessary	 */	if (state->irq && (!IRQ_ports[state->irq] ||			  !IRQ_ports[state->irq]->next_port)) {		if (IRQ_ports[state->irq]) {			free_irq(state->irq, &IRQ_ports[state->irq]);			retval = request_irq(state->irq, rs_interrupt_single,					     SA_SHIRQ, "serial",					     &IRQ_ports[state->irq]);						if (retval)				printk("serial shutdown: request_irq: error %d"				       "  Couldn't reacquire IRQ.\n", retval);		} else			free_irq(state->irq, &IRQ_ports[state->irq]);	}	if (info->xmit.buf) {		unsigned long pg = (unsigned long) info->xmit.buf;		info->xmit.buf = 0;		free_page(pg);	}	info->IER = 0;	serial_outp(info, UART_IER, 0x00);	/* disable all intrs */#ifdef CONFIG_SERIAL_MANY_PORTS	if (info->flags & ASYNC_FOURPORT) {		/* reset interrupts on the AST Fourport board */		(void) inb((info->port & 0xFE0) | 0x01F);		info->MCR |= UART_MCR_OUT1;	} else#endif		info->MCR &= ~UART_MCR_OUT2;		if (pxa_buggy_port(state->type))			info->MCR ^= UART_MCR_OUT2;	info->MCR |= ALPHA_KLUDGE_MCR; 		/* Don't ask */		/* disable break condition */	serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);		if (!info->tty || (info->tty->termios->c_cflag & HUPCL))		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);	serial_outp(info, UART_MCR, info->MCR);	/* disable FIFO's */		serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |				     UART_FCR_CLEAR_RCVR |				     UART_FCR_CLEAR_XMIT));	serial_outp(info, UART_FCR, 0);#ifdef CONFIG_SERIAL_RSA	/*	 * Reset the RSA board back to 115kbps compat mode.	 */	if ((state->type == PORT_RSA) &&	    (state->baud_base == SERIAL_RSA_BAUD_BASE &&	     disable_rsa(info)))		state->baud_base = SERIAL_RSA_BAUD_BASE_LO;#endif	#ifdef CONFIG_ARCH_PXA	if (state->type == PORT_PXA) {		switch ((long)state->iomem_base) {			case (long)&FFUART: CKEN &= ~CKEN6_FFUART; break;			case (long)&BTUART: CKEN &= ~CKEN7_BTUART; break;			case (long)&STUART: CKEN &= ~CKEN5_STUART; break;		}	}#endif	(void)serial_in(info, UART_RX);    /* read data port to reset things */		if (info->tty)		set_bit(TTY_IO_ERROR, &info->tty->flags);	if (uart_config[info->state->type].flags & UART_STARTECH) {		/* Arrange to enter sleep mode */		serial_outp(info, UART_LCR, 0xBF);		serial_outp(info, UART_EFR, UART_EFR_ECB);		serial_outp(info, UART_LCR, 0);		serial_outp(info, UART_IER, UART_IERX_SLEEP);		serial_outp(info, UART_LCR, 0xBF);		serial_outp(info, UART_EFR, 0);		serial_outp(info, UART_LCR, 0);	}	if (info->state->type == PORT_16750) {		/* Arrange to enter sleep mode */		serial_outp(info, UART_IER, UART_IERX_SLEEP);	}	info->flags &= ~ASYNC_INITIALIZED;	restore_flags(flags);}#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */static int baud_table[] = {	0, 50, 75, 110, 134, 150, 200, 300,	600, 1200, 1800, 2400, 4800, 9600, 19200,	38400, 57600, 115200, 230400, 460800, 0 };static int tty_get_baud_rate(struct tty_struct *tty){	struct async_struct * info = (struct async_struct *)tty->driver_data;	unsigned int cflag, i;	cflag = tty->termios->c_cflag;	i = cflag & CBAUD;	if (i & CBAUDEX) {		i &= ~CBAUDEX;		if (i < 1 || i > 2) 			tty->termios->c_cflag &= ~CBAUDEX;		else			i += 15;	}	if (i == 15) {		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)			i += 1;		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)			i += 2;	}	return baud_table[i];}#endif/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */static void change_speed(struct async_struct *info,			 struct termios *old_termios){	int	quot = 0, baud_base, baud;	unsigned cflag, cval, fcr = 0;	int	bits;	unsigned long	flags;	if (!info->tty || !info->tty->termios)		return;	cflag = info->tty->termios->c_cflag;	if (!CONFIGURED_SERIAL_PORT(info))		return;	/* byte size and parity */	switch (cflag & CSIZE) {	      case CS5: cval = 0x00; bits = 7; break;	      case CS6: cval = 0x01; bits = 8; break;	      case CS7: cval = 0x02; bits = 9; break;	      case CS8: cval = 0x03; bits = 10; break;	      /* Never happens, but GCC is too dumb to figure it out */	      default:  cval = 0x00; bits = 7; break;	      }	if (cflag & CSTOPB) {		cval |= 0x04;		bits++;	}	if (cflag & PARENB) {		cval |= UART_LCR_PARITY;		bits++;	}	if (!(cflag & PARODD))		cval |= UART_LCR_EPAR;#ifdef CMSPAR	if (cflag & CMSPAR)		cval |= UART_LCR_SPAR;#endif	/* Determine divisor based on baud rate */	baud = tty_get_baud_rate(info->tty);	if (!baud)		baud = 9600;	/* B0 transition handled in rs_set_termios */#ifdef CONFIG_SERIAL_RSA	if ((info->state->type == PORT_RSA) &&	    (info->state->baud_base != SERIAL_RSA_BAUD_BASE) &&	    enable_rsa(info))		info->state->baud_base = SERIAL_RSA_BAUD_BASE;#endif	baud_base = info->state->baud_base;	if (info->state->type == PORT_16C950) {		if (baud <= baud_base)			serial_icr_write(info, UART_TCR, 0);		else if (baud <= 2*baud_base) {			serial_icr_write(info, UART_TCR, 0x8);			baud_base = baud_base * 2;		} else if (baud <= 4*baud_base) {			serial_icr_write(info, UART_TCR, 0x4);			baud_base = baud_base * 4;		} else			serial_icr_write(info, UART_TCR, 0);	}	if (baud == 38400 &&	    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))		quot = info->state->custom_divisor;	else {		if (baud == 134)			/* Special case since 134 is really 134.5 */			quot = (2*baud_base / 269);		else if (baud)			quot = baud_base / baud;	}	/* If the quotient is zero refuse the change */	if (!quot && old_termios) {		info->tty->termios->c_cflag &= ~CBAUD;		info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);		baud = tty_get_baud_rate(info->tty);		if (!baud)			baud = 9600;		if (baud == 38400 &&		    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))			quot = info->state->custom_divisor;		else {			if (baud == 134)				/* Special case since 134 is really 134.5 */				quot = (2*baud_base / 269);			else if (baud)				quot = baud_base / baud;		}	}	/* As a last resort, if the quotient is zero, default to 9600 bps */	if (!quot)		quot = baud_base / 9600;	/*	 * Work around a bug in the Oxford Semiconductor 952 rev B	 * chip which causes it to seriously miscalculate baud rates	 * when DLL is 0.	 */	if (((quot & 0xFF) == 0) && (info->state->type == PORT_16C950) &&	    (info->state->revision == 0x5201))		quot++;		info->quot = quot;	info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);	info->timeout += HZ/50;		/* Add .02 seconds of slop */	/* Set up FIFO's */	if (uart_config[info->state->type].flags & UART_USE_FIFO) {		if ((info->state->baud_base / quot) < 2400)			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;#ifdef CONFIG_SERIAL_RSA		else if (info->state->type == PORT_RSA)			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;#endif		else			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;	}	if (info->state->type == PORT_16750)		fcr |= UART_FCR7_64BYTE;		/* CTS flow control flag and modem status interrupts */	info->IER &= ~UART_IER_MSI;	if (info->flags & ASYNC_HARDPPS_CD)		info->IER |= UART_IER_MSI;	if (cflag & CRTSCTS) {		info->flags |= ASYNC_CTS_FLOW;		info->IER |= UART_IER_MSI;	} else		info->flags &= ~ASYNC_CTS_FLOW;	if (cflag & CLOCAL)		info->flags &= ~ASYNC_CHECK_CD;	else {		info->flags |= ASYNC_CHECK_CD;		info->IER |= UART_IER_MSI;	}	serial_out(info, UART_IER, info->IER);	/*	 * Set up parity check flag	 */#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))	info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;	if (I_INPCK(info->tty))		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))		info->read_status_mask |= UART_LSR_BI;		/*	 * Characters to ignore	 */	info->ignore_status_mask = 0;	if (I_IGNPAR(info->tty))		info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;	if (I_IGNBRK(info->tty)) {		info->ignore_status_mask |= UART_LSR_BI;		/*		 * If we're ignore parity and break indicators, ignore 		 * overruns too.  (For real raw support).		 */		if (I_IGNPAR(info->tty))			info->ignore_status_mask |= UART_LSR_OE;	}	/*	 * !!! ignore all characters if CREAD is not set	 */	if ((cflag & CREAD) == 0)		info->ignore_status_mask |= UART_LSR_DR;	save_flags(flags); cli();	if (uart_config[info->state->type].flags & UART_STARTECH) {		serial_outp(info, UART_LCR, 0xBF);		serial_outp(info, UART_EFR,			    (cflag & CRTSCTS) ? UART_EFR_CTS : 0);	}	serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */	serial_outp(info, UART_DLL, quot & 0xff);	/* LS of divisor */	serial_outp(info, UART_DLM, quot >> 8);		/* MS of divisor */	if (info->state->type == PORT_16750)		serial_outp(info, UART_FCR, fcr); 	/* set fcr */	serial_outp(info, UART_LCR, cval);		/* reset DLAB */	info->LCR = cval;				/* Save LCR */ 	if (info->state->type != PORT_16750) { 		if (fcr & UART_FCR_ENABLE_FIFO) { 			/* emulated UARTs (Lucent Venus 167x) need two steps */ 			serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); 		}		serial_outp(info, UART_FCR, fcr); 	/* set fcr */	}	restore_flags(flags);}static void rs_put_char(struct tty_struct *tty, unsigned char ch){	struct async_struct *info = (struct async_struct *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "rs_put_char"))		return;	if (!tty || !info->xmit.buf)		return;	save_flags(flags); cli();	if (CIRC_SPACE(info->xmit.head,		       info->xmit.tail,		       SERIAL_XMIT_SIZE) == 0) {		restore_flags(flags);		return;	}	info->xmit.buf[info->xmit.head] = ch;	info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);	restore_flags(flags);}static void rs_flush_chars(struct tty_struct *tty){	struct async_struct *info = (struct async_struct *)tty->driver_data;	unsigned long flags;					if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))		return;	if (info->xmit.head == info->xmit.tail	    || tty->stopped	    || tty->hw_stopped	    || !info->xmit.buf)		return;	save_flags(flags); cli();	info->IER |= UART_IER_THRI;	serial_out(info, UART_IER, info->IER);	if (pxa_buggy_port(info->state->type))		rs_interrupt_single(info->state->irq, NULL, NULL);	restore_flags(flags);}static int rs_write(struct tty_struct * tty, int from_user,		    const unsigned char *buf, int count){	int	c, ret = 0;	struct async_struct *info = (struct async_struct *)tty->driver_data;	unsigned long flags;					if (serial_paranoia_check(info, tty->device, "rs_write"))		return 0;	if (!tty || !info->xmit.buf || !tmp_buf)		return 0;	save_flags(flags);	if (from_user) {		down(&tmp_buf_sem);		while (1) {			int c1;			c = CIRC_SPACE_TO_END(info->xmit.head,					      info->xmit.tail,					      SERIAL_XMIT_SIZE);			if (count < c)				c = count;			if (c <= 0)				break;			c -= copy_from_user(tmp_buf, buf, c);			if (!c) {				if (!ret)					ret = -EFAULT;				break;			}			cli();			c1 = CIRC_SPACE_TO_END(info->xmit.head,					       info->xmit.tail,					       SERIAL_XMIT_SIZE);			if (c1 < c)				c = c1;			memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);			info->xmit.head = ((info->xmit.head + c) &					   (SERIAL_XMIT_SIZE-1));			restore_flags(flags);			buf += c;			count -= c;			ret += c;		}		up(&tmp_buf_sem);	} else {		cli();		while (1) {			c = CIRC_SPACE_TO_END(info->xmit.head,					      info->xmit.tail,					      SERIAL_XMIT_SIZE);			if (count < c)				c = count;			if (c <= 0) {				break;			}			memcpy(info->xmit.buf + info->xmit.head, buf, c);			info->xmit.head = ((info->xmit.head + c) &					   (SERIAL_XMIT_SIZE-1));			buf += c;			count -= c;			ret += c;		}		restore_flags(flags);	}	if (info->xmit.head != info->xmit.tail	    && !tty->stopped	    && !tty->hw_stopped	    && !(info->IER & UART_IER_THRI)) {		info->IER |= UART_IER_THRI;		serial_out(info, UART_IER, info->IER);		if (pxa_buggy_port(info->state->type)) {			save_flags(flags); cli();			rs_interrupt_single(info->state->irq, NULL, NULL);			restore_flags(flags);

⌨️ 快捷键说明

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