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

📄 pmac_zilog.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Called upon match with an escc node in the devive-tree. */static int pmz_attach(struct macio_dev *mdev, const struct of_match *match){	int i;		/* Iterate the pmz_ports array to find a matching entry	 */	for (i = 0; i < MAX_ZS_PORTS; i++)		if (pmz_ports[i].node == mdev->ofdev.node) {			struct uart_pmac_port *uap = &pmz_ports[i];			uap->dev = mdev;			dev_set_drvdata(&mdev->ofdev.dev, uap);			if (macio_request_resources(uap->dev, "pmac_zilog"))				printk(KERN_WARNING "%s: Failed to request resource"				       ", port still active\n",				       uap->node->name);			else				uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED;							return 0;		}	return -ENODEV;}/* * That one should not be called, macio isn't really a hotswap device, * we don't expect one of those serial ports to go away... */static int pmz_detach(struct macio_dev *mdev){	struct uart_pmac_port	*uap = dev_get_drvdata(&mdev->ofdev.dev);		if (!uap)		return -ENODEV;	if (uap->flags & PMACZILOG_FLAG_RSRC_REQUESTED) {		macio_release_resources(uap->dev);		uap->flags &= ~PMACZILOG_FLAG_RSRC_REQUESTED;	}	dev_set_drvdata(&mdev->ofdev.dev, NULL);	uap->dev = NULL;		return 0;}static int pmz_suspend(struct macio_dev *mdev, u32 pm_state){	struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);	struct uart_state *state;	unsigned long flags;	if (uap == NULL) {		printk("HRM... pmz_suspend with NULL uap\n");		return 0;	}	if (pm_state == mdev->ofdev.dev.power_state || pm_state < 2)		return 0;	pmz_debug("suspend, switching to state %d\n", pm_state);	state = pmz_uart_reg.state + uap->port.line;	down(&pmz_irq_sem);	down(&state->sem);	spin_lock_irqsave(&uap->port.lock, flags);	if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) {		/* Disable receiver and transmitter.  */		uap->curregs[R3] &= ~RxENABLE;		uap->curregs[R5] &= ~TxENABLE;		/* Disable all interrupts and BRK assertion.  */		uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);		uap->curregs[R5] &= ~SND_BRK;		pmz_load_zsregs(uap, uap->curregs);		uap->flags |= PMACZILOG_FLAG_IS_ASLEEP;		mb();	}	spin_unlock_irqrestore(&uap->port.lock, flags);	if (ZS_IS_OPEN(uap) || ZS_IS_OPEN(uap->mate))		if (ZS_IS_ASLEEP(uap->mate) && ZS_IS_IRQ_ON(pmz_get_port_A(uap))) {			pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;			disable_irq(uap->port.irq);		}	if (ZS_IS_CONS(uap))		uap->port.cons->flags &= ~CON_ENABLED;	/* Shut the chip down */	pmz_set_scc_power(uap, 0);	up(&state->sem);	up(&pmz_irq_sem);	pmz_debug("suspend, switching complete\n");	mdev->ofdev.dev.power_state = pm_state;	return 0;}static int pmz_resume(struct macio_dev *mdev){	struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);	struct uart_state *state;	unsigned long flags;	int pwr_delay = 0;	if (uap == NULL)		return 0;	if (mdev->ofdev.dev.power_state == 0)		return 0;		pmz_debug("resume, switching to state 0\n");	state = pmz_uart_reg.state + uap->port.line;	down(&pmz_irq_sem);	down(&state->sem);	spin_lock_irqsave(&uap->port.lock, flags);	if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) {		spin_unlock_irqrestore(&uap->port.lock, flags);		goto bail;	}	pwr_delay = __pmz_startup(uap);	/* Take care of config that may have changed while asleep */	__pmz_set_termios(&uap->port, &uap->termios_cache, NULL);	if (ZS_IS_OPEN(uap)) {		/* Enable interrupts */				uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;		if (!ZS_IS_EXTCLK(uap))			uap->curregs[R1] |= EXT_INT_ENAB;		write_zsreg(uap, R1, uap->curregs[R1]);	}	spin_unlock_irqrestore(&uap->port.lock, flags);	if (ZS_IS_CONS(uap))		uap->port.cons->flags |= CON_ENABLED;	/* Re-enable IRQ on the controller */	if (ZS_IS_OPEN(uap) && !ZS_IS_IRQ_ON(pmz_get_port_A(uap))) {		pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;		enable_irq(uap->port.irq);	} bail:	up(&state->sem);	up(&pmz_irq_sem);	/* Right now, we deal with delay by blocking here, I'll be	 * smarter later on	 */	if (pwr_delay != 0) {		pmz_debug("pmz: delaying %d ms\n", pwr_delay);		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout((pwr_delay * HZ)/1000);	}	pmz_debug("resume, switching complete\n");	mdev->ofdev.dev.power_state = 0;	return 0;}/* * Probe all ports in the system and build the ports array, we register * with the serial layer at this point, the macio-type probing is only * used later to "attach" to the sysfs tree so we get power management * events */static int __init pmz_probe(void){	struct device_node	*node_p, *node_a, *node_b, *np;	int			count = 0;	int			rc;	/*	 * Find all escc chips in the system	 */	node_p = of_find_node_by_name(NULL, "escc");	while (node_p) {		/*		 * First get channel A/B node pointers		 * 		 * TODO: Add routines with proper locking to do that...		 */		node_a = node_b = NULL;		for (np = NULL; (np = of_get_next_child(node_p, np)) != NULL;) {			if (strncmp(np->name, "ch-a", 4) == 0)				node_a = of_node_get(np);			else if (strncmp(np->name, "ch-b", 4) == 0)				node_b = of_node_get(np);		}		if (!node_a && !node_b) {			of_node_put(node_a);			of_node_put(node_b);			printk(KERN_ERR "pmac_zilog: missing node %c for escc %s\n",				(!node_a) ? 'a' : 'b', node_p->full_name);			goto next;		}		/*		 * Fill basic fields in the port structures		 */		pmz_ports[count].mate		= &pmz_ports[count+1];		pmz_ports[count+1].mate		= &pmz_ports[count];		pmz_ports[count].flags		= PMACZILOG_FLAG_IS_CHANNEL_A;		pmz_ports[count].node		= node_a;		pmz_ports[count+1].node		= node_b;		pmz_ports[count].port.line	= count;		pmz_ports[count+1].port.line   	= count+1;		/*		 * Setup the ports for real		 */		rc = pmz_init_port(&pmz_ports[count]);		if (rc == 0 && node_b != NULL)			rc = pmz_init_port(&pmz_ports[count+1]);		if (rc != 0) {			of_node_put(node_a);			of_node_put(node_b);			memset(&pmz_ports[count], 0, sizeof(struct uart_pmac_port));			memset(&pmz_ports[count+1], 0, sizeof(struct uart_pmac_port));			goto next;		}		count += 2;next:		node_p = of_find_node_by_name(node_p, "escc");	}	pmz_ports_count = count;	return 0;}#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLEstatic void pmz_console_write(struct console *con, const char *s, unsigned int count);static int __init pmz_console_setup(struct console *co, char *options);static struct console pmz_console = {	.name	=	"ttyS",	.write	=	pmz_console_write,	.device	=	uart_console_device,	.setup	=	pmz_console_setup,	.flags	=	CON_PRINTBUFFER,	.index	=	-1,	.data   =	&pmz_uart_reg,};#define PMACZILOG_CONSOLE	&pmz_console#else /* CONFIG_SERIAL_PMACZILOG_CONSOLE */#define PMACZILOG_CONSOLE	(NULL)#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE *//* * Register the driver, console driver and ports with the serial * core */static int __init pmz_register(void){	int i, rc;		pmz_uart_reg.nr = pmz_ports_count;	pmz_uart_reg.cons = PMACZILOG_CONSOLE;	pmz_uart_reg.minor = 64;	/*	 * Register this driver with the serial core	 */	rc = uart_register_driver(&pmz_uart_reg);	if (rc)		return rc;	/*	 * Register each port with the serial core	 */	for (i = 0; i < pmz_ports_count; i++) {		struct uart_pmac_port *uport = &pmz_ports[i];		/* NULL node may happen on wallstreet */		if (uport->node != NULL)			rc = uart_add_one_port(&pmz_uart_reg, &uport->port);		if (rc)			goto err_out;	}	return 0;err_out:	while (i-- > 0) {		struct uart_pmac_port *uport = &pmz_ports[i];		uart_remove_one_port(&pmz_uart_reg, &uport->port);	}	uart_unregister_driver(&pmz_uart_reg);	return rc;}static struct of_match pmz_match[] = {	{	.name 		= "ch-a",	.type		= OF_ANY_MATCH,	.compatible	= OF_ANY_MATCH	},	{	.name 		= "ch-b",	.type		= OF_ANY_MATCH,	.compatible	= OF_ANY_MATCH	},	{},};static struct macio_driver pmz_driver = {	.name 		= "pmac_zilog",	.match_table	= pmz_match,	.probe		= pmz_attach,	.remove		= pmz_detach,	.suspend	= pmz_suspend,       	.resume		= pmz_resume,};static int __init init_pmz(void){	int rc, i;	printk(KERN_INFO "%s\n", version);	/* 	 * First, we need to do a direct OF-based probe pass. We	 * do that because we want serial console up before the	 * macio stuffs calls us back, and since that makes it	 * easier to pass the proper number of channels to	 * uart_register_driver()	 */	if (pmz_ports_count == 0)		pmz_probe();	/*	 * Bail early if no port found	 */	if (pmz_ports_count == 0)		return -ENODEV;	/*	 * Now we register with the serial layer	 */	rc = pmz_register();	if (rc) {		printk(KERN_ERR 			"pmac_zilog: Error registering serial device, disabling pmac_zilog.\n"		 	"pmac_zilog: Did another serial driver already claim the minors?\n"); 		/* effectively "pmz_unprobe()" */		for (i=0; i < pmz_ports_count; i++)			pmz_dispose_port(&pmz_ports[i]);		return rc;	}		/*	 * Then we register the macio driver itself	 */	return macio_register_driver(&pmz_driver);}static void __exit exit_pmz(void){	int i;	/* Get rid of macio-driver (detach from macio) */	macio_unregister_driver(&pmz_driver);	for (i = 0; i < pmz_ports_count; i++) {		struct uart_pmac_port *uport = &pmz_ports[i];		if (uport->node != NULL) {			uart_remove_one_port(&pmz_uart_reg, &uport->port);			pmz_dispose_port(uport);		}	}	/* Unregister UART driver */	uart_unregister_driver(&pmz_uart_reg);}#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE/* * Print a string to the serial port trying not to disturb * any possible real use of the port... */static void pmz_console_write(struct console *con, const char *s, unsigned int count){	struct uart_pmac_port *uap = &pmz_ports[con->index];	unsigned long flags;	int i;	spin_lock_irqsave(&uap->port.lock, flags);	/* Turn of interrupts and enable the transmitter. */	write_zsreg(uap, R1, uap->curregs[1] & ~TxINT_ENAB);	write_zsreg(uap, R5, uap->curregs[5] | TxENABLE | RTS | DTR);	for (i = 0; i < count; i++) {		/* Wait for the transmit buffer to empty. */		while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)			udelay(5);		write_zsdata(uap, s[i]);		if (s[i] == 10) {			while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)				udelay(5);			write_zsdata(uap, R13);		}	}	/* Restore the values in the registers. */	write_zsreg(uap, R1, uap->curregs[1]);	/* Don't disable the transmitter. */	spin_unlock_irqrestore(&uap->port.lock, flags);}/* * Setup the serial console */static int __init pmz_console_setup(struct console *co, char *options){	struct uart_pmac_port *uap;	struct uart_port *port;	int baud = 38400;	int bits = 8;	int parity = 'n';	int flow = 'n';	unsigned long pwr_delay;	/*	 * XServe's default to 57600 bps	 */	if (machine_is_compatible("RackMac1,1")	    || machine_is_compatible("RackMac1,2")	    || machine_is_compatible("MacRISC4"))	 	baud = 57600;	/*	 * Check whether an invalid uart number has been specified, and	 * if so, search for the first available port that does have	 * console support.	 */	if (co->index >= pmz_ports_count)		co->index = 0;	uap = &pmz_ports[co->index];	if (uap->node == NULL)		return -ENODEV;	port = &uap->port;	/*	 * Mark port as beeing a console	 */	uap->flags |= PMACZILOG_FLAG_IS_CONS;	/*	 * Temporary fix for uart layer who didn't setup the spinlock yet	 */	spin_lock_init(&port->lock);	/*	 * Enable the hardware	 */	pwr_delay = __pmz_startup(uap);	if (pwr_delay)		mdelay(pwr_delay);		if (options)		uart_parse_options(options, &baud, &parity, &bits, &flow);	return uart_set_options(port, co, baud, parity, bits, flow);}static int __init pmz_console_init(void){	/* Probe ports */	pmz_probe();	/* TODO: Autoprobe console based on OF */	/* pmz_console.index = i; */	register_console(&pmz_console);	return 0;}console_initcall(pmz_console_init);#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */module_init(init_pmz);module_exit(exit_pmz);

⌨️ 快捷键说明

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