+int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct usb_gadget *gadget = NULL; + unsigned long flags; + int ret; + + if (!driver || !driver->bind || !driver->setup) + return -EINVAL; + + spin_lock_irqsave(&gadget_lock, flags); + list_for_each_entry(gadget, &gadget_list, list) { + if (gadget->busy) + continue; + + dev_vdbg(gadget->dev, "registering driver [%s]\n", + driver->function); + + gadget->busy = true; + gadget->driver = driver; + gadget->dev->driver = &driver->driver; You need to break. + } + spin_unlock_irqrestore(&gadget_lock, flags); + + if (!gadget) + return -EBUSY; I believe this will always be true if the list is not-empty. I'd make it into something like: int __usb_gadget_register_driver(struct usb_gadget_driver *driver, const char *udc_name) { struct usb_gadget *gadget = NULL; unsigned long flags; int ret; if (!driver || !driver->bind || !driver->setup) return -EINVAL; spin_lock_irqsave(&gadget_lock, flags); list_for_each_entry(gadget, &gadget_list, list) if (!gadget->busy && (!udc_name || !strcmp(udc_name, gadget->name))) { dev_vdbg(gadget->dev, "registering driver [%s]\n", driver->function); gadget->busy = true; gadget->driver = driver; gadget->dev->driver = &driver->driver; goto found; } spin_unlock_irqrestore(&gadget_lock, flags); return -EBUSY; found: spin_unlock_irqrestore(&gadget_lock, flags); ... and in header file: static inline int __must_check usb_gadget_register_driver(struct usb_gadget_driver *driver) { return __usb_gadget_register_driver(driver, NULL); } This would allow for named UDCs which I mentioned when commenting on Matthieu's code. So the idea would be that gadget drivers would declare a module parameter and user space would be able to specify UDC gadget should bind to if that was required on given system. +static ssize_t usb_gadget_softconn_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t n) +{ + struct usb_gadget *gadget = dev_get_drvdata(dev); + + if (sysfs_streq(buf, "connect")) + usb_gadget_connect(gadget); + else if (sysfs_streq(buf, "disconnect")) + usb_gadget_disconnect(gadget); + else + dev_err(dev, "unknown value\n"); Shouldn't it return -EINVAL here? + + return n; +} +static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_gadget_softconn_store); + +static ssize_t usb_gadget_speed_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_gadget *gadget = dev_get_drvdata(dev); + + switch (gadget->speed) { + case USB_SPEED_LOW: + return snprintf(buf, 10, "low-speed\n"); Why not just strcpy()? Or memcpy() if you are willing to count characters. + case USB_SPEED_FULL: + return snprintf(buf, 11, "full-speed\n"); + case USB_SPEED_HIGH: + return snprintf(buf, 11, "high-speed\n"); + case USB_SPEED_WIRELESS: + return snprintf(buf, 9, "wireless\n"); + case USB_SPEED_SUPER: + return snprintf(buf, 12, "super-speed\n"); + case USB_SPEED_UNKNOWN: /* FALLTHROUGH */ + default: + return snprintf(buf, 8, "UNKNOWN\n"); + } +} +static DEVICE_ATTR(speed, S_IRUSR, usb_gadget_speed_show, NULL); + +#define USB_GADGET_ATTR(name) \ +ssize_t usb_gadget_##name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct usb_gadget *gadget = dev_get_drvdata(dev); \ + \ + return snprintf(buf, 1, "%d\n", gadget->name); \ Uh? 1? It will fit only NUL terminating byte. It should read PAGE_SIZE. +} \ +static void __exit usb_gadget_exit(void) +{ + class_destroy(gadget_class); +} +module_exit(usb_gadget_exit); + Empty line at the end. -- Best regards, _ _ | Humble Liege of Serenely Enlightened Majesty of o' \,=./ `o | Computer Science, Michał "mina86" Nazarewicz (o o) +----[mina86*mina86.com]---[mina86*jabber.org]----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