diff options
Diffstat (limited to 'drivers/media/video/pwc/pwc-ctrl.c')
-rw-r--r-- | drivers/media/video/pwc/pwc-ctrl.c | 726 |
1 files changed, 47 insertions, 679 deletions
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index 3977addf3ba8..905d41d90c6a 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c | |||
@@ -102,8 +102,6 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] = | |||
102 | #include "pwc-nala.h" | 102 | #include "pwc-nala.h" |
103 | }; | 103 | }; |
104 | 104 | ||
105 | static void pwc_set_image_buffer_size(struct pwc_device *pdev); | ||
106 | |||
107 | /****************************************************************************/ | 105 | /****************************************************************************/ |
108 | 106 | ||
109 | static int _send_control_msg(struct pwc_device *pdev, | 107 | static int _send_control_msg(struct pwc_device *pdev, |
@@ -113,10 +111,9 @@ static int _send_control_msg(struct pwc_device *pdev, | |||
113 | void *kbuf = NULL; | 111 | void *kbuf = NULL; |
114 | 112 | ||
115 | if (buflen) { | 113 | if (buflen) { |
116 | kbuf = kmalloc(buflen, GFP_KERNEL); /* not allowed on stack */ | 114 | kbuf = kmemdup(buf, buflen, GFP_KERNEL); /* not allowed on stack */ |
117 | if (kbuf == NULL) | 115 | if (kbuf == NULL) |
118 | return -ENOMEM; | 116 | return -ENOMEM; |
119 | memcpy(kbuf, buf, buflen); | ||
120 | } | 117 | } |
121 | 118 | ||
122 | rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), | 119 | rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), |
@@ -171,7 +168,8 @@ int send_control_msg(struct pwc_device *pdev, | |||
171 | request, value, pdev->vcinterface, buf, buflen); | 168 | request, value, pdev->vcinterface, buf, buflen); |
172 | } | 169 | } |
173 | 170 | ||
174 | static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) | 171 | static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames, |
172 | int *compression) | ||
175 | { | 173 | { |
176 | unsigned char buf[3]; | 174 | unsigned char buf[3]; |
177 | int ret, fps; | 175 | int ret, fps; |
@@ -221,10 +219,10 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) | |||
221 | 219 | ||
222 | /* Set various parameters */ | 220 | /* Set various parameters */ |
223 | pdev->vframes = frames; | 221 | pdev->vframes = frames; |
224 | pdev->vsize = size; | ||
225 | pdev->valternate = pEntry->alternate; | 222 | pdev->valternate = pEntry->alternate; |
226 | pdev->image = pwc_image_sizes[size]; | 223 | pdev->width = pwc_image_sizes[size][0]; |
227 | pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; | 224 | pdev->height = pwc_image_sizes[size][1]; |
225 | pdev->frame_size = (pdev->width * pdev->height * 3) / 2; | ||
228 | if (pEntry->compressed) { | 226 | if (pEntry->compressed) { |
229 | if (pdev->release < 5) { /* 4 fold compression */ | 227 | if (pdev->release < 5) { /* 4 fold compression */ |
230 | pdev->vbandlength = 528; | 228 | pdev->vbandlength = 528; |
@@ -237,38 +235,40 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) | |||
237 | } | 235 | } |
238 | else | 236 | else |
239 | pdev->vbandlength = 0; | 237 | pdev->vbandlength = 0; |
238 | |||
239 | /* Let pwc-if.c:isoc_init know we don't support higher compression */ | ||
240 | *compression = 3; | ||
241 | |||
240 | return 0; | 242 | return 0; |
241 | } | 243 | } |
242 | 244 | ||
243 | 245 | ||
244 | static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) | 246 | static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, |
247 | int *compression) | ||
245 | { | 248 | { |
246 | unsigned char buf[13]; | 249 | unsigned char buf[13]; |
247 | const struct Timon_table_entry *pChoose; | 250 | const struct Timon_table_entry *pChoose; |
248 | int ret, fps; | 251 | int ret, fps; |
249 | 252 | ||
250 | if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) | 253 | if (size >= PSZ_MAX || frames < 5 || frames > 30 || |
254 | *compression < 0 || *compression > 3) | ||
251 | return -EINVAL; | 255 | return -EINVAL; |
252 | if (size == PSZ_VGA && frames > 15) | 256 | if (size == PSZ_VGA && frames > 15) |
253 | return -EINVAL; | 257 | return -EINVAL; |
254 | fps = (frames / 5) - 1; | 258 | fps = (frames / 5) - 1; |
255 | 259 | ||
256 | /* Find a supported framerate with progressively higher compression ratios | 260 | /* Find a supported framerate with progressively higher compression */ |
257 | if the preferred ratio is not available. | ||
258 | */ | ||
259 | pChoose = NULL; | 261 | pChoose = NULL; |
260 | while (compression <= 3) { | 262 | while (*compression <= 3) { |
261 | pChoose = &Timon_table[size][fps][compression]; | 263 | pChoose = &Timon_table[size][fps][*compression]; |
262 | if (pChoose->alternate != 0) | 264 | if (pChoose->alternate != 0) |
263 | break; | 265 | break; |
264 | compression++; | 266 | (*compression)++; |
265 | } | 267 | } |
266 | if (pChoose == NULL || pChoose->alternate == 0) | 268 | if (pChoose == NULL || pChoose->alternate == 0) |
267 | return -ENOENT; /* Not supported. */ | 269 | return -ENOENT; /* Not supported. */ |
268 | 270 | ||
269 | memcpy(buf, pChoose->mode, 13); | 271 | memcpy(buf, pChoose->mode, 13); |
270 | if (snapshot) | ||
271 | buf[0] |= 0x80; | ||
272 | ret = send_video_command(pdev, pdev->vendpoint, buf, 13); | 272 | ret = send_video_command(pdev, pdev->vendpoint, buf, 13); |
273 | if (ret < 0) | 273 | if (ret < 0) |
274 | return ret; | 274 | return ret; |
@@ -284,55 +284,38 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, i | |||
284 | 284 | ||
285 | /* Set various parameters */ | 285 | /* Set various parameters */ |
286 | pdev->vframes = frames; | 286 | pdev->vframes = frames; |
287 | pdev->vsize = size; | ||
288 | pdev->vsnapshot = snapshot; | ||
289 | pdev->valternate = pChoose->alternate; | 287 | pdev->valternate = pChoose->alternate; |
290 | pdev->image = pwc_image_sizes[size]; | 288 | pdev->width = pwc_image_sizes[size][0]; |
289 | pdev->height = pwc_image_sizes[size][1]; | ||
291 | pdev->vbandlength = pChoose->bandlength; | 290 | pdev->vbandlength = pChoose->bandlength; |
292 | if (pChoose->bandlength > 0) | 291 | if (pChoose->bandlength > 0) |
293 | pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; | 292 | pdev->frame_size = (pChoose->bandlength * pdev->height) / 4; |
294 | else | 293 | else |
295 | pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; | 294 | pdev->frame_size = (pdev->width * pdev->height * 12) / 8; |
296 | return 0; | 295 | return 0; |
297 | } | 296 | } |
298 | 297 | ||
299 | 298 | ||
300 | static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) | 299 | static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, |
300 | int *compression) | ||
301 | { | 301 | { |
302 | const struct Kiara_table_entry *pChoose = NULL; | 302 | const struct Kiara_table_entry *pChoose = NULL; |
303 | int fps, ret; | 303 | int fps, ret; |
304 | unsigned char buf[12]; | 304 | unsigned char buf[12]; |
305 | struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; | ||
306 | 305 | ||
307 | if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) | 306 | if (size >= PSZ_MAX || frames < 5 || frames > 30 || |
307 | *compression < 0 || *compression > 3) | ||
308 | return -EINVAL; | 308 | return -EINVAL; |
309 | if (size == PSZ_VGA && frames > 15) | 309 | if (size == PSZ_VGA && frames > 15) |
310 | return -EINVAL; | 310 | return -EINVAL; |
311 | fps = (frames / 5) - 1; | 311 | fps = (frames / 5) - 1; |
312 | 312 | ||
313 | /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ | 313 | /* Find a supported framerate with progressively higher compression */ |
314 | if (size == PSZ_VGA && frames == 5 && snapshot && pdev->pixfmt != V4L2_PIX_FMT_YUV420) | 314 | while (*compression <= 3) { |
315 | { | 315 | pChoose = &Kiara_table[size][fps][*compression]; |
316 | /* Only available in case the raw palette is selected or | 316 | if (pChoose->alternate != 0) |
317 | we have the decompressor available. This mode is | 317 | break; |
318 | only available in compressed form | 318 | (*compression)++; |
319 | */ | ||
320 | PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n"); | ||
321 | pChoose = &RawEntry; | ||
322 | } | ||
323 | else | ||
324 | { | ||
325 | /* Find a supported framerate with progressively higher compression ratios | ||
326 | if the preferred ratio is not available. | ||
327 | Skip this step when using RAW modes. | ||
328 | */ | ||
329 | snapshot = 0; | ||
330 | while (compression <= 3) { | ||
331 | pChoose = &Kiara_table[size][fps][compression]; | ||
332 | if (pChoose->alternate != 0) | ||
333 | break; | ||
334 | compression++; | ||
335 | } | ||
336 | } | 319 | } |
337 | if (pChoose == NULL || pChoose->alternate == 0) | 320 | if (pChoose == NULL || pChoose->alternate == 0) |
338 | return -ENOENT; /* Not supported. */ | 321 | return -ENOENT; /* Not supported. */ |
@@ -341,8 +324,6 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, i | |||
341 | 324 | ||
342 | /* usb_control_msg won't take staticly allocated arrays as argument?? */ | 325 | /* usb_control_msg won't take staticly allocated arrays as argument?? */ |
343 | memcpy(buf, pChoose->mode, 12); | 326 | memcpy(buf, pChoose->mode, 12); |
344 | if (snapshot) | ||
345 | buf[0] |= 0x80; | ||
346 | 327 | ||
347 | /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ | 328 | /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ |
348 | ret = send_video_command(pdev, 4 /* pdev->vendpoint */, buf, 12); | 329 | ret = send_video_command(pdev, 4 /* pdev->vendpoint */, buf, 12); |
@@ -359,61 +340,43 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, i | |||
359 | memcpy(pdev->cmd_buf, buf, 12); | 340 | memcpy(pdev->cmd_buf, buf, 12); |
360 | /* All set and go */ | 341 | /* All set and go */ |
361 | pdev->vframes = frames; | 342 | pdev->vframes = frames; |
362 | pdev->vsize = size; | ||
363 | pdev->vsnapshot = snapshot; | ||
364 | pdev->valternate = pChoose->alternate; | 343 | pdev->valternate = pChoose->alternate; |
365 | pdev->image = pwc_image_sizes[size]; | 344 | pdev->width = pwc_image_sizes[size][0]; |
345 | pdev->height = pwc_image_sizes[size][1]; | ||
366 | pdev->vbandlength = pChoose->bandlength; | 346 | pdev->vbandlength = pChoose->bandlength; |
367 | if (pdev->vbandlength > 0) | 347 | if (pdev->vbandlength > 0) |
368 | pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; | 348 | pdev->frame_size = (pdev->vbandlength * pdev->height) / 4; |
369 | else | 349 | else |
370 | pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; | 350 | pdev->frame_size = (pdev->width * pdev->height * 12) / 8; |
371 | PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n", | 351 | PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n", |
372 | pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength); | 352 | pdev->frame_size, pdev->vframes, size, pdev->vbandlength); |
373 | return 0; | 353 | return 0; |
374 | } | 354 | } |
375 | 355 | ||
376 | 356 | int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, | |
377 | 357 | int frames, int *compression) | |
378 | /** | ||
379 | @pdev: device structure | ||
380 | @width: viewport width | ||
381 | @height: viewport height | ||
382 | @frame: framerate, in fps | ||
383 | @compression: preferred compression ratio | ||
384 | @snapshot: snapshot mode or streaming | ||
385 | */ | ||
386 | int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) | ||
387 | { | 358 | { |
388 | int ret, size; | 359 | int ret, size; |
389 | 360 | ||
390 | PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt); | 361 | PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt); |
391 | size = pwc_decode_size(pdev, width, height); | 362 | size = pwc_get_size(pdev, width, height); |
392 | if (size < 0) { | ||
393 | PWC_DEBUG_MODULE("Could not find suitable size.\n"); | ||
394 | return -ERANGE; | ||
395 | } | ||
396 | PWC_TRACE("decode_size = %d.\n", size); | 363 | PWC_TRACE("decode_size = %d.\n", size); |
397 | 364 | ||
398 | if (DEVICE_USE_CODEC1(pdev->type)) { | 365 | if (DEVICE_USE_CODEC1(pdev->type)) { |
399 | ret = set_video_mode_Nala(pdev, size, frames); | 366 | ret = set_video_mode_Nala(pdev, size, frames, compression); |
400 | 367 | ||
401 | } else if (DEVICE_USE_CODEC3(pdev->type)) { | 368 | } else if (DEVICE_USE_CODEC3(pdev->type)) { |
402 | ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); | 369 | ret = set_video_mode_Kiara(pdev, size, frames, compression); |
403 | 370 | ||
404 | } else { | 371 | } else { |
405 | ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); | 372 | ret = set_video_mode_Timon(pdev, size, frames, compression); |
406 | } | 373 | } |
407 | if (ret < 0) { | 374 | if (ret < 0) { |
408 | PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); | 375 | PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); |
409 | return ret; | 376 | return ret; |
410 | } | 377 | } |
411 | pdev->view.x = width; | ||
412 | pdev->view.y = height; | ||
413 | pdev->vcompression = compression; | ||
414 | pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; | 378 | pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; |
415 | pwc_set_image_buffer_size(pdev); | 379 | PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height); |
416 | PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); | ||
417 | return 0; | 380 | return 0; |
418 | } | 381 | } |
419 | 382 | ||
@@ -470,34 +433,6 @@ unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned i | |||
470 | return ret; | 433 | return ret; |
471 | } | 434 | } |
472 | 435 | ||
473 | static void pwc_set_image_buffer_size(struct pwc_device *pdev) | ||
474 | { | ||
475 | int factor = 0; | ||
476 | |||
477 | /* for V4L2_PIX_FMT_YUV420 */ | ||
478 | switch (pdev->pixfmt) { | ||
479 | case V4L2_PIX_FMT_YUV420: | ||
480 | factor = 6; | ||
481 | break; | ||
482 | case V4L2_PIX_FMT_PWC1: | ||
483 | case V4L2_PIX_FMT_PWC2: | ||
484 | factor = 6; /* can be uncompressed YUV420P */ | ||
485 | break; | ||
486 | } | ||
487 | |||
488 | /* Set sizes in bytes */ | ||
489 | pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; | ||
490 | pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; | ||
491 | |||
492 | /* Align offset, or you'll get some very weird results in | ||
493 | YUV420 mode... x must be multiple of 4 (to get the Y's in | ||
494 | place), and y even (or you'll mixup U & V). This is less of a | ||
495 | problem for YUV420P. | ||
496 | */ | ||
497 | pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; | ||
498 | pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; | ||
499 | } | ||
500 | |||
501 | int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) | 436 | int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) |
502 | { | 437 | { |
503 | int ret; | 438 | int ret; |
@@ -598,54 +533,6 @@ void pwc_camera_power(struct pwc_device *pdev, int power) | |||
598 | power ? "on" : "off", r); | 533 | power ? "on" : "off", r); |
599 | } | 534 | } |
600 | 535 | ||
601 | static int pwc_set_wb_speed(struct pwc_device *pdev, int speed) | ||
602 | { | ||
603 | unsigned char buf; | ||
604 | |||
605 | /* useful range is 0x01..0x20 */ | ||
606 | buf = speed / 0x7f0; | ||
607 | return send_control_msg(pdev, | ||
608 | SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf)); | ||
609 | } | ||
610 | |||
611 | static int pwc_get_wb_speed(struct pwc_device *pdev, int *value) | ||
612 | { | ||
613 | unsigned char buf; | ||
614 | int ret; | ||
615 | |||
616 | ret = recv_control_msg(pdev, | ||
617 | GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf)); | ||
618 | if (ret < 0) | ||
619 | return ret; | ||
620 | *value = buf * 0x7f0; | ||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | |||
625 | static int pwc_set_wb_delay(struct pwc_device *pdev, int delay) | ||
626 | { | ||
627 | unsigned char buf; | ||
628 | |||
629 | /* useful range is 0x01..0x3F */ | ||
630 | buf = (delay >> 10); | ||
631 | return send_control_msg(pdev, | ||
632 | SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf)); | ||
633 | } | ||
634 | |||
635 | static int pwc_get_wb_delay(struct pwc_device *pdev, int *value) | ||
636 | { | ||
637 | unsigned char buf; | ||
638 | int ret; | ||
639 | |||
640 | ret = recv_control_msg(pdev, | ||
641 | GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf)); | ||
642 | if (ret < 0) | ||
643 | return ret; | ||
644 | *value = buf << 10; | ||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | |||
649 | int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) | 536 | int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) |
650 | { | 537 | { |
651 | unsigned char buf[2]; | 538 | unsigned char buf[2]; |
@@ -675,108 +562,6 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) | |||
675 | return r; | 562 | return r; |
676 | } | 563 | } |
677 | 564 | ||
678 | static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) | ||
679 | { | ||
680 | unsigned char buf[2]; | ||
681 | int ret; | ||
682 | |||
683 | if (pdev->type < 730) { | ||
684 | *on_value = -1; | ||
685 | *off_value = -1; | ||
686 | return 0; | ||
687 | } | ||
688 | |||
689 | ret = recv_control_msg(pdev, | ||
690 | GET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf)); | ||
691 | if (ret < 0) | ||
692 | return ret; | ||
693 | *on_value = buf[0] * 100; | ||
694 | *off_value = buf[1] * 100; | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | static int _pwc_mpt_reset(struct pwc_device *pdev, int flags) | ||
699 | { | ||
700 | unsigned char buf; | ||
701 | |||
702 | buf = flags & 0x03; // only lower two bits are currently used | ||
703 | return send_control_msg(pdev, | ||
704 | SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, &buf, sizeof(buf)); | ||
705 | } | ||
706 | |||
707 | int pwc_mpt_reset(struct pwc_device *pdev, int flags) | ||
708 | { | ||
709 | int ret; | ||
710 | ret = _pwc_mpt_reset(pdev, flags); | ||
711 | if (ret >= 0) { | ||
712 | pdev->pan_angle = 0; | ||
713 | pdev->tilt_angle = 0; | ||
714 | } | ||
715 | return ret; | ||
716 | } | ||
717 | |||
718 | static int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) | ||
719 | { | ||
720 | unsigned char buf[4]; | ||
721 | |||
722 | /* set new relative angle; angles are expressed in degrees * 100, | ||
723 | but cam as .5 degree resolution, hence divide by 200. Also | ||
724 | the angle must be multiplied by 64 before it's send to | ||
725 | the cam (??) | ||
726 | */ | ||
727 | pan = 64 * pan / 100; | ||
728 | tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */ | ||
729 | buf[0] = pan & 0xFF; | ||
730 | buf[1] = (pan >> 8) & 0xFF; | ||
731 | buf[2] = tilt & 0xFF; | ||
732 | buf[3] = (tilt >> 8) & 0xFF; | ||
733 | return send_control_msg(pdev, | ||
734 | SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, &buf, sizeof(buf)); | ||
735 | } | ||
736 | |||
737 | int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) | ||
738 | { | ||
739 | int ret; | ||
740 | |||
741 | /* check absolute ranges */ | ||
742 | if (pan < pdev->angle_range.pan_min || | ||
743 | pan > pdev->angle_range.pan_max || | ||
744 | tilt < pdev->angle_range.tilt_min || | ||
745 | tilt > pdev->angle_range.tilt_max) | ||
746 | return -ERANGE; | ||
747 | |||
748 | /* go to relative range, check again */ | ||
749 | pan -= pdev->pan_angle; | ||
750 | tilt -= pdev->tilt_angle; | ||
751 | /* angles are specified in degrees * 100, thus the limit = 36000 */ | ||
752 | if (pan < -36000 || pan > 36000 || tilt < -36000 || tilt > 36000) | ||
753 | return -ERANGE; | ||
754 | |||
755 | ret = _pwc_mpt_set_angle(pdev, pan, tilt); | ||
756 | if (ret >= 0) { | ||
757 | pdev->pan_angle += pan; | ||
758 | pdev->tilt_angle += tilt; | ||
759 | } | ||
760 | if (ret == -EPIPE) /* stall -> out of range */ | ||
761 | ret = -ERANGE; | ||
762 | return ret; | ||
763 | } | ||
764 | |||
765 | static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status) | ||
766 | { | ||
767 | int ret; | ||
768 | unsigned char buf[5]; | ||
769 | |||
770 | ret = recv_control_msg(pdev, | ||
771 | GET_MPT_CTL, PT_STATUS_FORMATTER, &buf, sizeof(buf)); | ||
772 | if (ret < 0) | ||
773 | return ret; | ||
774 | status->status = buf[0] & 0x7; // 3 bits are used for reporting | ||
775 | status->time_pan = (buf[1] << 8) + buf[2]; | ||
776 | status->time_tilt = (buf[3] << 8) + buf[4]; | ||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | #ifdef CONFIG_USB_PWC_DEBUG | 565 | #ifdef CONFIG_USB_PWC_DEBUG |
781 | int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) | 566 | int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) |
782 | { | 567 | { |
@@ -801,420 +586,3 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) | |||
801 | return 0; | 586 | return 0; |
802 | } | 587 | } |
803 | #endif | 588 | #endif |
804 | |||
805 | /* End of Add-Ons */ | ||
806 | /* ************************************************* */ | ||
807 | |||
808 | /* Linux 2.5.something and 2.6 pass direct pointers to arguments of | ||
809 | ioctl() calls. With 2.4, you have to do tedious copy_from_user() | ||
810 | and copy_to_user() calls. With these macros we circumvent this, | ||
811 | and let me maintain only one source file. The functionality is | ||
812 | exactly the same otherwise. | ||
813 | */ | ||
814 | |||
815 | /* define local variable for arg */ | ||
816 | #define ARG_DEF(ARG_type, ARG_name)\ | ||
817 | ARG_type *ARG_name = arg; | ||
818 | /* copy arg to local variable */ | ||
819 | #define ARG_IN(ARG_name) /* nothing */ | ||
820 | /* argument itself (referenced) */ | ||
821 | #define ARGR(ARG_name) (*ARG_name) | ||
822 | /* argument address */ | ||
823 | #define ARGA(ARG_name) ARG_name | ||
824 | /* copy local variable to arg */ | ||
825 | #define ARG_OUT(ARG_name) /* nothing */ | ||
826 | |||
827 | /* | ||
828 | * Our ctrls use native values, but the old custom pwc ioctl interface expects | ||
829 | * values from 0 - 65535, define 2 helper functions to scale things. */ | ||
830 | static int pwc_ioctl_g_ctrl(struct v4l2_ctrl *ctrl) | ||
831 | { | ||
832 | return v4l2_ctrl_g_ctrl(ctrl) * 65535 / ctrl->maximum; | ||
833 | } | ||
834 | |||
835 | static int pwc_ioctl_s_ctrl(struct v4l2_ctrl *ctrl, int val) | ||
836 | { | ||
837 | return v4l2_ctrl_s_ctrl(ctrl, val * ctrl->maximum / 65535); | ||
838 | } | ||
839 | |||
840 | long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | ||
841 | { | ||
842 | long ret = 0; | ||
843 | |||
844 | switch(cmd) { | ||
845 | case VIDIOCPWCRUSER: | ||
846 | ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER); | ||
847 | break; | ||
848 | |||
849 | case VIDIOCPWCSUSER: | ||
850 | ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER); | ||
851 | break; | ||
852 | |||
853 | case VIDIOCPWCFACTORY: | ||
854 | ret = pwc_button_ctrl(pdev, RESTORE_FACTORY_DEFAULTS_FORMATTER); | ||
855 | break; | ||
856 | |||
857 | case VIDIOCPWCSCQUAL: | ||
858 | { | ||
859 | ARG_DEF(int, qual) | ||
860 | |||
861 | if (vb2_is_streaming(&pdev->vb_queue)) { | ||
862 | ret = -EBUSY; | ||
863 | break; | ||
864 | } | ||
865 | |||
866 | ARG_IN(qual) | ||
867 | if (ARGR(qual) < 0 || ARGR(qual) > 3) | ||
868 | ret = -EINVAL; | ||
869 | else | ||
870 | ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot); | ||
871 | break; | ||
872 | } | ||
873 | |||
874 | case VIDIOCPWCGCQUAL: | ||
875 | { | ||
876 | ARG_DEF(int, qual) | ||
877 | |||
878 | ARGR(qual) = pdev->vcompression; | ||
879 | ARG_OUT(qual) | ||
880 | break; | ||
881 | } | ||
882 | |||
883 | case VIDIOCPWCPROBE: | ||
884 | { | ||
885 | ARG_DEF(struct pwc_probe, probe) | ||
886 | |||
887 | strcpy(ARGR(probe).name, pdev->vdev.name); | ||
888 | ARGR(probe).type = pdev->type; | ||
889 | ARG_OUT(probe) | ||
890 | break; | ||
891 | } | ||
892 | |||
893 | case VIDIOCPWCGSERIAL: | ||
894 | { | ||
895 | ARG_DEF(struct pwc_serial, serial) | ||
896 | |||
897 | strcpy(ARGR(serial).serial, pdev->serial); | ||
898 | ARG_OUT(serial) | ||
899 | break; | ||
900 | } | ||
901 | |||
902 | case VIDIOCPWCSAGC: | ||
903 | { | ||
904 | ARG_DEF(int, agc) | ||
905 | ARG_IN(agc) | ||
906 | ret = v4l2_ctrl_s_ctrl(pdev->autogain, ARGR(agc) < 0); | ||
907 | if (ret == 0 && ARGR(agc) >= 0) | ||
908 | ret = pwc_ioctl_s_ctrl(pdev->gain, ARGR(agc)); | ||
909 | break; | ||
910 | } | ||
911 | |||
912 | case VIDIOCPWCGAGC: | ||
913 | { | ||
914 | ARG_DEF(int, agc) | ||
915 | if (v4l2_ctrl_g_ctrl(pdev->autogain)) | ||
916 | ARGR(agc) = -1; | ||
917 | else | ||
918 | ARGR(agc) = pwc_ioctl_g_ctrl(pdev->gain); | ||
919 | ARG_OUT(agc) | ||
920 | break; | ||
921 | } | ||
922 | |||
923 | case VIDIOCPWCSSHUTTER: | ||
924 | { | ||
925 | ARG_DEF(int, shutter) | ||
926 | ARG_IN(shutter) | ||
927 | ret = v4l2_ctrl_s_ctrl(pdev->exposure_auto, | ||
928 | /* Menu idx 0 = auto, idx 1 = manual */ | ||
929 | ARGR(shutter) >= 0); | ||
930 | if (ret == 0 && ARGR(shutter) >= 0) | ||
931 | ret = pwc_ioctl_s_ctrl(pdev->exposure, ARGR(shutter)); | ||
932 | break; | ||
933 | } | ||
934 | |||
935 | case VIDIOCPWCSAWB: | ||
936 | { | ||
937 | ARG_DEF(struct pwc_whitebalance, wb) | ||
938 | ARG_IN(wb) | ||
939 | ret = v4l2_ctrl_s_ctrl(pdev->auto_white_balance, | ||
940 | ARGR(wb).mode); | ||
941 | if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL) | ||
942 | ret = pwc_ioctl_s_ctrl(pdev->red_balance, | ||
943 | ARGR(wb).manual_red); | ||
944 | if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL) | ||
945 | ret = pwc_ioctl_s_ctrl(pdev->blue_balance, | ||
946 | ARGR(wb).manual_blue); | ||
947 | break; | ||
948 | } | ||
949 | |||
950 | case VIDIOCPWCGAWB: | ||
951 | { | ||
952 | ARG_DEF(struct pwc_whitebalance, wb) | ||
953 | ARGR(wb).mode = v4l2_ctrl_g_ctrl(pdev->auto_white_balance); | ||
954 | ARGR(wb).manual_red = ARGR(wb).read_red = | ||
955 | pwc_ioctl_g_ctrl(pdev->red_balance); | ||
956 | ARGR(wb).manual_blue = ARGR(wb).read_blue = | ||
957 | pwc_ioctl_g_ctrl(pdev->blue_balance); | ||
958 | ARG_OUT(wb) | ||
959 | break; | ||
960 | } | ||
961 | |||
962 | case VIDIOCPWCSAWBSPEED: | ||
963 | { | ||
964 | ARG_DEF(struct pwc_wb_speed, wbs) | ||
965 | |||
966 | if (ARGR(wbs).control_speed > 0) { | ||
967 | ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed); | ||
968 | } | ||
969 | if (ARGR(wbs).control_delay > 0) { | ||
970 | ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay); | ||
971 | } | ||
972 | break; | ||
973 | } | ||
974 | |||
975 | case VIDIOCPWCGAWBSPEED: | ||
976 | { | ||
977 | ARG_DEF(struct pwc_wb_speed, wbs) | ||
978 | |||
979 | ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed); | ||
980 | if (ret < 0) | ||
981 | break; | ||
982 | ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay); | ||
983 | if (ret < 0) | ||
984 | break; | ||
985 | ARG_OUT(wbs) | ||
986 | break; | ||
987 | } | ||
988 | |||
989 | case VIDIOCPWCSLED: | ||
990 | { | ||
991 | ARG_DEF(struct pwc_leds, leds) | ||
992 | |||
993 | ARG_IN(leds) | ||
994 | ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off); | ||
995 | break; | ||
996 | } | ||
997 | |||
998 | |||
999 | case VIDIOCPWCGLED: | ||
1000 | { | ||
1001 | ARG_DEF(struct pwc_leds, leds) | ||
1002 | |||
1003 | ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off); | ||
1004 | ARG_OUT(leds) | ||
1005 | break; | ||
1006 | } | ||
1007 | |||
1008 | case VIDIOCPWCSCONTOUR: | ||
1009 | { | ||
1010 | ARG_DEF(int, contour) | ||
1011 | ARG_IN(contour) | ||
1012 | ret = v4l2_ctrl_s_ctrl(pdev->autocontour, ARGR(contour) < 0); | ||
1013 | if (ret == 0 && ARGR(contour) >= 0) | ||
1014 | ret = pwc_ioctl_s_ctrl(pdev->contour, ARGR(contour)); | ||
1015 | break; | ||
1016 | } | ||
1017 | |||
1018 | case VIDIOCPWCGCONTOUR: | ||
1019 | { | ||
1020 | ARG_DEF(int, contour) | ||
1021 | if (v4l2_ctrl_g_ctrl(pdev->autocontour)) | ||
1022 | ARGR(contour) = -1; | ||
1023 | else | ||
1024 | ARGR(contour) = pwc_ioctl_g_ctrl(pdev->contour); | ||
1025 | ARG_OUT(contour) | ||
1026 | break; | ||
1027 | } | ||
1028 | |||
1029 | case VIDIOCPWCSBACKLIGHT: | ||
1030 | { | ||
1031 | ARG_DEF(int, backlight) | ||
1032 | ARG_IN(backlight) | ||
1033 | ret = v4l2_ctrl_s_ctrl(pdev->backlight, ARGR(backlight)); | ||
1034 | break; | ||
1035 | } | ||
1036 | |||
1037 | case VIDIOCPWCGBACKLIGHT: | ||
1038 | { | ||
1039 | ARG_DEF(int, backlight) | ||
1040 | ARGR(backlight) = v4l2_ctrl_g_ctrl(pdev->backlight); | ||
1041 | ARG_OUT(backlight) | ||
1042 | break; | ||
1043 | } | ||
1044 | |||
1045 | case VIDIOCPWCSFLICKER: | ||
1046 | { | ||
1047 | ARG_DEF(int, flicker) | ||
1048 | ARG_IN(flicker) | ||
1049 | ret = v4l2_ctrl_s_ctrl(pdev->flicker, ARGR(flicker)); | ||
1050 | break; | ||
1051 | } | ||
1052 | |||
1053 | case VIDIOCPWCGFLICKER: | ||
1054 | { | ||
1055 | ARG_DEF(int, flicker) | ||
1056 | ARGR(flicker) = v4l2_ctrl_g_ctrl(pdev->flicker); | ||
1057 | ARG_OUT(flicker) | ||
1058 | break; | ||
1059 | } | ||
1060 | |||
1061 | case VIDIOCPWCSDYNNOISE: | ||
1062 | { | ||
1063 | ARG_DEF(int, dynnoise) | ||
1064 | ARG_IN(dynnoise) | ||
1065 | ret = v4l2_ctrl_s_ctrl(pdev->noise_reduction, ARGR(dynnoise)); | ||
1066 | break; | ||
1067 | } | ||
1068 | |||
1069 | case VIDIOCPWCGDYNNOISE: | ||
1070 | { | ||
1071 | ARG_DEF(int, dynnoise) | ||
1072 | ARGR(dynnoise) = v4l2_ctrl_g_ctrl(pdev->noise_reduction); | ||
1073 | ARG_OUT(dynnoise); | ||
1074 | break; | ||
1075 | } | ||
1076 | |||
1077 | case VIDIOCPWCGREALSIZE: | ||
1078 | { | ||
1079 | ARG_DEF(struct pwc_imagesize, size) | ||
1080 | |||
1081 | ARGR(size).width = pdev->image.x; | ||
1082 | ARGR(size).height = pdev->image.y; | ||
1083 | ARG_OUT(size) | ||
1084 | break; | ||
1085 | } | ||
1086 | |||
1087 | case VIDIOCPWCMPTRESET: | ||
1088 | { | ||
1089 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1090 | { | ||
1091 | ARG_DEF(int, flags) | ||
1092 | |||
1093 | ARG_IN(flags) | ||
1094 | ret = pwc_mpt_reset(pdev, ARGR(flags)); | ||
1095 | } | ||
1096 | else | ||
1097 | { | ||
1098 | ret = -ENXIO; | ||
1099 | } | ||
1100 | break; | ||
1101 | } | ||
1102 | |||
1103 | case VIDIOCPWCMPTGRANGE: | ||
1104 | { | ||
1105 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1106 | { | ||
1107 | ARG_DEF(struct pwc_mpt_range, range) | ||
1108 | |||
1109 | ARGR(range) = pdev->angle_range; | ||
1110 | ARG_OUT(range) | ||
1111 | } | ||
1112 | else | ||
1113 | { | ||
1114 | ret = -ENXIO; | ||
1115 | } | ||
1116 | break; | ||
1117 | } | ||
1118 | |||
1119 | case VIDIOCPWCMPTSANGLE: | ||
1120 | { | ||
1121 | int new_pan, new_tilt; | ||
1122 | |||
1123 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1124 | { | ||
1125 | ARG_DEF(struct pwc_mpt_angles, angles) | ||
1126 | |||
1127 | ARG_IN(angles) | ||
1128 | /* The camera can only set relative angles, so | ||
1129 | do some calculations when getting an absolute angle . | ||
1130 | */ | ||
1131 | if (ARGR(angles).absolute) | ||
1132 | { | ||
1133 | new_pan = ARGR(angles).pan; | ||
1134 | new_tilt = ARGR(angles).tilt; | ||
1135 | } | ||
1136 | else | ||
1137 | { | ||
1138 | new_pan = pdev->pan_angle + ARGR(angles).pan; | ||
1139 | new_tilt = pdev->tilt_angle + ARGR(angles).tilt; | ||
1140 | } | ||
1141 | ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt); | ||
1142 | } | ||
1143 | else | ||
1144 | { | ||
1145 | ret = -ENXIO; | ||
1146 | } | ||
1147 | break; | ||
1148 | } | ||
1149 | |||
1150 | case VIDIOCPWCMPTGANGLE: | ||
1151 | { | ||
1152 | |||
1153 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1154 | { | ||
1155 | ARG_DEF(struct pwc_mpt_angles, angles) | ||
1156 | |||
1157 | ARGR(angles).absolute = 1; | ||
1158 | ARGR(angles).pan = pdev->pan_angle; | ||
1159 | ARGR(angles).tilt = pdev->tilt_angle; | ||
1160 | ARG_OUT(angles) | ||
1161 | } | ||
1162 | else | ||
1163 | { | ||
1164 | ret = -ENXIO; | ||
1165 | } | ||
1166 | break; | ||
1167 | } | ||
1168 | |||
1169 | case VIDIOCPWCMPTSTATUS: | ||
1170 | { | ||
1171 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1172 | { | ||
1173 | ARG_DEF(struct pwc_mpt_status, status) | ||
1174 | |||
1175 | ret = pwc_mpt_get_status(pdev, ARGA(status)); | ||
1176 | ARG_OUT(status) | ||
1177 | } | ||
1178 | else | ||
1179 | { | ||
1180 | ret = -ENXIO; | ||
1181 | } | ||
1182 | break; | ||
1183 | } | ||
1184 | |||
1185 | case VIDIOCPWCGVIDCMD: | ||
1186 | { | ||
1187 | ARG_DEF(struct pwc_video_command, vcmd); | ||
1188 | |||
1189 | ARGR(vcmd).type = pdev->type; | ||
1190 | ARGR(vcmd).release = pdev->release; | ||
1191 | ARGR(vcmd).command_len = pdev->cmd_len; | ||
1192 | memcpy(&ARGR(vcmd).command_buf, pdev->cmd_buf, pdev->cmd_len); | ||
1193 | ARGR(vcmd).bandlength = pdev->vbandlength; | ||
1194 | ARGR(vcmd).frame_size = pdev->frame_size; | ||
1195 | ARG_OUT(vcmd) | ||
1196 | break; | ||
1197 | } | ||
1198 | /* | ||
1199 | case VIDIOCPWCGVIDTABLE: | ||
1200 | { | ||
1201 | ARG_DEF(struct pwc_table_init_buffer, table); | ||
1202 | ARGR(table).len = pdev->cmd_len; | ||
1203 | memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size); | ||
1204 | ARG_OUT(table) | ||
1205 | break; | ||
1206 | } | ||
1207 | */ | ||
1208 | |||
1209 | default: | ||
1210 | ret = -ENOIOCTLCMD; | ||
1211 | break; | ||
1212 | } | ||
1213 | |||
1214 | if (ret > 0) | ||
1215 | return 0; | ||
1216 | return ret; | ||
1217 | } | ||
1218 | |||
1219 | |||
1220 | /* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ | ||