/* ------------------------------------------------------------------------- */
+void usb_gadget_set_state(struct usb_gadget *gadget,
+ enum usb_device_state state)
+{
+ gadget->state = state;
+ sysfs_notify(&gadget->dev.kobj, NULL, "status");
+}
+EXPORT_SYMBOL_GPL(usb_gadget_set_state);
+
+/* ------------------------------------------------------------------------- */
+
/**
* usb_gadget_udc_start - tells usb device controller to start up
* @gadget: The gadget we want to get started
}
static const struct attribute_group *usb_udc_attr_groups[];
+
+static void usb_udc_nop_release(struct device *dev)
+{
+ dev_vdbg(dev, "%s\n", __func__);
+}
+
/**
- * usb_add_gadget_udc - adds a new gadget to the udc class driver list
- * @parent: the parent device to this udc. Usually the controller
- * driver's device.
- * @gadget: the gadget to be added to the list
+ * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller driver's
+ * device.
+ * @gadget: the gadget to be added to the list.
+ * @release: a gadget release function.
*
* Returns zero on success, negative errno otherwise.
*/
-int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
+int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
+ void (*release)(struct device *dev))
{
struct usb_udc *udc;
int ret = -ENOMEM;
if (!udc)
goto err1;
+ dev_set_name(&gadget->dev, "gadget");
+ gadget->dev.parent = parent;
+
+ dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
+ gadget->dev.dma_parms = parent->dma_parms;
+ gadget->dev.dma_mask = parent->dma_mask;
+
+ if (release)
+ gadget->dev.release = release;
+ else
+ gadget->dev.release = usb_udc_nop_release;
+
+ ret = device_register(&gadget->dev);
+ if (ret)
+ goto err2;
+
device_initialize(&udc->dev);
udc->dev.release = usb_udc_release;
udc->dev.class = udc_class;
udc->dev.parent = parent;
ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
if (ret)
- goto err2;
+ goto err3;
udc->gadget = gadget;
ret = device_add(&udc->dev);
if (ret)
- goto err3;
+ goto err4;
+
+ usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
mutex_unlock(&udc_lock);
return 0;
-err3:
+
+err4:
list_del(&udc->list);
mutex_unlock(&udc_lock);
-err2:
+err3:
put_device(&udc->dev);
+err2:
+ put_device(&gadget->dev);
+
err1:
return ret;
}
+EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
+
+/**
+ * usb_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ *
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
+{
+ return usb_add_gadget_udc_release(parent, gadget, NULL);
+}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
static void usb_gadget_remove_driver(struct usb_udc *udc)
udc->driver = NULL;
udc->dev.driver = NULL;
+ udc->gadget->dev.driver = NULL;
}
/**
kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
device_unregister(&udc->dev);
+ device_unregister(&gadget->dev);
}
EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
udc->driver = driver;
udc->dev.driver = &driver->driver;
+ udc->gadget->dev.driver = &driver->driver;
ret = driver->bind(udc->gadget, driver);
if (ret)
udc->driver->function, ret);
udc->driver = NULL;
udc->dev.driver = NULL;
+ udc->gadget->dev.driver = NULL;
return ret;
}
}
static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
+static ssize_t usb_gadget_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
+ struct usb_gadget *gadget = udc->gadget;
+
+ return sprintf(buf, "%s\n", usb_state_string(gadget->state));
+}
+static DEVICE_ATTR(state, S_IRUGO, usb_gadget_state_show, NULL);
+
#define USB_UDC_SPEED_ATTR(name, param) \
ssize_t usb_udc_##param##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
static struct attribute *usb_udc_attrs[] = {
&dev_attr_srp.attr,
&dev_attr_soft_connect.attr,
+ &dev_attr_state.attr,
&dev_attr_current_speed.attr,
&dev_attr_maximum_speed.attr,