vr41xx_siu.c

来自「linux 内核源代码」· C语言 代码 · 共 963 行 · 第 1/2 页

C
963
字号
	(void)siu_read(port, UART_IIR);	(void)siu_read(port, UART_MSR);	return 0;}static void siu_shutdown(struct uart_port *port){	unsigned long flags;	uint8_t lcr;	siu_write(port, UART_IER, 0);	spin_lock_irqsave(&port->lock, flags);	port->mctrl &= ~TIOCM_OUT2;	siu_set_mctrl(port, port->mctrl);	spin_unlock_irqrestore(&port->lock, flags);	lcr = siu_read(port, UART_LCR);	lcr &= ~UART_LCR_SBC;	siu_write(port, UART_LCR, lcr);	siu_clear_fifo(port);	(void)siu_read(port, UART_RX);	if (port->type == PORT_VR41XX_DSIU)		vr41xx_disable_dsiuint(DSIUINT_ALL);	free_irq(port->irq, port);}static void siu_set_termios(struct uart_port *port, struct ktermios *new,                            struct ktermios *old){	tcflag_t c_cflag, c_iflag;	uint8_t lcr, fcr, ier;	unsigned int baud, quot;	unsigned long flags;	c_cflag = new->c_cflag;	switch (c_cflag & CSIZE) {	case CS5:		lcr = UART_LCR_WLEN5;		break;	case CS6:		lcr = UART_LCR_WLEN6;		break;	case CS7:		lcr = UART_LCR_WLEN7;		break;	default:		lcr = UART_LCR_WLEN8;		break;	}	if (c_cflag & CSTOPB)		lcr |= UART_LCR_STOP;	if (c_cflag & PARENB)		lcr |= UART_LCR_PARITY;	if ((c_cflag & PARODD) != PARODD)		lcr |= UART_LCR_EPAR;	if (c_cflag & CMSPAR)		lcr |= UART_LCR_SPAR;	baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);	quot = uart_get_divisor(port, baud);	fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;	spin_lock_irqsave(&port->lock, flags);	uart_update_timeout(port, c_cflag, baud);	c_iflag = new->c_iflag;	port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR;	if (c_iflag & INPCK)		port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;	if (c_iflag & (BRKINT | PARMRK))		port->read_status_mask |= UART_LSR_BI;	port->ignore_status_mask = 0;	if (c_iflag & IGNPAR)		port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;	if (c_iflag & IGNBRK) {		port->ignore_status_mask |= UART_LSR_BI;		if (c_iflag & IGNPAR)			port->ignore_status_mask |= UART_LSR_OE;	}	if ((c_cflag & CREAD) == 0)		port->ignore_status_mask |= UART_LSR_DR;	ier = siu_read(port, UART_IER);	ier &= ~UART_IER_MSI;	if (UART_ENABLE_MS(port, c_cflag))		ier |= UART_IER_MSI;	siu_write(port, UART_IER, ier);	siu_write(port, UART_LCR, lcr | UART_LCR_DLAB);	siu_write(port, UART_DLL, (uint8_t)quot);	siu_write(port, UART_DLM, (uint8_t)(quot >> 8));	siu_write(port, UART_LCR, lcr);	siu_write(port, UART_FCR, fcr);	siu_set_mctrl(port, port->mctrl);	spin_unlock_irqrestore(&port->lock, flags);}static void siu_pm(struct uart_port *port, unsigned int state, unsigned int oldstate){	switch (state) {	case 0:		switch (port->type) {		case PORT_VR41XX_SIU:			vr41xx_supply_clock(SIU_CLOCK);			break;		case PORT_VR41XX_DSIU:			vr41xx_supply_clock(DSIU_CLOCK);			break;		}		break;	case 3:		switch (port->type) {		case PORT_VR41XX_SIU:			vr41xx_mask_clock(SIU_CLOCK);			break;		case PORT_VR41XX_DSIU:			vr41xx_mask_clock(DSIU_CLOCK);			break;		}		break;	}}static const char *siu_type(struct uart_port *port){	return siu_type_name(port);}static void siu_release_port(struct uart_port *port){	unsigned long size;	if (port->flags	& UPF_IOREMAP) {		iounmap(port->membase);		port->membase = NULL;	}	size = siu_port_size(port);	release_mem_region(port->mapbase, size);}static int siu_request_port(struct uart_port *port){	unsigned long size;	struct resource *res;	size = siu_port_size(port);	res = request_mem_region(port->mapbase, size, siu_type_name(port));	if (res == NULL)		return -EBUSY;	if (port->flags & UPF_IOREMAP) {		port->membase = ioremap(port->mapbase, size);		if (port->membase == NULL) {			release_resource(res);			return -ENOMEM;		}	}	return 0;}static void siu_config_port(struct uart_port *port, int flags){	if (flags & UART_CONFIG_TYPE) {		port->type = siu_check_type(port);		(void)siu_request_port(port);	}}static int siu_verify_port(struct uart_port *port, struct serial_struct *serial){	if (port->type != PORT_VR41XX_SIU && port->type != PORT_VR41XX_DSIU)		return -EINVAL;	if (port->irq != serial->irq)		return -EINVAL;	if (port->iotype != serial->io_type)		return -EINVAL;	if (port->mapbase != (unsigned long)serial->iomem_base)		return -EINVAL;	return 0;}static struct uart_ops siu_uart_ops = {	.tx_empty	= siu_tx_empty,	.set_mctrl	= siu_set_mctrl,	.get_mctrl	= siu_get_mctrl,	.stop_tx	= siu_stop_tx,	.start_tx	= siu_start_tx,	.stop_rx	= siu_stop_rx,	.enable_ms	= siu_enable_ms,	.break_ctl	= siu_break_ctl,	.startup	= siu_startup,	.shutdown	= siu_shutdown,	.set_termios	= siu_set_termios,	.pm		= siu_pm,	.type		= siu_type,	.release_port	= siu_release_port,	.request_port	= siu_request_port,	.config_port	= siu_config_port,	.verify_port	= siu_verify_port,};static int siu_init_ports(struct platform_device *pdev){	struct uart_port *port;	struct resource *res;	int *type = pdev->dev.platform_data;	int i;	if (!type)		return 0;	port = siu_uart_ports;	for (i = 0; i < SIU_PORTS_MAX; i++) {		port->type = type[i];		if (port->type == PORT_UNKNOWN)			continue;		port->irq = platform_get_irq(pdev, i);		port->uartclk = SIU_BAUD_BASE * 16;		port->fifosize = 16;		port->regshift = 0;		port->iotype = UPIO_MEM;		port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;		port->line = i;		res = platform_get_resource(pdev, IORESOURCE_MEM, i);		port->mapbase = res->start;		port++;	}	return i;}#ifdef CONFIG_SERIAL_VR41XX_CONSOLE#define BOTH_EMPTY	(UART_LSR_TEMT | UART_LSR_THRE)static void wait_for_xmitr(struct uart_port *port){	int timeout = 10000;	uint8_t lsr, msr;	do {		lsr = siu_read(port, UART_LSR);		if (lsr & UART_LSR_BI)			lsr_break_flag[port->line] = UART_LSR_BI;		if ((lsr & BOTH_EMPTY) == BOTH_EMPTY)			break;	} while (timeout-- > 0);	if (port->flags & UPF_CONS_FLOW) {		timeout = 1000000;		do {			msr = siu_read(port, UART_MSR);			if ((msr & UART_MSR_CTS) != 0)				break;		} while (timeout-- > 0);	}}static void siu_console_putchar(struct uart_port *port, int ch){	wait_for_xmitr(port);	siu_write(port, UART_TX, ch);}static void siu_console_write(struct console *con, const char *s, unsigned count){	struct uart_port *port;	uint8_t ier;	port = &siu_uart_ports[con->index];	ier = siu_read(port, UART_IER);	siu_write(port, UART_IER, 0);	uart_console_write(port, s, count, siu_console_putchar);	wait_for_xmitr(port);	siu_write(port, UART_IER, ier);}static int __init siu_console_setup(struct console *con, char *options){	struct uart_port *port;	int baud = 9600;	int parity = 'n';	int bits = 8;	int flow = 'n';	if (con->index >= SIU_PORTS_MAX)		con->index = 0;	port = &siu_uart_ports[con->index];	if (port->membase == NULL) {		if (port->mapbase == 0)			return -ENODEV;		port->membase = ioremap(port->mapbase, siu_port_size(port));	}	if (port->type == PORT_VR41XX_SIU)		vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);	if (options != NULL)		uart_parse_options(options, &baud, &parity, &bits, &flow);	return uart_set_options(port, con, baud, parity, bits, flow);}static struct uart_driver siu_uart_driver;static struct console siu_console = {	.name	= "ttyVR",	.write	= siu_console_write,	.device	= uart_console_device,	.setup	= siu_console_setup,	.flags	= CON_PRINTBUFFER,	.index	= -1,	.data	= &siu_uart_driver,};static int __devinit siu_console_init(void){	struct uart_port *port;	int i;	for (i = 0; i < SIU_PORTS_MAX; i++) {		port = &siu_uart_ports[i];		port->ops = &siu_uart_ops;	}	register_console(&siu_console);	return 0;}console_initcall(siu_console_init);#define SERIAL_VR41XX_CONSOLE	&siu_console#else#define SERIAL_VR41XX_CONSOLE	NULL#endifstatic struct uart_driver siu_uart_driver = {	.owner		= THIS_MODULE,	.driver_name	= "SIU",	.dev_name	= "ttyVR",	.major		= SIU_MAJOR,	.minor		= SIU_MINOR_BASE,	.cons		= SERIAL_VR41XX_CONSOLE,};static int __devinit siu_probe(struct platform_device *dev){	struct uart_port *port;	int num, i, retval;	num = siu_init_ports(dev);	if (num <= 0)		return -ENODEV;	siu_uart_driver.nr = num;	retval = uart_register_driver(&siu_uart_driver);	if (retval)		return retval;	for (i = 0; i < num; i++) {		port = &siu_uart_ports[i];		port->ops = &siu_uart_ops;		port->dev = &dev->dev;		retval = uart_add_one_port(&siu_uart_driver, port);		if (retval < 0) {			port->dev = NULL;			break;		}	}	if (i == 0 && retval < 0) {		uart_unregister_driver(&siu_uart_driver);		return retval;	}	return 0;}static int __devexit siu_remove(struct platform_device *dev){	struct uart_port *port;	int i;	for (i = 0; i < siu_uart_driver.nr; i++) {		port = &siu_uart_ports[i];		if (port->dev == &dev->dev) {			uart_remove_one_port(&siu_uart_driver, port);			port->dev = NULL;		}	}	uart_unregister_driver(&siu_uart_driver);	return 0;}static int siu_suspend(struct platform_device *dev, pm_message_t state){	struct uart_port *port;	int i;	for (i = 0; i < siu_uart_driver.nr; i++) {		port = &siu_uart_ports[i];		if ((port->type == PORT_VR41XX_SIU ||		     port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)			uart_suspend_port(&siu_uart_driver, port);	}	return 0;}static int siu_resume(struct platform_device *dev){	struct uart_port *port;	int i;	for (i = 0; i < siu_uart_driver.nr; i++) {		port = &siu_uart_ports[i];		if ((port->type == PORT_VR41XX_SIU ||		     port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)			uart_resume_port(&siu_uart_driver, port);	}	return 0;}static struct platform_driver siu_device_driver = {	.probe		= siu_probe,	.remove		= __devexit_p(siu_remove),	.suspend	= siu_suspend,	.resume		= siu_resume,	.driver		= {		.name	= "SIU",		.owner	= THIS_MODULE,	},};static int __init vr41xx_siu_init(void){	return platform_driver_register(&siu_device_driver);}static void __exit vr41xx_siu_exit(void){	platform_driver_unregister(&siu_device_driver);}module_init(vr41xx_siu_init);module_exit(vr41xx_siu_exit);

⌨️ 快捷键说明

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