legacy_serial.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 554 行 · 第 1/2 页

C
554
字号
#include <linux/config.h>#include <linux/kernel.h>#include <linux/serial.h>#include <linux/serial_8250.h>#include <linux/serial_core.h>#include <linux/console.h>#include <linux/pci.h>#include <asm/io.h>#include <asm/mmu.h>#include <asm/prom.h>#include <asm/serial.h>#include <asm/udbg.h>#include <asm/pci-bridge.h>#include <asm/ppc-pci.h>#undef DEBUG#ifdef DEBUG#define DBG(fmt...) do { printk(fmt); } while(0)#else#define DBG(fmt...) do { } while(0)#endif#define MAX_LEGACY_SERIAL_PORTS	8static struct plat_serial8250_portlegacy_serial_ports[MAX_LEGACY_SERIAL_PORTS+1];static struct legacy_serial_info {	struct device_node		*np;	unsigned int			speed;	unsigned int			clock;	phys_addr_t			taddr;} legacy_serial_infos[MAX_LEGACY_SERIAL_PORTS];static unsigned int legacy_serial_count;static int legacy_serial_console = -1;static int __init add_legacy_port(struct device_node *np, int want_index,				  int iotype, phys_addr_t base,				  phys_addr_t taddr, unsigned long irq,				  upf_t flags){	u32 *clk, *spd, clock = BASE_BAUD * 16;	int index;	/* get clock freq. if present */	clk = (u32 *)get_property(np, "clock-frequency", NULL);	if (clk && *clk)		clock = *clk;	/* get default speed if present */	spd = (u32 *)get_property(np, "current-speed", NULL);	/* If we have a location index, then try to use it */	if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS)		index = want_index;	else		index = legacy_serial_count;	/* if our index is still out of range, that mean that	 * array is full, we could scan for a free slot but that	 * make little sense to bother, just skip the port	 */	if (index >= MAX_LEGACY_SERIAL_PORTS)		return -1;	if (index >= legacy_serial_count)		legacy_serial_count = index + 1;	/* Check if there is a port who already claimed our slot */	if (legacy_serial_infos[index].np != 0) {		/* if we still have some room, move it, else override */		if (legacy_serial_count < MAX_LEGACY_SERIAL_PORTS) {			printk(KERN_INFO "Moved legacy port %d -> %d\n",			       index, legacy_serial_count);			legacy_serial_ports[legacy_serial_count] =				legacy_serial_ports[index];			legacy_serial_infos[legacy_serial_count] =				legacy_serial_infos[index];			legacy_serial_count++;		} else {			printk(KERN_INFO "Replacing legacy port %d\n", index);		}	}	/* Now fill the entry */	memset(&legacy_serial_ports[index], 0,	       sizeof(struct plat_serial8250_port));	if (iotype == UPIO_PORT)		legacy_serial_ports[index].iobase = base;	else		legacy_serial_ports[index].mapbase = base;	legacy_serial_ports[index].iotype = iotype;	legacy_serial_ports[index].uartclk = clock;	legacy_serial_ports[index].irq = irq;	legacy_serial_ports[index].flags = flags;	legacy_serial_infos[index].taddr = taddr;	legacy_serial_infos[index].np = of_node_get(np);	legacy_serial_infos[index].clock = clock;	legacy_serial_infos[index].speed = spd ? *spd : 0;	printk(KERN_INFO "Found legacy serial port %d for %s\n",	       index, np->full_name);	printk(KERN_INFO "  %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d\n",	       (iotype == UPIO_PORT) ? "port" : "mem",	       (unsigned long long)base, (unsigned long long)taddr, irq,	       legacy_serial_ports[index].uartclk,	       legacy_serial_infos[index].speed);	return index;}static int __init add_legacy_soc_port(struct device_node *np,				      struct device_node *soc_dev){	phys_addr_t addr;	u32 *addrp;	upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;	/* We only support ports that have a clock frequency properly	 * encoded in the device-tree.	 */	if (get_property(np, "clock-frequency", NULL) == NULL)		return -1;	/* Get the address */	addrp = of_get_address(soc_dev, 0, NULL, NULL);	if (addrp == NULL)		return -1;	addr = of_translate_address(soc_dev, addrp);	/* Add port, irq will be dealt with later. We passed a translated	 * IO port value. It will be fixed up later along with the irq	 */	return add_legacy_port(np, -1, UPIO_MEM, addr, addr, NO_IRQ, flags);}static int __init add_legacy_isa_port(struct device_node *np,				      struct device_node *isa_brg){	u32 *reg;	char *typep;	int index = -1;	phys_addr_t taddr;	/* Get the ISA port number */	reg = (u32 *)get_property(np, "reg", NULL);	if (reg == NULL)		return -1;	/* Verify it's an IO port, we don't support anything else */	if (!(reg[0] & 0x00000001))		return -1;	/* Now look for an "ibm,aix-loc" property that gives us ordering	 * if any...	 */	typep = (char *)get_property(np, "ibm,aix-loc", NULL);	/* If we have a location index, then use it */	if (typep && *typep == 'S')		index = simple_strtol(typep+1, NULL, 0) - 1;	/* Translate ISA address */	taddr = of_translate_address(np, reg);	/* Add port, irq will be dealt with later */	return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr, NO_IRQ, UPF_BOOT_AUTOCONF);}#ifdef CONFIG_PCIstatic int __init add_legacy_pci_port(struct device_node *np,				      struct device_node *pci_dev){	phys_addr_t addr, base;	u32 *addrp;	unsigned int flags;	int iotype, index = -1, lindex = 0;	/* We only support ports that have a clock frequency properly	 * encoded in the device-tree (that is have an fcode). Anything	 * else can't be used that early and will be normally probed by	 * the generic 8250_pci driver later on. The reason is that 8250	 * compatible UARTs on PCI need all sort of quirks (port offsets	 * etc...) that this code doesn't know about	 */	if (get_property(np, "clock-frequency", NULL) == NULL)		return -1;	/* Get the PCI address. Assume BAR 0 */	addrp = of_get_pci_address(pci_dev, 0, NULL, &flags);	if (addrp == NULL)		return -1;	/* We only support BAR 0 for now */	iotype = (flags & IORESOURCE_MEM) ? UPIO_MEM : UPIO_PORT;	addr = of_translate_address(pci_dev, addrp);	/* Set the IO base to the same as the translated address for MMIO,	 * or to the domain local IO base for PIO (it will be fixed up later)	 */	if (iotype == UPIO_MEM)		base = addr;	else		base = addrp[2];	/* Try to guess an index... If we have subdevices of the pci dev,	 * we get to their "reg" property	 */	if (np != pci_dev) {		u32 *reg = (u32 *)get_property(np, "reg", NULL);		if (reg && (*reg < 4))			index = lindex = *reg;	}	/* Local index means it's the Nth port in the PCI chip. Unfortunately	 * the offset to add here is device specific. We know about those	 * EXAR ports and we default to the most common case. If your UART	 * doesn't work for these settings, you'll have to add your own special	 * cases here	 */	if (device_is_compatible(pci_dev, "pci13a8,152") ||	    device_is_compatible(pci_dev, "pci13a8,154") ||	    device_is_compatible(pci_dev, "pci13a8,158")) {		addr += 0x200 * lindex;		base += 0x200 * lindex;	} else {		addr += 8 * lindex;		base += 8 * lindex;	}	/* Add port, irq will be dealt with later. We passed a translated	 * IO port value. It will be fixed up later along with the irq	 */	return add_legacy_port(np, index, iotype, base, addr, NO_IRQ, UPF_BOOT_AUTOCONF);}#endifstatic void __init setup_legacy_serial_console(int console){	struct legacy_serial_info *info =		&legacy_serial_infos[console];	void __iomem *addr;	if (info->taddr == 0)		return;	addr = ioremap(info->taddr, 0x1000);	if (addr == NULL)		return;	if (info->speed == 0)		info->speed = udbg_probe_uart_speed(addr, info->clock);	DBG("default console speed = %d\n", info->speed);	udbg_init_uart(addr, info->speed, info->clock);}/* * This is called very early, as part of setup_system() or eventually * setup_arch(), basically before anything else in this file. This function * will try to build a list of all the available 8250-compatible serial ports * in the machine using the Open Firmware device-tree. It currently only deals * with ISA and PCI busses but could be extended. It allows a very early boot * console to be initialized, that list is also used later to provide 8250 with * the machine non-PCI ports and to properly pick the default console port */void __init find_legacy_serial_ports(void){	struct device_node *np, *stdout = NULL;	char *path;	int index;	DBG(" -> find_legacy_serial_port()\n");	/* Now find out if one of these is out firmware console */	path = (char *)get_property(of_chosen, "linux,stdout-path", NULL);	if (path != NULL) {		stdout = of_find_node_by_path(path);		if (stdout)

⌨️ 快捷键说明

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