Re: usb mass storage bug

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

 



On Thu, Oct 24, 2013 at 12:09:03PM -0400, Alan Stern wrote:
> On Thu, 24 Oct 2013, [iso-8859-2] J�nosi Zoli wrote:
> 
> > https://bugzilla.kernel.org/show_bug.cgi?id=63611
> > �
> > Bug ID: 63611
> > Summary: cant connect sony phones in mass storage mode
> 
> Is CONFIG_USB_OTG turned on in your kernel's .config?  If it is, try 
> building a new kernel with it turned off.

Sorry for the long delay here. This got lost in my maildir for whatever
reason.

> Felipe:
> 
> Is the usb_enumerate_device_otg() routine really correct?  It looks 
> like it will try to enable HNP whenever CONFIG_USB_OTG is set, even if 
> the root hub isn't OTG-capable.
> 
> The routine does this:
> 
> 				/* enable HNP before suspend, it's simpler */
> 				if (port1 == bus->otg_port)
> 					bus->b_hnp_enable = 1;
> 				err = usb_control_msg(udev,
> 					usb_sndctrlpipe(udev, 0),
> 					USB_REQ_SET_FEATURE, 0,
> 					bus->b_hnp_enable
> 						? USB_DEVICE_B_HNP_ENABLE
> 						: USB_DEVICE_A_ALT_HNP_SUPPORT,
> 					0, NULL, 0, USB_CTRL_SET_TIMEOUT);
> 				if (err < 0) {
> 					/* OTG MESSAGE: report errors here,
> 					 * customize to match your product.
> 					 */
> 					dev_info(&udev->dev,
> 						"can't set HNP mode: %d\n",
> 						err);
> 					bus->b_hnp_enable = 0;
> 				}
> 
> Maybe the usb_control_msg and the error check should be inside the 
> first "if" statement?

I don't think so, see below:

| static int usb_enumerate_device_otg(struct usb_device *udev)
| {
| 	int err = 0;
| 
| #ifdef	CONFIG_USB_OTG

first, we know OTG is enabled.

| 	/*
| 	 * OTG-aware devices on OTG-capable root hubs may be able to use SRP,
| 	 * to wake us after we've powered off VBUS; and HNP, switching roles
| 	 * "host" to "peripheral".  The OTG descriptor helps figure this out.
| 	 */
| 	if (!udev->bus->is_b_host
| 			&& udev->config
| 			&& udev->parent == udev->bus->root_hub) {
| 		struct usb_otg_descriptor	*desc = NULL;
| 		struct usb_bus			*bus = udev->bus;
| 
| 		/* descriptor may appear anywhere in config */
| 		if (__usb_get_extra_descriptor (udev->rawdescriptors[0],
| 					le16_to_cpu(udev->config[0].desc.wTotalLength),
| 					USB_DT_OTG, (void **) &desc) == 0) {
| 			if (desc->bmAttributes & USB_OTG_HNP) {

this check ensures the port supports HNP

| 				unsigned		port1 = udev->portnum;
| 
| 				dev_info(&udev->dev,
| 					"Dual-Role OTG device on %sHNP port\n",
| 					(port1 == bus->otg_port)
| 						? "" : "non-");
| 
| 				/* enable HNP before suspend, it's simpler */
| 				if (port1 == bus->otg_port)
| 					bus->b_hnp_enable = 1;

this check tells is just to help you choose between enabling HNP on a B
device, or telling the device that another root hub port supports HNP

| 				err = usb_control_msg(udev,
| 					usb_sndctrlpipe(udev, 0),
| 					USB_REQ_SET_FEATURE, 0,
| 					bus->b_hnp_enable
| 						? USB_DEVICE_B_HNP_ENABLE
| 						: USB_DEVICE_A_ALT_HNP_SUPPORT,

so, based on this, we're just enabling HNP on the device, but HNP won't
kick in until the root hub port is suspended.

| 					0, NULL, 0, USB_CTRL_SET_TIMEOUT);
| 				if (err < 0) {
| 					/* OTG MESSAGE: report errors here,
| 					 * customize to match your product.
| 					 */
| 					dev_info(&udev->dev,
| 						"can't set HNP mode: %d\n",
| 						err);
| 					bus->b_hnp_enable = 0;
| 				}
| 			}
| 		}
| 	}
| 
| 	if (!is_targeted(udev)) {

and, BTW, this needs to change. We shouldn't have a TPL *in* the kernel
as that hinders the possibility of allowing USB Accessory manufactures
to ship their driver in an App Store of some sort. Basically,
is_targeted() should return false only after we know the device doesn't
bind to any of our USB drivers. But that's for future, as that'd be a
*really* invasive change to usbcore.

hope this helps.

-- 
balbi

Attachment: signature.asc
Description: Digital signature


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

  Powered by Linux