/*
 * Solaris version
 * Probe a given nexus config space for devices.
 *
 * fd is the file descriptor of the nexus.
 * input_args contains commandline options as specified by the user.
 */
static int
do_probe(nexus_t *nexus, probe_info_t *pinfo)
{
    pcitool_reg_t prg;
    uint32_t bus;
    uint8_t dev;
    uint32_t last_bus = nexus->last_bus;
    uint8_t last_dev = PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT;
    uint8_t first_bus = nexus->first_bus;
    uint8_t first_dev = 0;
    int rval = 0;

    prg.barnum = 0;	/* Config space. */

    /* Must read in 4-byte quantities. */
    prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;

    prg.data = 0;

    /*
     * Loop through all valid bus / dev / func combinations to check for
     * all devices, with the following exceptions:
     *
     * When nothing is found at function 0 of a bus / dev combination, skip
     * the other functions of that bus / dev combination.
     *
     * When a found device's function 0 is probed and it is determined that
     * it is not a multifunction device, skip probing of that device's
     * other functions.
     */
    for (bus = first_bus; ((bus <= last_bus) && (rval == 0)); bus++) {
	prg.bus_no = (uint8_t)bus;

	for (dev = first_dev; ((dev <= last_dev) && (rval == 0)); dev++) {
	    prg.dev_no = dev;
	    rval = probe_dev(nexus, &prg, pinfo);
	}

	/*
	 * Ultra-45 southbridge workaround:
	 * ECANCELED tells to skip to the next bus.
	 */
	if (rval == ECANCELED) {
	    rval = 0;
	}
    }

    return (rval);
}
Esempio n. 2
0
static void *_monitor_thread(void *arg)
{
	int fd = open_udp_listenfd(VIRTUAL_SWITCH_BOX_LISTEN_PORT);
	fd_set rset;
	int ret;
	struct timeval tv;
	struct sockaddr_in mc_addr, dev_addr;
	socklen_t mc_len = sizeof(mc_addr);
	socklen_t dev_len = sizeof(dev_addr);
	uint8_t sbuf[16], rbuf[16];
	int cmd_len;

	set_broadcast(fd, true);

	get_broadcast_address(fd, &mc_addr.sin_addr);
	mc_addr.sin_family = AF_INET;
	mc_addr.sin_port = htons(VIRTUAL_SWITCH_LISTEN_PORT);

	while (1) {
		FD_ZERO(&rset);
		FD_SET(fd, &rset);
		tv.tv_sec = 2;
		tv.tv_usec = 0;

		ret = select(fd+1, &rset, NULL, NULL, &tv);

		if (ret < 0)
			continue;

		if (0 == ret) {	/* timeout, send keep alive */

			_remove_timeout_dev();

			memset(sbuf, 0, sizeof(sbuf));

			cmd_len = 4;
			SET_CMD_FIELD(sbuf, 0, uint16_t, VS_CMD_KEEP_ALIVE);
			SET_CMD_FIELD(sbuf, 2, uint16_t, cmd_len);
			
			sendto(fd, sbuf, cmd_len, 0, (struct sockaddr *)&mc_addr, mc_len);
			continue;
		}

		cmd_len = 16;
		/* get message */
		dev_len = sizeof(struct sockaddr_in);
		ret = recvfrom(fd, rbuf, cmd_len, 0, (struct sockaddr *)&dev_addr, &dev_len);

		if (ret < 4)
			continue;

		uint16_t cmd = GET_CMD_FIELD(rbuf, 0, uint16_t);
		uint16_t len = GET_CMD_FIELD(rbuf, 2, uint16_t);

		if (len != ret) {
			hsb_debug("error cmd: %d, %d\n", len, ret);
			continue;
		}

		//hsb_debug("get a cmd: %x\n", cmd);

		VS_DEV_T *pdev = _find_dev_by_ip(&dev_addr.sin_addr);
		if (!pdev) {
			probe_dev(virtual_switch_drv.id);
			continue;
		}

		switch (cmd) {
			case VS_CMD_KEEP_ALIVE:
			{
				break;
			}
			case VS_CMD_STATUS_CHANGED:
			{
				uint16_t id = GET_CMD_FIELD(rbuf, 4, uint16_t);
				uint16_t val = GET_CMD_FIELD(rbuf, 6, uint16_t);

				_status_updated(pdev->id, id, val);
				break;
			}
			case VS_CMD_EVENT:
			{
				uint16_t id = GET_CMD_FIELD(rbuf, 4, uint16_t);
				uint16_t param = GET_CMD_FIELD(rbuf, 6, uint16_t);
				uint32_t param2 = GET_CMD_FIELD(rbuf, 8, uint32_t);

				_event(pdev->id, id, param, param2);
				break;
			}
			default:
				break;
		}
	
		_refresh_device(pdev);
	}

	return NULL;
}