diff options
Diffstat (limited to 'drivers/net/usb/qmi_wwan.c')
-rw-r--r-- | drivers/net/usb/qmi_wwan.c | 47 |
1 files changed, 17 insertions, 30 deletions
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 3543c9e57824..6883c371c59f 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c | |||
@@ -108,7 +108,7 @@ static int qmi_wwan_register_subdriver(struct usbnet *dev) | |||
108 | atomic_set(&info->pmcount, 0); | 108 | atomic_set(&info->pmcount, 0); |
109 | 109 | ||
110 | /* register subdriver */ | 110 | /* register subdriver */ |
111 | subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc, 512, &qmi_wwan_cdc_wdm_manage_power); | 111 | subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc, 4096, &qmi_wwan_cdc_wdm_manage_power); |
112 | if (IS_ERR(subdriver)) { | 112 | if (IS_ERR(subdriver)) { |
113 | dev_err(&info->control->dev, "subdriver registration failed\n"); | 113 | dev_err(&info->control->dev, "subdriver registration failed\n"); |
114 | rv = PTR_ERR(subdriver); | 114 | rv = PTR_ERR(subdriver); |
@@ -139,10 +139,18 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) | |||
139 | 139 | ||
140 | BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) < sizeof(struct qmi_wwan_state))); | 140 | BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) < sizeof(struct qmi_wwan_state))); |
141 | 141 | ||
142 | /* require a single interrupt status endpoint for subdriver */ | 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 */ | ||
143 | if (intf->cur_altsetting->desc.bNumEndpoints != 1) | 150 | if (intf->cur_altsetting->desc.bNumEndpoints != 1) |
144 | goto err; | 151 | goto err; |
145 | 152 | ||
153 | /* and a number of CDC descriptors */ | ||
146 | while (len > 3) { | 154 | while (len > 3) { |
147 | struct usb_descriptor_header *h = (void *)buf; | 155 | struct usb_descriptor_header *h = (void *)buf; |
148 | 156 | ||
@@ -231,8 +239,9 @@ next_desc: | |||
231 | if (status < 0) | 239 | if (status < 0) |
232 | goto err; | 240 | goto err; |
233 | 241 | ||
242 | shared: | ||
234 | status = qmi_wwan_register_subdriver(dev); | 243 | status = qmi_wwan_register_subdriver(dev); |
235 | if (status < 0) { | 244 | if (status < 0 && info->control != info->data) { |
236 | usb_set_intfdata(info->data, NULL); | 245 | usb_set_intfdata(info->data, NULL); |
237 | usb_driver_release_interface(driver, info->data); | 246 | usb_driver_release_interface(driver, info->data); |
238 | } | 247 | } |
@@ -241,20 +250,6 @@ err: | |||
241 | return status; | 250 | return status; |
242 | } | 251 | } |
243 | 252 | ||
244 | /* Some devices combine the "control" and "data" functions into a | ||
245 | * single interface with all three endpoints: interrupt + bulk in and | ||
246 | * out | ||
247 | */ | ||
248 | static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf) | ||
249 | { | ||
250 | struct qmi_wwan_state *info = (void *)&dev->data; | ||
251 | |||
252 | /* control and data is shared */ | ||
253 | info->control = intf; | ||
254 | info->data = intf; | ||
255 | return qmi_wwan_register_subdriver(dev); | ||
256 | } | ||
257 | |||
258 | static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf) | 253 | static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf) |
259 | { | 254 | { |
260 | struct qmi_wwan_state *info = (void *)&dev->data; | 255 | struct qmi_wwan_state *info = (void *)&dev->data; |
@@ -331,20 +326,12 @@ static const struct driver_info qmi_wwan_info = { | |||
331 | .manage_power = qmi_wwan_manage_power, | 326 | .manage_power = qmi_wwan_manage_power, |
332 | }; | 327 | }; |
333 | 328 | ||
334 | static const struct driver_info qmi_wwan_shared = { | ||
335 | .description = "WWAN/QMI device", | ||
336 | .flags = FLAG_WWAN, | ||
337 | .bind = qmi_wwan_bind_shared, | ||
338 | .unbind = qmi_wwan_unbind, | ||
339 | .manage_power = qmi_wwan_manage_power, | ||
340 | }; | ||
341 | |||
342 | #define HUAWEI_VENDOR_ID 0x12D1 | 329 | #define HUAWEI_VENDOR_ID 0x12D1 |
343 | 330 | ||
344 | /* map QMI/wwan function by a fixed interface number */ | 331 | /* map QMI/wwan function by a fixed interface number */ |
345 | #define QMI_FIXED_INTF(vend, prod, num) \ | 332 | #define QMI_FIXED_INTF(vend, prod, num) \ |
346 | USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \ | 333 | USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \ |
347 | .driver_info = (unsigned long)&qmi_wwan_shared | 334 | .driver_info = (unsigned long)&qmi_wwan_info |
348 | 335 | ||
349 | /* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */ | 336 | /* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */ |
350 | #define QMI_GOBI1K_DEVICE(vend, prod) \ | 337 | #define QMI_GOBI1K_DEVICE(vend, prod) \ |
@@ -372,15 +359,15 @@ static const struct usb_device_id products[] = { | |||
372 | }, | 359 | }, |
373 | { /* Huawei E392, E398 and possibly others in "Windows mode" */ | 360 | { /* Huawei E392, E398 and possibly others in "Windows mode" */ |
374 | USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 17), | 361 | USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 17), |
375 | .driver_info = (unsigned long)&qmi_wwan_shared, | 362 | .driver_info = (unsigned long)&qmi_wwan_info, |
376 | }, | 363 | }, |
377 | { /* Pantech UML290, P4200 and more */ | 364 | { /* Pantech UML290, P4200 and more */ |
378 | USB_VENDOR_AND_INTERFACE_INFO(0x106c, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff), | 365 | USB_VENDOR_AND_INTERFACE_INFO(0x106c, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff), |
379 | .driver_info = (unsigned long)&qmi_wwan_shared, | 366 | .driver_info = (unsigned long)&qmi_wwan_info, |
380 | }, | 367 | }, |
381 | { /* Pantech UML290 - newer firmware */ | 368 | { /* Pantech UML290 - newer firmware */ |
382 | USB_VENDOR_AND_INTERFACE_INFO(0x106c, USB_CLASS_VENDOR_SPEC, 0xf1, 0xff), | 369 | USB_VENDOR_AND_INTERFACE_INFO(0x106c, USB_CLASS_VENDOR_SPEC, 0xf1, 0xff), |
383 | .driver_info = (unsigned long)&qmi_wwan_shared, | 370 | .driver_info = (unsigned long)&qmi_wwan_info, |
384 | }, | 371 | }, |
385 | 372 | ||
386 | /* 3. Combined interface devices matching on interface number */ | 373 | /* 3. Combined interface devices matching on interface number */ |
@@ -467,7 +454,7 @@ static int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id | |||
467 | */ | 454 | */ |
468 | if (!id->driver_info) { | 455 | if (!id->driver_info) { |
469 | dev_dbg(&intf->dev, "setting defaults for dynamic device id\n"); | 456 | dev_dbg(&intf->dev, "setting defaults for dynamic device id\n"); |
470 | id->driver_info = (unsigned long)&qmi_wwan_shared; | 457 | id->driver_info = (unsigned long)&qmi_wwan_info; |
471 | } | 458 | } |
472 | 459 | ||
473 | return usbnet_probe(intf, id); | 460 | return usbnet_probe(intf, id); |