diff options
Diffstat (limited to 'drivers/media/video/pwc/pwc-if.c')
-rw-r--r-- | drivers/media/video/pwc/pwc-if.c | 175 |
1 files changed, 16 insertions, 159 deletions
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 943d37ad0d33..122fbd0081eb 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c | |||
@@ -128,18 +128,11 @@ static struct usb_driver pwc_driver = { | |||
128 | #define MAX_DEV_HINTS 20 | 128 | #define MAX_DEV_HINTS 20 |
129 | #define MAX_ISOC_ERRORS 20 | 129 | #define MAX_ISOC_ERRORS 20 |
130 | 130 | ||
131 | static int default_fps = 10; | ||
132 | #ifdef CONFIG_USB_PWC_DEBUG | 131 | #ifdef CONFIG_USB_PWC_DEBUG |
133 | int pwc_trace = PWC_DEBUG_LEVEL; | 132 | int pwc_trace = PWC_DEBUG_LEVEL; |
134 | #endif | 133 | #endif |
135 | static int power_save = -1; | 134 | static int power_save = -1; |
136 | static int led_on = 100, led_off; /* defaults to LED that is on while in use */ | 135 | static int leds[2] = { 100, 0 }; |
137 | static struct { | ||
138 | int type; | ||
139 | char serial_number[30]; | ||
140 | int device_node; | ||
141 | struct pwc_device *pdev; | ||
142 | } device_hint[MAX_DEV_HINTS]; | ||
143 | 136 | ||
144 | /***/ | 137 | /***/ |
145 | 138 | ||
@@ -386,8 +379,8 @@ static int pwc_isoc_init(struct pwc_device *pdev) | |||
386 | retry: | 379 | retry: |
387 | /* We first try with low compression and then retry with a higher | 380 | /* We first try with low compression and then retry with a higher |
388 | compression setting if there is not enough bandwidth. */ | 381 | compression setting if there is not enough bandwidth. */ |
389 | ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, | 382 | ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt, |
390 | pdev->vframes, &compression); | 383 | pdev->vframes, &compression, 1); |
391 | 384 | ||
392 | /* Get the current alternate interface, adjust packet size */ | 385 | /* Get the current alternate interface, adjust packet size */ |
393 | intf = usb_ifnum_to_if(udev, 0); | 386 | intf = usb_ifnum_to_if(udev, 0); |
@@ -597,23 +590,9 @@ leave: | |||
597 | static void pwc_video_release(struct v4l2_device *v) | 590 | static void pwc_video_release(struct v4l2_device *v) |
598 | { | 591 | { |
599 | struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev); | 592 | struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev); |
600 | int hint; | ||
601 | |||
602 | /* search device_hint[] table if we occupy a slot, by any chance */ | ||
603 | for (hint = 0; hint < MAX_DEV_HINTS; hint++) | ||
604 | if (device_hint[hint].pdev == pdev) | ||
605 | device_hint[hint].pdev = NULL; | ||
606 | |||
607 | /* Free intermediate decompression buffer & tables */ | ||
608 | if (pdev->decompress_data != NULL) { | ||
609 | PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", | ||
610 | pdev->decompress_data); | ||
611 | kfree(pdev->decompress_data); | ||
612 | pdev->decompress_data = NULL; | ||
613 | } | ||
614 | 593 | ||
615 | v4l2_ctrl_handler_free(&pdev->ctrl_handler); | 594 | v4l2_ctrl_handler_free(&pdev->ctrl_handler); |
616 | 595 | kfree(pdev->ctrl_buf); | |
617 | kfree(pdev); | 596 | kfree(pdev); |
618 | } | 597 | } |
619 | 598 | ||
@@ -758,7 +737,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) | |||
758 | 737 | ||
759 | /* Turn on camera and set LEDS on */ | 738 | /* Turn on camera and set LEDS on */ |
760 | pwc_camera_power(pdev, 1); | 739 | pwc_camera_power(pdev, 1); |
761 | pwc_set_leds(pdev, led_on, led_off); | 740 | pwc_set_leds(pdev, leds[0], leds[1]); |
762 | 741 | ||
763 | r = pwc_isoc_init(pdev); | 742 | r = pwc_isoc_init(pdev); |
764 | if (r) { | 743 | if (r) { |
@@ -813,10 +792,9 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
813 | struct usb_device *udev = interface_to_usbdev(intf); | 792 | struct usb_device *udev = interface_to_usbdev(intf); |
814 | struct pwc_device *pdev = NULL; | 793 | struct pwc_device *pdev = NULL; |
815 | int vendor_id, product_id, type_id; | 794 | int vendor_id, product_id, type_id; |
816 | int hint, rc; | 795 | int rc; |
817 | int features = 0; | 796 | int features = 0; |
818 | int compression = 0; | 797 | int compression = 0; |
819 | int video_nr = -1; /* default: use next available device */ | ||
820 | int my_power_save = power_save; | 798 | int my_power_save = power_save; |
821 | char serial_number[30], *name; | 799 | char serial_number[30], *name; |
822 | 800 | ||
@@ -1076,7 +1054,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1076 | return -ENOMEM; | 1054 | return -ENOMEM; |
1077 | } | 1055 | } |
1078 | pdev->type = type_id; | 1056 | pdev->type = type_id; |
1079 | pdev->vframes = default_fps; | ||
1080 | pdev->features = features; | 1057 | pdev->features = features; |
1081 | pwc_construct(pdev); /* set min/max sizes correct */ | 1058 | pwc_construct(pdev); /* set min/max sizes correct */ |
1082 | 1059 | ||
@@ -1107,24 +1084,14 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1107 | pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); | 1084 | pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); |
1108 | PWC_DEBUG_PROBE("Release: %04x\n", pdev->release); | 1085 | PWC_DEBUG_PROBE("Release: %04x\n", pdev->release); |
1109 | 1086 | ||
1110 | /* Now search device_hint[] table for a match, so we can hint a node number. */ | 1087 | /* Allocate USB command buffers */ |
1111 | for (hint = 0; hint < MAX_DEV_HINTS; hint++) { | 1088 | pdev->ctrl_buf = kmalloc(sizeof(pdev->cmd_buf), GFP_KERNEL); |
1112 | if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && | 1089 | if (!pdev->ctrl_buf) { |
1113 | (device_hint[hint].pdev == NULL)) { | 1090 | PWC_ERROR("Oops, could not allocate memory for pwc_device.\n"); |
1114 | /* so far, so good... try serial number */ | 1091 | rc = -ENOMEM; |
1115 | if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) { | 1092 | goto err_free_mem; |
1116 | /* match! */ | ||
1117 | video_nr = device_hint[hint].device_node; | ||
1118 | PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr); | ||
1119 | break; | ||
1120 | } | ||
1121 | } | ||
1122 | } | 1093 | } |
1123 | 1094 | ||
1124 | /* occupy slot */ | ||
1125 | if (hint < MAX_DEV_HINTS) | ||
1126 | device_hint[hint].pdev = pdev; | ||
1127 | |||
1128 | #ifdef CONFIG_USB_PWC_DEBUG | 1095 | #ifdef CONFIG_USB_PWC_DEBUG |
1129 | /* Query sensor type */ | 1096 | /* Query sensor type */ |
1130 | if (pwc_get_cmos_sensor(pdev, &rc) >= 0) { | 1097 | if (pwc_get_cmos_sensor(pdev, &rc) >= 0) { |
@@ -1138,8 +1105,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1138 | pwc_set_leds(pdev, 0, 0); | 1105 | pwc_set_leds(pdev, 0, 0); |
1139 | 1106 | ||
1140 | /* Setup intial videomode */ | 1107 | /* Setup intial videomode */ |
1141 | rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT, pdev->vframes, | 1108 | rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT, |
1142 | &compression); | 1109 | V4L2_PIX_FMT_YUV420, 30, &compression, 1); |
1143 | if (rc) | 1110 | if (rc) |
1144 | goto err_free_mem; | 1111 | goto err_free_mem; |
1145 | 1112 | ||
@@ -1164,7 +1131,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1164 | pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler; | 1131 | pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler; |
1165 | pdev->vdev.v4l2_dev = &pdev->v4l2_dev; | 1132 | pdev->vdev.v4l2_dev = &pdev->v4l2_dev; |
1166 | 1133 | ||
1167 | rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr); | 1134 | rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1); |
1168 | if (rc < 0) { | 1135 | if (rc < 0) { |
1169 | PWC_ERROR("Failed to register as video device (%d).\n", rc); | 1136 | PWC_ERROR("Failed to register as video device (%d).\n", rc); |
1170 | goto err_unregister_v4l2_dev; | 1137 | goto err_unregister_v4l2_dev; |
@@ -1207,8 +1174,7 @@ err_unregister_v4l2_dev: | |||
1207 | err_free_controls: | 1174 | err_free_controls: |
1208 | v4l2_ctrl_handler_free(&pdev->ctrl_handler); | 1175 | v4l2_ctrl_handler_free(&pdev->ctrl_handler); |
1209 | err_free_mem: | 1176 | err_free_mem: |
1210 | if (hint < MAX_DEV_HINTS) | 1177 | kfree(pdev->ctrl_buf); |
1211 | device_hint[hint].pdev = NULL; | ||
1212 | kfree(pdev); | 1178 | kfree(pdev); |
1213 | return rc; | 1179 | return rc; |
1214 | } | 1180 | } |
@@ -1243,27 +1209,19 @@ static void usb_pwc_disconnect(struct usb_interface *intf) | |||
1243 | * Initialization code & module stuff | 1209 | * Initialization code & module stuff |
1244 | */ | 1210 | */ |
1245 | 1211 | ||
1246 | static int fps; | ||
1247 | static int leds[2] = { -1, -1 }; | ||
1248 | static unsigned int leds_nargs; | 1212 | static unsigned int leds_nargs; |
1249 | static char *dev_hint[MAX_DEV_HINTS]; | ||
1250 | static unsigned int dev_hint_nargs; | ||
1251 | 1213 | ||
1252 | module_param(fps, int, 0444); | ||
1253 | #ifdef CONFIG_USB_PWC_DEBUG | 1214 | #ifdef CONFIG_USB_PWC_DEBUG |
1254 | module_param_named(trace, pwc_trace, int, 0644); | 1215 | module_param_named(trace, pwc_trace, int, 0644); |
1255 | #endif | 1216 | #endif |
1256 | module_param(power_save, int, 0644); | 1217 | module_param(power_save, int, 0644); |
1257 | module_param_array(leds, int, &leds_nargs, 0444); | 1218 | module_param_array(leds, int, &leds_nargs, 0444); |
1258 | module_param_array(dev_hint, charp, &dev_hint_nargs, 0444); | ||
1259 | 1219 | ||
1260 | MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); | ||
1261 | #ifdef CONFIG_USB_PWC_DEBUG | 1220 | #ifdef CONFIG_USB_PWC_DEBUG |
1262 | MODULE_PARM_DESC(trace, "For debugging purposes"); | 1221 | MODULE_PARM_DESC(trace, "For debugging purposes"); |
1263 | #endif | 1222 | #endif |
1264 | MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off"); | 1223 | MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off"); |
1265 | MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); | 1224 | MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); |
1266 | MODULE_PARM_DESC(dev_hint, "Device node hints"); | ||
1267 | 1225 | ||
1268 | MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); | 1226 | MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); |
1269 | MODULE_AUTHOR("Luc Saillard <luc@saillard.org>"); | 1227 | MODULE_AUTHOR("Luc Saillard <luc@saillard.org>"); |
@@ -1273,114 +1231,13 @@ MODULE_VERSION( PWC_VERSION ); | |||
1273 | 1231 | ||
1274 | static int __init usb_pwc_init(void) | 1232 | static int __init usb_pwc_init(void) |
1275 | { | 1233 | { |
1276 | int i; | ||
1277 | |||
1278 | #ifdef CONFIG_USB_PWC_DEBUG | ||
1279 | PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n"); | ||
1280 | PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); | ||
1281 | PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); | ||
1282 | PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); | ||
1283 | |||
1284 | if (pwc_trace >= 0) { | ||
1285 | PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace); | ||
1286 | } | ||
1287 | #endif | ||
1288 | |||
1289 | if (fps) { | ||
1290 | if (fps < 4 || fps > 30) { | ||
1291 | PWC_ERROR("Framerate out of bounds (4-30).\n"); | ||
1292 | return -EINVAL; | ||
1293 | } | ||
1294 | default_fps = fps; | ||
1295 | PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps); | ||
1296 | } | ||
1297 | |||
1298 | if (leds[0] >= 0) | ||
1299 | led_on = leds[0]; | ||
1300 | if (leds[1] >= 0) | ||
1301 | led_off = leds[1]; | ||
1302 | |||
1303 | /* Big device node whoopla. Basically, it allows you to assign a | ||
1304 | device node (/dev/videoX) to a camera, based on its type | ||
1305 | & serial number. The format is [type[.serialnumber]:]node. | ||
1306 | |||
1307 | Any camera that isn't matched by these rules gets the next | ||
1308 | available free device node. | ||
1309 | */ | ||
1310 | for (i = 0; i < MAX_DEV_HINTS; i++) { | ||
1311 | char *s, *colon, *dot; | ||
1312 | |||
1313 | /* This loop also initializes the array */ | ||
1314 | device_hint[i].pdev = NULL; | ||
1315 | s = dev_hint[i]; | ||
1316 | if (s != NULL && *s != '\0') { | ||
1317 | device_hint[i].type = -1; /* wildcard */ | ||
1318 | strcpy(device_hint[i].serial_number, "*"); | ||
1319 | |||
1320 | /* parse string: chop at ':' & '/' */ | ||
1321 | colon = dot = s; | ||
1322 | while (*colon != '\0' && *colon != ':') | ||
1323 | colon++; | ||
1324 | while (*dot != '\0' && *dot != '.') | ||
1325 | dot++; | ||
1326 | /* Few sanity checks */ | ||
1327 | if (*dot != '\0' && dot > colon) { | ||
1328 | PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n"); | ||
1329 | return -EINVAL; | ||
1330 | } | ||
1331 | |||
1332 | if (*colon == '\0') { | ||
1333 | /* No colon */ | ||
1334 | if (*dot != '\0') { | ||
1335 | PWC_ERROR("Malformed camera hint: no colon + device node given.\n"); | ||
1336 | return -EINVAL; | ||
1337 | } | ||
1338 | else { | ||
1339 | /* No type or serial number specified, just a number. */ | ||
1340 | device_hint[i].device_node = | ||
1341 | simple_strtol(s, NULL, 10); | ||
1342 | } | ||
1343 | } | ||
1344 | else { | ||
1345 | /* There's a colon, so we have at least a type and a device node */ | ||
1346 | device_hint[i].type = | ||
1347 | simple_strtol(s, NULL, 10); | ||
1348 | device_hint[i].device_node = | ||
1349 | simple_strtol(colon + 1, NULL, 10); | ||
1350 | if (*dot != '\0') { | ||
1351 | /* There's a serial number as well */ | ||
1352 | int k; | ||
1353 | |||
1354 | dot++; | ||
1355 | k = 0; | ||
1356 | while (*dot != ':' && k < 29) { | ||
1357 | device_hint[i].serial_number[k++] = *dot; | ||
1358 | dot++; | ||
1359 | } | ||
1360 | device_hint[i].serial_number[k] = '\0'; | ||
1361 | } | ||
1362 | } | ||
1363 | PWC_TRACE("device_hint[%d]:\n", i); | ||
1364 | PWC_TRACE(" type : %d\n", device_hint[i].type); | ||
1365 | PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number); | ||
1366 | PWC_TRACE(" node : %d\n", device_hint[i].device_node); | ||
1367 | } | ||
1368 | else | ||
1369 | device_hint[i].type = 0; /* not filled */ | ||
1370 | } /* ..for MAX_DEV_HINTS */ | ||
1371 | |||
1372 | PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver); | ||
1373 | return usb_register(&pwc_driver); | 1234 | return usb_register(&pwc_driver); |
1374 | } | 1235 | } |
1375 | 1236 | ||
1376 | static void __exit usb_pwc_exit(void) | 1237 | static void __exit usb_pwc_exit(void) |
1377 | { | 1238 | { |
1378 | PWC_DEBUG_MODULE("Deregistering driver.\n"); | ||
1379 | usb_deregister(&pwc_driver); | 1239 | usb_deregister(&pwc_driver); |
1380 | PWC_INFO("Philips webcam module removed.\n"); | ||
1381 | } | 1240 | } |
1382 | 1241 | ||
1383 | module_init(usb_pwc_init); | 1242 | module_init(usb_pwc_init); |
1384 | module_exit(usb_pwc_exit); | 1243 | module_exit(usb_pwc_exit); |
1385 | |||
1386 | /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ | ||