/* Callback from VMBUS subsystem when new channel created. */ static void hv_uio_new_channel(struct vmbus_channel *new_sc) { struct hv_device *hv_dev = new_sc->primary_channel->device_obj; struct device *device = &hv_dev->device; const size_t ring_bytes = HV_RING_SIZE * PAGE_SIZE; int ret; /* Create host communication ring */ ret = vmbus_open(new_sc, ring_bytes, ring_bytes, NULL, 0, hv_uio_channel_cb, new_sc); if (ret) { dev_err(device, "vmbus_open subchannel failed: %d\n", ret); return; } /* Disable interrupts on sub channel */ new_sc->inbound.ring_buffer->interrupt_mask = 1; set_channel_read_mode(new_sc, HV_CALL_ISR); ret = sysfs_create_bin_file(&new_sc->kobj, &ring_buffer_bin_attr); if (ret) { dev_err(device, "sysfs create ring bin file failed; %d\n", ret); vmbus_close(new_sc); } }
static int hv_kbd_probe(struct hv_device *hv_dev, const struct hv_vmbus_device_id *dev_id) { struct hv_kbd_dev *kbd_dev; struct serio *hv_serio; int error; kbd_dev = kzalloc(sizeof(struct hv_kbd_dev), GFP_KERNEL); hv_serio = kzalloc(sizeof(struct serio), GFP_KERNEL); if (!kbd_dev || !hv_serio) { error = -ENOMEM; goto err_free_mem; } kbd_dev->hv_dev = hv_dev; kbd_dev->hv_serio = hv_serio; spin_lock_init(&kbd_dev->lock); init_completion(&kbd_dev->wait_event); hv_set_drvdata(hv_dev, kbd_dev); hv_serio->dev.parent = &hv_dev->device; hv_serio->id.type = SERIO_8042_XL; hv_serio->port_data = kbd_dev; strlcpy(hv_serio->name, dev_name(&hv_dev->device), sizeof(hv_serio->name)); strlcpy(hv_serio->phys, dev_name(&hv_dev->device), sizeof(hv_serio->phys)); hv_serio->start = hv_kbd_start; hv_serio->stop = hv_kbd_stop; error = vmbus_open(hv_dev->channel, KBD_VSC_SEND_RING_BUFFER_SIZE, KBD_VSC_RECV_RING_BUFFER_SIZE, NULL, 0, hv_kbd_on_channel_callback, hv_dev); if (error) goto err_free_mem; error = hv_kbd_connect_to_vsp(hv_dev); if (error) goto err_close_vmbus; serio_register_port(kbd_dev->hv_serio); device_init_wakeup(&hv_dev->device, true); return 0; err_close_vmbus: vmbus_close(hv_dev->channel); err_free_mem: kfree(hv_serio); kfree(kbd_dev); return error; }
/* Connect to VSP (Virtual Service Provider) on host */ static int synthvid_connect_vsp(struct hv_device *hdev) { struct fb_info *info = hv_get_drvdata(hdev); struct hvfb_par *par = info->par; int ret; ret = vmbus_open(hdev->channel, RING_BUFSIZE, RING_BUFSIZE, NULL, 0, synthvid_receive, hdev); if (ret) { pr_err("Unable to open vmbus channel\n"); return ret; } /* Negotiate the protocol version with host */ if (vmbus_proto_version == VERSION_WS2008 || vmbus_proto_version == VERSION_WIN7) ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN7); else ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8); if (ret) { pr_err("Synthetic video device version not accepted\n"); goto error; } if (par->synthvid_version == SYNTHVID_VERSION_WIN7) screen_depth = SYNTHVID_DEPTH_WIN7; else screen_depth = SYNTHVID_DEPTH_WIN8; screen_fb_size = hdev->channel->offermsg.offer. mmio_megabytes * 1024 * 1024; return 0; error: vmbus_close(hdev->channel); return ret; }
static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size) { struct vmstorage_channel_properties props; int ret; memset(&props, 0, sizeof(struct vmstorage_channel_properties)); /* Open the channel */ ret = vmbus_open(device->channel, ring_size, ring_size, (void *)&props, sizeof(struct vmstorage_channel_properties), storvsc_on_channel_callback, device); if (ret != 0) return -1; ret = storvsc_channel_init(device); return ret; }
/* * netvsc_device_add - Callback when the device belonging to this * driver is added */ int netvsc_device_add(struct hv_device *device, void *additional_info) { int ret = 0; int ring_size = ((struct netvsc_device_info *)additional_info)->ring_size; struct netvsc_device *net_device; struct net_device *ndev; net_device = alloc_net_device(device); if (!net_device) return -ENOMEM; net_device->ring_size = ring_size; /* * Coming into this function, struct net_device * is * registered as the driver private data. * In alloc_net_device(), we register struct netvsc_device * * as the driver private data and stash away struct net_device * * in struct netvsc_device *. */ ndev = net_device->ndev; /* Add netvsc_device context to netvsc_device */ net_device->nd_ctx = netdev_priv(ndev); /* Initialize the NetVSC channel extension */ init_completion(&net_device->channel_init_wait); set_per_channel_state(device->channel, net_device->cb_buffer); /* Open the channel */ ret = vmbus_open(device->channel, ring_size * PAGE_SIZE, ring_size * PAGE_SIZE, NULL, 0, netvsc_channel_cb, device->channel); if (ret != 0) { netdev_err(ndev, "unable to open channel: %d\n", ret); goto cleanup; } /* Channel is opened */ pr_info("hv_netvsc channel opened successfully\n"); net_device->chn_table[0] = device->channel; /* Connect with the NetVsp */ ret = netvsc_connect_vsp(device); if (ret != 0) { netdev_err(ndev, "unable to connect to NetVSP - %d\n", ret); goto close; } return ret; close: /* Now, we can close the channel safely */ vmbus_close(device->channel); cleanup: free_netvsc_device(net_device); return ret; }
static int hv_uio_probe(struct hv_device *dev, const struct hv_vmbus_device_id *dev_id) { struct hv_uio_private_data *pdata; int ret; pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; ret = vmbus_open(dev->channel, HV_RING_SIZE * PAGE_SIZE, HV_RING_SIZE * PAGE_SIZE, NULL, 0, hv_uio_channel_cb, pdata); if (ret) goto fail; /* Communicating with host has to be via shared memory not hypercall */ if (!dev->channel->offermsg.monitor_allocated) { dev_err(&dev->device, "vmbus channel requires hypercall\n"); ret = -ENOTSUPP; goto fail_close; } dev->channel->inbound.ring_buffer->interrupt_mask = 1; set_channel_read_mode(dev->channel, HV_CALL_ISR); /* Fill general uio info */ pdata->info.name = "uio_hv_generic"; pdata->info.version = DRIVER_VERSION; pdata->info.irqcontrol = hv_uio_irqcontrol; pdata->info.irq = UIO_IRQ_CUSTOM; /* mem resources */ pdata->info.mem[TXRX_RING_MAP].name = "txrx_rings"; pdata->info.mem[TXRX_RING_MAP].addr = (phys_addr_t)dev->channel->ringbuffer_pages; pdata->info.mem[TXRX_RING_MAP].size = dev->channel->ringbuffer_pagecount << PAGE_SHIFT; pdata->info.mem[TXRX_RING_MAP].memtype = UIO_MEM_LOGICAL; pdata->info.mem[INT_PAGE_MAP].name = "int_page"; pdata->info.mem[INT_PAGE_MAP].addr = (phys_addr_t)vmbus_connection.int_page; pdata->info.mem[INT_PAGE_MAP].size = PAGE_SIZE; pdata->info.mem[INT_PAGE_MAP].memtype = UIO_MEM_LOGICAL; pdata->info.mem[MON_PAGE_MAP].name = "monitor_page"; pdata->info.mem[MON_PAGE_MAP].addr = (phys_addr_t)vmbus_connection.monitor_pages[1]; pdata->info.mem[MON_PAGE_MAP].size = PAGE_SIZE; pdata->info.mem[MON_PAGE_MAP].memtype = UIO_MEM_LOGICAL; pdata->recv_buf = vzalloc(RECV_BUFFER_SIZE); if (pdata->recv_buf == NULL) { ret = -ENOMEM; goto fail_close; } ret = vmbus_establish_gpadl(dev->channel, pdata->recv_buf, RECV_BUFFER_SIZE, &pdata->recv_gpadl); if (ret) goto fail_close; /* put Global Physical Address Label in name */ snprintf(pdata->recv_name, sizeof(pdata->recv_name), "recv:%u", pdata->recv_gpadl); pdata->info.mem[RECV_BUF_MAP].name = pdata->recv_name; pdata->info.mem[RECV_BUF_MAP].addr = (phys_addr_t)pdata->recv_buf; pdata->info.mem[RECV_BUF_MAP].size = RECV_BUFFER_SIZE; pdata->info.mem[RECV_BUF_MAP].memtype = UIO_MEM_VIRTUAL; pdata->send_buf = vzalloc(SEND_BUFFER_SIZE); if (pdata->send_buf == NULL) { ret = -ENOMEM; goto fail_close; } ret = vmbus_establish_gpadl(dev->channel, pdata->send_buf, SEND_BUFFER_SIZE, &pdata->send_gpadl); if (ret) goto fail_close; snprintf(pdata->send_name, sizeof(pdata->send_name), "send:%u", pdata->send_gpadl); pdata->info.mem[SEND_BUF_MAP].name = pdata->send_name; pdata->info.mem[SEND_BUF_MAP].addr = (phys_addr_t)pdata->send_buf; pdata->info.mem[SEND_BUF_MAP].size = SEND_BUFFER_SIZE; pdata->info.mem[SEND_BUF_MAP].memtype = UIO_MEM_VIRTUAL; pdata->info.priv = pdata; pdata->device = dev; ret = uio_register_device(&dev->device, &pdata->info); if (ret) { dev_err(&dev->device, "hv_uio register failed\n"); goto fail_close; } vmbus_set_chn_rescind_callback(dev->channel, hv_uio_rescind); hv_set_drvdata(dev, pdata); return 0; fail_close: hv_uio_cleanup(dev, pdata); vmbus_close(dev->channel); fail: kfree(pdata); return ret; }
static int mousevsc_probe(struct hv_device *device, const struct hv_vmbus_device_id *dev_id) { int ret; struct mousevsc_dev *input_dev; struct hid_device *hid_dev; input_dev = mousevsc_alloc_device(device); if (!input_dev) return -ENOMEM; ret = vmbus_open(device->channel, INPUTVSC_SEND_RING_BUFFER_SIZE, INPUTVSC_RECV_RING_BUFFER_SIZE, NULL, 0, mousevsc_on_channel_callback, device ); if (ret) goto probe_err0; ret = mousevsc_connect_to_vsp(device); if (ret) goto probe_err1; /* workaround SA-167 */ if (input_dev->report_desc[14] == 0x25) input_dev->report_desc[14] = 0x29; hid_dev = hid_allocate_device(); if (IS_ERR(hid_dev)) { ret = PTR_ERR(hid_dev); goto probe_err1; } hid_dev->ll_driver = &mousevsc_ll_driver; hid_dev->driver = &mousevsc_hid_driver; hid_dev->bus = BUS_VIRTUAL; hid_dev->vendor = input_dev->hid_dev_info.vendor; hid_dev->product = input_dev->hid_dev_info.product; hid_dev->version = input_dev->hid_dev_info.version; input_dev->hid_device = hid_dev; sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse"); hid_set_drvdata(hid_dev, device); ret = hid_add_device(hid_dev); if (ret) goto probe_err1; ret = hid_parse(hid_dev); if (ret) { hid_err(hid_dev, "parse failed\n"); goto probe_err2; } ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV); if (ret) { hid_err(hid_dev, "hw start failed\n"); goto probe_err2; } input_dev->connected = true; input_dev->init_complete = true; return ret; probe_err2: hid_destroy_device(hid_dev); probe_err1: vmbus_close(device->channel); probe_err0: mousevsc_free_device(input_dev); return ret; }
/* * netvsc_device_add - Callback when the device belonging to this * driver is added */ int netvsc_device_add(struct hv_device *device, void *additional_info) { int i, ret = 0; int ring_size = ((struct netvsc_device_info *)additional_info)->ring_size; struct netvsc_device *net_device; struct net_device *ndev = hv_get_drvdata(device); struct net_device_context *net_device_ctx = netdev_priv(ndev); net_device = alloc_net_device(); if (!net_device) return -ENOMEM; net_device->ring_size = ring_size; /* Initialize the NetVSC channel extension */ init_completion(&net_device->channel_init_wait); set_per_channel_state(device->channel, net_device->cb_buffer); /* Open the channel */ ret = vmbus_open(device->channel, ring_size * PAGE_SIZE, ring_size * PAGE_SIZE, NULL, 0, netvsc_channel_cb, device->channel); if (ret != 0) { netdev_err(ndev, "unable to open channel: %d\n", ret); goto cleanup; } /* Channel is opened */ pr_info("hv_netvsc channel opened successfully\n"); /* If we're reopening the device we may have multiple queues, fill the * chn_table with the default channel to use it before subchannels are * opened. */ for (i = 0; i < VRSS_CHANNEL_MAX; i++) net_device->chn_table[i] = device->channel; /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is * populated. */ wmb(); net_device_ctx->nvdev = net_device; /* Connect with the NetVsp */ ret = netvsc_connect_vsp(device); if (ret != 0) { netdev_err(ndev, "unable to connect to NetVSP - %d\n", ret); goto close; } return ret; close: /* Now, we can close the channel safely */ vmbus_close(device->channel); cleanup: free_netvsc_device(net_device); return ret; }