Example #1
0
static int cmd_rbd_list(struct vmm_chardev *cdev)
{
	int num, count;
	char addr[32], size[32];
	struct rbd *d;

	vmm_cprintf(cdev, "----------------------------------------"
			  "----------------------------------------\n");
	vmm_cprintf(cdev, " %-32s %-22s %-22s\n", 
			  "Name", "Physical Address", "Physical Size");
	vmm_cprintf(cdev, "----------------------------------------"
			  "----------------------------------------\n");
	count = rbd_count();
	for (num = 0; num < count; num++) {
		d = rbd_get(num);
		vmm_snprintf(addr, sizeof(addr), "0x%"PRIPADDR, d->addr);
		vmm_snprintf(size, sizeof(size), "0x%"PRIPADDR, d->size);
		vmm_cprintf(cdev, " %-32s %-22s %-22s\n",
			    d->bdev->name, addr, size);
	}
	vmm_cprintf(cdev, "----------------------------------------"
			  "----------------------------------------\n");

	return VMM_OK;
}
Example #2
0
static void vmm_fb_cvt_print_name(struct vmm_fb_cvt_data *cvt)
{
	u32 pixcount, pixcount_mod;
	int cnt = 255, offset = 0, read = 0;
	char *buf = vmm_zalloc(256);

	if (!buf)
		return;

	pixcount = (cvt->xres * udiv32(cvt->yres, cvt->interlace))/1000000;
	pixcount_mod = (cvt->xres * udiv32(cvt->yres, cvt->interlace)) % 1000000;
	pixcount_mod /= 1000;

	read = vmm_snprintf(buf+offset, cnt, "fbcvt: %dx%d@%d: CVT Name - ",
			cvt->xres, cvt->yres, cvt->refresh);
	offset += read;
	cnt -= read;

	if (cvt->status)
		vmm_snprintf(buf+offset, cnt, "Not a CVT standard - %d.%03d Mega "
			 "Pixel Image\n", pixcount, pixcount_mod);
	else {
		if (pixcount) {
			read = vmm_snprintf(buf+offset, cnt, "%d", pixcount);
			cnt -= read;
			offset += read;
		}

		read = vmm_snprintf(buf+offset, cnt, ".%03dM", pixcount_mod);
		cnt -= read;
		offset += read;

		if (cvt->aspect_ratio == 0)
			read = vmm_snprintf(buf+offset, cnt, "3");
		else if (cvt->aspect_ratio == 3)
			read = vmm_snprintf(buf+offset, cnt, "4");
		else if (cvt->aspect_ratio == 1 || cvt->aspect_ratio == 4)
			read = vmm_snprintf(buf+offset, cnt, "9");
		else if (cvt->aspect_ratio == 2)
			read = vmm_snprintf(buf+offset, cnt, "A");
		else
			read = 0;
		cnt -= read;
		offset += read;

		if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) {
			read = vmm_snprintf(buf+offset, cnt, "-R");
			cnt -= read;
			offset += read;
		}
	}

	vmm_printf("%s\n", buf);
	vmm_free(buf);
}
Example #3
0
int __cpuinit vmm_scheduler_init(void)
{
	int rc;
	char vcpu_name[VMM_FIELD_NAME_SIZE];
	u32 cpu = vmm_smp_processor_id();
	struct vmm_scheduler_ctrl *schedp = &this_cpu(sched);

	/* Reset the scheduler control structure */
	memset(schedp, 0, sizeof(struct vmm_scheduler_ctrl));

	/* Create ready queue (Per Host CPU) */
	schedp->rq = vmm_schedalgo_rq_create();
	if (!schedp->rq) {
		return VMM_EFAIL;
	}
	INIT_SPIN_LOCK(&schedp->rq_lock);

	/* Initialize current VCPU. (Per Host CPU) */
	schedp->current_vcpu = NULL;

	/* Initialize IRQ state (Per Host CPU) */
	schedp->irq_context = FALSE;
	schedp->irq_regs = NULL;

	/* Initialize yield on exit (Per Host CPU) */
	schedp->yield_on_irq_exit = FALSE;

	/* Create timer event and start it. (Per Host CPU) */
	INIT_TIMER_EVENT(&schedp->ev, &vmm_scheduler_timer_event, schedp);

	/* Create idle orphan vcpu with default time slice. (Per Host CPU) */
	vmm_snprintf(vcpu_name, sizeof(vcpu_name), "idle/%d", cpu);
	schedp->idle_vcpu = vmm_manager_vcpu_orphan_create(vcpu_name,
						(virtual_addr_t)&idle_orphan,
						IDLE_VCPU_STACK_SZ,
						IDLE_VCPU_PRIORITY, 
						IDLE_VCPU_TIMESLICE);
	if (!schedp->idle_vcpu) {
		return VMM_EFAIL;
	}

	/* The idle vcpu need to stay on this cpu */
	if ((rc = vmm_manager_vcpu_set_affinity(schedp->idle_vcpu,
						vmm_cpumask_of(cpu)))) {
		return rc;
	}

	/* Kick idle orphan vcpu */
	if ((rc = vmm_manager_vcpu_kick(schedp->idle_vcpu))) {
		return rc;
	}

	/* Start scheduler timer event */
	vmm_timer_event_start(&schedp->ev, 0);

	/* Mark this CPU online */
	vmm_set_cpu_online(cpu, TRUE);

	return VMM_OK;
}
Example #4
0
static int virtio_pci_bar_probe(struct vmm_guest *guest,
				struct vmm_emudev *edev,
				const struct vmm_devtree_nodeid *eid)
{
	int rc = VMM_OK;
	struct virtio_pci_dev *vdev;

	vdev = vmm_zalloc(sizeof(struct virtio_pci_dev));
	if (!vdev) {
		rc = VMM_ENOMEM;
		goto virtio_pci_probe_done;
	}

	vdev->guest = guest;

	vmm_snprintf(vdev->dev.name, VMM_VIRTIO_DEVICE_MAX_NAME_LEN,
		     "%s/%s", guest->name, edev->node->name);
	vdev->dev.edev = edev;
	vdev->dev.tra = &pci_tra;
	vdev->dev.tra_data = vdev;
	vdev->dev.guest = guest;

	vdev->config = (struct vmm_virtio_pci_config) {
		.queue_num  = 256,
	};

	rc = vmm_devtree_read_u32(edev->node, "virtio_type",
				  &vdev->dev.id.type);
	if (rc) {
		goto virtio_pci_probe_freestate_fail;
	}

	rc = vmm_devtree_read_u32_atindex(edev->node,
					  VMM_DEVTREE_INTERRUPTS_ATTR_NAME,
					  &vdev->irq, 0);
	if (rc) {
		goto virtio_pci_probe_freestate_fail;
	}

	if ((rc = vmm_virtio_register_device(&vdev->dev))) {
		goto virtio_pci_probe_freestate_fail;
	}

	edev->priv = vdev;

	goto virtio_pci_probe_done;

virtio_pci_probe_freestate_fail:
	vmm_free(vdev);
virtio_pci_probe_done:
	return rc;
}

static struct vmm_devtree_nodeid virtio_pci_emuid_table[] = {
	{
		.type = "virtio",
		.compatible = "virtio,pci",
	},
	{ /* end of list */ },
};
Example #5
0
static int virtio_mmio_probe(struct vmm_guest *guest,
			     struct vmm_emudev *edev,
			     const struct vmm_devtree_nodeid *eid)
{
	int rc = VMM_OK;
	const char *attr;
	struct virtio_mmio_dev *m;

	m = vmm_zalloc(sizeof(struct virtio_mmio_dev));
	if (!m) {
		rc = VMM_EFAIL;
		goto virtio_mmio_probe_done;
	}

	m->guest = guest;

	vmm_snprintf(m->dev.name, VIRTIO_DEVICE_MAX_NAME_LEN, 
		     "%s/%s", guest->name, edev->node->name); 
	m->dev.edev = edev;
	m->dev.tra = &mmio_tra;
	m->dev.tra_data = m;
	m->dev.guest = guest;

	m->config = (struct virtio_mmio_config) {
		     .magic          = {'v', 'i', 'r', 't'},
		     .version        = 1,
		     .vendor_id      = 0x52535658, /* XVSR */
		     .queue_num_max  = 256,
	};

	attr = vmm_devtree_attrval(edev->node, "virtio_type");
	if (attr) {
		m->config.device_id = *((u32 *)attr);
	} else {
		rc = VMM_EFAIL;
		goto virtio_mmio_probe_freestate_fail;
	}

	m->dev.id.type = m->config.device_id;

	rc = vmm_devtree_irq_get(edev->node, &m->irq, 0);
	if (rc) {
		goto virtio_mmio_probe_freestate_fail;
	}

	if ((rc = virtio_register_device(&m->dev))) {
		goto virtio_mmio_probe_freestate_fail;
	}

	edev->priv = m;

	goto virtio_mmio_probe_done;

virtio_mmio_probe_freestate_fail:
	vmm_free(m);
virtio_mmio_probe_done:
	return rc;
}
Example #6
0
static int virtio_mmio_probe(struct vmm_guest *guest,
			     struct vmm_emudev *edev,
			     const struct vmm_devtree_nodeid *eid)
{
	int rc = VMM_OK;
	struct virtio_mmio_dev *m;

	m = vmm_zalloc(sizeof(struct virtio_mmio_dev));
	if (!m) {
		rc = VMM_ENOMEM;
		goto virtio_mmio_probe_done;
	}

	m->guest = guest;

	vmm_snprintf(m->dev.name, VMM_VIRTIO_DEVICE_MAX_NAME_LEN, 
		     "%s/%s", guest->name, edev->node->name); 
	m->dev.edev = edev;
	m->dev.tra = &mmio_tra;
	m->dev.tra_data = m;
	m->dev.guest = guest;

	m->config = (struct vmm_virtio_mmio_config) {
		     .magic          = {'v', 'i', 'r', 't'},
		     .version        = 1,
		     .vendor_id      = 0x52535658, /* XVSR */
		     .queue_num_max  = 256,
	};

	rc = vmm_devtree_read_u32(edev->node, "virtio_type",
				  &m->config.device_id);
	if (rc) {
		goto virtio_mmio_probe_freestate_fail;
	}

	m->dev.id.type = m->config.device_id;

	rc = vmm_devtree_read_u32_atindex(edev->node,
					  VMM_DEVTREE_INTERRUPTS_ATTR_NAME,
					  &m->irq, 0);
	if (rc) {
		goto virtio_mmio_probe_freestate_fail;
	}

	if ((rc = vmm_virtio_register_device(&m->dev))) {
		goto virtio_mmio_probe_freestate_fail;
	}

	edev->priv = m;

	goto virtio_mmio_probe_done;

virtio_mmio_probe_freestate_fail:
	vmm_free(m);
virtio_mmio_probe_done:
	return rc;
}
Example #7
0
static int cmd_host_cpu_stats(struct vmm_chardev *cdev)
{
	int rc;
	char str[16];
	u32 c, p, khz, util;
	unsigned long hwid;

	vmm_cprintf(cdev, "----------------------------------------"
			  "----------------------------------------\n");
	vmm_cprintf(cdev, " %4s %14s %15s %13s %12s %16s\n",
			  "CPU#", "HWID", "Speed (MHz)", "Util. (%)",
			  "IRQs (%)", "Active VCPUs");
	vmm_cprintf(cdev, "----------------------------------------"
			  "----------------------------------------\n");

	for_each_online_cpu(c) {
		vmm_cprintf(cdev, " %4d", c);

		rc = vmm_smp_map_hwid(c, &hwid);
		if (rc)
			return rc;
		vmm_snprintf(str, sizeof(str), "0x%lx", hwid);
		vmm_cprintf(cdev, " %14s", str);

		khz = vmm_delay_estimate_cpu_khz(c);
		vmm_cprintf(cdev, " %11d.%03d",
			    udiv32(khz, 1000), umod32(khz, 1000));

		util = udiv64(vmm_scheduler_idle_time(c) * 1000,
			      vmm_scheduler_get_sample_period(c));
		util = (util > 1000) ? 1000 : util;
		util = 1000 - util;
		vmm_cprintf(cdev, " %11d.%01d",
			    udiv32(util, 10), umod32(util, 10));

		util = udiv64(vmm_scheduler_irq_time(c) * 1000,
			      vmm_scheduler_get_sample_period(c));
		util = (util > 1000) ? 1000 : util;
		vmm_cprintf(cdev, " %10d.%01d",
			    udiv32(util, 10), umod32(util, 10));

		util = 1;
		for (p = VMM_VCPU_MIN_PRIORITY;
		     p <= VMM_VCPU_MAX_PRIORITY; p++) {
			util += vmm_scheduler_ready_count(c, p);
		}
		vmm_cprintf(cdev, " %15d ", util);

		vmm_cprintf(cdev, "\n");
	}

	vmm_cprintf(cdev, "----------------------------------------"
			  "----------------------------------------\n");

	return VMM_OK;
}
Example #8
0
int vmm_blockdev_add_child(struct vmm_blockdev *bdev, 
			   u64 start_lba, u64 num_blocks)
{
	int rc;
	struct vmm_blockdev *child_bdev;

	if (!bdev) {
		return VMM_EFAIL;
	}

	if (bdev->num_blocks < num_blocks) {
		return VMM_ERANGE;
	}
	if ((start_lba < bdev->start_lba) ||
	    ((bdev->start_lba + bdev->num_blocks) <= start_lba)) {
		return VMM_ERANGE;
	}
	if ((bdev->start_lba + bdev->num_blocks) < (start_lba + num_blocks)) {
		return VMM_ERANGE;
	}

	child_bdev = __blockdev_alloc(FALSE);
	child_bdev->parent = bdev;
	vmm_mutex_lock(&bdev->child_lock);
	vmm_snprintf(child_bdev->name, sizeof(child_bdev->name),
			"%sp%d", bdev->name, bdev->child_count);
	if (strlcpy(child_bdev->desc, bdev->desc, sizeof(child_bdev->desc)) >=
	    sizeof(child_bdev->desc)) {
		rc = VMM_EOVERFLOW;
		goto free_blockdev;
	}
	bdev->child_count++;
	list_add_tail(&child_bdev->head, &bdev->child_list);
	vmm_mutex_unlock(&bdev->child_lock);
	child_bdev->flags = bdev->flags;
	child_bdev->start_lba = start_lba;
	child_bdev->num_blocks = num_blocks;
	child_bdev->block_size = bdev->block_size;
	child_bdev->rq = bdev->rq;

	rc = vmm_blockdev_register(child_bdev);
	if (rc) {
		goto remove_from_list;
	}

	return rc;

remove_from_list:
	vmm_mutex_lock(&bdev->child_lock);
	list_del(&child_bdev->head);
	vmm_mutex_unlock(&bdev->child_lock);
free_blockdev:
	__blockdev_free(child_bdev, FALSE);
	return rc;
}
int u64_to_size_str(u64 val, char *out, size_t out_len)
{
	const char *suffix = "";

	if (!out || (out_len < 16))
		return VMM_EINVALID;

	if (val < SZ_1K) {
		suffix = "B";
		goto found;
	}
	val = val >> 10;

	if (val < SZ_1K) {
		suffix = "KB";
		goto found;
	}
	val = val >> 10;

	if (val < SZ_1K) {
		suffix = "MB";
		goto found;
	}
	val = val >> 10;

	if (val < SZ_1K) {
		suffix = "GB";
		goto found;
	}
	val = val >> 10;

	if (val < SZ_1K) {
		suffix = "TB";
		goto found;
	}
	val = val >> 10;

	if (val < SZ_1K) {
		suffix = "PB";
		goto found;
	}
	val = val >> 10;

	if (val < SZ_1K) {
		suffix = "EB";
		goto found;
	}

	suffix = "ZB";

found:
	vmm_snprintf(out, out_len, "%"PRIu64" %s", val, suffix);

	return VMM_OK;
}
Example #10
0
static int virtio_net_connect(struct virtio_device *dev, 
			      struct virtio_emulator *emu)
{
	int i, rc;
	char *attr;
	struct virtio_net_dev *ndev;
	struct vmm_netswitch *nsw;

	ndev = vmm_zalloc(sizeof(struct virtio_net_dev));
	if (!ndev) {
		vmm_printf("Failed to allocate virtio net device....\n");
		return VMM_EFAIL;
	}

	ndev->vdev = dev;
	vmm_snprintf(ndev->name, VIRTIO_DEVICE_MAX_NAME_LEN, "%s", dev->name);
	ndev->port = vmm_netport_alloc(ndev->name, VMM_NETPORT_DEF_QUEUE_SIZE);
	ndev->port->mtu = VIRTIO_NET_MTU;
	ndev->port->link_changed = virtio_net_set_link;
	ndev->port->can_receive = virtio_net_can_receive;
	ndev->port->switch2port_xfer = virtio_net_switch2port_xfer;
	ndev->port->priv = ndev;

	rc = vmm_netport_register(ndev->port);
	if (rc) {
		vmm_netport_free(ndev->port);
		vmm_free(ndev);
		return rc;
	}

	attr = vmm_devtree_attrval(dev->edev->node, "switch");
	if (attr) {
		nsw = vmm_netswitch_find((char *)attr);
		if (!nsw) {
			vmm_printf("%s: Cannot find netswitch \"%s\"\n",
					__func__, (char *)attr);
		} else {
			vmm_netswitch_port_add(nsw, ndev->port);
		}
	}

	for (i = 0; i < 6; i++) {
		ndev->config.mac[i] = vmm_netport_mac(ndev->port)[i];
	}

	ndev->config.status = VIRTIO_NET_S_LINK_UP;
	dev->emu_data = ndev;

	return VMM_OK;
}
Example #11
0
static int cmd_rbd_list(struct vmm_chardev *cdev)
{
	int num, count;
	char addr[32], size[32];
	struct rbd *d;

	vmm_cprintf(cdev, "----------------------------------------"
			  "----------------------------------------\n");
	vmm_cprintf(cdev, " %-32s %-22s %-22s\n", 
			  "Name", "Physical Address", "Physical Size");
	vmm_cprintf(cdev, "----------------------------------------"
			  "----------------------------------------\n");
	count = rbd_count();
	for (num = 0; num < count; num++) {
		d = rbd_get(num);
		if (sizeof(physical_addr_t) == sizeof(u64)) {
			vmm_snprintf(addr, sizeof(addr),
				     "0x%016llx", (u64)d->addr);
		} else {
			vmm_snprintf(addr, sizeof(addr),
				     "0x%08x", (u32)d->addr);
		}
		if (sizeof(physical_size_t) == sizeof(u64)) {
			vmm_snprintf(size, sizeof(size),
				     "0x%016llx", (u64)d->size);
		} else {
			vmm_snprintf(size, sizeof(size),
				     "0x%08x", (u32)d->size);
		}
		vmm_cprintf(cdev, " %-32s %-22s %-22s\n",
			    d->bdev->name, addr, size);
	}
	vmm_cprintf(cdev, "----------------------------------------"
			  "----------------------------------------\n");

	return VMM_OK;
}
Example #12
0
static struct dir_entry *path_to_dentry(struct vmm_blockdev *mdev,
					const char *path,
					struct dir_entry *pdentry)
{
	char dirname[VFS_MAX_NAME] = { 0 };
	struct dir_entry *dentry, *d_root;
	int i = 0, rd;
	int len = 0;
	char rpath[VFS_MAX_NAME];

	len = strlen(path);

	if (!len) return NULL;

	vmm_snprintf(rpath, len, "%s", path);
	if (rpath[len - 1] != '/') {
		rpath[len] = '/';
		rpath[len+1] = 0;
	}

	path = rpath;

	if (*path == '/') {
		path++;
		if (!*path) return pdentry;
	}

	while (*path && *path != '/') {
		dirname[i] = *path;
		path++;
		i++;
	}

	dentry = lookup_dentry(dirname, pdentry);
	if (dentry) {
		d_root = vmm_zalloc(dentry->dlen.lsb);
		rd = vmm_blockdev_read(mdev, (u8 *)d_root,
				       (dentry->start_lba.lsb * 2048),
				       dentry->dlen.lsb);
		if (rd != dentry->dlen.lsb) {
			vmm_free(d_root);
			return NULL;
		}
		dentry = path_to_dentry(mdev, path, d_root);
	}

	return dentry;
}
Example #13
0
static int gen_hex( struct ud *u )
{
  unsigned int i;
  unsigned char *src_ptr = inp_sess( u );
  char* src_hex;

  /* bail out if in error stat. */
  if ( u->error ) return -1;
  /* output buffer pointe */
  src_hex = ( char* ) u->insn_hexcode;
  /* for each byte used to decode instruction */
  for ( i = 0; i < u->inp_ctr; ++i, ++src_ptr) {
    vmm_snprintf( src_hex, 32, "%02x", *src_ptr & 0xFF );
    src_hex += 2;
  }
  return 0;
}
Example #14
0
static int virtio_blk_connect(struct virtio_device *dev, 
			      struct virtio_emulator *emu)
{
	int rc;
	char *attr;
	struct virtio_blk_dev *bdev;

	bdev = vmm_zalloc(sizeof(struct virtio_blk_dev));
	if (!bdev) {
		vmm_printf("Failed to allocate virtio block device....\n");
		return VMM_ENOMEM;
	}
	bdev->vdev = dev;

	vmm_snprintf(bdev->name, VIRTIO_DEVICE_MAX_NAME_LEN, "%s", dev->name);

	bdev->blk_client.notifier_call = &virtio_blk_notification;
	bdev->blk_client.priority = 0;
	rc = vmm_blockdev_register_client(&bdev->blk_client);
	if (rc) {
		vmm_free(bdev);
		return rc;
	}

	INIT_SPIN_LOCK(&bdev->blk_lock);

	attr = vmm_devtree_attrval(dev->edev->node, "blkdev");
	if (attr) {
		strncpy(bdev->blk_name,attr, VMM_BLOCKDEV_MAX_NAME_SIZE);
		bdev->blk = vmm_blockdev_find(bdev->blk_name);
	} else {
		strncpy(bdev->blk_name,"", VMM_BLOCKDEV_MAX_NAME_SIZE);
		bdev->blk = NULL;
	}

	bdev->config.capacity = (bdev->blk) ? bdev->blk->num_blocks : 0;
	bdev->config.seg_max = VIRTIO_BLK_DISK_SEG_MAX,
	bdev->config.blk_size = 
		(bdev->blk) ? bdev->blk->block_size : VIRTIO_BLK_SECTOR_SIZE;

	dev->emu_data = bdev;

	return VMM_OK;
}
Example #15
0
static int cmd_rtcdev_list_iter(struct rtc_device *rd, void *data)
{
	int rc;
	char path[256];
	struct vmm_chardev *cdev = data;

	if (rd->dev.parent && rd->dev.parent->of_node) {
		rc = vmm_devtree_getpath(path, sizeof(path),
				    rd->dev.parent->of_node);
		if (rc) {
			vmm_snprintf(path, sizeof(path),
				     "----- (error %d)", rc);
		}
	} else {
		strcpy(path, "-----");
	}
	vmm_cprintf(cdev, " %-24s %-53s\n", rd->name, path);

	return VMM_OK;
}
Example #16
0
static int semaphore5_run(struct wboxtest *test, struct vmm_chardev *cdev,
			  u32 test_hcpu)
{
	int i, ret = VMM_OK;
	char wname[VMM_FIELD_NAME_SIZE];
	u8 current_priority = vmm_scheduler_current_priority();
	const struct vmm_cpumask *cpu_mask = vmm_cpumask_of(test_hcpu);

	/* Initialise global data */
	memset(workers, 0, sizeof(workers));

	/* Create worker threads */
	for (i = 0; i < NUM_THREADS; i++) {
		vmm_snprintf(wname, VMM_FIELD_NAME_SIZE,
			     "semaphore5_worker%d", i);
		workers[i] = vmm_threads_create(wname,
						semaphore5_worker_thread_main,
						(void *)(unsigned long)i,
						current_priority,
						VMM_THREAD_DEF_TIME_SLICE);
		if (workers[i] == NULL) {
			ret = VMM_EFAIL;
			goto destroy_workers;
		}
		vmm_threads_set_affinity(workers[i], cpu_mask);
	}

	/* Do the test */
	ret = semaphore5_do_test(cdev);

	/* Destroy worker threads */
destroy_workers:
	for (i = 0; i < NUM_THREADS; i++) {
		if (workers[i]) {
			vmm_threads_destroy(workers[i]);
			workers[i] = NULL;
		}
	}

	return ret;
}
Example #17
0
struct usb_device *usb_alloc_device(struct usb_device *parent,
				    struct usb_hcd *hcd, unsigned port)
{
	int i;
	irq_flags_t flags;
	struct usb_device *dev;

	/* Sanity checks */
	if (parent) {
		if (USB_MAXCHILDREN <= port) {
			return NULL;
		}
		vmm_spin_lock_irqsave(&parent->children_lock, flags);
		if (parent->children[port]) {
			vmm_spin_unlock_irqrestore(&parent->children_lock,
						   flags);
			return NULL;
		}
		vmm_spin_unlock_irqrestore(&parent->children_lock, flags);
	}

	/* Alloc new device */
	dev = vmm_zalloc(sizeof(*dev));
	if (!dev) {
		return NULL;
	}

	/* Initialize devdrv context */
	vmm_devdrv_initialize_device(&dev->dev);
	dev->dev.autoprobe_disabled = TRUE;
	dev->dev.parent = (parent) ? &parent->dev : NULL;
	dev->dev.bus = &usb_bus_type;
	dev->dev.type = &usb_device_type;

	/* Increment reference count of HCD */
	usb_ref_hcd(hcd);

	/* Root hubs aren't true devices, so don't allocate HCD resources */
	if (hcd->driver->alloc_dev && parent &&
		!hcd->driver->alloc_dev(hcd, dev)) {
		usb_dref_hcd(hcd);
		vmm_free(dev);
		return NULL;
	}

	/* Update device state */
	dev->state = USB_STATE_NOTATTACHED;

	/* Update device name, devpath, route, and level */
	if (unlikely(!parent)) {
		dev->devpath[0] = '0';
		dev->route = 0;
		dev->level = 0;
		vmm_snprintf(dev->dev.name, sizeof(dev->dev.name),
			     "usb%d", hcd->bus_num);
	} else {
		if (parent->level == 0) {
			/* Root hub port is not counted in route string
			 * because it is always zero.
			 */
			vmm_snprintf(dev->devpath, sizeof(dev->devpath),
				     "%d", port);
		} else {
			vmm_snprintf(dev->devpath, sizeof(dev->devpath),
				     "%s.%d", parent->devpath, port);
		}
		/* Route string assumes hubs have less than 16 ports */
		if (port < 15) {
			dev->route = parent->route +
				(port << (parent->level * 4));
		} else {
			dev->route = parent->route +
				(15 << (parent->level * 4));
		}
		dev->level = parent->level + 1;
		vmm_snprintf(dev->dev.name, sizeof(dev->dev.name),
			     "usb%d-%s", hcd->bus_num, dev->devpath);
		/* FIXME: hub driver sets up TT records */
		/* Update parent device */
		vmm_spin_lock_irqsave(&parent->children_lock, flags);
		parent->children[port] = dev;
		vmm_spin_unlock_irqrestore(&parent->children_lock, flags);
	}

	/* Update rest of the device fields */
	dev->portnum = port;
	dev->hcd = hcd;
	dev->maxchild = 0;
	INIT_SPIN_LOCK(&dev->children_lock);
	for (i = 0; i < USB_MAXCHILDREN; i++) {
		dev->children[i] = NULL;
	}

	/* Assign device number based on HCD device bitmap
	 * Note: Device number starts from 1.
	 * Note: Device number 0 is default device.
	 */
	vmm_spin_lock_irqsave(&hcd->devicemap_lock, flags);
	dev->devnum = 0;
	for (i = 0; i < USB_MAXCHILDREN; i++) {
		if (!test_bit(i, hcd->devicemap)) {
			__set_bit(i, hcd->devicemap);
			dev->devnum = i + 1;
			break;
		}
	}
	i = dev->devnum;
	vmm_spin_unlock_irqrestore(&hcd->devicemap_lock, flags);
	if (i == 0) {
		usb_dref_hcd(hcd);
		vmm_free(dev);
		return NULL;
	}

	return dev;
}