diff options
author | Bjørn Mork <bjorn@mork.no> | 2012-06-18 20:42:00 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-06-19 18:04:14 -0400 |
commit | f47cd1360f36e599815650522986673b9aa83393 (patch) | |
tree | a5a6acdbfd1ed92ae194b05561431bf8380b59e6 /drivers | |
parent | 853c24f79dd6f4a3d6d7b52f235fe121aee08b45 (diff) |
net: qmi_wwan: rearranging to prepare for code sharing
Most of the subdriver registration code can be reused for devices
with separate control and data interfaces. Move the code a bit
around to prepare for such reuse.
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 | 128 |
1 files changed, 76 insertions, 52 deletions
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index c7b9be81ad08..6fcf54d43eab 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c | |||
@@ -58,9 +58,80 @@ | |||
58 | struct qmi_wwan_state { | 58 | struct qmi_wwan_state { |
59 | struct usb_driver *subdriver; | 59 | struct usb_driver *subdriver; |
60 | atomic_t pmcount; | 60 | atomic_t pmcount; |
61 | unsigned long unused[3]; | 61 | unsigned long unused; |
62 | struct usb_interface *control; | ||
63 | struct usb_interface *data; | ||
62 | }; | 64 | }; |
63 | 65 | ||
66 | /* using a counter to merge subdriver requests with our own into a combined state */ | ||
67 | static int qmi_wwan_manage_power(struct usbnet *dev, int on) | ||
68 | { | ||
69 | struct qmi_wwan_state *info = (void *)&dev->data; | ||
70 | int rv = 0; | ||
71 | |||
72 | dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, atomic_read(&info->pmcount), on); | ||
73 | |||
74 | if ((on && atomic_add_return(1, &info->pmcount) == 1) || (!on && atomic_dec_and_test(&info->pmcount))) { | ||
75 | /* need autopm_get/put here to ensure the usbcore sees the new value */ | ||
76 | rv = usb_autopm_get_interface(dev->intf); | ||
77 | if (rv < 0) | ||
78 | goto err; | ||
79 | dev->intf->needs_remote_wakeup = on; | ||
80 | usb_autopm_put_interface(dev->intf); | ||
81 | } | ||
82 | err: | ||
83 | return rv; | ||
84 | } | ||
85 | |||
86 | static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on) | ||
87 | { | ||
88 | struct usbnet *dev = usb_get_intfdata(intf); | ||
89 | return qmi_wwan_manage_power(dev, on); | ||
90 | } | ||
91 | |||
92 | /* collect all three endpoints and register subdriver */ | ||
93 | static int qmi_wwan_register_subdriver(struct usbnet *dev) | ||
94 | { | ||
95 | int rv; | ||
96 | struct usb_driver *subdriver = NULL; | ||
97 | struct qmi_wwan_state *info = (void *)&dev->data; | ||
98 | |||
99 | /* collect bulk endpoints */ | ||
100 | rv = usbnet_get_endpoints(dev, info->data); | ||
101 | if (rv < 0) | ||
102 | goto err; | ||
103 | |||
104 | /* update status endpoint if separate control interface */ | ||
105 | if (info->control != info->data) | ||
106 | dev->status = &info->control->cur_altsetting->endpoint[0]; | ||
107 | |||
108 | /* require interrupt endpoint for subdriver */ | ||
109 | if (!dev->status) { | ||
110 | rv = -EINVAL; | ||
111 | goto err; | ||
112 | } | ||
113 | |||
114 | /* for subdriver power management */ | ||
115 | atomic_set(&info->pmcount, 0); | ||
116 | |||
117 | /* register subdriver */ | ||
118 | subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc, 512, &qmi_wwan_cdc_wdm_manage_power); | ||
119 | if (IS_ERR(subdriver)) { | ||
120 | dev_err(&info->control->dev, "subdriver registration failed\n"); | ||
121 | rv = PTR_ERR(subdriver); | ||
122 | goto err; | ||
123 | } | ||
124 | |||
125 | /* prevent usbnet from using status endpoint */ | ||
126 | dev->status = NULL; | ||
127 | |||
128 | /* save subdriver struct for suspend/resume wrappers */ | ||
129 | info->subdriver = subdriver; | ||
130 | |||
131 | err: | ||
132 | return rv; | ||
133 | } | ||
134 | |||
64 | static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) | 135 | static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) |
65 | { | 136 | { |
66 | int status = -1; | 137 | int status = -1; |
@@ -183,32 +254,6 @@ err: | |||
183 | return status; | 254 | return status; |
184 | } | 255 | } |
185 | 256 | ||
186 | /* using a counter to merge subdriver requests with our own into a combined state */ | ||
187 | static int qmi_wwan_manage_power(struct usbnet *dev, int on) | ||
188 | { | ||
189 | struct qmi_wwan_state *info = (void *)&dev->data; | ||
190 | int rv = 0; | ||
191 | |||
192 | dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, atomic_read(&info->pmcount), on); | ||
193 | |||
194 | if ((on && atomic_add_return(1, &info->pmcount) == 1) || (!on && atomic_dec_and_test(&info->pmcount))) { | ||
195 | /* need autopm_get/put here to ensure the usbcore sees the new value */ | ||
196 | rv = usb_autopm_get_interface(dev->intf); | ||
197 | if (rv < 0) | ||
198 | goto err; | ||
199 | dev->intf->needs_remote_wakeup = on; | ||
200 | usb_autopm_put_interface(dev->intf); | ||
201 | } | ||
202 | err: | ||
203 | return rv; | ||
204 | } | ||
205 | |||
206 | static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on) | ||
207 | { | ||
208 | struct usbnet *dev = usb_get_intfdata(intf); | ||
209 | return qmi_wwan_manage_power(dev, on); | ||
210 | } | ||
211 | |||
212 | /* Some devices combine the "control" and "data" functions into a | 257 | /* Some devices combine the "control" and "data" functions into a |
213 | * single interface with all three endpoints: interrupt + bulk in and | 258 | * single interface with all three endpoints: interrupt + bulk in and |
214 | * out | 259 | * out |
@@ -220,7 +265,6 @@ static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on) | |||
220 | static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf) | 265 | static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf) |
221 | { | 266 | { |
222 | int rv; | 267 | int rv; |
223 | struct usb_driver *subdriver = NULL; | ||
224 | struct qmi_wwan_state *info = (void *)&dev->data; | 268 | struct qmi_wwan_state *info = (void *)&dev->data; |
225 | 269 | ||
226 | /* ZTE makes devices where the interface descriptors and endpoint | 270 | /* ZTE makes devices where the interface descriptors and endpoint |
@@ -237,30 +281,10 @@ static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf) | |||
237 | goto err; | 281 | goto err; |
238 | } | 282 | } |
239 | 283 | ||
240 | atomic_set(&info->pmcount, 0); | 284 | /* control and data is shared */ |
241 | 285 | info->control = intf; | |
242 | /* collect all three endpoints */ | 286 | info->data = intf; |
243 | rv = usbnet_get_endpoints(dev, intf); | 287 | rv = qmi_wwan_register_subdriver(dev); |
244 | if (rv < 0) | ||
245 | goto err; | ||
246 | |||
247 | /* require interrupt endpoint for subdriver */ | ||
248 | if (!dev->status) { | ||
249 | rv = -EINVAL; | ||
250 | goto err; | ||
251 | } | ||
252 | |||
253 | subdriver = usb_cdc_wdm_register(intf, &dev->status->desc, 512, &qmi_wwan_cdc_wdm_manage_power); | ||
254 | if (IS_ERR(subdriver)) { | ||
255 | rv = PTR_ERR(subdriver); | ||
256 | goto err; | ||
257 | } | ||
258 | |||
259 | /* can't let usbnet use the interrupt endpoint */ | ||
260 | dev->status = NULL; | ||
261 | |||
262 | /* save subdriver struct for suspend/resume wrappers */ | ||
263 | info->subdriver = subdriver; | ||
264 | 288 | ||
265 | err: | 289 | err: |
266 | return rv; | 290 | return rv; |