Exemplo n.º 1
0
/* 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;
}
Exemplo n.º 2
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;
}