diff options
author | Bjørn Mork <bjorn@mork.no> | 2012-09-07 03:36:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-09-07 14:50:06 -0400 |
commit | bd877e489126b2214f971ae8ef7bd17b48a94a7b (patch) | |
tree | 7463d29b62f399f75b4e1618d8c90c9e25f58a4a /drivers | |
parent | 3ee2403739db7ec8b683e6451c3401ad716ad5a2 (diff) |
net: qmi_wwan: use a single bind function for all device types
Refactoring the bind code lets us use a common driver_info struct
for all supported devices, simplifying the code a bit. The
real advantage is that devices using the CDC ECM interface
layout now also can be added dynamically using the new_id sysfs
interface. This simplifies testing of new devices.
Signed-off-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/usb/qmi_wwan.c | 45 |
1 files changed, 16 insertions, 29 deletions
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 516653f39512..84923334ca5b 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c | |||
@@ -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; |
@@ -330,20 +325,12 @@ static const struct driver_info qmi_wwan_info = { | |||
330 | .manage_power = qmi_wwan_manage_power, | 325 | .manage_power = qmi_wwan_manage_power, |
331 | }; | 326 | }; |
332 | 327 | ||
333 | static const struct driver_info qmi_wwan_shared = { | ||
334 | .description = "WWAN/QMI device", | ||
335 | .flags = FLAG_WWAN, | ||
336 | .bind = qmi_wwan_bind_shared, | ||
337 | .unbind = qmi_wwan_unbind, | ||
338 | .manage_power = qmi_wwan_manage_power, | ||
339 | }; | ||
340 | |||
341 | #define HUAWEI_VENDOR_ID 0x12D1 | 328 | #define HUAWEI_VENDOR_ID 0x12D1 |
342 | 329 | ||
343 | /* map QMI/wwan function by a fixed interface number */ | 330 | /* map QMI/wwan function by a fixed interface number */ |
344 | #define QMI_FIXED_INTF(vend, prod, num) \ | 331 | #define QMI_FIXED_INTF(vend, prod, num) \ |
345 | USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \ | 332 | USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \ |
346 | .driver_info = (unsigned long)&qmi_wwan_shared | 333 | .driver_info = (unsigned long)&qmi_wwan_info |
347 | 334 | ||
348 | /* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */ | 335 | /* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */ |
349 | #define QMI_GOBI1K_DEVICE(vend, prod) \ | 336 | #define QMI_GOBI1K_DEVICE(vend, prod) \ |
@@ -367,15 +354,15 @@ static const struct usb_device_id products[] = { | |||
367 | /* 2. Combined interface devices matching on class+protocol */ | 354 | /* 2. Combined interface devices matching on class+protocol */ |
368 | { /* Huawei E392, E398 and possibly others in "Windows mode" */ | 355 | { /* Huawei E392, E398 and possibly others in "Windows mode" */ |
369 | USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 17), | 356 | USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 17), |
370 | .driver_info = (unsigned long)&qmi_wwan_shared, | 357 | .driver_info = (unsigned long)&qmi_wwan_info, |
371 | }, | 358 | }, |
372 | { /* Pantech UML290 */ | 359 | { /* Pantech UML290 */ |
373 | USB_DEVICE_AND_INTERFACE_INFO(0x106c, 0x3718, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff), | 360 | USB_DEVICE_AND_INTERFACE_INFO(0x106c, 0x3718, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff), |
374 | .driver_info = (unsigned long)&qmi_wwan_shared, | 361 | .driver_info = (unsigned long)&qmi_wwan_info, |
375 | }, | 362 | }, |
376 | { /* Pantech UML290 - newer firmware */ | 363 | { /* Pantech UML290 - newer firmware */ |
377 | USB_DEVICE_AND_INTERFACE_INFO(0x106c, 0x3718, USB_CLASS_VENDOR_SPEC, 0xf1, 0xff), | 364 | USB_DEVICE_AND_INTERFACE_INFO(0x106c, 0x3718, USB_CLASS_VENDOR_SPEC, 0xf1, 0xff), |
378 | .driver_info = (unsigned long)&qmi_wwan_shared, | 365 | .driver_info = (unsigned long)&qmi_wwan_info, |
379 | }, | 366 | }, |
380 | 367 | ||
381 | /* 3. Combined interface devices matching on interface number */ | 368 | /* 3. Combined interface devices matching on interface number */ |
@@ -457,7 +444,7 @@ static int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id | |||
457 | */ | 444 | */ |
458 | if (!id->driver_info) { | 445 | if (!id->driver_info) { |
459 | dev_dbg(&intf->dev, "setting defaults for dynamic device id\n"); | 446 | dev_dbg(&intf->dev, "setting defaults for dynamic device id\n"); |
460 | id->driver_info = (unsigned long)&qmi_wwan_shared; | 447 | id->driver_info = (unsigned long)&qmi_wwan_info; |
461 | } | 448 | } |
462 | 449 | ||
463 | return usbnet_probe(intf, id); | 450 | return usbnet_probe(intf, id); |