Re: USB Storage Device Not Working

balajirrao <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <20071113185748.GA4150@yogi>
On Mon, Nov 12, 2007 at 03:29:57PM -0500, Alan Stern wrote:
> On Mon, 12 Nov 2007, balajirrao wrote:
> 
Thank you for replying.
> > > You will have to add a new method pointer to struct usb_hcd, maybe call
> 
> I made a mistake here.  The new method pointer should be added to 
> struct hc_driver, not struct usb_hcd.  In other words, it should be 
> stored along with all the other method pointers.
> 
Oh.. I thought that may be it should go to hc_driver. But because you
told me, i put it in usb_hcd itself. I shall put it in hc_driver itself.
> > Also, there is one more problem. When the device which is forced to work
> > by the kernel to work under companion is removed, the port should be
> > removed from the companion list. Otherwise, when another high speed
> > device is plugged into the same port, it would work in full speed.
> 
> This happens automatically.  For example, if you plug in a full-speed 
> device it gets handed to the companion; when the device is unplugged 
> and you plug a high-speed device into the same port, the new device is 
> not forced to run at full speed.
Right. But not with this patch applied, as the method to force a device
to work under companion is not the way the kernel does it for  full
speed devices plugged into hi speed ports.

I think i need to change the way the device is handed over to the
companion. It is implemented in a wrong manner in this patch. What it
does is, it sets the bit in companion_ports, and the port number is
shown up in the companion list. And this is the cause for the problem
mentioned above.

> 
> > So, my idea is to have a variable called forced_companion_ports, and a
> > method called un_relinqush, which takes care of removing the forced from
> > the companion list.
> 
> You don't need this.  And you don't need to add anything to the 
> companion list either.  Just hand the port to the companion and leave 
> the list alone.
> 
Right. I understand it now.
> > But i didnt know from where to call this function.
> > I tried calling it in the hub_port_connect_change function, but i got a
> > OOPS in which khubd was killed. So if i could know which port the
> > disconnected device was connected to, it would be helpful i guess.
> > 
> > The patch is inlined below. Please comment. (Please tell where i am
> > wrong. )
> > 
> > Index: linux-2.6.24-rc2-usb/drivers/usb/host/ehci-hcd.c
> > ===================================================================
> > --- linux-2.6.24-rc2-usb.orig/drivers/usb/host/ehci-hcd.c
> > +++ linux-2.6.24-rc2-usb/drivers/usb/host/ehci-hcd.c
> > @@ -433,6 +433,13 @@ static void ehci_stop (struct usb_hcd *h
> >  		    ehci_readl(ehci, &ehci->regs->status));
> >  }
> >  
> > +static void relinquish_port (struct usb_hcd *hcd, int port_num) {
> > +	struct ehci_hcd *ehci;
> > +
> > +	ehci = hcd_to_ehci(hcd);
> > + 	store_companion(ehci, port_num, PORT_OWNER);	
> 
> Don't steal an existing name for your new routine.  Make up a new name
> for it, like set_port_companion().
> 
> Remember also that not all EHCI controllers have companions.  Some have
> built-in Transaction Translators; I don't know how to force such
> controllers to set a port to full speed (maybe it can't be done).  See
> how the ehci_is_TDI() test is used.  Your code must work with both
> sorts of controllers.
> 
I think the hardware takes of this if the device wont work under high
speed. 
> And don't forget that none of this should even be attempted if the port 
> doesn't belong to the root hub.  There's no way to tell an external hub 
> to force a port to full speed.  Your routine needs to test for this.
>
But suppose, a full speed device is plugged into a external hub. Wont
ehci_hcd then hand it over to the companion controller ? 
Ok. Then I need to find out how to indentify a root hub.
> > +}
> > +
> >  /* one-time init, only for memory state */
> >  static int ehci_init(struct usb_hcd *hcd)
> >  {
> > @@ -443,6 +450,8 @@ static int ehci_init(struct usb_hcd *hcd
> >  
> >  	spin_lock_init(&ehci->lock);
> >  
> > +	hcd->relinquish_port = relinquish_port;
> > +
> 
> This field should be part of the hc_driver structure, not the usb_hcd
> structure.  It should be initialized statically in ehci-pci.c, along
> with the rest of ehci_pci_hc_driver.
> 
> >  	init_timer(&ehci->watchdog);
> >  	ehci->watchdog.function = ehci_watchdog;
> >  	ehci->watchdog.data = (unsigned long) ehci;
> > Index: linux-2.6.24-rc2-usb/drivers/usb/host/ehci-hub.c
> > ===================================================================
> > --- linux-2.6.24-rc2-usb.orig/drivers/usb/host/ehci-hub.c
> > +++ linux-2.6.24-rc2-usb/drivers/usb/host/ehci-hub.c
> > @@ -316,24 +316,12 @@ static ssize_t show_companion(struct cla
> >   * Syntax is "[-]portnum", where a leading '-' sign means
> >   * return control of the port to the EHCI controller.
> >   */
> > -static ssize_t store_companion(struct class_device *class_dev,
> > -		const char *buf, size_t count)
> > -{
> > -	struct ehci_hcd		*ehci;
> > -	int			portnum, new_owner, try;
> > +void store_companion(struct ehci_hcd *ehci, int portnum, int new_owner)
> 
> Change the new routine's name.
> 
> > +{			
> >  	u32 __iomem		*status_reg;
> >  	u32			port_status;
> > -
> > -	ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
> > -	new_owner = PORT_OWNER;		/* Owned by companion */
> > -	if (sscanf(buf, "%d", &portnum) != 1)
> > -		return -EINVAL;
> > -	if (portnum < 0) {
> > -		portnum = - portnum;
> > -		new_owner = 0;		/* Owned by EHCI */
> > -	}
> > -	if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
> > -		return -ENOENT;
> > +	int			try;
> > +	
> >  	status_reg = &ehci->regs->port_status[--portnum];
> >  	if (new_owner)
> >  		set_bit(portnum, &ehci->companion_ports);
> > @@ -341,10 +329,10 @@ static ssize_t store_companion(struct cl
> >  		clear_bit(portnum, &ehci->companion_ports);
> >  
> >  	/*
> > -	 * The controller won't set the OWNER bit if the port is
> > -	 * enabled, so this loop will sometimes require at least two
> > -	 * iterations: one to disable the port and one to set OWNER.
> > -	 */
> > +	* The controller won't set the OWNER bit if the port is
> > +	* enabled, so this loop will sometimes require at least two
> > +	* iterations: one to disable the port and one to set OWNER.
> > +	*/
> 
> Don't change the spacing of existing comments, especially if the old 
> spacing was correct and your new spacing is wrong.
> 
Sorry. This was not intended.
> >  
> >  	for (try = 4; try > 0; --try) {
> >  		spin_lock_irq(&ehci->lock);
> > @@ -361,10 +349,29 @@ static ssize_t store_companion(struct cl
> >  		spin_unlock_irq(&ehci->lock);
> >  		if (try > 1)
> >  			msleep(5);
> > +	}	
> > +}
> > +
> > +static ssize_t sysfs_store_companion(struct class_device *class_dev,
> > +		const char *buf, size_t count) {
> 
> Don't change the names of existing routines.
> 
> > +	
> > +	struct ehci_hcd		*ehci;
> > +	int			portnum, new_owner;
> > +		
> > +	ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
> > +	new_owner = PORT_OWNER;		/* Owned by companion */
> > +	if (sscanf(buf, "%d", &portnum) != 1)
> > +		return -EINVAL;
> > +	if (portnum < 0) {
> > +		portnum = - portnum;
> > +		new_owner = 0;		/* Owned by EHCI */
> >  	}
> > +	if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
> > +		return -ENOENT;
> > +	store_companion(ehci, portnum, new_owner);
> >  	return count;
> >  }
> > -static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion);
> > +static CLASS_DEVICE_ATTR(companion, 0644, show_companion, sysfs_store_companion);
> >  
> >  static inline void create_companion_file(struct ehci_hcd *ehci)
> >  {
> > Index: linux-2.6.24-rc2-usb/drivers/usb/core/hcd.h
> > ===================================================================
> > --- linux-2.6.24-rc2-usb.orig/drivers/usb/core/hcd.h
> > +++ linux-2.6.24-rc2-usb/drivers/usb/core/hcd.h
> > @@ -90,6 +90,8 @@ struct usb_hcd {
> >  #define HCD_FLAG_HW_ACCESSIBLE	0x00000001
> >  #define HCD_FLAG_SAW_IRQ	0x00000002
> >  
> > +	void 		(*relinquish_port)(struct usb_hcd *, int port_num);
> > +
> 
> Put this in struct hc_driver, not struct usb_hcd.  And add a comment 
> explaining what it's supposed to do.
> 
OK. I shall do it.
> >  	unsigned		rh_registered:1;/* is root hub registered? */
> >  
> >  	/* The next flag is a stopgap, to be removed when all the HCDs
> > @@ -110,6 +112,7 @@ struct usb_hcd {
> >  	struct dma_pool		*pool [HCD_BUFFER_POOLS];
> >  
> >  	int			state;
> > +	
> 
> Don't add extra blank lines to existing code.
> 
Sorry, by mistake.
> >  #	define	__ACTIVE		0x01
> >  #	define	__SUSPEND		0x04
> >  #	define	__TRANSIENT		0x80
> > Index: linux-2.6.24-rc2-usb/drivers/usb/core/hub.c
> > ===================================================================
> > --- linux-2.6.24-rc2-usb.orig/drivers/usb/core/hub.c
> > +++ linux-2.6.24-rc2-usb/drivers/usb/core/hub.c
> > @@ -2484,6 +2484,7 @@ static void hub_port_connect_change(stru
> >  	struct device *hub_dev = hub->intfdev;
> >  	u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
> >  	int status, i;
> > +	struct usb_hcd *hcd;
> >   
> >  	dev_dbg (hub_dev,
> >  		"port %d, status %04x, change %04x, %s\n",
> > @@ -2644,6 +2645,9 @@ loop:
> >  	}
> >   
> >  done:
> > +	hcd = bus_to_hcd(hub->hdev->bus);
> > +	if (hcd->relinquish_port)
> > +		hcd->relinquish_port(hcd, port1);
> >  	hub_port_disable(hub, port1, 1);
> >  }
> 
> This should be hcd->driver->relinquish_port, not hcd->relinquish_port.
> 
> Alan Stern
> 
thank you,

regards,
balaji rao

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.