diff options
Diffstat (limited to 'drivers/media/video/uvc/uvc_driver.c')
-rw-r--r-- | drivers/media/video/uvc/uvc_driver.c | 428 |
1 files changed, 225 insertions, 203 deletions
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 8756be569154..c31bc50113bc 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c | |||
@@ -46,6 +46,7 @@ | |||
46 | unsigned int uvc_no_drop_param; | 46 | unsigned int uvc_no_drop_param; |
47 | static unsigned int uvc_quirks_param; | 47 | static unsigned int uvc_quirks_param; |
48 | unsigned int uvc_trace_param; | 48 | unsigned int uvc_trace_param; |
49 | unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT; | ||
49 | 50 | ||
50 | /* ------------------------------------------------------------------------ | 51 | /* ------------------------------------------------------------------------ |
51 | * Video formats | 52 | * Video formats |
@@ -248,29 +249,9 @@ static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev, | |||
248 | entity = list_entry(&dev->entities, struct uvc_entity, list); | 249 | entity = list_entry(&dev->entities, struct uvc_entity, list); |
249 | 250 | ||
250 | list_for_each_entry_continue(entity, &dev->entities, list) { | 251 | list_for_each_entry_continue(entity, &dev->entities, list) { |
251 | switch (UVC_ENTITY_TYPE(entity)) { | 252 | for (i = 0; i < entity->bNrInPins; ++i) |
252 | case UVC_TT_STREAMING: | 253 | if (entity->baSourceID[i] == id) |
253 | if (entity->output.bSourceID == id) | ||
254 | return entity; | ||
255 | break; | ||
256 | |||
257 | case UVC_VC_PROCESSING_UNIT: | ||
258 | if (entity->processing.bSourceID == id) | ||
259 | return entity; | 254 | return entity; |
260 | break; | ||
261 | |||
262 | case UVC_VC_SELECTOR_UNIT: | ||
263 | for (i = 0; i < entity->selector.bNrInPins; ++i) | ||
264 | if (entity->selector.baSourceID[i] == id) | ||
265 | return entity; | ||
266 | break; | ||
267 | |||
268 | case UVC_VC_EXTENSION_UNIT: | ||
269 | for (i = 0; i < entity->extension.bNrInPins; ++i) | ||
270 | if (entity->extension.baSourceID[i] == id) | ||
271 | return entity; | ||
272 | break; | ||
273 | } | ||
274 | } | 255 | } |
275 | 256 | ||
276 | return NULL; | 257 | return NULL; |
@@ -426,7 +407,8 @@ static int uvc_parse_format(struct uvc_device *dev, | |||
426 | /* Parse the frame descriptors. Only uncompressed, MJPEG and frame | 407 | /* Parse the frame descriptors. Only uncompressed, MJPEG and frame |
427 | * based formats have frame descriptors. | 408 | * based formats have frame descriptors. |
428 | */ | 409 | */ |
429 | while (buflen > 2 && buffer[2] == ftype) { | 410 | while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && |
411 | buffer[2] == ftype) { | ||
430 | frame = &format->frame[format->nframes]; | 412 | frame = &format->frame[format->nframes]; |
431 | if (ftype != UVC_VS_FRAME_FRAME_BASED) | 413 | if (ftype != UVC_VS_FRAME_FRAME_BASED) |
432 | n = buflen > 25 ? buffer[25] : 0; | 414 | n = buflen > 25 ? buffer[25] : 0; |
@@ -503,12 +485,14 @@ static int uvc_parse_format(struct uvc_device *dev, | |||
503 | buffer += buffer[0]; | 485 | buffer += buffer[0]; |
504 | } | 486 | } |
505 | 487 | ||
506 | if (buflen > 2 && buffer[2] == UVC_VS_STILL_IMAGE_FRAME) { | 488 | if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && |
489 | buffer[2] == UVC_VS_STILL_IMAGE_FRAME) { | ||
507 | buflen -= buffer[0]; | 490 | buflen -= buffer[0]; |
508 | buffer += buffer[0]; | 491 | buffer += buffer[0]; |
509 | } | 492 | } |
510 | 493 | ||
511 | if (buflen > 2 && buffer[2] == UVC_VS_COLORFORMAT) { | 494 | if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && |
495 | buffer[2] == UVC_VS_COLORFORMAT) { | ||
512 | if (buflen < 6) { | 496 | if (buflen < 6) { |
513 | uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " | 497 | uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " |
514 | "interface %d COLORFORMAT error\n", | 498 | "interface %d COLORFORMAT error\n", |
@@ -749,6 +733,11 @@ static int uvc_parse_streaming(struct uvc_device *dev, | |||
749 | buffer += buffer[0]; | 733 | buffer += buffer[0]; |
750 | } | 734 | } |
751 | 735 | ||
736 | if (buflen) | ||
737 | uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " | ||
738 | "%d has %u bytes of trailing descriptor garbage.\n", | ||
739 | dev->udev->devnum, alts->desc.bInterfaceNumber, buflen); | ||
740 | |||
752 | /* Parse the alternate settings to find the maximum bandwidth. */ | 741 | /* Parse the alternate settings to find the maximum bandwidth. */ |
753 | for (i = 0; i < intf->num_altsetting; ++i) { | 742 | for (i = 0; i < intf->num_altsetting; ++i) { |
754 | struct usb_host_endpoint *ep; | 743 | struct usb_host_endpoint *ep; |
@@ -776,6 +765,28 @@ error: | |||
776 | return ret; | 765 | return ret; |
777 | } | 766 | } |
778 | 767 | ||
768 | static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id, | ||
769 | unsigned int num_pads, unsigned int extra_size) | ||
770 | { | ||
771 | struct uvc_entity *entity; | ||
772 | unsigned int num_inputs; | ||
773 | unsigned int size; | ||
774 | |||
775 | num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1; | ||
776 | size = sizeof(*entity) + extra_size + num_inputs; | ||
777 | entity = kzalloc(size, GFP_KERNEL); | ||
778 | if (entity == NULL) | ||
779 | return NULL; | ||
780 | |||
781 | entity->id = id; | ||
782 | entity->type = type; | ||
783 | |||
784 | entity->bNrInPins = num_inputs; | ||
785 | entity->baSourceID = ((__u8 *)entity) + sizeof(*entity) + extra_size; | ||
786 | |||
787 | return entity; | ||
788 | } | ||
789 | |||
779 | /* Parse vendor-specific extensions. */ | 790 | /* Parse vendor-specific extensions. */ |
780 | static int uvc_parse_vendor_control(struct uvc_device *dev, | 791 | static int uvc_parse_vendor_control(struct uvc_device *dev, |
781 | const unsigned char *buffer, int buflen) | 792 | const unsigned char *buffer, int buflen) |
@@ -827,21 +838,18 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, | |||
827 | break; | 838 | break; |
828 | } | 839 | } |
829 | 840 | ||
830 | unit = kzalloc(sizeof *unit + p + 2*n, GFP_KERNEL); | 841 | unit = uvc_alloc_entity(UVC_VC_EXTENSION_UNIT, buffer[3], |
842 | p + 1, 2*n); | ||
831 | if (unit == NULL) | 843 | if (unit == NULL) |
832 | return -ENOMEM; | 844 | return -ENOMEM; |
833 | 845 | ||
834 | unit->id = buffer[3]; | ||
835 | unit->type = UVC_VC_EXTENSION_UNIT; | ||
836 | memcpy(unit->extension.guidExtensionCode, &buffer[4], 16); | 846 | memcpy(unit->extension.guidExtensionCode, &buffer[4], 16); |
837 | unit->extension.bNumControls = buffer[20]; | 847 | unit->extension.bNumControls = buffer[20]; |
838 | unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]); | 848 | memcpy(unit->baSourceID, &buffer[22], p); |
839 | unit->extension.baSourceID = (__u8 *)unit + sizeof *unit; | ||
840 | memcpy(unit->extension.baSourceID, &buffer[22], p); | ||
841 | unit->extension.bControlSize = buffer[22+p]; | 849 | unit->extension.bControlSize = buffer[22+p]; |
842 | unit->extension.bmControls = (__u8 *)unit + sizeof *unit + p; | 850 | unit->extension.bmControls = (__u8 *)unit + sizeof(*unit); |
843 | unit->extension.bmControlsType = (__u8 *)unit + sizeof *unit | 851 | unit->extension.bmControlsType = (__u8 *)unit + sizeof(*unit) |
844 | + p + n; | 852 | + n; |
845 | memcpy(unit->extension.bmControls, &buffer[23+p], 2*n); | 853 | memcpy(unit->extension.bmControls, &buffer[23+p], 2*n); |
846 | 854 | ||
847 | if (buffer[24+p+2*n] != 0) | 855 | if (buffer[24+p+2*n] != 0) |
@@ -938,13 +946,11 @@ static int uvc_parse_standard_control(struct uvc_device *dev, | |||
938 | return -EINVAL; | 946 | return -EINVAL; |
939 | } | 947 | } |
940 | 948 | ||
941 | term = kzalloc(sizeof *term + n + p, GFP_KERNEL); | 949 | term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3], |
950 | 1, n + p); | ||
942 | if (term == NULL) | 951 | if (term == NULL) |
943 | return -ENOMEM; | 952 | return -ENOMEM; |
944 | 953 | ||
945 | term->id = buffer[3]; | ||
946 | term->type = type | UVC_TERM_INPUT; | ||
947 | |||
948 | if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) { | 954 | if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) { |
949 | term->camera.bControlSize = n; | 955 | term->camera.bControlSize = n; |
950 | term->camera.bmControls = (__u8 *)term + sizeof *term; | 956 | term->camera.bmControls = (__u8 *)term + sizeof *term; |
@@ -999,13 +1005,12 @@ static int uvc_parse_standard_control(struct uvc_device *dev, | |||
999 | return 0; | 1005 | return 0; |
1000 | } | 1006 | } |
1001 | 1007 | ||
1002 | term = kzalloc(sizeof *term, GFP_KERNEL); | 1008 | term = uvc_alloc_entity(type | UVC_TERM_OUTPUT, buffer[3], |
1009 | 1, 0); | ||
1003 | if (term == NULL) | 1010 | if (term == NULL) |
1004 | return -ENOMEM; | 1011 | return -ENOMEM; |
1005 | 1012 | ||
1006 | term->id = buffer[3]; | 1013 | memcpy(term->baSourceID, &buffer[7], 1); |
1007 | term->type = type | UVC_TERM_OUTPUT; | ||
1008 | term->output.bSourceID = buffer[7]; | ||
1009 | 1014 | ||
1010 | if (buffer[8] != 0) | 1015 | if (buffer[8] != 0) |
1011 | usb_string(udev, buffer[8], term->name, | 1016 | usb_string(udev, buffer[8], term->name, |
@@ -1026,15 +1031,11 @@ static int uvc_parse_standard_control(struct uvc_device *dev, | |||
1026 | return -EINVAL; | 1031 | return -EINVAL; |
1027 | } | 1032 | } |
1028 | 1033 | ||
1029 | unit = kzalloc(sizeof *unit + p, GFP_KERNEL); | 1034 | unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, 0); |
1030 | if (unit == NULL) | 1035 | if (unit == NULL) |
1031 | return -ENOMEM; | 1036 | return -ENOMEM; |
1032 | 1037 | ||
1033 | unit->id = buffer[3]; | 1038 | memcpy(unit->baSourceID, &buffer[5], p); |
1034 | unit->type = buffer[2]; | ||
1035 | unit->selector.bNrInPins = buffer[4]; | ||
1036 | unit->selector.baSourceID = (__u8 *)unit + sizeof *unit; | ||
1037 | memcpy(unit->selector.baSourceID, &buffer[5], p); | ||
1038 | 1039 | ||
1039 | if (buffer[5+p] != 0) | 1040 | if (buffer[5+p] != 0) |
1040 | usb_string(udev, buffer[5+p], unit->name, | 1041 | usb_string(udev, buffer[5+p], unit->name, |
@@ -1056,13 +1057,11 @@ static int uvc_parse_standard_control(struct uvc_device *dev, | |||
1056 | return -EINVAL; | 1057 | return -EINVAL; |
1057 | } | 1058 | } |
1058 | 1059 | ||
1059 | unit = kzalloc(sizeof *unit + n, GFP_KERNEL); | 1060 | unit = uvc_alloc_entity(buffer[2], buffer[3], 2, n); |
1060 | if (unit == NULL) | 1061 | if (unit == NULL) |
1061 | return -ENOMEM; | 1062 | return -ENOMEM; |
1062 | 1063 | ||
1063 | unit->id = buffer[3]; | 1064 | memcpy(unit->baSourceID, &buffer[4], 1); |
1064 | unit->type = buffer[2]; | ||
1065 | unit->processing.bSourceID = buffer[4]; | ||
1066 | unit->processing.wMaxMultiplier = | 1065 | unit->processing.wMaxMultiplier = |
1067 | get_unaligned_le16(&buffer[5]); | 1066 | get_unaligned_le16(&buffer[5]); |
1068 | unit->processing.bControlSize = buffer[7]; | 1067 | unit->processing.bControlSize = buffer[7]; |
@@ -1091,19 +1090,15 @@ static int uvc_parse_standard_control(struct uvc_device *dev, | |||
1091 | return -EINVAL; | 1090 | return -EINVAL; |
1092 | } | 1091 | } |
1093 | 1092 | ||
1094 | unit = kzalloc(sizeof *unit + p + n, GFP_KERNEL); | 1093 | unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, n); |
1095 | if (unit == NULL) | 1094 | if (unit == NULL) |
1096 | return -ENOMEM; | 1095 | return -ENOMEM; |
1097 | 1096 | ||
1098 | unit->id = buffer[3]; | ||
1099 | unit->type = buffer[2]; | ||
1100 | memcpy(unit->extension.guidExtensionCode, &buffer[4], 16); | 1097 | memcpy(unit->extension.guidExtensionCode, &buffer[4], 16); |
1101 | unit->extension.bNumControls = buffer[20]; | 1098 | unit->extension.bNumControls = buffer[20]; |
1102 | unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]); | 1099 | memcpy(unit->baSourceID, &buffer[22], p); |
1103 | unit->extension.baSourceID = (__u8 *)unit + sizeof *unit; | ||
1104 | memcpy(unit->extension.baSourceID, &buffer[22], p); | ||
1105 | unit->extension.bControlSize = buffer[22+p]; | 1100 | unit->extension.bControlSize = buffer[22+p]; |
1106 | unit->extension.bmControls = (__u8 *)unit + sizeof *unit + p; | 1101 | unit->extension.bmControls = (__u8 *)unit + sizeof *unit; |
1107 | memcpy(unit->extension.bmControls, &buffer[23+p], n); | 1102 | memcpy(unit->extension.bmControls, &buffer[23+p], n); |
1108 | 1103 | ||
1109 | if (buffer[23+p+n] != 0) | 1104 | if (buffer[23+p+n] != 0) |
@@ -1209,13 +1204,12 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, | |||
1209 | if (uvc_trace_param & UVC_TRACE_PROBE) | 1204 | if (uvc_trace_param & UVC_TRACE_PROBE) |
1210 | printk(" <- XU %d", entity->id); | 1205 | printk(" <- XU %d", entity->id); |
1211 | 1206 | ||
1212 | if (entity->extension.bNrInPins != 1) { | 1207 | if (entity->bNrInPins != 1) { |
1213 | uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more " | 1208 | uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more " |
1214 | "than 1 input pin.\n", entity->id); | 1209 | "than 1 input pin.\n", entity->id); |
1215 | return -1; | 1210 | return -1; |
1216 | } | 1211 | } |
1217 | 1212 | ||
1218 | list_add_tail(&entity->chain, &chain->extensions); | ||
1219 | break; | 1213 | break; |
1220 | 1214 | ||
1221 | case UVC_VC_PROCESSING_UNIT: | 1215 | case UVC_VC_PROCESSING_UNIT: |
@@ -1236,7 +1230,7 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, | |||
1236 | printk(" <- SU %d", entity->id); | 1230 | printk(" <- SU %d", entity->id); |
1237 | 1231 | ||
1238 | /* Single-input selector units are ignored. */ | 1232 | /* Single-input selector units are ignored. */ |
1239 | if (entity->selector.bNrInPins == 1) | 1233 | if (entity->bNrInPins == 1) |
1240 | break; | 1234 | break; |
1241 | 1235 | ||
1242 | if (chain->selector != NULL) { | 1236 | if (chain->selector != NULL) { |
@@ -1254,20 +1248,17 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, | |||
1254 | if (uvc_trace_param & UVC_TRACE_PROBE) | 1248 | if (uvc_trace_param & UVC_TRACE_PROBE) |
1255 | printk(" <- IT %d\n", entity->id); | 1249 | printk(" <- IT %d\n", entity->id); |
1256 | 1250 | ||
1257 | list_add_tail(&entity->chain, &chain->iterms); | ||
1258 | break; | 1251 | break; |
1259 | 1252 | ||
1260 | case UVC_TT_STREAMING: | 1253 | case UVC_TT_STREAMING: |
1261 | if (uvc_trace_param & UVC_TRACE_PROBE) | 1254 | if (UVC_ENTITY_IS_ITERM(entity)) { |
1262 | printk(" <- IT %d\n", entity->id); | 1255 | if (uvc_trace_param & UVC_TRACE_PROBE) |
1263 | 1256 | printk(" <- IT %d\n", entity->id); | |
1264 | if (!UVC_ENTITY_IS_ITERM(entity)) { | 1257 | } else { |
1265 | uvc_trace(UVC_TRACE_DESCR, "Unsupported input " | 1258 | if (uvc_trace_param & UVC_TRACE_PROBE) |
1266 | "terminal %u.\n", entity->id); | 1259 | printk(" OT %d", entity->id); |
1267 | return -1; | ||
1268 | } | 1260 | } |
1269 | 1261 | ||
1270 | list_add_tail(&entity->chain, &chain->iterms); | ||
1271 | break; | 1262 | break; |
1272 | 1263 | ||
1273 | default: | 1264 | default: |
@@ -1276,6 +1267,7 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, | |||
1276 | return -1; | 1267 | return -1; |
1277 | } | 1268 | } |
1278 | 1269 | ||
1270 | list_add_tail(&entity->chain, &chain->entities); | ||
1279 | return 0; | 1271 | return 0; |
1280 | } | 1272 | } |
1281 | 1273 | ||
@@ -1299,14 +1291,14 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, | |||
1299 | 1291 | ||
1300 | switch (UVC_ENTITY_TYPE(forward)) { | 1292 | switch (UVC_ENTITY_TYPE(forward)) { |
1301 | case UVC_VC_EXTENSION_UNIT: | 1293 | case UVC_VC_EXTENSION_UNIT: |
1302 | if (forward->extension.bNrInPins != 1) { | 1294 | if (forward->bNrInPins != 1) { |
1303 | uvc_trace(UVC_TRACE_DESCR, "Extension unit %d " | 1295 | uvc_trace(UVC_TRACE_DESCR, "Extension unit %d " |
1304 | "has more than 1 input pin.\n", | 1296 | "has more than 1 input pin.\n", |
1305 | entity->id); | 1297 | entity->id); |
1306 | return -EINVAL; | 1298 | return -EINVAL; |
1307 | } | 1299 | } |
1308 | 1300 | ||
1309 | list_add_tail(&forward->chain, &chain->extensions); | 1301 | list_add_tail(&forward->chain, &chain->entities); |
1310 | if (uvc_trace_param & UVC_TRACE_PROBE) { | 1302 | if (uvc_trace_param & UVC_TRACE_PROBE) { |
1311 | if (!found) | 1303 | if (!found) |
1312 | printk(" (->"); | 1304 | printk(" (->"); |
@@ -1326,7 +1318,7 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, | |||
1326 | return -EINVAL; | 1318 | return -EINVAL; |
1327 | } | 1319 | } |
1328 | 1320 | ||
1329 | list_add_tail(&forward->chain, &chain->oterms); | 1321 | list_add_tail(&forward->chain, &chain->entities); |
1330 | if (uvc_trace_param & UVC_TRACE_PROBE) { | 1322 | if (uvc_trace_param & UVC_TRACE_PROBE) { |
1331 | if (!found) | 1323 | if (!found) |
1332 | printk(" (->"); | 1324 | printk(" (->"); |
@@ -1344,24 +1336,22 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, | |||
1344 | } | 1336 | } |
1345 | 1337 | ||
1346 | static int uvc_scan_chain_backward(struct uvc_video_chain *chain, | 1338 | static int uvc_scan_chain_backward(struct uvc_video_chain *chain, |
1347 | struct uvc_entity *entity) | 1339 | struct uvc_entity **_entity) |
1348 | { | 1340 | { |
1341 | struct uvc_entity *entity = *_entity; | ||
1349 | struct uvc_entity *term; | 1342 | struct uvc_entity *term; |
1350 | int id = -1, i; | 1343 | int id = -EINVAL, i; |
1351 | 1344 | ||
1352 | switch (UVC_ENTITY_TYPE(entity)) { | 1345 | switch (UVC_ENTITY_TYPE(entity)) { |
1353 | case UVC_VC_EXTENSION_UNIT: | 1346 | case UVC_VC_EXTENSION_UNIT: |
1354 | id = entity->extension.baSourceID[0]; | ||
1355 | break; | ||
1356 | |||
1357 | case UVC_VC_PROCESSING_UNIT: | 1347 | case UVC_VC_PROCESSING_UNIT: |
1358 | id = entity->processing.bSourceID; | 1348 | id = entity->baSourceID[0]; |
1359 | break; | 1349 | break; |
1360 | 1350 | ||
1361 | case UVC_VC_SELECTOR_UNIT: | 1351 | case UVC_VC_SELECTOR_UNIT: |
1362 | /* Single-input selector units are ignored. */ | 1352 | /* Single-input selector units are ignored. */ |
1363 | if (entity->selector.bNrInPins == 1) { | 1353 | if (entity->bNrInPins == 1) { |
1364 | id = entity->selector.baSourceID[0]; | 1354 | id = entity->baSourceID[0]; |
1365 | break; | 1355 | break; |
1366 | } | 1356 | } |
1367 | 1357 | ||
@@ -1369,8 +1359,8 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain, | |||
1369 | printk(" <- IT"); | 1359 | printk(" <- IT"); |
1370 | 1360 | ||
1371 | chain->selector = entity; | 1361 | chain->selector = entity; |
1372 | for (i = 0; i < entity->selector.bNrInPins; ++i) { | 1362 | for (i = 0; i < entity->bNrInPins; ++i) { |
1373 | id = entity->selector.baSourceID[i]; | 1363 | id = entity->baSourceID[i]; |
1374 | term = uvc_entity_by_id(chain->dev, id); | 1364 | term = uvc_entity_by_id(chain->dev, id); |
1375 | if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) { | 1365 | if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) { |
1376 | uvc_trace(UVC_TRACE_DESCR, "Selector unit %d " | 1366 | uvc_trace(UVC_TRACE_DESCR, "Selector unit %d " |
@@ -1382,7 +1372,7 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain, | |||
1382 | if (uvc_trace_param & UVC_TRACE_PROBE) | 1372 | if (uvc_trace_param & UVC_TRACE_PROBE) |
1383 | printk(" %d", term->id); | 1373 | printk(" %d", term->id); |
1384 | 1374 | ||
1385 | list_add_tail(&term->chain, &chain->iterms); | 1375 | list_add_tail(&term->chain, &chain->entities); |
1386 | uvc_scan_chain_forward(chain, term, entity); | 1376 | uvc_scan_chain_forward(chain, term, entity); |
1387 | } | 1377 | } |
1388 | 1378 | ||
@@ -1391,34 +1381,49 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain, | |||
1391 | 1381 | ||
1392 | id = 0; | 1382 | id = 0; |
1393 | break; | 1383 | break; |
1384 | |||
1385 | case UVC_ITT_VENDOR_SPECIFIC: | ||
1386 | case UVC_ITT_CAMERA: | ||
1387 | case UVC_ITT_MEDIA_TRANSPORT_INPUT: | ||
1388 | case UVC_OTT_VENDOR_SPECIFIC: | ||
1389 | case UVC_OTT_DISPLAY: | ||
1390 | case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: | ||
1391 | case UVC_TT_STREAMING: | ||
1392 | id = UVC_ENTITY_IS_OTERM(entity) ? entity->baSourceID[0] : 0; | ||
1393 | break; | ||
1394 | } | ||
1395 | |||
1396 | if (id <= 0) { | ||
1397 | *_entity = NULL; | ||
1398 | return id; | ||
1394 | } | 1399 | } |
1395 | 1400 | ||
1396 | return id; | 1401 | entity = uvc_entity_by_id(chain->dev, id); |
1402 | if (entity == NULL) { | ||
1403 | uvc_trace(UVC_TRACE_DESCR, "Found reference to " | ||
1404 | "unknown entity %d.\n", id); | ||
1405 | return -EINVAL; | ||
1406 | } | ||
1407 | |||
1408 | *_entity = entity; | ||
1409 | return 0; | ||
1397 | } | 1410 | } |
1398 | 1411 | ||
1399 | static int uvc_scan_chain(struct uvc_video_chain *chain, | 1412 | static int uvc_scan_chain(struct uvc_video_chain *chain, |
1400 | struct uvc_entity *oterm) | 1413 | struct uvc_entity *term) |
1401 | { | 1414 | { |
1402 | struct uvc_entity *entity, *prev; | 1415 | struct uvc_entity *entity, *prev; |
1403 | int id; | ||
1404 | 1416 | ||
1405 | entity = oterm; | 1417 | uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain:"); |
1406 | list_add_tail(&entity->chain, &chain->oterms); | ||
1407 | uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id); | ||
1408 | 1418 | ||
1409 | id = entity->output.bSourceID; | 1419 | entity = term; |
1410 | while (id != 0) { | 1420 | prev = NULL; |
1411 | prev = entity; | ||
1412 | entity = uvc_entity_by_id(chain->dev, id); | ||
1413 | if (entity == NULL) { | ||
1414 | uvc_trace(UVC_TRACE_DESCR, "Found reference to " | ||
1415 | "unknown entity %d.\n", id); | ||
1416 | return -EINVAL; | ||
1417 | } | ||
1418 | 1421 | ||
1422 | while (entity != NULL) { | ||
1423 | /* Entity must not be part of an existing chain */ | ||
1419 | if (entity->chain.next || entity->chain.prev) { | 1424 | if (entity->chain.next || entity->chain.prev) { |
1420 | uvc_trace(UVC_TRACE_DESCR, "Found reference to " | 1425 | uvc_trace(UVC_TRACE_DESCR, "Found reference to " |
1421 | "entity %d already in chain.\n", id); | 1426 | "entity %d already in chain.\n", entity->id); |
1422 | return -EINVAL; | 1427 | return -EINVAL; |
1423 | } | 1428 | } |
1424 | 1429 | ||
@@ -1430,34 +1435,34 @@ static int uvc_scan_chain(struct uvc_video_chain *chain, | |||
1430 | if (uvc_scan_chain_forward(chain, entity, prev) < 0) | 1435 | if (uvc_scan_chain_forward(chain, entity, prev) < 0) |
1431 | return -EINVAL; | 1436 | return -EINVAL; |
1432 | 1437 | ||
1433 | /* Stop when a terminal is found. */ | ||
1434 | if (UVC_ENTITY_IS_TERM(entity)) | ||
1435 | break; | ||
1436 | |||
1437 | /* Backward scan */ | 1438 | /* Backward scan */ |
1438 | id = uvc_scan_chain_backward(chain, entity); | 1439 | prev = entity; |
1439 | if (id < 0) | 1440 | if (uvc_scan_chain_backward(chain, &entity) < 0) |
1440 | return id; | 1441 | return -EINVAL; |
1441 | } | 1442 | } |
1442 | 1443 | ||
1443 | return 0; | 1444 | return 0; |
1444 | } | 1445 | } |
1445 | 1446 | ||
1446 | static unsigned int uvc_print_terms(struct list_head *terms, char *buffer) | 1447 | static unsigned int uvc_print_terms(struct list_head *terms, u16 dir, |
1448 | char *buffer) | ||
1447 | { | 1449 | { |
1448 | struct uvc_entity *term; | 1450 | struct uvc_entity *term; |
1449 | unsigned int nterms = 0; | 1451 | unsigned int nterms = 0; |
1450 | char *p = buffer; | 1452 | char *p = buffer; |
1451 | 1453 | ||
1452 | list_for_each_entry(term, terms, chain) { | 1454 | list_for_each_entry(term, terms, chain) { |
1453 | p += sprintf(p, "%u", term->id); | 1455 | if (!UVC_ENTITY_IS_TERM(term) || |
1454 | if (term->chain.next != terms) { | 1456 | UVC_TERM_DIRECTION(term) != dir) |
1457 | continue; | ||
1458 | |||
1459 | if (nterms) | ||
1455 | p += sprintf(p, ","); | 1460 | p += sprintf(p, ","); |
1456 | if (++nterms >= 4) { | 1461 | if (++nterms >= 4) { |
1457 | p += sprintf(p, "..."); | 1462 | p += sprintf(p, "..."); |
1458 | break; | 1463 | break; |
1459 | } | ||
1460 | } | 1464 | } |
1465 | p += sprintf(p, "%u", term->id); | ||
1461 | } | 1466 | } |
1462 | 1467 | ||
1463 | return p - buffer; | 1468 | return p - buffer; |
@@ -1468,9 +1473,9 @@ static const char *uvc_print_chain(struct uvc_video_chain *chain) | |||
1468 | static char buffer[43]; | 1473 | static char buffer[43]; |
1469 | char *p = buffer; | 1474 | char *p = buffer; |
1470 | 1475 | ||
1471 | p += uvc_print_terms(&chain->iterms, p); | 1476 | p += uvc_print_terms(&chain->entities, UVC_TERM_INPUT, p); |
1472 | p += sprintf(p, " -> "); | 1477 | p += sprintf(p, " -> "); |
1473 | uvc_print_terms(&chain->oterms, p); | 1478 | uvc_print_terms(&chain->entities, UVC_TERM_OUTPUT, p); |
1474 | 1479 | ||
1475 | return buffer; | 1480 | return buffer; |
1476 | } | 1481 | } |
@@ -1501,9 +1506,7 @@ static int uvc_scan_device(struct uvc_device *dev) | |||
1501 | if (chain == NULL) | 1506 | if (chain == NULL) |
1502 | return -ENOMEM; | 1507 | return -ENOMEM; |
1503 | 1508 | ||
1504 | INIT_LIST_HEAD(&chain->iterms); | 1509 | INIT_LIST_HEAD(&chain->entities); |
1505 | INIT_LIST_HEAD(&chain->oterms); | ||
1506 | INIT_LIST_HEAD(&chain->extensions); | ||
1507 | mutex_init(&chain->ctrl_mutex); | 1510 | mutex_init(&chain->ctrl_mutex); |
1508 | chain->dev = dev; | 1511 | chain->dev = dev; |
1509 | 1512 | ||
@@ -1531,22 +1534,92 @@ static int uvc_scan_device(struct uvc_device *dev) | |||
1531 | */ | 1534 | */ |
1532 | 1535 | ||
1533 | /* | 1536 | /* |
1537 | * Delete the UVC device. | ||
1538 | * | ||
1539 | * Called by the kernel when the last reference to the uvc_device structure | ||
1540 | * is released. | ||
1541 | * | ||
1542 | * As this function is called after or during disconnect(), all URBs have | ||
1543 | * already been canceled by the USB core. There is no need to kill the | ||
1544 | * interrupt URB manually. | ||
1545 | */ | ||
1546 | static void uvc_delete(struct uvc_device *dev) | ||
1547 | { | ||
1548 | struct list_head *p, *n; | ||
1549 | |||
1550 | usb_put_intf(dev->intf); | ||
1551 | usb_put_dev(dev->udev); | ||
1552 | |||
1553 | uvc_status_cleanup(dev); | ||
1554 | uvc_ctrl_cleanup_device(dev); | ||
1555 | |||
1556 | list_for_each_safe(p, n, &dev->chains) { | ||
1557 | struct uvc_video_chain *chain; | ||
1558 | chain = list_entry(p, struct uvc_video_chain, list); | ||
1559 | kfree(chain); | ||
1560 | } | ||
1561 | |||
1562 | list_for_each_safe(p, n, &dev->entities) { | ||
1563 | struct uvc_entity *entity; | ||
1564 | entity = list_entry(p, struct uvc_entity, list); | ||
1565 | kfree(entity); | ||
1566 | } | ||
1567 | |||
1568 | list_for_each_safe(p, n, &dev->streams) { | ||
1569 | struct uvc_streaming *streaming; | ||
1570 | streaming = list_entry(p, struct uvc_streaming, list); | ||
1571 | usb_driver_release_interface(&uvc_driver.driver, | ||
1572 | streaming->intf); | ||
1573 | usb_put_intf(streaming->intf); | ||
1574 | kfree(streaming->format); | ||
1575 | kfree(streaming->header.bmaControls); | ||
1576 | kfree(streaming); | ||
1577 | } | ||
1578 | |||
1579 | kfree(dev); | ||
1580 | } | ||
1581 | |||
1582 | static void uvc_release(struct video_device *vdev) | ||
1583 | { | ||
1584 | struct uvc_streaming *stream = video_get_drvdata(vdev); | ||
1585 | struct uvc_device *dev = stream->dev; | ||
1586 | |||
1587 | video_device_release(vdev); | ||
1588 | |||
1589 | /* Decrement the registered streams count and delete the device when it | ||
1590 | * reaches zero. | ||
1591 | */ | ||
1592 | if (atomic_dec_and_test(&dev->nstreams)) | ||
1593 | uvc_delete(dev); | ||
1594 | } | ||
1595 | |||
1596 | /* | ||
1534 | * Unregister the video devices. | 1597 | * Unregister the video devices. |
1535 | */ | 1598 | */ |
1536 | static void uvc_unregister_video(struct uvc_device *dev) | 1599 | static void uvc_unregister_video(struct uvc_device *dev) |
1537 | { | 1600 | { |
1538 | struct uvc_streaming *stream; | 1601 | struct uvc_streaming *stream; |
1539 | 1602 | ||
1603 | /* Unregistering all video devices might result in uvc_delete() being | ||
1604 | * called from inside the loop if there's no open file handle. To avoid | ||
1605 | * that, increment the stream count before iterating over the streams | ||
1606 | * and decrement it when done. | ||
1607 | */ | ||
1608 | atomic_inc(&dev->nstreams); | ||
1609 | |||
1540 | list_for_each_entry(stream, &dev->streams, list) { | 1610 | list_for_each_entry(stream, &dev->streams, list) { |
1541 | if (stream->vdev == NULL) | 1611 | if (stream->vdev == NULL) |
1542 | continue; | 1612 | continue; |
1543 | 1613 | ||
1544 | if (stream->vdev->minor == -1) | 1614 | video_unregister_device(stream->vdev); |
1545 | video_device_release(stream->vdev); | ||
1546 | else | ||
1547 | video_unregister_device(stream->vdev); | ||
1548 | stream->vdev = NULL; | 1615 | stream->vdev = NULL; |
1549 | } | 1616 | } |
1617 | |||
1618 | /* Decrement the stream count and call uvc_delete explicitly if there | ||
1619 | * are no stream left. | ||
1620 | */ | ||
1621 | if (atomic_dec_and_test(&dev->nstreams)) | ||
1622 | uvc_delete(dev); | ||
1550 | } | 1623 | } |
1551 | 1624 | ||
1552 | static int uvc_register_video(struct uvc_device *dev, | 1625 | static int uvc_register_video(struct uvc_device *dev, |
@@ -1580,7 +1653,7 @@ static int uvc_register_video(struct uvc_device *dev, | |||
1580 | vdev->parent = &dev->intf->dev; | 1653 | vdev->parent = &dev->intf->dev; |
1581 | vdev->minor = -1; | 1654 | vdev->minor = -1; |
1582 | vdev->fops = &uvc_fops; | 1655 | vdev->fops = &uvc_fops; |
1583 | vdev->release = video_device_release; | 1656 | vdev->release = uvc_release; |
1584 | strlcpy(vdev->name, dev->name, sizeof vdev->name); | 1657 | strlcpy(vdev->name, dev->name, sizeof vdev->name); |
1585 | 1658 | ||
1586 | /* Set the driver data before calling video_register_device, otherwise | 1659 | /* Set the driver data before calling video_register_device, otherwise |
@@ -1598,6 +1671,7 @@ static int uvc_register_video(struct uvc_device *dev, | |||
1598 | return ret; | 1671 | return ret; |
1599 | } | 1672 | } |
1600 | 1673 | ||
1674 | atomic_inc(&dev->nstreams); | ||
1601 | return 0; | 1675 | return 0; |
1602 | } | 1676 | } |
1603 | 1677 | ||
@@ -1605,13 +1679,13 @@ static int uvc_register_video(struct uvc_device *dev, | |||
1605 | * Register all video devices in all chains. | 1679 | * Register all video devices in all chains. |
1606 | */ | 1680 | */ |
1607 | static int uvc_register_terms(struct uvc_device *dev, | 1681 | static int uvc_register_terms(struct uvc_device *dev, |
1608 | struct uvc_video_chain *chain, struct list_head *terms) | 1682 | struct uvc_video_chain *chain) |
1609 | { | 1683 | { |
1610 | struct uvc_streaming *stream; | 1684 | struct uvc_streaming *stream; |
1611 | struct uvc_entity *term; | 1685 | struct uvc_entity *term; |
1612 | int ret; | 1686 | int ret; |
1613 | 1687 | ||
1614 | list_for_each_entry(term, terms, chain) { | 1688 | list_for_each_entry(term, &chain->entities, chain) { |
1615 | if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING) | 1689 | if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING) |
1616 | continue; | 1690 | continue; |
1617 | 1691 | ||
@@ -1637,11 +1711,7 @@ static int uvc_register_chains(struct uvc_device *dev) | |||
1637 | int ret; | 1711 | int ret; |
1638 | 1712 | ||
1639 | list_for_each_entry(chain, &dev->chains, list) { | 1713 | list_for_each_entry(chain, &dev->chains, list) { |
1640 | ret = uvc_register_terms(dev, chain, &chain->iterms); | 1714 | ret = uvc_register_terms(dev, chain); |
1641 | if (ret < 0) | ||
1642 | return ret; | ||
1643 | |||
1644 | ret = uvc_register_terms(dev, chain, &chain->oterms); | ||
1645 | if (ret < 0) | 1715 | if (ret < 0) |
1646 | return ret; | 1716 | return ret; |
1647 | } | 1717 | } |
@@ -1653,61 +1723,6 @@ static int uvc_register_chains(struct uvc_device *dev) | |||
1653 | * USB probe, disconnect, suspend and resume | 1723 | * USB probe, disconnect, suspend and resume |
1654 | */ | 1724 | */ |
1655 | 1725 | ||
1656 | /* | ||
1657 | * Delete the UVC device. | ||
1658 | * | ||
1659 | * Called by the kernel when the last reference to the uvc_device structure | ||
1660 | * is released. | ||
1661 | * | ||
1662 | * Unregistering the video devices is done here because every opened instance | ||
1663 | * must be closed before the device can be unregistered. An alternative would | ||
1664 | * have been to use another reference count for uvc_v4l2_open/uvc_release, and | ||
1665 | * unregister the video devices on disconnect when that reference count drops | ||
1666 | * to zero. | ||
1667 | * | ||
1668 | * As this function is called after or during disconnect(), all URBs have | ||
1669 | * already been canceled by the USB core. There is no need to kill the | ||
1670 | * interrupt URB manually. | ||
1671 | */ | ||
1672 | void uvc_delete(struct kref *kref) | ||
1673 | { | ||
1674 | struct uvc_device *dev = container_of(kref, struct uvc_device, kref); | ||
1675 | struct list_head *p, *n; | ||
1676 | |||
1677 | /* Unregister the video devices. */ | ||
1678 | uvc_unregister_video(dev); | ||
1679 | usb_put_intf(dev->intf); | ||
1680 | usb_put_dev(dev->udev); | ||
1681 | |||
1682 | uvc_status_cleanup(dev); | ||
1683 | uvc_ctrl_cleanup_device(dev); | ||
1684 | |||
1685 | list_for_each_safe(p, n, &dev->chains) { | ||
1686 | struct uvc_video_chain *chain; | ||
1687 | chain = list_entry(p, struct uvc_video_chain, list); | ||
1688 | kfree(chain); | ||
1689 | } | ||
1690 | |||
1691 | list_for_each_safe(p, n, &dev->entities) { | ||
1692 | struct uvc_entity *entity; | ||
1693 | entity = list_entry(p, struct uvc_entity, list); | ||
1694 | kfree(entity); | ||
1695 | } | ||
1696 | |||
1697 | list_for_each_safe(p, n, &dev->streams) { | ||
1698 | struct uvc_streaming *streaming; | ||
1699 | streaming = list_entry(p, struct uvc_streaming, list); | ||
1700 | usb_driver_release_interface(&uvc_driver.driver, | ||
1701 | streaming->intf); | ||
1702 | usb_put_intf(streaming->intf); | ||
1703 | kfree(streaming->format); | ||
1704 | kfree(streaming->header.bmaControls); | ||
1705 | kfree(streaming); | ||
1706 | } | ||
1707 | |||
1708 | kfree(dev); | ||
1709 | } | ||
1710 | |||
1711 | static int uvc_probe(struct usb_interface *intf, | 1726 | static int uvc_probe(struct usb_interface *intf, |
1712 | const struct usb_device_id *id) | 1727 | const struct usb_device_id *id) |
1713 | { | 1728 | { |
@@ -1730,7 +1745,7 @@ static int uvc_probe(struct usb_interface *intf, | |||
1730 | INIT_LIST_HEAD(&dev->entities); | 1745 | INIT_LIST_HEAD(&dev->entities); |
1731 | INIT_LIST_HEAD(&dev->chains); | 1746 | INIT_LIST_HEAD(&dev->chains); |
1732 | INIT_LIST_HEAD(&dev->streams); | 1747 | INIT_LIST_HEAD(&dev->streams); |
1733 | kref_init(&dev->kref); | 1748 | atomic_set(&dev->nstreams, 0); |
1734 | atomic_set(&dev->users, 0); | 1749 | atomic_set(&dev->users, 0); |
1735 | 1750 | ||
1736 | dev->udev = usb_get_dev(udev); | 1751 | dev->udev = usb_get_dev(udev); |
@@ -1792,7 +1807,7 @@ static int uvc_probe(struct usb_interface *intf, | |||
1792 | return 0; | 1807 | return 0; |
1793 | 1808 | ||
1794 | error: | 1809 | error: |
1795 | kref_put(&dev->kref, uvc_delete); | 1810 | uvc_unregister_video(dev); |
1796 | return -ENODEV; | 1811 | return -ENODEV; |
1797 | } | 1812 | } |
1798 | 1813 | ||
@@ -1809,21 +1824,9 @@ static void uvc_disconnect(struct usb_interface *intf) | |||
1809 | UVC_SC_VIDEOSTREAMING) | 1824 | UVC_SC_VIDEOSTREAMING) |
1810 | return; | 1825 | return; |
1811 | 1826 | ||
1812 | /* uvc_v4l2_open() might race uvc_disconnect(). A static driver-wide | ||
1813 | * lock is needed to prevent uvc_disconnect from releasing its | ||
1814 | * reference to the uvc_device instance after uvc_v4l2_open() received | ||
1815 | * the pointer to the device (video_devdata) but before it got the | ||
1816 | * chance to increase the reference count (kref_get). | ||
1817 | * | ||
1818 | * Note that the reference can't be released with the lock held, | ||
1819 | * otherwise a AB-BA deadlock can occur with videodev_lock that | ||
1820 | * videodev acquires in videodev_open() and video_unregister_device(). | ||
1821 | */ | ||
1822 | mutex_lock(&uvc_driver.open_mutex); | ||
1823 | dev->state |= UVC_DEV_DISCONNECTED; | 1827 | dev->state |= UVC_DEV_DISCONNECTED; |
1824 | mutex_unlock(&uvc_driver.open_mutex); | ||
1825 | 1828 | ||
1826 | kref_put(&dev->kref, uvc_delete); | 1829 | uvc_unregister_video(dev); |
1827 | } | 1830 | } |
1828 | 1831 | ||
1829 | static int uvc_suspend(struct usb_interface *intf, pm_message_t message) | 1832 | static int uvc_suspend(struct usb_interface *intf, pm_message_t message) |
@@ -1899,6 +1902,15 @@ static int uvc_reset_resume(struct usb_interface *intf) | |||
1899 | * though they are compliant. | 1902 | * though they are compliant. |
1900 | */ | 1903 | */ |
1901 | static struct usb_device_id uvc_ids[] = { | 1904 | static struct usb_device_id uvc_ids[] = { |
1905 | /* Genius eFace 2025 */ | ||
1906 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | ||
1907 | | USB_DEVICE_ID_MATCH_INT_INFO, | ||
1908 | .idVendor = 0x0458, | ||
1909 | .idProduct = 0x706e, | ||
1910 | .bInterfaceClass = USB_CLASS_VIDEO, | ||
1911 | .bInterfaceSubClass = 1, | ||
1912 | .bInterfaceProtocol = 0, | ||
1913 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, | ||
1902 | /* Microsoft Lifecam NX-6000 */ | 1914 | /* Microsoft Lifecam NX-6000 */ |
1903 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | 1915 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
1904 | | USB_DEVICE_ID_MATCH_INT_INFO, | 1916 | | USB_DEVICE_ID_MATCH_INT_INFO, |
@@ -2123,6 +2135,15 @@ static struct usb_device_id uvc_ids[] = { | |||
2123 | .bInterfaceSubClass = 1, | 2135 | .bInterfaceSubClass = 1, |
2124 | .bInterfaceProtocol = 0, | 2136 | .bInterfaceProtocol = 0, |
2125 | .driver_info = UVC_QUIRK_STATUS_INTERVAL }, | 2137 | .driver_info = UVC_QUIRK_STATUS_INTERVAL }, |
2138 | /* MSI StarCam 370i */ | ||
2139 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | ||
2140 | | USB_DEVICE_ID_MATCH_INT_INFO, | ||
2141 | .idVendor = 0x1b3b, | ||
2142 | .idProduct = 0x2951, | ||
2143 | .bInterfaceClass = USB_CLASS_VIDEO, | ||
2144 | .bInterfaceSubClass = 1, | ||
2145 | .bInterfaceProtocol = 0, | ||
2146 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, | ||
2126 | /* SiGma Micro USB Web Camera */ | 2147 | /* SiGma Micro USB Web Camera */ |
2127 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | 2148 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
2128 | | USB_DEVICE_ID_MATCH_INT_INFO, | 2149 | | USB_DEVICE_ID_MATCH_INT_INFO, |
@@ -2159,7 +2180,6 @@ static int __init uvc_init(void) | |||
2159 | 2180 | ||
2160 | INIT_LIST_HEAD(&uvc_driver.devices); | 2181 | INIT_LIST_HEAD(&uvc_driver.devices); |
2161 | INIT_LIST_HEAD(&uvc_driver.controls); | 2182 | INIT_LIST_HEAD(&uvc_driver.controls); |
2162 | mutex_init(&uvc_driver.open_mutex); | ||
2163 | mutex_init(&uvc_driver.ctrl_mutex); | 2183 | mutex_init(&uvc_driver.ctrl_mutex); |
2164 | 2184 | ||
2165 | uvc_ctrl_init(); | 2185 | uvc_ctrl_init(); |
@@ -2184,6 +2204,8 @@ module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR); | |||
2184 | MODULE_PARM_DESC(quirks, "Forced device quirks"); | 2204 | MODULE_PARM_DESC(quirks, "Forced device quirks"); |
2185 | module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR); | 2205 | module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR); |
2186 | MODULE_PARM_DESC(trace, "Trace level bitmask"); | 2206 | MODULE_PARM_DESC(trace, "Trace level bitmask"); |
2207 | module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR); | ||
2208 | MODULE_PARM_DESC(timeout, "Streaming control requests timeout"); | ||
2187 | 2209 | ||
2188 | MODULE_AUTHOR(DRIVER_AUTHOR); | 2210 | MODULE_AUTHOR(DRIVER_AUTHOR); |
2189 | MODULE_DESCRIPTION(DRIVER_DESC); | 2211 | MODULE_DESCRIPTION(DRIVER_DESC); |