Skip to content

Commit 7c9704c

Browse files
bmorkgregkh
authored andcommitted
net: qmi_wwan: set correct altsetting for Gobi 1K devices
[ Upstream commit b701f16 ] commit bd877e4 ("net: qmi_wwan: use a single bind function for all device types") made Gobi 1K devices fail probing. Using the number of endpoints in the default altsetting to decide whether the function use one or two interfaces is wrong. Other altsettings may provide more endpoints. With Gobi 1K devices, USB interface #3's altsetting is 0 by default, but altsetting 0 only provides one interrupt endpoint and is not sufficent for QMI. Altsetting 1 provides all 3 endpoints required for qmi_wwan and works with QMI. Gobi 1K layout for intf#3 is: Interface Descriptor: 255/255/255 bInterfaceNumber 3 bAlternateSetting 0 Endpoint Descriptor: Interrupt IN Interface Descriptor: 255/255/255 bInterfaceNumber 3 bAlternateSetting 1 Endpoint Descriptor: Interrupt IN Endpoint Descriptor: Bulk IN Endpoint Descriptor: Bulk OUT Prior to commit bd877e4, we would call usbnet_get_endpoints before giving up finding enough endpoints. Removing the early endpoint number test and the strict functional descriptor requirement allow qmi_wwan_bind to continue until usbnet_get_endpoints has made the final attempt to collect endpoints. This restores the behaviour from before commit bd877e4 without losing the added benefit of using a single bind function. The driver has always required a CDC Union functional descriptor for two-interface functions. Using the existence of this descriptor to detect two-interface functions is the logically correct method. Reported-by: Dan Williams <dcbw@redhat.com> Signed-off-by: Bjørn Mork <bjorn@mork.no> Tested-by: Dan Williams <dcbw@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 5367fe7 commit 7c9704c

1 file changed

Lines changed: 16 additions & 33 deletions

File tree

drivers/net/usb/qmi_wwan.c

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -139,16 +139,9 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
139139

140140
BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) < sizeof(struct qmi_wwan_state)));
141141

142-
/* control and data is shared? */
143-
if (intf->cur_altsetting->desc.bNumEndpoints == 3) {
144-
info->control = intf;
145-
info->data = intf;
146-
goto shared;
147-
}
148-
149-
/* else require a single interrupt status endpoint on control intf */
150-
if (intf->cur_altsetting->desc.bNumEndpoints != 1)
151-
goto err;
142+
/* set up initial state */
143+
info->control = intf;
144+
info->data = intf;
152145

153146
/* and a number of CDC descriptors */
154147
while (len > 3) {
@@ -207,25 +200,14 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
207200
buf += h->bLength;
208201
}
209202

210-
/* did we find all the required ones? */
211-
if (!(found & (1 << USB_CDC_HEADER_TYPE)) ||
212-
!(found & (1 << USB_CDC_UNION_TYPE))) {
213-
dev_err(&intf->dev, "CDC functional descriptors missing\n");
214-
goto err;
215-
}
216-
217-
/* verify CDC Union */
218-
if (desc->bInterfaceNumber != cdc_union->bMasterInterface0) {
219-
dev_err(&intf->dev, "bogus CDC Union: master=%u\n", cdc_union->bMasterInterface0);
220-
goto err;
221-
}
222-
223-
/* need to save these for unbind */
224-
info->control = intf;
225-
info->data = usb_ifnum_to_if(dev->udev, cdc_union->bSlaveInterface0);
226-
if (!info->data) {
227-
dev_err(&intf->dev, "bogus CDC Union: slave=%u\n", cdc_union->bSlaveInterface0);
228-
goto err;
203+
/* Use separate control and data interfaces if we found a CDC Union */
204+
if (cdc_union) {
205+
info->data = usb_ifnum_to_if(dev->udev, cdc_union->bSlaveInterface0);
206+
if (desc->bInterfaceNumber != cdc_union->bMasterInterface0 || !info->data) {
207+
dev_err(&intf->dev, "bogus CDC Union: master=%u, slave=%u\n",
208+
cdc_union->bMasterInterface0, cdc_union->bSlaveInterface0);
209+
goto err;
210+
}
229211
}
230212

231213
/* errors aren't fatal - we can live with the dynamic address */
@@ -235,11 +217,12 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
235217
}
236218

237219
/* claim data interface and set it up */
238-
status = usb_driver_claim_interface(driver, info->data, dev);
239-
if (status < 0)
240-
goto err;
220+
if (info->control != info->data) {
221+
status = usb_driver_claim_interface(driver, info->data, dev);
222+
if (status < 0)
223+
goto err;
224+
}
241225

242-
shared:
243226
status = qmi_wwan_register_subdriver(dev);
244227
if (status < 0 && info->control != info->data) {
245228
usb_set_intfdata(info->data, NULL);

0 commit comments

Comments
 (0)