/* Register a device */ int drvmgr_dev_register(struct drvmgr_dev *dev) { struct rtems_driver_manager *mgr = &drv_mgr; struct drvmgr_drv *drv; struct drvmgr_bus *bus = dev->parent; struct drvmgr_key *keys; struct drvmgr_list *init_list = &mgr->devices_inactive; DBG("DEV_REG: %s at bus \"%s\"\n", dev->name, bus && bus->dev && bus->dev->name ? bus->dev->name : "UNKNOWN"); /* Custom driver assocation? */ if (dev->drv) { drv = dev->drv; DBG("CUSTOM ASSOCIATION (%s to %s)\n", dev->name, drv->name); } else { /* Try to find a driver that can handle this device */ dev->drv = drv = drvmgr_dev_find_drv(dev); } DRVMGR_LOCK_WRITE(); /* Assign Bus Minor number and put into bus device list * unless root device. */ if (bus) drvmgr_insert_dev_into_bus(bus, dev); if (!drv) { /* No driver found that can handle this device, put into * inactive list */ dev->minor_drv = -1; dev->state |= DEV_STATE_LIST_INACTIVE; } else { /* United device with driver. * Put the device on the registered device list */ dev->state |= DEV_STATE_UNITED; /* Check if user want to skip this core. This is not a * normal request, however in a multi-processor system * the two(or more) RTEMS instances must not use the same * devices in a system, not reporting a device to * it's driver will effectively accomplish this. In a * non Plug & Play system one can easily avoid this * problem by not report the core, but in a Plug & Play * system the bus driver will report all found cores. * * To stop the two RTEMS instances from using the same * device the user can simply define a resource entry * for a certain device but set the keys field to NULL. */ if (drvmgr_keys_get(dev, &keys) == 0 && keys == NULL) { /* Found Driver resource entry point * for this device, it was NULL, this * indicates to skip the core. * * We put it into the inactive list * marking it as ignored. */ dev->state |= DEV_STATE_IGNORED; } else { /* Assign Driver Minor number and put into driver's * device list */ drvmgr_insert_dev_into_drv(drv, dev); /* Just register device, it will be initialized * later together with bus. * * At the end of the list (breadth first search) */ init_list = &mgr->devices[0]; DBG("Registered %s (DRV: %s) on %s\n", dev->name, drv->name, bus ? bus->dev->name : "NO PARENT"); } } drvmgr_list_add_tail(init_list, dev); DRVMGR_UNLOCK(); /* Trigger Device initialization if not root device and * has a driver */ if (bus && dev->drv) drvmgr_init_update(); return 0; }
int apbuart_init1(struct drvmgr_dev *dev) { struct apbuart_priv *priv; struct amba_dev_info *ambadev; struct ambapp_core *pnpinfo; union drvmgr_key_value *value; char prefix[32]; unsigned int db; static int first_uart = 1; /* The default operation in AMP is to use APBUART[0] for CPU[0], * APBUART[1] for CPU[1] and so on. The remaining UARTs is not used * since we don't know how many CPU-cores there are. Note this only * affects the on-chip amba bus (the root bus). The user can override * the default resource sharing by defining driver resources for the * APBUART devices on each AMP OS instance. */ #if defined(RTEMS_MULTIPROCESSING) && defined(LEON3) if (drvmgr_on_rootbus(dev) && dev->minor_drv != LEON3_Cpu_Index && drvmgr_keys_get(dev, NULL) != 0) { /* User hasn't configured on-chip APBUART, leave it untouched */ return DRVMGR_EBUSY; } #endif DBG("APBUART[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); /* Private data was allocated and zeroed by driver manager */ priv = dev->priv; if (!priv) return DRVMGR_NOMEM; priv->dev = dev; /* Get device information from AMBA PnP information */ ambadev = (struct amba_dev_info *)priv->dev->businfo; if (ambadev == NULL) return -1; pnpinfo = &ambadev->info; priv->regs = (struct apbuart_regs *)pnpinfo->apb_slv->start; /* Clear HW regs, leave baudrate register as it is */ priv->regs->status = 0; /* leave Transmitter/receiver if this is the RTEMS debug UART (assume * it has been setup by boot loader). */ db = 0; #ifdef LEON3 if (priv->regs == leon3_debug_uart) { db = priv->regs->ctrl & (LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE | LEON_REG_UART_CTRL_PE | LEON_REG_UART_CTRL_PS); } #endif /* Let UART debug tunnelling be untouched if Flow-control is set. * * With old APBUARTs debug is enabled by setting LB and FL, since LB or * DB are not reset we can not trust them. However since FL is reset we * guess that we are debugging if FL is already set, the debugger set * either LB or DB depending on UART capabilities. */ if (priv->regs->ctrl & LEON_REG_UART_CTRL_FL) { db |= priv->regs->ctrl & (LEON_REG_UART_CTRL_DB | LEON_REG_UART_CTRL_LB | LEON_REG_UART_CTRL_FL); } priv->regs->ctrl = db; priv->cap = probecap(priv->regs); /* The system console and Debug console may depend on this device, so * initialize it straight away. * * We default to have System Console on first APBUART, user may override * this behaviour by setting the syscon option to 0. */ if (drvmgr_on_rootbus(dev) && first_uart) { priv->condev.flags = CONSOLE_FLAG_SYSCON; first_uart = 0; } else { priv->condev.flags = 0; } value = drvmgr_dev_key_get(priv->dev, "syscon", DRVMGR_KT_INT); if (value) { if (value->i) priv->condev.flags |= CONSOLE_FLAG_SYSCON; else priv->condev.flags &= ~CONSOLE_FLAG_SYSCON; } /* Select 0=Polled, 1=IRQ, 2=Task-Driven UART Mode */ value = drvmgr_dev_key_get(priv->dev, "mode", DRVMGR_KT_INT); if (value) priv->mode = value->i; else priv->mode = TERMIOS_POLLED; /* TERMIOS device handlers */ if (priv->mode == TERMIOS_IRQ_DRIVEN) { priv->condev.handler = &handler_interrupt; } else if (priv->mode == TERMIOS_TASK_DRIVEN) { priv->condev.handler = &handler_task; } else { priv->condev.handler = &handler_polled; } priv->condev.fsname = NULL; /* Get Filesystem name prefix */ prefix[0] = '\0'; if (drvmgr_get_dev_prefix(dev, prefix)) { /* Got special prefix, this means we have a bus prefix * And we should use our "bus minor" */ sprintf(priv->devName, "/dev/%sapbuart%d", prefix, dev->minor_bus); priv->condev.fsname = priv->devName; } else { sprintf(priv->devName, "/dev/apbuart%d", dev->minor_drv); } /* Register it as a console device, the console driver will register * a termios device as well */ console_dev_register(&priv->condev); return DRVMGR_OK; }