diff options
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 91 | 
1 files changed, 47 insertions, 44 deletions
| diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 7f6f3ab5b8a6..1e7568867910 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -173,7 +173,7 @@ static int acm_wb_alloc(struct acm *acm)  	for (;;) {  		wb = &acm->wb[wbn];  		if (!wb->use) { -			wb->use = 1; +			wb->use = true;  			wb->len = 0;  			return wbn;  		} @@ -191,7 +191,8 @@ static int acm_wb_is_avail(struct acm *acm)  	n = ACM_NW;  	spin_lock_irqsave(&acm->write_lock, flags);  	for (i = 0; i < ACM_NW; i++) -		n -= acm->wb[i].use; +		if(acm->wb[i].use) +			n--;  	spin_unlock_irqrestore(&acm->write_lock, flags);  	return n;  } @@ -201,7 +202,7 @@ static int acm_wb_is_avail(struct acm *acm)   */  static void acm_write_done(struct acm *acm, struct acm_wb *wb)  { -	wb->use = 0; +	wb->use = false;  	acm->transmitting--;  	usb_autopm_put_interface_async(acm->control);  } @@ -507,6 +508,7 @@ static void acm_read_bulk_callback(struct urb *urb)  			"%s - cooling babbling device\n", __func__);  		usb_mark_last_busy(acm->dev);  		set_bit(rb->index, &acm->urbs_in_error_delay); +		set_bit(ACM_ERROR_DELAY, &acm->flags);  		cooldown = true;  		break;  	default: @@ -532,7 +534,7 @@ static void acm_read_bulk_callback(struct urb *urb)  	if (stopped || stalled || cooldown) {  		if (stalled) -			schedule_work(&acm->work); +			schedule_delayed_work(&acm->dwork, 0);  		else if (cooldown)  			schedule_delayed_work(&acm->dwork, HZ / 2);  		return; @@ -562,13 +564,13 @@ static void acm_write_bulk(struct urb *urb)  	acm_write_done(acm, wb);  	spin_unlock_irqrestore(&acm->write_lock, flags);  	set_bit(EVENT_TTY_WAKEUP, &acm->flags); -	schedule_work(&acm->work); +	schedule_delayed_work(&acm->dwork, 0);  }  static void acm_softint(struct work_struct *work)  {  	int i; -	struct acm *acm = container_of(work, struct acm, work); +	struct acm *acm = container_of(work, struct acm, dwork.work);  	if (test_bit(EVENT_RX_STALL, &acm->flags)) {  		smp_mb(); /* against acm_suspend() */ @@ -584,7 +586,7 @@ static void acm_softint(struct work_struct *work)  	if (test_and_clear_bit(ACM_ERROR_DELAY, &acm->flags)) {  		for (i = 0; i < acm->rx_buflimit; i++)  			if (test_and_clear_bit(i, &acm->urbs_in_error_delay)) -					acm_submit_read_urb(acm, i, GFP_NOIO); +				acm_submit_read_urb(acm, i, GFP_KERNEL);  	}  	if (test_and_clear_bit(EVENT_TTY_WAKEUP, &acm->flags)) @@ -741,7 +743,7 @@ static void acm_port_shutdown(struct tty_port *port)  		if (!urb)  			break;  		wb = urb->context; -		wb->use = 0; +		wb->use = false;  		usb_autopm_put_interface_async(acm->control);  	} @@ -792,7 +794,7 @@ static int acm_tty_write(struct tty_struct *tty,  	wb = &acm->wb[wbn];  	if (!acm->dev) { -		wb->use = 0; +		wb->use = false;  		spin_unlock_irqrestore(&acm->write_lock, flags);  		return -ENODEV;  	} @@ -804,7 +806,7 @@ static int acm_tty_write(struct tty_struct *tty,  	stat = usb_autopm_get_interface_async(acm->control);  	if (stat) { -		wb->use = 0; +		wb->use = false;  		spin_unlock_irqrestore(&acm->write_lock, flags);  		return stat;  	} @@ -1196,9 +1198,6 @@ static int acm_probe(struct usb_interface *intf,  		return -EINVAL;  	} -	if (!intf->cur_altsetting) -		return -EINVAL; -  	if (!buflen) {  		if (intf->cur_altsetting->endpoint &&  				intf->cur_altsetting->endpoint->extralen && @@ -1221,39 +1220,42 @@ static int acm_probe(struct usb_interface *intf,  		call_intf_num = cmgmd->bDataInterface;  	if (!union_header) { -		if (call_intf_num > 0) { +		if (intf->cur_altsetting->desc.bNumEndpoints == 3) { +			dev_dbg(&intf->dev, "No union descriptor, assuming single interface\n"); +			combined_interfaces = 1; +			control_interface = data_interface = intf; +			goto look_for_collapsed_interface; +		} else if (call_intf_num > 0) {  			dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n"); -			/* quirks for Droids MuIn LCD */ -			if (quirks & NO_DATA_INTERFACE) { -				data_interface = usb_ifnum_to_if(usb_dev, 0); -			} else { -				data_intf_num = call_intf_num; -				data_interface = usb_ifnum_to_if(usb_dev, data_intf_num); -			} +			data_intf_num = call_intf_num; +			data_interface = usb_ifnum_to_if(usb_dev, data_intf_num);  			control_interface = intf;  		} else { -			if (intf->cur_altsetting->desc.bNumEndpoints != 3) { -				dev_dbg(&intf->dev,"No union descriptor, giving up\n"); -				return -ENODEV; -			} else { -				dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n"); -				combined_interfaces = 1; -				control_interface = data_interface = intf; -				goto look_for_collapsed_interface; -			} +			dev_dbg(&intf->dev, "No union descriptor, giving up\n"); +			return -ENODEV;  		}  	} else { +		int class = -1; +  		data_intf_num = union_header->bSlaveInterface0;  		control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);  		data_interface = usb_ifnum_to_if(usb_dev, data_intf_num); + +		if (control_interface) +			class = control_interface->cur_altsetting->desc.bInterfaceClass; + +		if (class != USB_CLASS_COMM && class != USB_CLASS_CDC_DATA) { +			dev_dbg(&intf->dev, "Broken union descriptor, assuming single interface\n"); +			combined_interfaces = 1; +			control_interface = data_interface = intf; +			goto look_for_collapsed_interface; +		}  	}  	if (!control_interface || !data_interface) {  		dev_dbg(&intf->dev, "no interfaces\n");  		return -ENODEV;  	} -	if (!data_interface->cur_altsetting || !control_interface->cur_altsetting) -		return -ENODEV;  	if (data_intf_num != call_intf_num)  		dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n"); @@ -1280,10 +1282,8 @@ look_for_collapsed_interface:  skip_normal_probe:  	/*workaround for switched interfaces */ -	if (data_interface->cur_altsetting->desc.bInterfaceClass -						!= CDC_DATA_INTERFACE_TYPE) { -		if (control_interface->cur_altsetting->desc.bInterfaceClass -						== CDC_DATA_INTERFACE_TYPE) { +	if (data_interface->cur_altsetting->desc.bInterfaceClass != USB_CLASS_CDC_DATA) { +		if (control_interface->cur_altsetting->desc.bInterfaceClass == USB_CLASS_CDC_DATA) {  			dev_dbg(&intf->dev,  				"Your device has switched interfaces.\n");  			swap(control_interface, data_interface); @@ -1352,7 +1352,6 @@ made_compressed_probe:  	acm->ctrlsize = ctrlsize;  	acm->readsize = readsize;  	acm->rx_buflimit = num_rx_buf; -	INIT_WORK(&acm->work, acm_softint);  	INIT_DELAYED_WORK(&acm->dwork, acm_softint);  	init_waitqueue_head(&acm->wioctl);  	spin_lock_init(&acm->write_lock); @@ -1562,7 +1561,6 @@ static void acm_disconnect(struct usb_interface *intf)  	}  	acm_kill_urbs(acm); -	cancel_work_sync(&acm->work);  	cancel_delayed_work_sync(&acm->dwork);  	tty_unregister_device(acm_tty_driver, acm->minor); @@ -1605,7 +1603,6 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)  		return 0;  	acm_kill_urbs(acm); -	cancel_work_sync(&acm->work);  	cancel_delayed_work_sync(&acm->dwork);  	acm->urbs_in_error_delay = 0; @@ -1876,11 +1873,6 @@ static const struct usb_device_id acm_ids[] = {  	/* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ -	/* Support for Droids MuIn LCD */ -	{ USB_DEVICE(0x04d8, 0x000b), -	.driver_info = NO_DATA_INTERFACE, -	}, -  #if IS_ENABLED(CONFIG_INPUT_IMS_PCU)  	{ USB_DEVICE(0x04d8, 0x0082),	/* Application mode */  	.driver_info = IGNORE_DEVICE, @@ -1906,6 +1898,17 @@ static const struct usb_device_id acm_ids[] = {  	.driver_info = IGNORE_DEVICE,  	}, +	/* Exclude ETAS ES58x */ +	{ USB_DEVICE(0x108c, 0x0159), /* ES581.4 */ +	.driver_info = IGNORE_DEVICE, +	}, +	{ USB_DEVICE(0x108c, 0x0168), /* ES582.1 */ +	.driver_info = IGNORE_DEVICE, +	}, +	{ USB_DEVICE(0x108c, 0x0169), /* ES584.1 */ +	.driver_info = IGNORE_DEVICE, +	}, +  	{ USB_DEVICE(0x1bc7, 0x0021), /* Telit 3G ACM only composition */  	.driver_info = SEND_ZERO_PACKET,  	}, |