.. | .. |
---|
21 | 21 | |
---|
22 | 22 | #include <linux/usb.h> |
---|
23 | 23 | #include <linux/usb/hcd.h> |
---|
| 24 | +#include <uapi/linux/usb/audio.h> |
---|
24 | 25 | #include "usb.h" |
---|
25 | 26 | |
---|
26 | 27 | static inline const char *plural(int n) |
---|
.. | .. |
---|
42 | 43 | && desc->bInterfaceProtocol == 1; |
---|
43 | 44 | } |
---|
44 | 45 | |
---|
45 | | -static int get_usb_audio_config(struct usb_host_bos *bos) |
---|
| 46 | +static bool is_audio(struct usb_interface_descriptor *desc) |
---|
46 | 47 | { |
---|
47 | | - unsigned int desc_cnt, num_cfg_desc, len = 0; |
---|
48 | | - unsigned char *buffer; |
---|
49 | | - struct usb_config_summary_descriptor *conf_summary; |
---|
| 48 | + return desc->bInterfaceClass == USB_CLASS_AUDIO; |
---|
| 49 | +} |
---|
50 | 50 | |
---|
51 | | - if (!bos || !bos->config_summary) |
---|
52 | | - goto done; |
---|
53 | | - |
---|
54 | | - num_cfg_desc = bos->num_config_summary_desc; |
---|
55 | | - conf_summary = bos->config_summary; |
---|
56 | | - buffer = (unsigned char *)conf_summary; |
---|
57 | | - for (desc_cnt = 0; desc_cnt < num_cfg_desc; desc_cnt++) { |
---|
58 | | - conf_summary = |
---|
59 | | - (struct usb_config_summary_descriptor *)(buffer + len); |
---|
60 | | - |
---|
61 | | - len += conf_summary->bLength; |
---|
62 | | - |
---|
63 | | - if (conf_summary->bcdVersion != USB_CONFIG_SUMMARY_DESC_REV || |
---|
64 | | - conf_summary->bClass != USB_CLASS_AUDIO) |
---|
65 | | - continue; |
---|
66 | | - |
---|
67 | | - /* return 1st config as per device preference */ |
---|
68 | | - return conf_summary->bConfigurationIndex[0]; |
---|
69 | | - } |
---|
70 | | - |
---|
71 | | -done: |
---|
72 | | - return -EINVAL; |
---|
| 51 | +static bool is_uac3_config(struct usb_interface_descriptor *desc) |
---|
| 52 | +{ |
---|
| 53 | + return desc->bInterfaceProtocol == UAC_VERSION_3; |
---|
73 | 54 | } |
---|
74 | 55 | |
---|
75 | 56 | int usb_choose_configuration(struct usb_device *udev) |
---|
.. | .. |
---|
137 | 118 | continue; |
---|
138 | 119 | } |
---|
139 | 120 | |
---|
| 121 | + /* |
---|
| 122 | + * Select first configuration as default for audio so that |
---|
| 123 | + * devices that don't comply with UAC3 protocol are supported. |
---|
| 124 | + * But, still iterate through other configurations and |
---|
| 125 | + * select UAC3 compliant config if present. |
---|
| 126 | + */ |
---|
| 127 | + if (desc && is_audio(desc)) { |
---|
| 128 | + /* Always prefer the first found UAC3 config */ |
---|
| 129 | + if (is_uac3_config(desc)) { |
---|
| 130 | + best = c; |
---|
| 131 | + break; |
---|
| 132 | + } |
---|
| 133 | + |
---|
| 134 | + /* If there is no UAC3 config, prefer the first config */ |
---|
| 135 | + else if (i == 0) |
---|
| 136 | + best = c; |
---|
| 137 | + |
---|
| 138 | + /* Unconditional continue, because the rest of the code |
---|
| 139 | + * in the loop is irrelevant for audio devices, and |
---|
| 140 | + * because it can reassign best, which for audio devices |
---|
| 141 | + * we don't want. |
---|
| 142 | + */ |
---|
| 143 | + continue; |
---|
| 144 | + } |
---|
| 145 | + |
---|
140 | 146 | /* When the first config's first interface is one of Microsoft's |
---|
141 | 147 | * pet nonstandard Ethernet-over-USB protocols, ignore it unless |
---|
142 | 148 | * this kernel has enabled the necessary host side driver. |
---|
.. | .. |
---|
175 | 181 | insufficient_power, plural(insufficient_power)); |
---|
176 | 182 | |
---|
177 | 183 | if (best) { |
---|
178 | | - /* choose device preferred config */ |
---|
179 | | - i = get_usb_audio_config(udev->bos); |
---|
180 | | - if (i < 0) |
---|
181 | | - i = best->desc.bConfigurationValue; |
---|
| 184 | + i = best->desc.bConfigurationValue; |
---|
182 | 185 | dev_dbg(&udev->dev, |
---|
183 | 186 | "configuration #%d chosen from %d choice%s\n", |
---|
184 | 187 | i, num_configs, plural(num_configs)); |
---|
.. | .. |
---|
192 | 195 | } |
---|
193 | 196 | EXPORT_SYMBOL_GPL(usb_choose_configuration); |
---|
194 | 197 | |
---|
195 | | -static int generic_probe(struct usb_device *udev) |
---|
| 198 | +static int __check_for_non_generic_match(struct device_driver *drv, void *data) |
---|
| 199 | +{ |
---|
| 200 | + struct usb_device *udev = data; |
---|
| 201 | + struct usb_device_driver *udrv; |
---|
| 202 | + |
---|
| 203 | + if (!is_usb_device_driver(drv)) |
---|
| 204 | + return 0; |
---|
| 205 | + udrv = to_usb_device_driver(drv); |
---|
| 206 | + if (udrv == &usb_generic_driver) |
---|
| 207 | + return 0; |
---|
| 208 | + return usb_driver_applicable(udev, udrv); |
---|
| 209 | +} |
---|
| 210 | + |
---|
| 211 | +static bool usb_generic_driver_match(struct usb_device *udev) |
---|
| 212 | +{ |
---|
| 213 | + if (udev->use_generic_driver) |
---|
| 214 | + return true; |
---|
| 215 | + |
---|
| 216 | + /* |
---|
| 217 | + * If any other driver wants the device, leave the device to this other |
---|
| 218 | + * driver. |
---|
| 219 | + */ |
---|
| 220 | + if (bus_for_each_drv(&usb_bus_type, NULL, udev, __check_for_non_generic_match)) |
---|
| 221 | + return false; |
---|
| 222 | + |
---|
| 223 | + return true; |
---|
| 224 | +} |
---|
| 225 | + |
---|
| 226 | +int usb_generic_driver_probe(struct usb_device *udev) |
---|
196 | 227 | { |
---|
197 | 228 | int err, c; |
---|
198 | 229 | |
---|
.. | .. |
---|
219 | 250 | return 0; |
---|
220 | 251 | } |
---|
221 | 252 | |
---|
222 | | -static void generic_disconnect(struct usb_device *udev) |
---|
| 253 | +void usb_generic_driver_disconnect(struct usb_device *udev) |
---|
223 | 254 | { |
---|
224 | 255 | usb_notify_remove_device(udev); |
---|
225 | 256 | |
---|
.. | .. |
---|
231 | 262 | |
---|
232 | 263 | #ifdef CONFIG_PM |
---|
233 | 264 | |
---|
234 | | -static int generic_suspend(struct usb_device *udev, pm_message_t msg) |
---|
| 265 | +int usb_generic_driver_suspend(struct usb_device *udev, pm_message_t msg) |
---|
235 | 266 | { |
---|
236 | 267 | int rc; |
---|
237 | 268 | |
---|
.. | .. |
---|
254 | 285 | else |
---|
255 | 286 | rc = usb_port_suspend(udev, msg); |
---|
256 | 287 | |
---|
| 288 | + if (rc == 0) |
---|
| 289 | + usbfs_notify_suspend(udev); |
---|
257 | 290 | return rc; |
---|
258 | 291 | } |
---|
259 | 292 | |
---|
260 | | -static int generic_resume(struct usb_device *udev, pm_message_t msg) |
---|
| 293 | +int usb_generic_driver_resume(struct usb_device *udev, pm_message_t msg) |
---|
261 | 294 | { |
---|
262 | 295 | int rc; |
---|
263 | 296 | |
---|
.. | .. |
---|
270 | 303 | rc = hcd_bus_resume(udev, msg); |
---|
271 | 304 | else |
---|
272 | 305 | rc = usb_port_resume(udev, msg); |
---|
| 306 | + |
---|
| 307 | + if (rc == 0) |
---|
| 308 | + usbfs_notify_resume(udev); |
---|
273 | 309 | return rc; |
---|
274 | 310 | } |
---|
275 | 311 | |
---|
.. | .. |
---|
277 | 313 | |
---|
278 | 314 | struct usb_device_driver usb_generic_driver = { |
---|
279 | 315 | .name = "usb", |
---|
280 | | - .probe = generic_probe, |
---|
281 | | - .disconnect = generic_disconnect, |
---|
| 316 | + .match = usb_generic_driver_match, |
---|
| 317 | + .probe = usb_generic_driver_probe, |
---|
| 318 | + .disconnect = usb_generic_driver_disconnect, |
---|
282 | 319 | #ifdef CONFIG_PM |
---|
283 | | - .suspend = generic_suspend, |
---|
284 | | - .resume = generic_resume, |
---|
| 320 | + .suspend = usb_generic_driver_suspend, |
---|
| 321 | + .resume = usb_generic_driver_resume, |
---|
285 | 322 | #endif |
---|
286 | 323 | .supports_autosuspend = 1, |
---|
287 | 324 | }; |
---|