forked from mirrors/linux
		
	USB: cdc-wdm: support back-to-back USB_CDC_NOTIFY_RESPONSE_AVAILABLE notifications
Some MBIM devices send back-to-back USB_CDC_NOTIFY_RESPONSE_AVAILABLE notifications when sending a message over multiple fragments or when there are unsolicited messages available. Count up the number of USB_CDC_NOTIFY_RESPONSE_AVAILABLE notifications received and decrement the count and submit the urb for the next response each time userspace completes a read the response. Signed-off-by: Greg Suarez <gsuarez@smithmicro.com> Acked-by: Bjørn Mork <bjorn@mork.no> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
							parent
							
								
									32e24930fb
								
							
						
					
					
						commit
						73e06865ea
					
				
					 1 changed files with 34 additions and 4 deletions
				
			
		| 
						 | 
				
			
			@ -101,6 +101,7 @@ struct wdm_device {
 | 
			
		|||
	struct work_struct	rxwork;
 | 
			
		||||
	int			werr;
 | 
			
		||||
	int			rerr;
 | 
			
		||||
	int                     resp_count;
 | 
			
		||||
 | 
			
		||||
	struct list_head	device_list;
 | 
			
		||||
	int			(*manage_power)(struct usb_interface *, int);
 | 
			
		||||
| 
						 | 
				
			
			@ -262,9 +263,9 @@ static void wdm_int_callback(struct urb *urb)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	spin_lock(&desc->iuspin);
 | 
			
		||||
	clear_bit(WDM_READ, &desc->flags);
 | 
			
		||||
	responding = test_and_set_bit(WDM_RESPONDING, &desc->flags);
 | 
			
		||||
	if (!responding && !test_bit(WDM_DISCONNECTING, &desc->flags)
 | 
			
		||||
	if (!desc->resp_count++ && !responding
 | 
			
		||||
		&& !test_bit(WDM_DISCONNECTING, &desc->flags)
 | 
			
		||||
		&& !test_bit(WDM_SUSPENDING, &desc->flags)) {
 | 
			
		||||
		rv = usb_submit_urb(desc->response, GFP_ATOMIC);
 | 
			
		||||
		dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d",
 | 
			
		||||
| 
						 | 
				
			
			@ -521,10 +522,36 @@ static ssize_t wdm_read
 | 
			
		|||
 | 
			
		||||
	desc->length -= cntr;
 | 
			
		||||
	/* in case we had outstanding data */
 | 
			
		||||
	if (!desc->length)
 | 
			
		||||
	if (!desc->length) {
 | 
			
		||||
		clear_bit(WDM_READ, &desc->flags);
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irq(&desc->iuspin);
 | 
			
		||||
		if (--desc->resp_count) {
 | 
			
		||||
			set_bit(WDM_RESPONDING, &desc->flags);
 | 
			
		||||
			spin_unlock_irq(&desc->iuspin);
 | 
			
		||||
 | 
			
		||||
			rv = usb_submit_urb(desc->response, GFP_KERNEL);
 | 
			
		||||
			if (rv) {
 | 
			
		||||
				dev_err(&desc->intf->dev,
 | 
			
		||||
					"%s: usb_submit_urb failed with result %d\n",
 | 
			
		||||
					__func__, rv);
 | 
			
		||||
				spin_lock_irq(&desc->iuspin);
 | 
			
		||||
				clear_bit(WDM_RESPONDING, &desc->flags);
 | 
			
		||||
				spin_unlock_irq(&desc->iuspin);
 | 
			
		||||
 | 
			
		||||
				if (rv == -ENOMEM) {
 | 
			
		||||
					rv = schedule_work(&desc->rxwork);
 | 
			
		||||
					if (rv)
 | 
			
		||||
						dev_err(&desc->intf->dev, "Cannot schedule work\n");
 | 
			
		||||
				} else {
 | 
			
		||||
					spin_lock_irq(&desc->iuspin);
 | 
			
		||||
					desc->resp_count = 0;
 | 
			
		||||
					spin_unlock_irq(&desc->iuspin);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else
 | 
			
		||||
			spin_unlock_irq(&desc->iuspin);
 | 
			
		||||
	} else
 | 
			
		||||
		spin_unlock_irq(&desc->iuspin);
 | 
			
		||||
 | 
			
		||||
	rv = cntr;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -635,6 +662,9 @@ static int wdm_release(struct inode *inode, struct file *file)
 | 
			
		|||
		if (!test_bit(WDM_DISCONNECTING, &desc->flags)) {
 | 
			
		||||
			dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
 | 
			
		||||
			kill_urbs(desc);
 | 
			
		||||
			spin_lock_irq(&desc->iuspin);
 | 
			
		||||
			desc->resp_count = 0;
 | 
			
		||||
			spin_unlock_irq(&desc->iuspin);
 | 
			
		||||
			desc->manage_power(desc->intf, 0);
 | 
			
		||||
		} else {
 | 
			
		||||
			/* must avoid dev_printk here as desc->intf is invalid */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue