/** * dim2_remove - dim2 remove handler * @pdev: platform device structure * * Unregister the interface from mostcore */ static int dim2_remove(struct platform_device *pdev) { struct dim2_hdm *dev = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct dim2_platform_data *pdata = pdev->dev.platform_data; unsigned long flags; spin_lock_irqsave(&dim_lock, flags); dim_shutdown(); spin_unlock_irqrestore(&dim_lock, flags); if (pdata && pdata->destroy) pdata->destroy(pdata); dim2_sysfs_destroy(&dev->bus); most_deregister_interface(&dev->most_iface); kthread_stop(dev->netinfo_task); #if !defined(ENABLE_HDM_TEST) free_irq(dev->irq_ahb0, dev); iounmap(dev->io_base); release_mem_region(res->start, resource_size(res)); #endif kfree(dev); platform_set_drvdata(pdev, NULL); /* * break link to local platform_device_id struct * to prevent crash by unload platform device module */ pdev->id_entry = NULL; return 0; }
/** * dim2_remove - dim2 remove handler * @pdev: platform device structure * * Unregister the interface from mostcore */ static int dim2_remove(struct platform_device *pdev) { struct dim2_hdm *dev = platform_get_drvdata(pdev); struct dim2_platform_data *pdata = pdev->dev.platform_data; unsigned long flags; spin_lock_irqsave(&dim_lock, flags); dim_shutdown(); spin_unlock_irqrestore(&dim_lock, flags); if (pdata && pdata->destroy) pdata->destroy(pdata); dim2_sysfs_destroy(&dev->bus); most_deregister_interface(&dev->most_iface); kthread_stop(dev->netinfo_task); /* * break link to local platform_device_id struct * to prevent crash by unload platform device module */ pdev->id_entry = NULL; return 0; }
/** * dim2_remove - dim2 remove handler * @pdev: platform device structure * * Unregister the interface from mostcore */ static int dim2_remove(struct platform_device *pdev) { struct dim2_hdm *dev = platform_get_drvdata(pdev); unsigned long flags; dim2_sysfs_destroy(&dev->dev); most_deregister_interface(&dev->most_iface); kthread_stop(dev->netinfo_task); spin_lock_irqsave(&dim_lock, flags); dim_shutdown(); spin_unlock_irqrestore(&dim_lock, flags); if (dev->disable_platform) dev->disable_platform(pdev); return 0; }
/** * hdm_disconnect - disconnect function of USB device driver * @interface: Interface of the attached USB device * * This deregisters the interface with the core, removes the kernel timer * and frees resources. * * Context: hub kernel thread */ static void hdm_disconnect(struct usb_interface *interface) { struct most_dev *mdev = usb_get_intfdata(interface); mutex_lock(&mdev->io_mutex); usb_set_intfdata(interface, NULL); mdev->usb_device = NULL; mutex_unlock(&mdev->io_mutex); del_timer_sync(&mdev->link_stat_timer); cancel_work_sync(&mdev->poll_work_obj); destroy_most_dci_obj(mdev->dci); most_deregister_interface(&mdev->iface); kfree(mdev->busy_urbs); kfree(mdev->cap); kfree(mdev->conf); kfree(mdev->ep_address); kfree(mdev); }
/* * dim2_probe - dim2 probe handler * @pdev: platform device structure * * Register the dim2 interface with mostcore and initialize it. * Return 0 on success, negative on failure. */ static int dim2_probe(struct platform_device *pdev) { const struct dim2_platform_data *pdata; const struct of_device_id *of_id; const char *clock_speed; struct dim2_hdm *dev; struct resource *res; int ret, i; u8 hal_ret; int irq; enum { MLB_INT_IDX, AHB0_INT_IDX }; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; dev->atx_idx = -1; platform_set_drvdata(pdev, dev); ret = of_property_read_string(pdev->dev.of_node, "microchip,clock-speed", &clock_speed); if (ret) { dev_err(&pdev->dev, "missing dt property clock-speed\n"); return ret; } ret = get_dim2_clk_speed(clock_speed, &dev->clk_speed); if (ret) { dev_err(&pdev->dev, "bad dt property clock-speed\n"); return ret; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->io_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(dev->io_base)) return PTR_ERR(dev->io_base); of_id = of_match_node(dim2_of_match, pdev->dev.of_node); pdata = of_id->data; ret = pdata && pdata->enable ? pdata->enable(pdev) : 0; if (ret) return ret; dev->disable_platform = pdata ? pdata->disable : 0; dev_info(&pdev->dev, "sync: num of frames per sub-buffer: %u\n", fcnt); hal_ret = dim_startup(dev->io_base, dev->clk_speed, fcnt); if (hal_ret != DIM_NO_ERROR) { dev_err(&pdev->dev, "dim_startup failed: %d\n", hal_ret); ret = -ENODEV; goto err_disable_platform; } irq = platform_get_irq(pdev, AHB0_INT_IDX); if (irq < 0) { dev_err(&pdev->dev, "failed to get ahb0_int irq: %d\n", irq); ret = irq; goto err_shutdown_dim; } ret = devm_request_irq(&pdev->dev, irq, dim2_ahb_isr, 0, "dim2_ahb0_int", dev); if (ret) { dev_err(&pdev->dev, "failed to request ahb0_int irq %d\n", irq); goto err_shutdown_dim; } irq = platform_get_irq(pdev, MLB_INT_IDX); if (irq < 0) { dev_err(&pdev->dev, "failed to get mlb_int irq: %d\n", irq); ret = irq; goto err_shutdown_dim; } ret = devm_request_irq(&pdev->dev, irq, dim2_mlb_isr, 0, "dim2_mlb_int", dev); if (ret) { dev_err(&pdev->dev, "failed to request mlb_int irq %d\n", irq); goto err_shutdown_dim; } init_waitqueue_head(&dev->netinfo_waitq); dev->deliver_netinfo = 0; dev->netinfo_task = kthread_run(&deliver_netinfo_thread, dev, "dim2_netinfo"); if (IS_ERR(dev->netinfo_task)) { ret = PTR_ERR(dev->netinfo_task); goto err_shutdown_dim; } for (i = 0; i < DMA_CHANNELS; i++) { struct most_channel_capability *cap = dev->capabilities + i; struct hdm_channel *hdm_ch = dev->hch + i; INIT_LIST_HEAD(&hdm_ch->pending_list); INIT_LIST_HEAD(&hdm_ch->started_list); hdm_ch->is_initialized = false; snprintf(hdm_ch->name, sizeof(hdm_ch->name), "ca%d", i * 2 + 2); cap->name_suffix = hdm_ch->name; cap->direction = MOST_CH_RX | MOST_CH_TX; cap->data_type = MOST_CH_CONTROL | MOST_CH_ASYNC | MOST_CH_ISOC | MOST_CH_SYNC; cap->num_buffers_packet = MAX_BUFFERS_PACKET; cap->buffer_size_packet = MAX_BUF_SIZE_PACKET; cap->num_buffers_streaming = MAX_BUFFERS_STREAMING; cap->buffer_size_streaming = MAX_BUF_SIZE_STREAMING; } { const char *fmt; if (sizeof(res->start) == sizeof(long long)) fmt = "dim2-%016llx"; else if (sizeof(res->start) == sizeof(long)) fmt = "dim2-%016lx"; else fmt = "dim2-%016x"; snprintf(dev->name, sizeof(dev->name), fmt, res->start); } dev->most_iface.interface = ITYPE_MEDIALB_DIM2; dev->most_iface.description = dev->name; dev->most_iface.num_channels = DMA_CHANNELS; dev->most_iface.channel_vector = dev->capabilities; dev->most_iface.configure = configure_channel; dev->most_iface.enqueue = enqueue; dev->most_iface.dma_alloc = dma_alloc; dev->most_iface.dma_free = dma_free; dev->most_iface.poison_channel = poison_channel; dev->most_iface.request_netinfo = request_netinfo; dev->most_iface.driver_dev = &pdev->dev; dev->dev.init_name = "dim2_state"; dev->dev.parent = &dev->most_iface.dev; ret = most_register_interface(&dev->most_iface); if (ret) { dev_err(&pdev->dev, "failed to register MOST interface\n"); goto err_stop_thread; } ret = dim2_sysfs_probe(&dev->dev); if (ret) { dev_err(&pdev->dev, "failed to create sysfs attribute\n"); goto err_unreg_iface; } return 0; err_unreg_iface: most_deregister_interface(&dev->most_iface); err_stop_thread: kthread_stop(dev->netinfo_task); err_shutdown_dim: dim_shutdown(); err_disable_platform: if (dev->disable_platform) dev->disable_platform(pdev); return ret; }
/* * dim2_probe - dim2 probe handler * @pdev: platform device structure * * Register the dim2 interface with mostcore and initialize it. * Return 0 on success, negative on failure. */ static int dim2_probe(struct platform_device *pdev) { struct dim2_hdm *dev; struct resource *res; int ret, i; struct kobject *kobj; int irq; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; dev->atx_idx = -1; platform_set_drvdata(pdev, dev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->io_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(dev->io_base)) return PTR_ERR(dev->io_base); irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "failed to get ahb0_int irq\n"); return -ENODEV; } ret = devm_request_irq(&pdev->dev, irq, dim2_ahb_isr, 0, "dim2_ahb0_int", dev); if (ret) { dev_err(&pdev->dev, "failed to request ahb0_int irq %d\n", irq); return ret; } irq = platform_get_irq(pdev, 1); if (irq < 0) { dev_err(&pdev->dev, "failed to get mlb_int irq\n"); return -ENODEV; } ret = devm_request_irq(&pdev->dev, irq, dim2_mlb_isr, 0, "dim2_mlb_int", dev); if (ret) { dev_err(&pdev->dev, "failed to request mlb_int irq %d\n", irq); return ret; } init_waitqueue_head(&dev->netinfo_waitq); dev->deliver_netinfo = 0; dev->netinfo_task = kthread_run(&deliver_netinfo_thread, (void *)dev, "dim2_netinfo"); if (IS_ERR(dev->netinfo_task)) return PTR_ERR(dev->netinfo_task); for (i = 0; i < DMA_CHANNELS; i++) { struct most_channel_capability *cap = dev->capabilities + i; struct hdm_channel *hdm_ch = dev->hch + i; INIT_LIST_HEAD(&hdm_ch->pending_list); INIT_LIST_HEAD(&hdm_ch->started_list); hdm_ch->is_initialized = false; snprintf(hdm_ch->name, sizeof(hdm_ch->name), "ca%d", i * 2 + 2); cap->name_suffix = hdm_ch->name; cap->direction = MOST_CH_RX | MOST_CH_TX; cap->data_type = MOST_CH_CONTROL | MOST_CH_ASYNC | MOST_CH_ISOC | MOST_CH_SYNC; cap->num_buffers_packet = MAX_BUFFERS_PACKET; cap->buffer_size_packet = MAX_BUF_SIZE_PACKET; cap->num_buffers_streaming = MAX_BUFFERS_STREAMING; cap->buffer_size_streaming = MAX_BUF_SIZE_STREAMING; } { const char *fmt; if (sizeof(res->start) == sizeof(long long)) fmt = "dim2-%016llx"; else if (sizeof(res->start) == sizeof(long)) fmt = "dim2-%016lx"; else fmt = "dim2-%016x"; snprintf(dev->name, sizeof(dev->name), fmt, res->start); } dev->most_iface.interface = ITYPE_MEDIALB_DIM2; dev->most_iface.description = dev->name; dev->most_iface.num_channels = DMA_CHANNELS; dev->most_iface.channel_vector = dev->capabilities; dev->most_iface.configure = configure_channel; dev->most_iface.enqueue = enqueue; dev->most_iface.poison_channel = poison_channel; dev->most_iface.request_netinfo = request_netinfo; kobj = most_register_interface(&dev->most_iface); if (IS_ERR(kobj)) { ret = PTR_ERR(kobj); dev_err(&pdev->dev, "failed to register MOST interface\n"); goto err_stop_thread; } ret = dim2_sysfs_probe(&dev->bus, kobj); if (ret) goto err_unreg_iface; ret = startup_dim(pdev); if (ret) { dev_err(&pdev->dev, "failed to initialize DIM2\n"); goto err_destroy_bus; } return 0; err_destroy_bus: dim2_sysfs_destroy(&dev->bus); err_unreg_iface: most_deregister_interface(&dev->most_iface); err_stop_thread: kthread_stop(dev->netinfo_task); return ret; }
/* * dim2_probe - dim2 probe handler * @pdev: platform device structure * * Register the dim2 interface with mostcore and initialize it. * Return 0 on success, negative on failure. */ static int dim2_probe(struct platform_device *pdev) { struct dim2_hdm *dev; struct resource *res; int ret, i; struct kobject *kobj; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; dev->atx_idx = -1; platform_set_drvdata(pdev, dev); #if defined(ENABLE_HDM_TEST) test_dev = dev; #else res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { pr_err("no memory region defined\n"); ret = -ENOENT; goto err_free_dev; } if (!request_mem_region(res->start, resource_size(res), pdev->name)) { pr_err("failed to request mem region\n"); ret = -EBUSY; goto err_free_dev; } dev->io_base = ioremap(res->start, resource_size(res)); if (!dev->io_base) { pr_err("failed to ioremap\n"); ret = -ENOMEM; goto err_release_mem; } ret = platform_get_irq(pdev, 0); if (ret < 0) { pr_err("failed to get irq\n"); goto err_unmap_io; } dev->irq_ahb0 = ret; ret = request_irq(dev->irq_ahb0, dim2_ahb_isr, 0, "mlb_ahb0", dev); if (ret) { pr_err("failed to request IRQ: %d, err: %d\n", dev->irq_ahb0, ret); goto err_unmap_io; } #endif init_waitqueue_head(&dev->netinfo_waitq); dev->deliver_netinfo = 0; dev->netinfo_task = kthread_run(&deliver_netinfo_thread, (void *)dev, "dim2_netinfo"); if (IS_ERR(dev->netinfo_task)) { ret = PTR_ERR(dev->netinfo_task); goto err_free_irq; } for (i = 0; i < DMA_CHANNELS; i++) { struct most_channel_capability *cap = dev->capabilities + i; struct hdm_channel *hdm_ch = dev->hch + i; INIT_LIST_HEAD(&hdm_ch->pending_list); INIT_LIST_HEAD(&hdm_ch->started_list); hdm_ch->is_initialized = false; snprintf(hdm_ch->name, sizeof(hdm_ch->name), "ca%d", i * 2 + 2); cap->name_suffix = hdm_ch->name; cap->direction = MOST_CH_RX | MOST_CH_TX; cap->data_type = MOST_CH_CONTROL | MOST_CH_ASYNC | MOST_CH_ISOC_AVP | MOST_CH_SYNC; cap->num_buffers_packet = MAX_BUFFERS_PACKET; cap->buffer_size_packet = MAX_BUF_SIZE_PACKET; cap->num_buffers_streaming = MAX_BUFFERS_STREAMING; cap->buffer_size_streaming = MAX_BUF_SIZE_STREAMING; } { const char *fmt; if (sizeof(res->start) == sizeof(long long)) fmt = "dim2-%016llx"; else if (sizeof(res->start) == sizeof(long)) fmt = "dim2-%016lx"; else fmt = "dim2-%016x"; snprintf(dev->name, sizeof(dev->name), fmt, res->start); } dev->most_iface.interface = ITYPE_MEDIALB_DIM2; dev->most_iface.description = dev->name; dev->most_iface.num_channels = DMA_CHANNELS; dev->most_iface.channel_vector = dev->capabilities; dev->most_iface.configure = configure_channel; dev->most_iface.enqueue = enqueue; dev->most_iface.poison_channel = poison_channel; dev->most_iface.request_netinfo = request_netinfo; kobj = most_register_interface(&dev->most_iface); if (IS_ERR(kobj)) { ret = PTR_ERR(kobj); pr_err("failed to register MOST interface\n"); goto err_stop_thread; } ret = dim2_sysfs_probe(&dev->bus, kobj); if (ret) goto err_unreg_iface; ret = startup_dim(pdev); if (ret) { pr_err("failed to initialize DIM2\n"); goto err_destroy_bus; } return 0; err_destroy_bus: dim2_sysfs_destroy(&dev->bus); err_unreg_iface: most_deregister_interface(&dev->most_iface); err_stop_thread: kthread_stop(dev->netinfo_task); err_free_irq: #if !defined(ENABLE_HDM_TEST) free_irq(dev->irq_ahb0, dev); err_unmap_io: iounmap(dev->io_base); err_release_mem: release_mem_region(res->start, resource_size(res)); err_free_dev: #endif kfree(dev); return ret; }
/** * hdm_probe - probe function of USB device driver * @interface: Interface of the attached USB device * @id: Pointer to the USB ID table. * * This allocates and initializes the device instance, adds the new * entry to the internal list, scans the USB descriptors and registers * the interface with the core. * Additionally, the DCI objects are created and the hardware is sync'd. * * Return 0 on success. In case of an error a negative number is returned. */ static int hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_host_interface *usb_iface_desc = interface->cur_altsetting; struct usb_device *usb_dev = interface_to_usbdev(interface); struct device *dev = &usb_dev->dev; struct most_dev *mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); unsigned int i; unsigned int num_endpoints; struct most_channel_capability *tmp_cap; struct usb_endpoint_descriptor *ep_desc; int ret = 0; int err; if (!mdev) goto exit_ENOMEM; usb_set_intfdata(interface, mdev); num_endpoints = usb_iface_desc->desc.bNumEndpoints; mutex_init(&mdev->io_mutex); INIT_WORK(&mdev->poll_work_obj, wq_netinfo); setup_timer(&mdev->link_stat_timer, link_stat_timer_handler, (unsigned long)mdev); mdev->usb_device = usb_dev; mdev->link_stat_timer.expires = jiffies + (2 * HZ); mdev->iface.mod = hdm_usb_fops.owner; mdev->iface.interface = ITYPE_USB; mdev->iface.configure = hdm_configure_channel; mdev->iface.request_netinfo = hdm_request_netinfo; mdev->iface.enqueue = hdm_enqueue; mdev->iface.poison_channel = hdm_poison_channel; mdev->iface.description = mdev->description; mdev->iface.num_channels = num_endpoints; snprintf(mdev->description, sizeof(mdev->description), "usb_device %d-%s:%d.%d", usb_dev->bus->busnum, usb_dev->devpath, usb_dev->config->desc.bConfigurationValue, usb_iface_desc->desc.bInterfaceNumber); mdev->conf = kcalloc(num_endpoints, sizeof(*mdev->conf), GFP_KERNEL); if (!mdev->conf) goto exit_free; mdev->cap = kcalloc(num_endpoints, sizeof(*mdev->cap), GFP_KERNEL); if (!mdev->cap) goto exit_free1; mdev->iface.channel_vector = mdev->cap; mdev->iface.priv = NULL; mdev->ep_address = kcalloc(num_endpoints, sizeof(*mdev->ep_address), GFP_KERNEL); if (!mdev->ep_address) goto exit_free2; mdev->busy_urbs = kcalloc(num_endpoints, sizeof(*mdev->busy_urbs), GFP_KERNEL); if (!mdev->busy_urbs) goto exit_free3; tmp_cap = mdev->cap; for (i = 0; i < num_endpoints; i++) { ep_desc = &usb_iface_desc->endpoint[i].desc; mdev->ep_address[i] = ep_desc->bEndpointAddress; mdev->padding_active[i] = false; mdev->is_channel_healthy[i] = true; snprintf(&mdev->suffix[i][0], MAX_SUFFIX_LEN, "ep%02x", mdev->ep_address[i]); tmp_cap->name_suffix = &mdev->suffix[i][0]; tmp_cap->buffer_size_packet = MAX_BUF_SIZE; tmp_cap->buffer_size_streaming = MAX_BUF_SIZE; tmp_cap->num_buffers_packet = BUF_CHAIN_SIZE; tmp_cap->num_buffers_streaming = BUF_CHAIN_SIZE; tmp_cap->data_type = MOST_CH_CONTROL | MOST_CH_ASYNC | MOST_CH_ISOC | MOST_CH_SYNC; if (usb_endpoint_dir_in(ep_desc)) tmp_cap->direction = MOST_CH_RX; else tmp_cap->direction = MOST_CH_TX; tmp_cap++; init_usb_anchor(&mdev->busy_urbs[i]); spin_lock_init(&mdev->channel_lock[i]); err = drci_wr_reg(usb_dev, DRCI_REG_BASE + DRCI_COMMAND + ep_desc->bEndpointAddress * 16, 1); if (err < 0) dev_warn(dev, "DCI Sync for EP %02x failed", ep_desc->bEndpointAddress); } dev_notice(dev, "claimed gadget: Vendor=%4.4x ProdID=%4.4x Bus=%02x Device=%02x\n", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), usb_dev->bus->busnum, usb_dev->devnum); dev_notice(dev, "device path: /sys/bus/usb/devices/%d-%s:%d.%d\n", usb_dev->bus->busnum, usb_dev->devpath, usb_dev->config->desc.bConfigurationValue, usb_iface_desc->desc.bInterfaceNumber); mdev->parent = most_register_interface(&mdev->iface); if (IS_ERR(mdev->parent)) { ret = PTR_ERR(mdev->parent); goto exit_free4; } mutex_lock(&mdev->io_mutex); if (le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_OS81118 || le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_OS81119 || le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_OS81210) { /* this increments the reference count of the instance * object of the core */ mdev->dci = create_most_dci_obj(mdev->parent); if (!mdev->dci) { mutex_unlock(&mdev->io_mutex); most_deregister_interface(&mdev->iface); ret = -ENOMEM; goto exit_free4; } kobject_uevent(&mdev->dci->kobj, KOBJ_ADD); mdev->dci->usb_device = mdev->usb_device; } mutex_unlock(&mdev->io_mutex); return 0; exit_free4: kfree(mdev->busy_urbs); exit_free3: kfree(mdev->ep_address); exit_free2: kfree(mdev->cap); exit_free1: kfree(mdev->conf); exit_free: kfree(mdev); exit_ENOMEM: if (ret == 0 || ret == -ENOMEM) { ret = -ENOMEM; dev_err(dev, "out of memory\n"); } return ret; }
/** * hdm_probe - probe function of USB device driver * @interface: Interface of the attached USB device * @id: Pointer to the USB ID table. * * This allocates and initializes the device instance, adds the new * entry to the internal list, scans the USB descriptors and registers * the interface with the core. * Additionally, the DCI objects are created and the hardware is sync'd. * * Return 0 on success. In case of an error a negative number is returned. */ static int hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_host_interface *usb_iface_desc = interface->cur_altsetting; struct usb_device *usb_dev = interface_to_usbdev(interface); struct device *dev = &usb_dev->dev; struct most_dev *mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); unsigned int i; unsigned int num_endpoints; struct most_channel_capability *tmp_cap; struct usb_endpoint_descriptor *ep_desc; int ret = 0; if (!mdev) goto err_out_of_memory; usb_set_intfdata(interface, mdev); num_endpoints = usb_iface_desc->desc.bNumEndpoints; mutex_init(&mdev->io_mutex); INIT_WORK(&mdev->poll_work_obj, wq_netinfo); timer_setup(&mdev->link_stat_timer, link_stat_timer_handler, 0); mdev->usb_device = usb_dev; mdev->link_stat_timer.expires = jiffies + (2 * HZ); mdev->iface.mod = hdm_usb_fops.owner; mdev->iface.driver_dev = &interface->dev; mdev->iface.interface = ITYPE_USB; mdev->iface.configure = hdm_configure_channel; mdev->iface.request_netinfo = hdm_request_netinfo; mdev->iface.enqueue = hdm_enqueue; mdev->iface.poison_channel = hdm_poison_channel; mdev->iface.dma_alloc = hdm_dma_alloc; mdev->iface.dma_free = hdm_dma_free; mdev->iface.description = mdev->description; mdev->iface.num_channels = num_endpoints; snprintf(mdev->description, sizeof(mdev->description), "%d-%s:%d.%d", usb_dev->bus->busnum, usb_dev->devpath, usb_dev->config->desc.bConfigurationValue, usb_iface_desc->desc.bInterfaceNumber); mdev->conf = kcalloc(num_endpoints, sizeof(*mdev->conf), GFP_KERNEL); if (!mdev->conf) goto err_free_mdev; mdev->cap = kcalloc(num_endpoints, sizeof(*mdev->cap), GFP_KERNEL); if (!mdev->cap) goto err_free_conf; mdev->iface.channel_vector = mdev->cap; mdev->ep_address = kcalloc(num_endpoints, sizeof(*mdev->ep_address), GFP_KERNEL); if (!mdev->ep_address) goto err_free_cap; mdev->busy_urbs = kcalloc(num_endpoints, sizeof(*mdev->busy_urbs), GFP_KERNEL); if (!mdev->busy_urbs) goto err_free_ep_address; tmp_cap = mdev->cap; for (i = 0; i < num_endpoints; i++) { ep_desc = &usb_iface_desc->endpoint[i].desc; mdev->ep_address[i] = ep_desc->bEndpointAddress; mdev->padding_active[i] = false; mdev->is_channel_healthy[i] = true; snprintf(&mdev->suffix[i][0], MAX_SUFFIX_LEN, "ep%02x", mdev->ep_address[i]); tmp_cap->name_suffix = &mdev->suffix[i][0]; tmp_cap->buffer_size_packet = MAX_BUF_SIZE; tmp_cap->buffer_size_streaming = MAX_BUF_SIZE; tmp_cap->num_buffers_packet = BUF_CHAIN_SIZE; tmp_cap->num_buffers_streaming = BUF_CHAIN_SIZE; tmp_cap->data_type = MOST_CH_CONTROL | MOST_CH_ASYNC | MOST_CH_ISOC | MOST_CH_SYNC; if (usb_endpoint_dir_in(ep_desc)) tmp_cap->direction = MOST_CH_RX; else tmp_cap->direction = MOST_CH_TX; tmp_cap++; init_usb_anchor(&mdev->busy_urbs[i]); spin_lock_init(&mdev->channel_lock[i]); } dev_notice(dev, "claimed gadget: Vendor=%4.4x ProdID=%4.4x Bus=%02x Device=%02x\n", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), usb_dev->bus->busnum, usb_dev->devnum); dev_notice(dev, "device path: /sys/bus/usb/devices/%d-%s:%d.%d\n", usb_dev->bus->busnum, usb_dev->devpath, usb_dev->config->desc.bConfigurationValue, usb_iface_desc->desc.bInterfaceNumber); ret = most_register_interface(&mdev->iface); if (ret) goto err_free_busy_urbs; mutex_lock(&mdev->io_mutex); if (le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_OS81118 || le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_OS81119 || le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_OS81210) { mdev->dci = kzalloc(sizeof(*mdev->dci), GFP_KERNEL); if (!mdev->dci) { mutex_unlock(&mdev->io_mutex); most_deregister_interface(&mdev->iface); ret = -ENOMEM; goto err_free_busy_urbs; } mdev->dci->dev.init_name = "dci"; mdev->dci->dev.parent = &mdev->iface.dev; mdev->dci->dev.groups = dci_attr_groups; mdev->dci->dev.release = release_dci; if (device_register(&mdev->dci->dev)) { mutex_unlock(&mdev->io_mutex); most_deregister_interface(&mdev->iface); ret = -ENOMEM; goto err_free_dci; } mdev->dci->usb_device = mdev->usb_device; } mutex_unlock(&mdev->io_mutex); return 0; err_free_dci: kfree(mdev->dci); err_free_busy_urbs: kfree(mdev->busy_urbs); err_free_ep_address: kfree(mdev->ep_address); err_free_cap: kfree(mdev->cap); err_free_conf: kfree(mdev->conf); err_free_mdev: kfree(mdev); err_out_of_memory: if (ret == 0 || ret == -ENOMEM) { ret = -ENOMEM; dev_err(dev, "out of memory\n"); } return ret; }