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

📄 mpsc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	else if (pi->port.uartclk / 16 != ser->baud_base) /* Not sure */		rc = -EINVAL;	else if ((void *)pi->port.mapbase != ser->iomem_base)		rc = -EINVAL;	else if (pi->port.iobase != ser->port)		rc = -EINVAL;	else if (ser->hub6 != 0)		rc = -EINVAL;	return rc;}static struct uart_ops mpsc_pops = {	.tx_empty	= mpsc_tx_empty,	.set_mctrl	= mpsc_set_mctrl,	.get_mctrl	= mpsc_get_mctrl,	.stop_tx	= mpsc_stop_tx,	.start_tx	= mpsc_start_tx,	.stop_rx	= mpsc_stop_rx,	.enable_ms	= mpsc_enable_ms,	.break_ctl	= mpsc_break_ctl,	.startup	= mpsc_startup,	.shutdown	= mpsc_shutdown,	.set_termios	= mpsc_set_termios,	.type		= mpsc_type,	.release_port	= mpsc_release_port,	.request_port	= mpsc_request_port,	.config_port	= mpsc_config_port,	.verify_port	= mpsc_verify_port,};/* ****************************************************************************** * * Console Interface Routines * ****************************************************************************** */#ifdef CONFIG_SERIAL_MPSC_CONSOLEstatic void mpsc_console_write(struct console *co, const char *s, uint count){	struct mpsc_port_info *pi = &mpsc_ports[co->index];	u8 *bp, *dp, add_cr = 0;	int i;	unsigned long iflags;	spin_lock_irqsave(&pi->tx_lock, iflags);	while (pi->txr_head != pi->txr_tail) {		while (mpsc_sdma_tx_active(pi))			udelay(100);		mpsc_sdma_intr_ack(pi);		mpsc_tx_intr(pi);	}	while (mpsc_sdma_tx_active(pi))		udelay(100);	while (count > 0) {		bp = dp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);		for (i = 0; i < MPSC_TXBE_SIZE; i++) {			if (count == 0)				break;			if (add_cr) {				*(dp++) = '\r';				add_cr = 0;			} else {				*(dp++) = *s;				if (*(s++) == '\n') { /* add '\r' after '\n' */					add_cr = 1;					count++;				}			}			count--;		}		dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,				DMA_BIDIRECTIONAL);#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)		if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */			flush_dcache_range((ulong)bp,					(ulong)bp + MPSC_TXBE_SIZE);#endif		mpsc_setup_tx_desc(pi, i, 0);		pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);		mpsc_sdma_start_tx(pi);		while (mpsc_sdma_tx_active(pi))			udelay(100);		pi->txr_tail = (pi->txr_tail + 1) & (MPSC_TXR_ENTRIES - 1);	}	spin_unlock_irqrestore(&pi->tx_lock, iflags);}static int __init mpsc_console_setup(struct console *co, char *options){	struct mpsc_port_info *pi;	int baud, bits, parity, flow;	pr_debug("mpsc_console_setup[%d]: options: %s\n", co->index, options);	if (co->index >= MPSC_NUM_CTLRS)		co->index = 0;	pi = &mpsc_ports[co->index];	baud = pi->default_baud;	bits = pi->default_bits;	parity = pi->default_parity;	flow = pi->default_flow;	if (!pi->port.ops)		return -ENODEV;	spin_lock_init(&pi->port.lock);	/* Temporary fix--copied from 8250.c */	if (options)		uart_parse_options(options, &baud, &parity, &bits, &flow);	return uart_set_options(&pi->port, co, baud, parity, bits, flow);}static struct console mpsc_console = {	.name	= MPSC_DEV_NAME,	.write	= mpsc_console_write,	.device	= uart_console_device,	.setup	= mpsc_console_setup,	.flags	= CON_PRINTBUFFER,	.index	= -1,	.data	= &mpsc_reg,};static int __init mpsc_late_console_init(void){	pr_debug("mpsc_late_console_init: Enter\n");	if (!(mpsc_console.flags & CON_ENABLED))		register_console(&mpsc_console);	return 0;}late_initcall(mpsc_late_console_init);#define MPSC_CONSOLE	&mpsc_console#else#define MPSC_CONSOLE	NULL#endif/* ****************************************************************************** * * Dummy Platform Driver to extract & map shared register regions * ****************************************************************************** */static void mpsc_resource_err(char *s){	printk(KERN_WARNING "MPSC: Platform device resource error in %s\n", s);}static int mpsc_shared_map_regs(struct platform_device *pd){	struct resource	*r;	if ((r = platform_get_resource(pd, IORESOURCE_MEM,					MPSC_ROUTING_BASE_ORDER))			&& request_mem_region(r->start,				MPSC_ROUTING_REG_BLOCK_SIZE,				"mpsc_routing_regs")) {		mpsc_shared_regs.mpsc_routing_base = ioremap(r->start,				MPSC_ROUTING_REG_BLOCK_SIZE);		mpsc_shared_regs.mpsc_routing_base_p = r->start;	} else {		mpsc_resource_err("MPSC routing base");		return -ENOMEM;	}	if ((r = platform_get_resource(pd, IORESOURCE_MEM,					MPSC_SDMA_INTR_BASE_ORDER))			&& request_mem_region(r->start,				MPSC_SDMA_INTR_REG_BLOCK_SIZE,				"sdma_intr_regs")) {		mpsc_shared_regs.sdma_intr_base = ioremap(r->start,			MPSC_SDMA_INTR_REG_BLOCK_SIZE);		mpsc_shared_regs.sdma_intr_base_p = r->start;	} else {		iounmap(mpsc_shared_regs.mpsc_routing_base);		release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,				MPSC_ROUTING_REG_BLOCK_SIZE);		mpsc_resource_err("SDMA intr base");		return -ENOMEM;	}	return 0;}static void mpsc_shared_unmap_regs(void){	if (!mpsc_shared_regs.mpsc_routing_base) {		iounmap(mpsc_shared_regs.mpsc_routing_base);		release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,				MPSC_ROUTING_REG_BLOCK_SIZE);	}	if (!mpsc_shared_regs.sdma_intr_base) {		iounmap(mpsc_shared_regs.sdma_intr_base);		release_mem_region(mpsc_shared_regs.sdma_intr_base_p,				MPSC_SDMA_INTR_REG_BLOCK_SIZE);	}	mpsc_shared_regs.mpsc_routing_base = NULL;	mpsc_shared_regs.sdma_intr_base = NULL;	mpsc_shared_regs.mpsc_routing_base_p = 0;	mpsc_shared_regs.sdma_intr_base_p = 0;}static int mpsc_shared_drv_probe(struct platform_device *dev){	struct mpsc_shared_pdata	*pdata;	int				 rc = -ENODEV;	if (dev->id == 0) {		if (!(rc = mpsc_shared_map_regs(dev))) {			pdata = (struct mpsc_shared_pdata *)				dev->dev.platform_data;			mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;			mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;			mpsc_shared_regs.MPSC_TCRR_m= pdata->tcrr_val;			mpsc_shared_regs.SDMA_INTR_CAUSE_m =				pdata->intr_cause_val;			mpsc_shared_regs.SDMA_INTR_MASK_m =				pdata->intr_mask_val;			rc = 0;		}	}	return rc;}static int mpsc_shared_drv_remove(struct platform_device *dev){	int	rc = -ENODEV;	if (dev->id == 0) {		mpsc_shared_unmap_regs();		mpsc_shared_regs.MPSC_MRR_m = 0;		mpsc_shared_regs.MPSC_RCRR_m = 0;		mpsc_shared_regs.MPSC_TCRR_m = 0;		mpsc_shared_regs.SDMA_INTR_CAUSE_m = 0;		mpsc_shared_regs.SDMA_INTR_MASK_m = 0;		rc = 0;	}	return rc;}static struct platform_driver mpsc_shared_driver = {	.probe	= mpsc_shared_drv_probe,	.remove	= mpsc_shared_drv_remove,	.driver	= {		.name	= MPSC_SHARED_NAME,	},};/* ****************************************************************************** * * Driver Interface Routines * ****************************************************************************** */static struct uart_driver mpsc_reg = {	.owner		= THIS_MODULE,	.driver_name	= MPSC_DRIVER_NAME,	.dev_name	= MPSC_DEV_NAME,	.major		= MPSC_MAJOR,	.minor		= MPSC_MINOR_START,	.nr		= MPSC_NUM_CTLRS,	.cons		= MPSC_CONSOLE,};static int mpsc_drv_map_regs(struct mpsc_port_info *pi,		struct platform_device *pd){	struct resource	*r;	if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_BASE_ORDER))			&& request_mem_region(r->start, MPSC_REG_BLOCK_SIZE,			"mpsc_regs")) {		pi->mpsc_base = ioremap(r->start, MPSC_REG_BLOCK_SIZE);		pi->mpsc_base_p = r->start;	} else {		mpsc_resource_err("MPSC base");		goto err;	}	if ((r = platform_get_resource(pd, IORESOURCE_MEM,					MPSC_SDMA_BASE_ORDER))			&& request_mem_region(r->start,				MPSC_SDMA_REG_BLOCK_SIZE, "sdma_regs")) {		pi->sdma_base = ioremap(r->start,MPSC_SDMA_REG_BLOCK_SIZE);		pi->sdma_base_p = r->start;	} else {		mpsc_resource_err("SDMA base");		if (pi->mpsc_base) {			iounmap(pi->mpsc_base);			pi->mpsc_base = NULL;		}		goto err;	}	if ((r = platform_get_resource(pd,IORESOURCE_MEM,MPSC_BRG_BASE_ORDER))			&& request_mem_region(r->start,				MPSC_BRG_REG_BLOCK_SIZE, "brg_regs")) {		pi->brg_base = ioremap(r->start, MPSC_BRG_REG_BLOCK_SIZE);		pi->brg_base_p = r->start;	} else {		mpsc_resource_err("BRG base");		if (pi->mpsc_base) {			iounmap(pi->mpsc_base);			pi->mpsc_base = NULL;		}		if (pi->sdma_base) {			iounmap(pi->sdma_base);			pi->sdma_base = NULL;		}		goto err;	}	return 0;err:	return -ENOMEM;}static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi){	if (!pi->mpsc_base) {		iounmap(pi->mpsc_base);		release_mem_region(pi->mpsc_base_p, MPSC_REG_BLOCK_SIZE);	}	if (!pi->sdma_base) {		iounmap(pi->sdma_base);		release_mem_region(pi->sdma_base_p, MPSC_SDMA_REG_BLOCK_SIZE);	}	if (!pi->brg_base) {		iounmap(pi->brg_base);		release_mem_region(pi->brg_base_p, MPSC_BRG_REG_BLOCK_SIZE);	}	pi->mpsc_base = NULL;	pi->sdma_base = NULL;	pi->brg_base = NULL;	pi->mpsc_base_p = 0;	pi->sdma_base_p = 0;	pi->brg_base_p = 0;}static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,		struct platform_device *pd, int num){	struct mpsc_pdata	*pdata;	pdata = (struct mpsc_pdata *)pd->dev.platform_data;	pi->port.uartclk = pdata->brg_clk_freq;	pi->port.iotype = UPIO_MEM;	pi->port.line = num;	pi->port.type = PORT_MPSC;	pi->port.fifosize = MPSC_TXBE_SIZE;	pi->port.membase = pi->mpsc_base;	pi->port.mapbase = (ulong)pi->mpsc_base;	pi->port.ops = &mpsc_pops;	pi->mirror_regs = pdata->mirror_regs;	pi->cache_mgmt = pdata->cache_mgmt;	pi->brg_can_tune = pdata->brg_can_tune;	pi->brg_clk_src = pdata->brg_clk_src;	pi->mpsc_max_idle = pdata->max_idle;	pi->default_baud = pdata->default_baud;	pi->default_bits = pdata->default_bits;	pi->default_parity = pdata->default_parity;	pi->default_flow = pdata->default_flow;	/* Initial values of mirrored regs */	pi->MPSC_CHR_1_m = pdata->chr_1_val;	pi->MPSC_CHR_2_m = pdata->chr_2_val;	pi->MPSC_CHR_10_m = pdata->chr_10_val;	pi->MPSC_MPCR_m = pdata->mpcr_val;	pi->BRG_BCR_m = pdata->bcr_val;	pi->shared_regs = &mpsc_shared_regs;	pi->port.irq = platform_get_irq(pd, 0);}static int mpsc_drv_probe(struct platform_device *dev){	struct mpsc_port_info	*pi;	int			rc = -ENODEV;	pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id);	if (dev->id < MPSC_NUM_CTLRS) {		pi = &mpsc_ports[dev->id];		if (!(rc = mpsc_drv_map_regs(pi, dev))) {			mpsc_drv_get_platform_data(pi, dev, dev->id);			if (!(rc = mpsc_make_ready(pi))) {				spin_lock_init(&pi->tx_lock);				if (!(rc = uart_add_one_port(&mpsc_reg,								&pi->port))) {					rc = 0;				} else {					mpsc_release_port((struct uart_port *)							pi);					mpsc_drv_unmap_regs(pi);				}			} else {				mpsc_drv_unmap_regs(pi);			}		}	}	return rc;}static int mpsc_drv_remove(struct platform_device *dev){	pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id);	if (dev->id < MPSC_NUM_CTLRS) {		uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port);		mpsc_release_port((struct uart_port *)				&mpsc_ports[dev->id].port);		mpsc_drv_unmap_regs(&mpsc_ports[dev->id]);		return 0;	} else {		return -ENODEV;	}}static struct platform_driver mpsc_driver = {	.probe	= mpsc_drv_probe,	.remove	= mpsc_drv_remove,	.driver	= {		.name	= MPSC_CTLR_NAME,	},};static int __init mpsc_drv_init(void){	int	rc;	printk(KERN_INFO "Serial: MPSC driver $Revision: 1.00 $\n");	memset(mpsc_ports, 0, sizeof(mpsc_ports));	memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));	if (!(rc = uart_register_driver(&mpsc_reg))) {		if (!(rc = platform_driver_register(&mpsc_shared_driver))) {			if ((rc = platform_driver_register(&mpsc_driver))) {				platform_driver_unregister(&mpsc_shared_driver);				uart_unregister_driver(&mpsc_reg);			}		} else {			uart_unregister_driver(&mpsc_reg);		}	}	return rc;}static void __exit mpsc_drv_exit(void){	platform_driver_unregister(&mpsc_driver);	platform_driver_unregister(&mpsc_shared_driver);	uart_unregister_driver(&mpsc_reg);	memset(mpsc_ports, 0, sizeof(mpsc_ports));	memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));}module_init(mpsc_drv_init);module_exit(mpsc_drv_exit);MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver $Revision: 1.00 $");MODULE_VERSION(MPSC_VERSION);MODULE_LICENSE("GPL");MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR);

⌨️ 快捷键说明

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