Re: [PATCH] USB: Add LVS Test device driver

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

 



Hi Alan,

On Mon, May 12, 2014 at 11:19:33PM +0800, Alan Stern wrote:
> On Mon, 12 May 2014, Pratyush Anand wrote:
> 
> > OTG3 and EH Compliance Plan 1.0 talks about Super Speed OTG Verification
> > system (SS-OVS) which consists of an excersizer and analyzer.
> >
> > USB Compliance Suite from Lecroy can act as such SS-OVS for Link Layer
> > Validation (LVS).
> >
> > Some modifications are needed for an embedded Linux USB host to pass all
> > these tests.  Most of these tests require just Link to be in U0. They do
> > not work with default Linux USB stack since, default stack does port
> > reset and then starts sending setup packet, which is not expected by
> > Link Layer Validation (LVS) device of Lecroy Compliance Suit.  Then,
> > There are many Link Layer Tests which need host to generate specific
> > traffic.
> >
> > This patch supports specific traffic generation cases. As of now all the
> > host Lecroy Link Layer-USBIF tests (except TD7.26 and TD7.34) passes
> > with this patch for single run using  Lecroy USB Compliance Suite
> > Version 1.98 Build 239 and Lecroy USB Protocol Analyzer version 4.80
> > Build 1603. Therefore patch seems to be a good candidate for inclusion.
> > Further modification can be done on top of it.
> >
> > To avoid any port reset and setup packet generation, a simple step
> > needed is to unbind the hub driver from root hub device. If 2-0:1.0 is
> > the root hub, then execute following to unbind hub driver.
> >
> >  echo 2-0:1.0 > /sys/bus/usb/drivers/hub/unbind
> >
> > Then bind lvs driver as follows
> >
> >  echo 2-0:1.0 > /sys/bus/usb/drivers/lvs/bind
> >
> > Now connect LVS device with root hub port.
> > Test case specific traffic can be generated as follows whenever needed:
> >
> > 1. To issue "Get Device descriptor" command for TD.7.06:
> >  echo 1 > /sys/bus/usb/devices/2-0\:1.0/get_dev_desc
> >
> > 2. To set U1 timeout to 127 for TD.7.18
> >  echo 127 > /sys/bus/usb/devices/2-0\:1.0/u1_timeout
> >
> > 3. To set U2 timeout to 0 for TD.7.18
> >  echo 0 > /sys/bus/usb/devices/2-0\:1.0/u2_timeout
> >
> > 4. To issue "Hot Reset" for TD.7.29
> >  echo 1 > /sys/bus/usb/devices/2-0\:1.0/hot_reset
> >
> > 5. To issue "U3 Entry" for TD.7.35
> >  echo 1 > /sys/bus/usb/devices/2-0\:1.0/u3_entry
> >
> > 6. To issue "U3 Exit" for TD.7.36
> >  echo 1 > /sys/bus/usb/devices/2-0\:1.0/u3_exit
> >
> > Signed-off-by: Pratyush Anand <pratyush.anand@xxxxxx>
> 
> This looks pretty much okay, but it has got a few bugs.
> 
> The biggest bug may not be an obvious one.  Suppose the lvstest driver
> has been built into the kernel.  When the kernel boots and the root
> hubs are registered, what will prevent them all from binding to lvstest
> instead of the normal hub driver?

Sorry, I do not have much knowledge of device model, so may be I am
wrong, but this is what I understand.

Since core comes before misc in makefile, so won't it insure that
hub_diver is registered before lvs_driver on usb bus? And if that is
insured than, would n't a root hub device always binds to the first
driver and ie hub_driver. Infact, I am working with lvstest driver
being built into the kernel.

> 
> A similar question arises if lvstest was built as a module, and after
> the module is loaded, the user hot-plugs a USB-3 host controller.

I see issue only when both lvstest and hub driver are loaded as
module, but lvstest is loaded before hub.

> 
> > --- /dev/null
> > +++ b/Documentation/ABI/testing/sysfs-bus-usb-lvstest
> > @@ -0,0 +1,40 @@
> > +Link Layer Validation Device is a standard device for testing of Super
> > +Speed Link Layer tests. These nodes are available in sysfs only when lvs
> > +driver is binded with root hub device.
> > +
> > +What:                /sys/bus/usb/devices/.../get_dev_desc
> > +Date:                March 2014
> > +Contact:     Pratyush Anand <pratyush.anand@xxxxxx>
> > +Description:
> > +             Write 1 to this node to issue "Get Device Descriptor"
> > +             for Link Layer Validation device. It is needed for TD.7.06.
> 
> Why does the user have to write "1"?  Why not accept any write at all?
> 
> The same complaint applies to u3_entry, u3_exit, and hot_reset.

No issue in that..can check for any non zero value.

> 
> > +What:                /sys/bus/usb/devices/.../u1_timeout
> > +Date:                March 2014
> > +Contact:     Pratyush Anand <pratyush.anand@xxxxxx>
> > +Description:
> > +             Set "U1 timeout" for the downstream port where Link Layer
> > +             Validation device is connected. It is needed for TD.7.18,
> > +             TD.7.19, TD.7.20 and TD.7.21.
> > +
> > +What:                /sys/bus/usb/devices/.../u2_timeout
> > +Date:                March 2014
> > +Contact:     Pratyush Anand <pratyush.anand@xxxxxx>
> > +Description:
> > +             Set "U2 timeout" for the downstream port where Link Layer
> > +             Validation device is connected. It is needed for TD.7.18,
> > +             TD.7.19, TD.7.20 and TD.7.21.
> > +
> > +What:                /sys/bus/usb/devices/.../hot_reset
> > +Date:                March 2014
> > +Contact:     Pratyush Anand <pratyush.anand@xxxxxx>
> > +Description:
> > +             Write 1 to this node to issue "Reset" for Link Layer Validation
> > +             device. It is needed for TD.7.29, TD.7.31, TD.7.34 and TD.7.35.
> > +
> > +What:                /sys/bus/usb/devices/.../u3_entry
> > +Date:                March 2014
> > +Contact:     Pratyush Anand <pratyush.anand@xxxxxx>
> > +Description:
> > +             Write 1 to this node to issue "u3 entry" for Link Layer
> > +             Validation device. It is needed for TD.7.35 and TD.7.36.
> 
> Where's the documentation for u3_exit?

Oh..will add in v2.

> 
> > diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
> > index a51e7d6..6ef1f81 100644
> > --- a/drivers/usb/misc/Kconfig
> > +++ b/drivers/usb/misc/Kconfig
> > @@ -235,3 +235,9 @@ config USB_HSIC_USB3503
> >         depends on I2C
> >         help
> >           This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver.
> > +
> > +config USB_LINK_LAYER_TEST
> > +     tristate "USB Link Layer Test driver"
> > +     help
> > +       This driver is for generating specific traffic for Super Speed Link
> > +       Layer Test Device.
> 
> Mention that unless the user wants to conduct low-level electrical
> tests of USB-3 host controllers, this value should be 'N'.

OK.

> 
> ...
> 
> > +static struct usb_device *create_lvs_device(struct usb_interface *intf)
> > +{
> > +     struct usb_device *udev, *hdev;
> > +     struct usb_hcd *hcd;
> > +     struct lvs_rh *lvs = usb_get_intfdata(intf);
> > +
> > +     if (!lvs->present) {
> > +             dev_err(&intf->dev, "No LVS device is present\n");
> > +             return NULL;
> > +     }
> > +
> > +     hdev = interface_to_usbdev(intf);
> > +     hcd = bus_to_hcd(hdev->bus);
> > +     lvs = usb_get_intfdata(intf);
> 
> What is the reason for this line?  lvs has already been assigned.

Will correct.

> 
> > +
> > +     udev = usb_alloc_dev(hdev, hdev->bus, lvs->portnum);
> > +     if (!udev) {
> > +             dev_err(&intf->dev, "Could not allocate lvs udev\n");
> > +             return NULL;
> > +     }
> > +     udev->speed = USB_SPEED_SUPER;
> > +     udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
> > +     usb_set_device_state(udev, USB_STATE_DEFAULT);
> > +
> > +     if (hcd->driver->enable_device) {
> > +             if (hcd->driver->enable_device(hcd, udev) < 0) {
> > +                     dev_err(&intf->dev, "Failed to enable\n");
> > +                     kfree(udev);
> 
> You need to call usb_put_dev(), not kfree().

and I think also hcd->driver->free_dev(), right?
So , better to call destroy_lvs_device().

> 
> > +                     return NULL;
> > +             }
> > +     }
> > +
> > +     return udev;
> > +}
> > +
> > +static void destroy_lvs_device(struct usb_device *udev)
> > +{
> > +     kfree(udev);
> 
> This is wrong for two reasons.  First, you forgot to call
> hcd->driver->free_dev(), and second you called kfree() instead of
> usb_put_dev().
> 

OK, will correct.

> > +}
> > +
> > +static ssize_t issue_u3_entry(struct device *dev,
> > +             struct device_attribute *attr, const char *buf, size_t count)
> > +{
> > +     struct usb_interface *intf = to_usb_interface(dev);
> > +     struct usb_device *hdev = interface_to_usbdev(intf);
> > +     struct lvs_rh *lvs = usb_get_intfdata(intf);
> > +     struct usb_device *udev;
> > +     unsigned long val;
> > +     int ret;
> > +
> > +     ret = kstrtoul(buf, 10, &val);
> > +     if (ret < 0) {
> > +             dev_err(dev, "couldn't parse string %d\n", ret);
> > +             return ret;
> > +     }
> > +
> > +     if (val != 1)
> > +             return -EINVAL;
> > +
> > +     udev = create_lvs_device(intf);
> > +     if (!udev) {
> > +             dev_err(dev, "failed to create lvs device\n");
> > +             return -ENOMEM;
> > +     }
> > +
> > +     ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
> > +             USB_REQ_SET_FEATURE, USB_RT_PORT, USB_PORT_FEAT_SUSPEND,
> > +             lvs->portnum, NULL, 0, 1000);
> > +     if (ret < 0)
> > +             dev_err(dev, "can't issue U3 entry %d\n", ret);
> > +
> > +     destroy_lvs_device(udev);
> > +
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     return count;
> > +}
> > +static DEVICE_ATTR(u3_entry, S_IWUSR, NULL, issue_u3_entry);
> > +
> > +static ssize_t issue_u3_exit(struct device *dev,
> > +             struct device_attribute *attr, const char *buf, size_t count)
> > +{
> > +     struct usb_interface *intf = to_usb_interface(dev);
> > +     struct usb_device *hdev = interface_to_usbdev(intf);
> > +     struct lvs_rh *lvs = usb_get_intfdata(intf);
> > +     struct usb_device *udev;
> > +     unsigned long val;
> > +     int ret;
> > +
> > +     ret = kstrtoul(buf, 10, &val);
> > +     if (ret < 0) {
> > +             dev_err(dev, "couldn't parse string %d\n", ret);
> > +             return ret;
> > +     }
> > +
> > +     if (val != 1)
> > +             return -EINVAL;
> > +
> > +     udev = create_lvs_device(intf);
> > +     if (!udev) {
> > +             dev_err(dev, "failed to create lvs device\n");
> > +             return -ENOMEM;
> > +     }
> > +
> > +     ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
> > +             USB_REQ_CLEAR_FEATURE, USB_RT_PORT, USB_PORT_FEAT_SUSPEND,
> > +             lvs->portnum, NULL, 0, 1000);
> > +     if (ret < 0)
> > +             dev_err(dev, "can't issue U3 entry %d\n", ret);
> 
> Don't you mean "U3 exit"?

Yes :( 

> 
> > +
> > +     destroy_lvs_device(udev);
> > +
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     return count;
> > +}
> > +static DEVICE_ATTR(u3_exit, S_IWUSR, NULL, issue_u3_exit);
> > +
> > +static ssize_t issue_hot_reset(struct device *dev,
> > +             struct device_attribute *attr, const char *buf, size_t count)
> > +{
> > +     struct usb_interface *intf = to_usb_interface(dev);
> > +     struct usb_device *hdev = interface_to_usbdev(intf);
> > +     struct lvs_rh *lvs = usb_get_intfdata(intf);
> > +     unsigned long val;
> > +     int ret;
> > +
> > +     ret = kstrtoul(buf, 10, &val);
> > +     if (ret < 0) {
> > +             dev_err(dev, "couldn't parse string %d\n", ret);
> > +             return ret;
> > +     }
> > +
> > +     if (val != 1)
> > +             return -EINVAL;
> > +
> > +     ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
> > +             USB_REQ_SET_FEATURE, USB_RT_PORT, USB_PORT_FEAT_RESET,
> > +             lvs->portnum, NULL, 0, 1000);
> > +     if (ret < 0) {
> > +             dev_err(dev, "can't issue hot reset %d\n", ret);
> > +             return ret;
> > +     }
> > +
> > +     return count;
> > +}
> > +static DEVICE_ATTR(hot_reset, S_IWUSR, NULL, issue_hot_reset);
> > +
> > +static ssize_t issue_u2_timeout(struct device *dev,
> > +             struct device_attribute *attr, const char *buf, size_t count)
> > +{
> > +     struct usb_interface *intf = to_usb_interface(dev);
> > +     struct usb_device *hdev = interface_to_usbdev(intf);
> > +     struct lvs_rh *lvs = usb_get_intfdata(intf);
> > +     unsigned long val;
> > +     int ret;
> > +
> > +     ret = kstrtoul(buf, 10, &val);
> > +     if (ret < 0) {
> > +             dev_err(dev, "couldn't parse string %d\n", ret);
> > +             return ret;
> > +     }
> > +
> > +     if (val != 0 && val != 127)
> > +             return -EINVAL;
> 
> Why accept only 0 and 127?  Why not also accept any value in between?

Link Layer Test specification asks to set only these two values in
different tests.

> 
> > +
> > +     ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
> > +             USB_REQ_SET_FEATURE, USB_RT_PORT, USB_PORT_FEAT_U2_TIMEOUT,
> > +             lvs->portnum | (((val) & 0xff) << 8), NULL, 0, 1000);
> 
> You know that val lies between 0 and 127.  Why bother to do "((val) &
> 0xff)"?  And why do you have the extra parentheses around "val"?

OK..will correct.

> 
> > +     if (ret < 0) {
> > +             dev_err(dev, "can't set u2 Timeout %d\n", ret);
> 
> Mention val in this error message, so the reader will know what you
> were trying to set the U2 timeout to.  Also, write "U2" instead of
> "u2".

OK.

> 
> > +             return ret;
> > +     }
> > +
> > +     return count;
> > +}
> > +static DEVICE_ATTR(u2_timeout, S_IWUSR, NULL, issue_u2_timeout);
> > +
> > +static ssize_t issue_u1_timeout(struct device *dev,
> > +             struct device_attribute *attr, const char *buf, size_t count)
> > +{
> > +     struct usb_interface *intf = to_usb_interface(dev);
> > +     struct usb_device *hdev = interface_to_usbdev(intf);
> > +     struct lvs_rh *lvs = usb_get_intfdata(intf);
> > +     unsigned long val;
> > +     int ret;
> > +
> > +     ret = kstrtoul(buf, 10, &val);
> > +     if (ret < 0) {
> > +             dev_err(dev, "couldn't parse string %d\n", ret);
> > +             return ret;
> > +     }
> > +
> > +     if (val != 0 && val != 127)
> > +             return -EINVAL;
> 
> Same comments as above for U2.
> 
> > +
> > +     ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
> > +             USB_REQ_SET_FEATURE, USB_RT_PORT, USB_PORT_FEAT_U1_TIMEOUT,
> > +             lvs->portnum | (((val) & 0xff) << 8), NULL, 0, 1000);
> > +     if (ret < 0) {
> > +             dev_err(dev, "can't set U1 Timeout %d\n", ret);
> > +             return ret;
> > +     }
> > +
> > +     return count;
> > +}
> > +static DEVICE_ATTR(u1_timeout, S_IWUSR, NULL, issue_u1_timeout);
> > +
> > +static ssize_t issue_get_device_descriptor(struct device *dev,
> > +             struct device_attribute *attr, const char *buf, size_t count)
> > +{
> > +     struct usb_interface *intf = to_usb_interface(dev);
> > +     unsigned long val;
> > +     struct usb_device *udev;
> > +     int ret;
> > +
> > +     ret = kstrtoul(buf, 10, &val);
> > +     if (ret < 0) {
> > +             dev_err(dev, "couldn't parse string %d\n", ret);
> > +             return ret;
> > +     }
> > +
> > +     if (val != 1)
> > +             return -EINVAL;
> > +
> > +     udev = create_lvs_device(intf);
> > +     if (!udev) {
> > +             dev_err(dev, "failed to create lvs device\n");
> > +             return -ENOMEM;
> > +     }
> > +
> > +     ret = usb_control_msg(udev, (PIPE_CONTROL << 30) | USB_DIR_IN,
> > +                     USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, USB_DT_DEVICE << 8,
> > +                     0, &udev->descriptor, sizeof(udev->descriptor),
> > +                     USB_CTRL_GET_TIMEOUT);
> 
> An URB's buffer should be separately allocated.  Not part of a larger
> structure.

You mean to use a local memory for descriptor and not to use the one
which comes as default with udev for device descriptor?

> 
> > +     if (ret < 0)
> > +             dev_err(dev, "can't read device descriptor %d\n", ret);
> > +
> > +     destroy_lvs_device(udev);
> > +
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     return count;
> > +}
> > +static DEVICE_ATTR(get_dev_desc, S_IWUSR, NULL, issue_get_device_descriptor);
> > +
> > +static struct attribute *lvs_attributes[] = {
> > +     &dev_attr_get_dev_desc.attr,
> > +     &dev_attr_u1_timeout.attr,
> > +     &dev_attr_u2_timeout.attr,
> > +     &dev_attr_hot_reset.attr,
> > +     &dev_attr_u3_entry.attr,
> > +     &dev_attr_u3_exit.attr,
> > +     NULL
> > +};
> > +
> > +static const struct attribute_group lvs_attr_group = {
> > +     .attrs = lvs_attributes,
> > +};
> > +
> > +static void lvs_rh_irq(struct urb *urb)
> > +{
> > +     struct lvs_rh *lvs = urb->context;
> > +     struct usb_interface *intf = lvs->intf;
> > +     struct usb_device *hdev = interface_to_usbdev(intf);
> > +     struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
> > +     struct usb_hub_descriptor *descriptor = &lvs->descriptor;
> > +     struct usb_port_status port_status;
> > +     int i, ret = 0;
> > +
> > +     /* Examine each root port */
> > +     for (i = 1; i <= descriptor->bNbrPorts; i++) {
> > +             ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
> > +                     USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, i,
> > +                     &port_status, sizeof(port_status), 1000);
> 
> You cannot call usb_control_msg() from within an URB completion
> handler, because usb_control_msg() sleeps and completion handlers are
> not allowed to sleep.

Hummmmm...So I need to create a thread like hub_thread. I wanted to avoid that.
But It seems, I will have to..no other alternative.

> 
> > +             if (ret < 4)
> > +                     continue;
> > +             /* handle only connection change notification */
> > +             if (!(port_status.wPortChange & USB_PORT_STAT_C_CONNECTION))
> > +                     continue;
> > +             usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
> > +                             USB_REQ_CLEAR_FEATURE, USB_RT_PORT,
> > +                             USB_PORT_FEAT_C_CONNECTION, i, NULL, 0, 1000);
> > +
> > +             if (port_status.wPortStatus & USB_PORT_STAT_CONNECTION) {
> > +                     lvs->present = true;
> > +                     lvs->portnum = i;
> > +                     if (hcd->phy)
> > +                             usb_phy_notify_connect(hcd->phy,
> > +                                             USB_SPEED_SUPER);
> > +             } else {
> > +                     lvs->present = false;
> > +                     if (hcd->phy)
> > +                             usb_phy_notify_disconnect(hcd->phy,
> > +                                             USB_SPEED_SUPER);
> > +             }
> > +             goto resubmit;
> 
> How about just "break;" instead?  Then you could avoid using "goto" and
> you could omit the statement label.

OK.

> 
> > +     }
> 
> What happens if you exit the loop from the bottom?  That is, if no
> ports have a connect-change notification?

I ignore all other events. None of the Link Layer Tests needs them as
of now. If we see any need, we can add that in future.

> 
> > +
> > +resubmit:
> > +     ret = usb_submit_urb(lvs->urb, GFP_ATOMIC);
> > +     if (ret != 0 && ret != -ENODEV && ret != -EPERM)
> > +             dev_err(&intf->dev, "urb resubmit error %d\n", ret);
> > +}
> > +
> > +static int lvs_rh_probe(struct usb_interface *intf,
> > +             const struct usb_device_id *id)
> > +{
> > +     struct usb_device *hdev;
> > +     struct usb_host_interface *desc;
> > +     struct usb_endpoint_descriptor *endpoint;
> > +     struct lvs_rh *lvs;
> > +     unsigned int pipe;
> > +     int ret, maxp;
> > +
> > +     hdev = interface_to_usbdev(intf);
> > +     desc = intf->cur_altsetting;
> > +     endpoint = &desc->endpoint[0].desc;
> > +
> > +     /* valid only for SS root hub */
> > +     if (hdev->descriptor.bDeviceProtocol != USB_HUB_PR_SS || hdev->parent) {
> > +             dev_err(&intf->dev, "Bind LVS driver with SS root Hub only\n");
> > +             return -EINVAL;
> > +     }
> > +
> > +     /* This Root hub endpoint must be interrupt */
> > +     if (!usb_endpoint_is_int_in(endpoint)) {
> > +             dev_err(&intf->dev, "Root hub does not have interrupt endpoint\n");
> > +             return -EINVAL;
> > +     }
> 
> You don't need to test this; it is guaranteed by usbcore.

OK.

> 
> > +
> > +     lvs = devm_kzalloc(&intf->dev, sizeof(*lvs), GFP_KERNEL);
> > +     if (!lvs) {
> > +             dev_err(&intf->dev, "couldn't allocate lvs_rh struct\n");
> > +             return -ENOMEM;
> > +     }
> 
> The devm_* routines print out their own error messages if an allocation
> fails; you don't need to add your own.

OK.

> 
> > +
> > +     lvs->intf = intf;
> > +     usb_set_intfdata(intf, lvs);
> > +
> > +     /* how many number of ports this root hub has */
> > +     ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
> > +                     USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
> > +                     USB_DT_SS_HUB << 8, 0, &lvs->descriptor,
> > +                     USB_DT_SS_HUB_SIZE, USB_CTRL_GET_TIMEOUT);
> > +     if (ret < (USB_DT_HUB_NONVAR_SIZE + 2)) {
> > +             dev_err(&hdev->dev, "wrong root hub descriptor read %d\n", ret);
> > +             return ret;
> > +     }
> > +
> > +     /* submit urb to poll interrupt endpoint */
> > +     lvs->urb = usb_alloc_urb(0, GFP_KERNEL);
> > +     if (!lvs->urb) {
> > +             dev_err(&intf->dev, "couldn't allocate lvs urb\n");
> > +             return -ENOMEM;
> > +     }
> > +
> > +     pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
> > +     maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));
> > +     usb_fill_int_urb(lvs->urb, hdev, pipe, &lvs->buffer[0], maxp,
> > +                     lvs_rh_irq, lvs, endpoint->bInterval);
> > +
> > +     ret = usb_submit_urb(lvs->urb, GFP_NOIO);
> > +     if (ret < 0) {
> > +             dev_err(&intf->dev, "couldn't submit lvs urb %d\n", ret);
> 
> Here you leak lvs->urb.

Oh yes..will correct.

> 
> > +             return ret;
> > +     }
> > +
> > +     ret = sysfs_create_group(&intf->dev.kobj, &lvs_attr_group);
> > +     if (ret < 0)
> > +             dev_err(&intf->dev, "Failed to create sysfs node %d\n", ret);
> 
> Here too.

will correct.

> 
> > +
> > +     return ret;
> > +}
> > +
> > +static void lvs_rh_disconnect(struct usb_interface *intf)
> > +{
> > +     struct lvs_rh *lvs = usb_get_intfdata(intf);
> > +
> > +     sysfs_remove_group(&intf->dev.kobj, &lvs_attr_group);
> > +     usb_free_urb(lvs->urb);
> > +     usb_set_intfdata(intf, NULL);
> 
> This line isn't needed; the device core automatically clears the driver
> data field following an unbind.

OK.

> 
> > +}
> > +
> > +static const struct usb_device_id lvs_id_table[] = {
> > +     { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
> > +             .bDeviceClass = USB_CLASS_HUB},
> > +     { }
> > +};
> > +
> > +MODULE_DEVICE_TABLE(usb, lvs_id_table);
> > +
> > +static struct usb_driver lvs_driver = {
> > +     .name =         "lvs",
> > +     .probe =        lvs_rh_probe,
> > +     .disconnect =   lvs_rh_disconnect,
> > +     .id_table =     lvs_id_table,
> > +};
> > +
> > +static int __init lvs_init(void)
> > +{
> > +     return usb_register(&lvs_driver);
> > +}
> > +module_init(lvs_init);
> > +
> > +static void __exit lvs_exit(void)
> > +{
> > +     usb_deregister(&lvs_driver);
> > +}
> > +module_exit(lvs_exit);
> > +
> > +MODULE_DESCRIPTION("Link Layer Validation System Driver");
> > +MODULE_LICENSE("GPL");
> 
> Alan Stern

Thanks a lot for your quick review. Its highly appreciated.

~ Pratyush
--
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