static ssize_t value_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { u16 val; u16 reg_addr; const char *name = attr->attr.name; struct most_dci_obj *dci_obj = to_dci_obj(dev); struct usb_device *usb_dev = dci_obj->usb_device; int err = kstrtou16(buf, 16, &val); if (err) return err; if (!strcmp(name, "arb_address")) { dci_obj->reg_addr = val; return count; } if (!strcmp(name, "arb_value")) err = drci_wr_reg(usb_dev, dci_obj->reg_addr, val); else if (!strcmp(name, "sync_ep")) err = start_sync_ep(usb_dev, val); else if (!get_static_reg_addr(rw_regs, name, ®_addr)) err = drci_wr_reg(usb_dev, reg_addr, val); else return -EFAULT; if (err < 0) return err; return count; }
static ssize_t store_value(struct most_dci_obj *dci_obj, struct most_dci_attribute *attr, const char *buf, size_t count) { u16 val; u16 reg_addr; const char *name = attr->attr.name; int err = kstrtou16(buf, 16, &val); if (err) return err; if (!strcmp(name, "arb_address")) { dci_obj->reg_addr = val; return count; } if (!strcmp(name, "arb_value")) { reg_addr = dci_obj->reg_addr; } else if (!strcmp(name, "sync_ep")) { u16 ep = val; reg_addr = DRCI_REG_BASE + DRCI_COMMAND + ep * 16; val = 1; } else if (get_static_reg_addr(ro_regs, name, ®_addr)) { return -EFAULT; } err = drci_wr_reg(dci_obj->usb_device, reg_addr, val); if (err < 0) return err; return count; }
/** * 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; }
static inline int start_sync_ep(struct usb_device *usb_dev, u16 ep) { return drci_wr_reg(usb_dev, DRCI_REG_BASE + DRCI_COMMAND + ep * 16, 1); }