Re: [PATCH 2/3] usb: gadget: introduce UDC Class

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 20 May 2011 12:02:59 +0200, Sebastian Andrzej Siewior wrote:
+/**
+ * struct usb_udc - describes one usb device controller
+ * @driver - the gadget driver pointer. For use by the class code
+ * @dev - the child device to the actual controller
+ * @gadget - the gadget. For use by the class code
+ * @list - for use by the udc class driver
+ * @name - a human friendly name representation
+ *
+ * This represents the internal data structure which is used by the UDC-class
+ * to hold information about udc driver and gadget together.
+ */
+struct usb_udc {
+	struct usb_gadget_driver	*driver;
+	struct usb_gadget		*gadget;
+	struct device			dev;
+	struct list_head		list;
+};

So the idea is for all gadgets to use this framework, right? If that's the case,
maybe it's better to just stash those fields inside usb_gadget structure?

Also, isn't it that UDC drivers store pointer to usb_gadget_driver internally?
Because if so, then stashing the above fields inside the usb_gadget_driver
structure would allow UDC drivers to drop their own internal pointer to
usb_gadget_driver.


+int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
+{
+	struct usb_udc		*udc;
+	int			ret = -ENOMEM;
+
+	udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+	if (!udc)
+		goto err1;
+
+	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;
+
+	udc->gadget = gadget;
+
+	mutex_lock(&udc_lock);

mutex_lock_interruptible()?  This applies to other places as well.

+	list_add_tail(&udc->list, &udc_list);
+	mutex_unlock(&udc_lock);

What if someone calls usb_gadget_register_driver() right about now?

I think that since you've converted udc_lock to mutex rather then spinlock,
it'd be better to extend the lock all the way to the end of the function.

On another note, it's bit of a pity that you replaced the spinlock with mutex
but I see how that can be needed.

I remember I posted a version of this code which used a sipnlock and a fake
value of udc->driver to mark udc as being busy initialising.

+	ret = device_add(&udc->dev);
+	if (ret)
+		goto err3;
+
+	kobject_uevent(&udc->dev.kobj, KOBJ_ADD);
+	return 0;
+err3:
+	mutex_lock(&udc_lock);
+	list_del(&udc->list);
+	mutex_unlock(&udc_lock);
+
+err2:
+	put_device(&udc->dev);
+
+err1:
+	return ret;
+}


+void usb_del_gadget_udc(struct usb_gadget *gadget)
+{
+	struct usb_udc		*udc = NULL;
+
+	dev_vdbg(gadget->dev.parent, "unregistering gadget\n");
+
+	mutex_lock(&udc_lock);
+	list_for_each_entry(udc, &udc_list, list) {
+		if (udc->gadget == gadget)
+			goto found;
+	}

The braces are not needed.

+	dev_err(gadget->dev.parent, "gadget not registered.\n");
+	goto out;
+found:
+
+	list_del(&udc->list);
+
+	if (udc->driver)
+		usb_gadget_remove_driver(udc);
+
+	kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
+	device_unregister(&udc->dev);
+out:
+	mutex_unlock(&udc_lock);

I think the mutex_unlock() can be put just after list_del().

+}


+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct usb_udc		*udc = NULL;
+	int			ret;
+
+	if (!driver || !driver->bind || !driver->setup)
+		return -EINVAL;
+
+	mutex_lock(&udc_lock);
+	list_for_each_entry(udc, &udc_list, list) {
+		/* For now we take the first one */
+		if (!udc->driver) {
+			pr_debug("using UDC '%s'\n", udc->gadget->name);

I don't think this pr_debug() is needed since first instruction at
"found" label is a dev_dbg().

+			goto found;
+		}
+	}

The outer { ... } are not needed.

+	pr_debug("couldn't find an available UDC\n");
+	return -ENODEV;

Mutex remains locked.

+found:
+	dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
+			driver->function);
+
+	udc->driver = driver;
+	udc->dev.driver = &driver->driver;
+
+	ret = usb_gadget_start(udc->gadget, driver);
+	if (ret) {
+		dev_err(&udc->dev, "failed to start %s --> %d\n",
+				udc->driver->function, ret);
+		goto err1;
+	}
+
+#if 0

Could we just drop this from the initial patch?

+	/*
+	 * in long term we try to move same/simmilar steps from every gadget's
+	 * ->start() callback into here. ->start() should only change some bits
+	 * in the HW if possible.
+	 */
+	ret = driver->bind(udc->gadget);
+	if (ret) {
+		dev_err(&udc->dev, "bind to driver %s failed --> %d\n",
+				driver->function, ret);
+		goto err2;
+	}
+
+	ret = usb_gadget_connect(udc->gadget);
+	if (ret) {
+		dev_err(&udc->dev, "failed to start %s --> %d\n",
+				udc->gadget->name, ret);
+		goto err3;
+	}
+#endif
+	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
+	mutex_unlock(&udc_lock);
+	return 0;
+
+#if 0
+err3:
+	driver->unbind(udc->gadget);
+
+err2:
+	usb_gadget_stop(udc->gadget);
+
+#endif
+err1:
+	udc->driver = NULL;
+	udc->dev.driver = NULL;
+	mutex_unlock(&udc_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct usb_udc		*udc = NULL;
+	int			ret = -ENODEV;
+
+	if (!driver || !driver->unbind)
+		return -EINVAL;
+
+	mutex_lock(&udc_lock);
+	list_for_each_entry(udc, &udc_list, list) {
+		if (udc->driver == driver) {
+			usb_gadget_remove_driver(udc);
+			ret = 0;
+			break;
+		}
+	}

Outer { ... } not needed.

+	mutex_unlock(&udc_lock);
+	return ret;
+}

--
Best regards,                                         _     _
.o. | Liege of Serenely Enlightened Majesty of      o' \,=./ `o
..o | Computer Science,  Michal "mina86" Nazarewicz    (o o)
ooo +-----<email/xmpp: mnazarewicz@xxxxxxxxxx>-----ooO--(_)--Ooo--
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux