diff options
Diffstat (limited to 'drivers/media/video')
59 files changed, 43956 insertions, 2 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index b3d3b22d3f78..1f8a46b5916e 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -291,8 +291,6 @@ config VIDEO_HEXIUM_GEMINI | |||
291 | 291 | ||
292 | source "drivers/media/video/cx88/Kconfig" | 292 | source "drivers/media/video/cx88/Kconfig" |
293 | 293 | ||
294 | source "drivers/media/video/em28xx/Kconfig" | ||
295 | |||
296 | config VIDEO_OVCAMCHIP | 294 | config VIDEO_OVCAMCHIP |
297 | tristate "OmniVision Camera Chip support" | 295 | tristate "OmniVision Camera Chip support" |
298 | depends on VIDEO_DEV && I2C | 296 | depends on VIDEO_DEV && I2C |
@@ -367,4 +365,234 @@ config VIDEO_SAA7127 | |||
367 | To compile this driver as a module, choose M here: the | 365 | To compile this driver as a module, choose M here: the |
368 | module will be called saa7127 | 366 | module will be called saa7127 |
369 | 367 | ||
368 | # | ||
369 | # USB Multimedia device configuration | ||
370 | # | ||
371 | |||
372 | menu "V4L USB devices" | ||
373 | depends on USB && VIDEO_DEV | ||
374 | |||
375 | source "drivers/media/video/em28xx/Kconfig" | ||
376 | |||
377 | config USB_VICAM | ||
378 | tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)" | ||
379 | depends on USB && VIDEO_DEV && EXPERIMENTAL | ||
380 | ---help--- | ||
381 | Say Y here if you have 3com homeconnect camera (vicam). | ||
382 | |||
383 | This driver uses the Video For Linux API. You must say Y or M to | ||
384 | "Video For Linux" (under Multimedia Devices) to use this driver. | ||
385 | Information on this API and pointers to "v4l" programs may be found | ||
386 | at <file:Documentation/video4linux/API.html>. | ||
387 | |||
388 | To compile this driver as a module, choose M here: the | ||
389 | module will be called vicam. | ||
390 | |||
391 | config USB_DSBR | ||
392 | tristate "D-Link USB FM radio support (EXPERIMENTAL)" | ||
393 | depends on USB && VIDEO_DEV && EXPERIMENTAL | ||
394 | ---help--- | ||
395 | Say Y here if you want to connect this type of radio to your | ||
396 | computer's USB port. Note that the audio is not digital, and | ||
397 | you must connect the line out connector to a sound card or a | ||
398 | set of speakers. | ||
399 | |||
400 | This driver uses the Video For Linux API. You must enable | ||
401 | (Y or M in config) Video For Linux (under Character Devices) | ||
402 | to use this driver. Information on this API and pointers to | ||
403 | "v4l" programs may be found at | ||
404 | <file:Documentation/video4linux/API.html>. | ||
405 | |||
406 | To compile this driver as a module, choose M here: the | ||
407 | module will be called dsbr100. | ||
408 | |||
409 | config USB_ET61X251 | ||
410 | tristate "USB ET61X[12]51 PC Camera Controller support" | ||
411 | depends on USB && VIDEO_DEV | ||
412 | ---help--- | ||
413 | Say Y here if you want support for cameras based on Etoms ET61X151 | ||
414 | or ET61X251 PC Camera Controllers. | ||
415 | |||
416 | See <file:Documentation/usb/et61x251.txt> for more informations. | ||
417 | |||
418 | This driver uses the Video For Linux API. You must say Y or M to | ||
419 | "Video For Linux" to use this driver. | ||
420 | |||
421 | To compile this driver as a module, choose M here: the | ||
422 | module will be called et61x251. | ||
423 | |||
424 | config USB_IBMCAM | ||
425 | tristate "USB IBM (Xirlink) C-it Camera support" | ||
426 | depends on USB && VIDEO_DEV | ||
427 | ---help--- | ||
428 | Say Y here if you want to connect a IBM "C-It" camera, also known as | ||
429 | "Xirlink PC Camera" to your computer's USB port. For more | ||
430 | information, read <file:Documentation/usb/ibmcam.txt>. | ||
431 | |||
432 | This driver uses the Video For Linux API. You must enable | ||
433 | (Y or M in config) Video For Linux (under Character Devices) | ||
434 | to use this driver. Information on this API and pointers to | ||
435 | "v4l" programs may be found at | ||
436 | <file:Documentation/video4linux/API.html>. | ||
437 | |||
438 | To compile this driver as a module, choose M here: the | ||
439 | module will be called ibmcam. | ||
440 | |||
441 | This camera has several configuration options which | ||
442 | can be specified when you load the module. Read | ||
443 | <file:Documentation/usb/ibmcam.txt> to learn more. | ||
444 | |||
445 | config USB_KONICAWC | ||
446 | tristate "USB Konica Webcam support" | ||
447 | depends on USB && VIDEO_DEV | ||
448 | ---help--- | ||
449 | Say Y here if you want support for webcams based on a Konica | ||
450 | chipset. This is known to work with the Intel YC76 webcam. | ||
451 | |||
452 | This driver uses the Video For Linux API. You must enable | ||
453 | (Y or M in config) Video For Linux (under Character Devices) | ||
454 | to use this driver. Information on this API and pointers to | ||
455 | "v4l" programs may be found at | ||
456 | <file:Documentation/video4linux/API.html>. | ||
457 | |||
458 | To compile this driver as a module, choose M here: the | ||
459 | module will be called konicawc. | ||
460 | |||
461 | config USB_OV511 | ||
462 | tristate "USB OV511 Camera support" | ||
463 | depends on USB && VIDEO_DEV | ||
464 | ---help--- | ||
465 | Say Y here if you want to connect this type of camera to your | ||
466 | computer's USB port. See <file:Documentation/usb/ov511.txt> for more | ||
467 | information and for a list of supported cameras. | ||
468 | |||
469 | This driver uses the Video For Linux API. You must say Y or M to | ||
470 | "Video For Linux" (under Character Devices) to use this driver. | ||
471 | Information on this API and pointers to "v4l" programs may be found | ||
472 | at <file:Documentation/video4linux/API.html>. | ||
473 | |||
474 | To compile this driver as a module, choose M here: the | ||
475 | module will be called ov511. | ||
476 | |||
477 | config USB_SE401 | ||
478 | tristate "USB SE401 Camera support" | ||
479 | depends on USB && VIDEO_DEV | ||
480 | ---help--- | ||
481 | Say Y here if you want to connect this type of camera to your | ||
482 | computer's USB port. See <file:Documentation/usb/se401.txt> for more | ||
483 | information and for a list of supported cameras. | ||
484 | |||
485 | This driver uses the Video For Linux API. You must say Y or M to | ||
486 | "Video For Linux" (under Multimedia Devices) to use this driver. | ||
487 | Information on this API and pointers to "v4l" programs may be found | ||
488 | at <file:Documentation/video4linux/API.html>. | ||
489 | |||
490 | To compile this driver as a module, choose M here: the | ||
491 | module will be called se401. | ||
492 | |||
493 | config USB_SN9C102 | ||
494 | tristate "USB SN9C10x PC Camera Controller support" | ||
495 | depends on USB && VIDEO_DEV | ||
496 | ---help--- | ||
497 | Say Y here if you want support for cameras based on SONiX SN9C101, | ||
498 | SN9C102 or SN9C103 PC Camera Controllers. | ||
499 | |||
500 | See <file:Documentation/usb/sn9c102.txt> for more informations. | ||
501 | |||
502 | This driver uses the Video For Linux API. You must say Y or M to | ||
503 | "Video For Linux" to use this driver. | ||
504 | |||
505 | To compile this driver as a module, choose M here: the | ||
506 | module will be called sn9c102. | ||
507 | |||
508 | config USB_STV680 | ||
509 | tristate "USB STV680 (Pencam) Camera support" | ||
510 | depends on USB && VIDEO_DEV | ||
511 | ---help--- | ||
512 | Say Y here if you want to connect this type of camera to your | ||
513 | computer's USB port. This includes the Pencam line of cameras. | ||
514 | See <file:Documentation/usb/stv680.txt> for more information and for | ||
515 | a list of supported cameras. | ||
516 | |||
517 | This driver uses the Video For Linux API. You must say Y or M to | ||
518 | "Video For Linux" (under Multimedia Devices) to use this driver. | ||
519 | Information on this API and pointers to "v4l" programs may be found | ||
520 | at <file:Documentation/video4linux/API.html>. | ||
521 | |||
522 | To compile this driver as a module, choose M here: the | ||
523 | module will be called stv680. | ||
524 | |||
525 | config USB_W9968CF | ||
526 | tristate "USB W996[87]CF JPEG Dual Mode Camera support" | ||
527 | depends on USB && VIDEO_DEV && I2C && VIDEO_OVCAMCHIP | ||
528 | ---help--- | ||
529 | Say Y here if you want support for cameras based on OV681 or | ||
530 | Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips. | ||
531 | |||
532 | This driver has an optional plugin, which is distributed as a | ||
533 | separate module only (released under GPL). It allows to use higher | ||
534 | resolutions and framerates, but cannot be included in the official | ||
535 | Linux kernel for performance purposes. | ||
536 | |||
537 | See <file:Documentation/usb/w9968cf.txt> for more informations. | ||
538 | |||
539 | This driver uses the Video For Linux and the I2C APIs. It needs the | ||
540 | OmniVision Camera Chip support as well. You must say Y or M to | ||
541 | "Video For Linux", "I2C Support" and "OmniVision Camera Chip | ||
542 | support" to use this driver. | ||
543 | |||
544 | To compile this driver as a module, choose M here: the | ||
545 | module will be called w9968cf. | ||
546 | |||
547 | config USB_ZC0301 | ||
548 | tristate "USB ZC0301 Image Processor and Control Chip support" | ||
549 | depends on USB && VIDEO_DEV | ||
550 | ---help--- | ||
551 | Say Y here if you want support for cameras based on the ZC0301 | ||
552 | Image Processor and Control Chip. | ||
553 | |||
554 | See <file:Documentation/usb/zc0301.txt> for more informations. | ||
555 | |||
556 | This driver uses the Video For Linux API. You must say Y or M to | ||
557 | "Video For Linux" to use this driver. | ||
558 | |||
559 | To compile this driver as a module, choose M here: the | ||
560 | module will be called zc0301. | ||
561 | |||
562 | config USB_PWC | ||
563 | tristate "USB Philips Cameras" | ||
564 | depends on USB && VIDEO_DEV | ||
565 | ---help--- | ||
566 | Say Y or M here if you want to use one of these Philips & OEM | ||
567 | webcams: | ||
568 | * Philips PCA645, PCA646 | ||
569 | * Philips PCVC675, PCVC680, PCVC690 | ||
570 | * Philips PCVC720/40, PCVC730, PCVC740, PCVC750 | ||
571 | * Askey VC010 | ||
572 | * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' | ||
573 | and 'Orbit'/'Sphere' | ||
574 | * Samsung MPC-C10, MPC-C30 | ||
575 | * Creative Webcam 5, Pro Ex | ||
576 | * SOTEC Afina Eye | ||
577 | * Visionite VCS-UC300, VCS-UM100 | ||
578 | |||
579 | The PCA635, PCVC665 and PCVC720/20 are not supported by this driver | ||
580 | and never will be, but the 665 and 720/20 are supported by other | ||
581 | drivers. | ||
582 | |||
583 | See <file:Documentation/usb/philips.txt> for more information and | ||
584 | installation instructions. | ||
585 | |||
586 | The built-in microphone is enabled by selecting USB Audio support. | ||
587 | |||
588 | This driver uses the Video For Linux API. You must say Y or M to | ||
589 | "Video For Linux" (under Character Devices) to use this driver. | ||
590 | Information on this API and pointers to "v4l" programs may be found | ||
591 | at <file:Documentation/video4linux/API.html>. | ||
592 | |||
593 | To compile this driver as a module, choose M here: the | ||
594 | module will be called pwc. | ||
595 | |||
596 | endmenu # V4L USB devices | ||
597 | |||
370 | endmenu | 598 | endmenu |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 1a56a2d9e294..1c0e72e5a593 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -65,4 +65,23 @@ obj-$(CONFIG_VIDEO_CX25840) += cx25840/ | |||
65 | obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o | 65 | obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o |
66 | obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o | 66 | obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o |
67 | 67 | ||
68 | et61x251-objs := et61x251_core.o et61x251_tas5130d1b.o | ||
69 | zc0301-objs := zc0301_core.o zc0301_pas202bcb.o | ||
70 | |||
71 | obj-$(CONFIG_USB_DABUSB) += dabusb.o | ||
72 | obj-$(CONFIG_USB_DSBR) += dsbr100.o | ||
73 | obj-$(CONFIG_USB_OV511) += ov511.o | ||
74 | obj-$(CONFIG_USB_SE401) += se401.o | ||
75 | obj-$(CONFIG_USB_STV680) += stv680.o | ||
76 | obj-$(CONFIG_USB_W9968CF) += w9968cf.o | ||
77 | |||
78 | obj-$(CONFIG_USB_SN9C102) += sn9c102/ | ||
79 | obj-$(CONFIG_USB_ET61X251) += et61x251/ | ||
80 | obj-$(CONFIG_USB_PWC) += pwc/ | ||
81 | obj-$(CONFIG_USB_ZC0301) += zc0301/ | ||
82 | |||
83 | obj-$(CONFIG_USB_IBMCAM) += usbvideo/ | ||
84 | obj-$(CONFIG_USB_KONICAWC) += usbvideo/ | ||
85 | obj-$(CONFIG_USB_VICAM) += usbvideo/ | ||
86 | |||
68 | EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core | 87 | EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core |
diff --git a/drivers/media/video/dabfirmware.h b/drivers/media/video/dabfirmware.h new file mode 100644 index 000000000000..d14d803566a3 --- /dev/null +++ b/drivers/media/video/dabfirmware.h | |||
@@ -0,0 +1,1408 @@ | |||
1 | /* | ||
2 | * dabdata.h - dab usb firmware and bitstream data | ||
3 | */ | ||
4 | |||
5 | static INTEL_HEX_RECORD firmware[] = { | ||
6 | |||
7 | { 2, 0x0000, 0, {0x21,0x57} }, | ||
8 | { 3, 0x0003, 0, {0x02,0x01,0x66} }, | ||
9 | { 3, 0x000b, 0, {0x02,0x01,0x66} }, | ||
10 | { 3, 0x0013, 0, {0x02,0x01,0x66} }, | ||
11 | { 3, 0x001b, 0, {0x02,0x01,0x66} }, | ||
12 | { 3, 0x0023, 0, {0x02,0x01,0x66} }, | ||
13 | { 3, 0x002b, 0, {0x02,0x01,0x66} }, | ||
14 | { 3, 0x0033, 0, {0x02,0x03,0x0f} }, | ||
15 | { 3, 0x003b, 0, {0x02,0x01,0x66} }, | ||
16 | { 3, 0x0043, 0, {0x02,0x01,0x00} }, | ||
17 | { 3, 0x004b, 0, {0x02,0x01,0x66} }, | ||
18 | { 3, 0x0053, 0, {0x02,0x01,0x66} }, | ||
19 | { 3, 0x005b, 0, {0x02,0x04,0xbd} }, | ||
20 | { 3, 0x0063, 0, {0x02,0x01,0x67} }, | ||
21 | { 3, 0x0100, 0, {0x02,0x0c,0x5a} }, | ||
22 | { 3, 0x0104, 0, {0x02,0x01,0xed} }, | ||
23 | { 3, 0x0108, 0, {0x02,0x02,0x51} }, | ||
24 | { 3, 0x010c, 0, {0x02,0x02,0x7c} }, | ||
25 | { 3, 0x0110, 0, {0x02,0x02,0xe4} }, | ||
26 | { 1, 0x0114, 0, {0x32} }, | ||
27 | { 1, 0x0118, 0, {0x32} }, | ||
28 | { 3, 0x011c, 0, {0x02,0x05,0xfd} }, | ||
29 | { 3, 0x0120, 0, {0x02,0x00,0x00} }, | ||
30 | { 3, 0x0124, 0, {0x02,0x00,0x00} }, | ||
31 | { 3, 0x0128, 0, {0x02,0x04,0x3c} }, | ||
32 | { 3, 0x012c, 0, {0x02,0x04,0x6a} }, | ||
33 | { 3, 0x0130, 0, {0x02,0x00,0x00} }, | ||
34 | { 3, 0x0134, 0, {0x02,0x00,0x00} }, | ||
35 | { 3, 0x0138, 0, {0x02,0x00,0x00} }, | ||
36 | { 3, 0x013c, 0, {0x02,0x00,0x00} }, | ||
37 | { 3, 0x0140, 0, {0x02,0x00,0x00} }, | ||
38 | { 3, 0x0144, 0, {0x02,0x00,0x00} }, | ||
39 | { 3, 0x0148, 0, {0x02,0x00,0x00} }, | ||
40 | { 3, 0x014c, 0, {0x02,0x00,0x00} }, | ||
41 | { 3, 0x0150, 0, {0x02,0x00,0x00} }, | ||
42 | { 3, 0x0154, 0, {0x02,0x00,0x00} }, | ||
43 | { 10, 0x0157, 0, {0x75,0x81,0x7f,0xe5,0x82,0x60,0x03,0x02,0x01,0x61} }, | ||
44 | { 5, 0x0161, 0, {0x12,0x07,0x6f,0x21,0x64} }, | ||
45 | { 1, 0x0166, 0, {0x32} }, | ||
46 | { 14, 0x0167, 0, {0xc0,0xd0,0xc0,0x86,0xc0,0x82,0xc0,0x83,0xc0,0xe0,0x90,0x7f,0x97,0xe0} }, | ||
47 | { 14, 0x0175, 0, {0x44,0x80,0xf0,0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} }, | ||
48 | { 14, 0x0183, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} }, | ||
49 | { 14, 0x0191, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x90,0x7f,0x97,0xe0} }, | ||
50 | { 3, 0x019f, 0, {0x55,0x7f,0xf0} }, | ||
51 | { 14, 0x01a2, 0, {0x90,0x7f,0x9a,0xe0,0x30,0xe4,0x23,0x90,0x7f,0x68,0xf0,0xf0,0xf0,0xf0} }, | ||
52 | { 14, 0x01b0, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} }, | ||
53 | { 14, 0x01be, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} }, | ||
54 | { 14, 0x01cc, 0, {0xe5,0xd8,0xc2,0xe3,0xf5,0xd8,0xd0,0xe0,0xd0,0x83,0xd0,0x82,0xd0,0x86} }, | ||
55 | { 3, 0x01da, 0, {0xd0,0xd0,0x32} }, | ||
56 | { 8, 0x01dd, 0, {0x75,0x86,0x00,0x90,0xff,0xc3,0x7c,0x05} }, | ||
57 | { 7, 0x01e5, 0, {0xa3,0xe5,0x82,0x45,0x83,0x70,0xf9} }, | ||
58 | { 1, 0x01ec, 0, {0x22} }, | ||
59 | { 14, 0x01ed, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0xd0} }, | ||
60 | { 14, 0x01fb, 0, {0x75,0xd0,0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91} }, | ||
61 | { 13, 0x0209, 0, {0x90,0x88,0x00,0xe0,0xf5,0x41,0x90,0x7f,0xab,0x74,0x02,0xf0,0x90} }, | ||
62 | { 9, 0x0216, 0, {0x7f,0xab,0x74,0x02,0xf0,0xe5,0x32,0x60,0x21} }, | ||
63 | { 4, 0x021f, 0, {0x7a,0x00,0x7b,0x00} }, | ||
64 | { 11, 0x0223, 0, {0xc3,0xea,0x94,0x18,0xeb,0x64,0x80,0x94,0x80,0x50,0x12} }, | ||
65 | { 14, 0x022e, 0, {0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0a,0xba,0x00} }, | ||
66 | { 2, 0x023c, 0, {0x01,0x0b} }, | ||
67 | { 2, 0x023e, 0, {0x80,0xe3} }, | ||
68 | { 2, 0x0240, 0, {0xd0,0x86} }, | ||
69 | { 14, 0x0242, 0, {0xd0,0xd0,0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0} }, | ||
70 | { 1, 0x0250, 0, {0x32} }, | ||
71 | { 14, 0x0251, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, | ||
72 | { 14, 0x025f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} }, | ||
73 | { 4, 0x026d, 0, {0x04,0xf0,0xd0,0x86} }, | ||
74 | { 11, 0x0271, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
75 | { 14, 0x027c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} }, | ||
76 | { 14, 0x028a, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} }, | ||
77 | { 13, 0x0298, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} }, | ||
78 | { 12, 0x02a5, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0x6e,0x00,0x75,0x6f,0x02,0x12} }, | ||
79 | { 6, 0x02b1, 0, {0x11,0x44,0x75,0x70,0x39,0x75} }, | ||
80 | { 6, 0x02b7, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} }, | ||
81 | { 12, 0x02bd, 0, {0x11,0x75,0x90,0x7f,0xd6,0xe4,0xf0,0x75,0xd8,0x20,0xd0,0x86} }, | ||
82 | { 14, 0x02c9, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} }, | ||
83 | { 13, 0x02d7, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
84 | { 14, 0x02e4, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, | ||
85 | { 14, 0x02f2, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} }, | ||
86 | { 4, 0x0300, 0, {0x10,0xf0,0xd0,0x86} }, | ||
87 | { 11, 0x0304, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
88 | { 14, 0x030f, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} }, | ||
89 | { 14, 0x031d, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} }, | ||
90 | { 12, 0x032b, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0x75,0x6e,0x00,0x75,0x6f,0x02} }, | ||
91 | { 7, 0x0337, 0, {0x12,0x11,0x44,0x75,0x70,0x40,0x75} }, | ||
92 | { 6, 0x033e, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} }, | ||
93 | { 14, 0x0344, 0, {0x11,0x75,0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0} }, | ||
94 | { 5, 0x0352, 0, {0x75,0xd8,0x10,0xd0,0x86} }, | ||
95 | { 14, 0x0357, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} }, | ||
96 | { 13, 0x0365, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
97 | { 13, 0x0372, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} }, | ||
98 | { 12, 0x037f, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x42,0xf0,0x12,0x10,0x1b,0x90} }, | ||
99 | { 13, 0x038b, 0, {0x7f,0xa6,0xe5,0x43,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40} }, | ||
100 | { 1, 0x0398, 0, {0xf0} }, | ||
101 | { 1, 0x0399, 0, {0x22} }, | ||
102 | { 13, 0x039a, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} }, | ||
103 | { 12, 0x03a7, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x44,0xf0,0x12,0x10,0x1b,0x90} }, | ||
104 | { 12, 0x03b3, 0, {0x7f,0xa6,0xe5,0x45,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0xe5} }, | ||
105 | { 11, 0x03bf, 0, {0x46,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40,0xf0} }, | ||
106 | { 1, 0x03ca, 0, {0x22} }, | ||
107 | { 10, 0x03cb, 0, {0x75,0x44,0x02,0x75,0x45,0x00,0x75,0x46,0x00,0x12} }, | ||
108 | { 9, 0x03d5, 0, {0x03,0x9a,0x75,0x42,0x03,0x75,0x43,0x00,0x12} }, | ||
109 | { 2, 0x03de, 0, {0x03,0x72} }, | ||
110 | { 1, 0x03e0, 0, {0x22} }, | ||
111 | { 12, 0x03e1, 0, {0x90,0x88,0x00,0xe5,0x36,0xf0,0x90,0x88,0x00,0x74,0x10,0x25} }, | ||
112 | { 9, 0x03ed, 0, {0x36,0xf0,0x12,0x01,0xdd,0x75,0x42,0x01,0x75} }, | ||
113 | { 9, 0x03f6, 0, {0x43,0x18,0x12,0x03,0x72,0x75,0x44,0x02,0x75} }, | ||
114 | { 9, 0x03ff, 0,{0x45,0x00,0x75,0x46,0x00,0x12,0x03,0x9a,0x75} }, | ||
115 | { 8, 0x0408, 0,{0x42,0x03,0x75,0x43,0x44,0x12,0x03,0x72} }, | ||
116 | { 1, 0x0410, 0,{0x22} }, | ||
117 | { 14, 0x0411, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, | ||
118 | { 14, 0x041f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} }, | ||
119 | { 4, 0x042d, 0, {0x02,0xf0,0xd0,0x86} }, | ||
120 | { 11, 0x0431, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
121 | { 14, 0x043c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, | ||
122 | { 14, 0x044a, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xa9,0x74} }, | ||
123 | { 7, 0x0458, 0, {0x04,0xf0,0x75,0x30,0x01,0xd0,0x86} }, | ||
124 | { 11, 0x045f, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
125 | { 14, 0x046a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, | ||
126 | { 14, 0x0478, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} }, | ||
127 | { 7, 0x0486, 0, {0x04,0xf0,0x75,0x31,0x01,0xd0,0x86} }, | ||
128 | { 11, 0x048d, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
129 | { 14, 0x0498, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, | ||
130 | { 12, 0x04a6, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe5,0xf5,0x91,0xd0,0x86} }, | ||
131 | { 11, 0x04b2, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
132 | { 14, 0x04bd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, | ||
133 | { 12, 0x04cb, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe7,0xf5,0x91,0xd0,0x86} }, | ||
134 | { 11, 0x04d7, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
135 | { 12, 0x04e2, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x20,0x90,0x7f,0x96,0xe4,0xf0} }, | ||
136 | { 1, 0x04ee, 0, {0x22} }, | ||
137 | { 7, 0x04ef, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x21} }, | ||
138 | { 1, 0x04f6, 0, {0x22} }, | ||
139 | { 14, 0x04f7, 0, {0x90,0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xe0,0xfb,0x74,0x80,0x2a,0xfa} }, | ||
140 | { 14, 0x0505, 0, {0x74,0x80,0x2b,0xfb,0xea,0x03,0x03,0x54,0x3f,0xfc,0xea,0xc4,0x23,0x54} }, | ||
141 | { 14, 0x0513, 0, {0x1f,0xfa,0x2c,0xfa,0xeb,0x03,0x03,0x54,0x3f,0xfc,0xeb,0xc4,0x23,0x54} }, | ||
142 | { 11, 0x0521, 0, {0x1f,0xfb,0x2c,0xfb,0x90,0x17,0x0a,0xe0,0xfc,0x60,0x02} }, | ||
143 | { 2, 0x052c, 0, {0x7a,0x00} }, | ||
144 | { 7, 0x052e, 0, {0x90,0x17,0x0c,0xe0,0xfc,0x60,0x02} }, | ||
145 | { 2, 0x0535, 0, {0x7b,0x00} }, | ||
146 | { 11, 0x0537, 0, {0xea,0x2b,0xfc,0xc3,0x13,0xf5,0x3a,0x75,0x44,0x02,0x8b} }, | ||
147 | { 7, 0x0542, 0, {0x45,0x8a,0x46,0x12,0x03,0x9a,0x75} }, | ||
148 | { 9, 0x0549, 0, {0x6e,0x08,0x75,0x6f,0x00,0x12,0x11,0x44,0x75} }, | ||
149 | { 4, 0x0552, 0, {0x70,0x47,0x75,0x71} }, | ||
150 | { 8, 0x0556, 0, {0x0c,0x75,0x72,0x02,0x12,0x11,0x75,0x85} }, | ||
151 | { 5, 0x055e, 0, {0x3a,0x73,0x12,0x11,0xa0} }, | ||
152 | { 1, 0x0563, 0, {0x22} }, | ||
153 | { 14, 0x0564, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} }, | ||
154 | { 14, 0x0572, 0, {0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xef,0xe0,0xfc} }, | ||
155 | { 14, 0x0580, 0, {0x33,0x95,0xe0,0xfd,0x8c,0x05,0x7c,0x00,0x90,0x7f,0xee,0xe0,0xfe,0x33} }, | ||
156 | { 14, 0x058e, 0, {0x95,0xe0,0xff,0xec,0x2e,0xfc,0xed,0x3f,0xfd,0x90,0x7f,0xe9,0xe0,0xfe} }, | ||
157 | { 5, 0x059c, 0, {0xbe,0x01,0x02,0x80,0x03} }, | ||
158 | { 3, 0x05a1, 0, {0x02,0x05,0xf9} }, | ||
159 | { 6, 0x05a4, 0, {0xbc,0x01,0x21,0xbd,0x00,0x1e} }, | ||
160 | { 14, 0x05aa, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfc,0xeb,0x25,0xe0,0xfd,0x2c,0x24,0x00,0xfc} }, | ||
161 | { 14, 0x05b8, 0, {0xe4,0x34,0x17,0xfd,0x90,0x7e,0xc0,0xe0,0xfe,0x8c,0x82,0x8d,0x83,0xf0} }, | ||
162 | { 2, 0x05c6, 0, {0x80,0x31} }, | ||
163 | { 14, 0x05c8, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfa,0xeb,0x25,0xe0,0xfb,0x2a,0xfa,0x24,0x00} }, | ||
164 | { 14, 0x05d6, 0, {0xfb,0xe4,0x34,0x17,0xfc,0x90,0x7e,0xc0,0xe0,0xfd,0x8b,0x82,0x8c,0x83} }, | ||
165 | { 14, 0x05e4, 0, {0xf0,0x74,0x01,0x2a,0x24,0x00,0xfa,0xe4,0x34,0x17,0xfb,0x90,0x7e,0xc1} }, | ||
166 | { 7, 0x05f2, 0, {0xe0,0xfc,0x8a,0x82,0x8b,0x83,0xf0} }, | ||
167 | { 3, 0x05f9, 0, {0x75,0x38,0x01} }, | ||
168 | { 1, 0x05fc, 0, {0x22} }, | ||
169 | { 14, 0x05fd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} }, | ||
170 | { 14, 0x060b, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} }, | ||
171 | { 13, 0x0619, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} }, | ||
172 | { 13, 0x0626, 0, {0x7f,0xaa,0x74,0x01,0xf0,0x12,0x05,0x64,0x75,0x37,0x00,0xd0,0x86} }, | ||
173 | { 14, 0x0633, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} }, | ||
174 | { 13, 0x0641, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
175 | { 14, 0x064e, 0, {0x90,0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xee,0xe0} }, | ||
176 | { 14, 0x065c, 0, {0xfc,0x33,0x95,0xe0,0xfd,0x90,0x7f,0x96,0xe0,0xfe,0x90,0x7f,0x96,0x74} }, | ||
177 | { 14, 0x066a, 0, {0x80,0x65,0x06,0xf0,0x90,0x7f,0x00,0x74,0x01,0xf0,0xea,0xc4,0x03,0x54} }, | ||
178 | { 14, 0x0678, 0, {0xf8,0xfe,0xeb,0x25,0xe0,0xfb,0x2e,0xfe,0x24,0x00,0xfb,0xe4,0x34,0x17} }, | ||
179 | { 14, 0x0686, 0, {0xff,0x8b,0x82,0x8f,0x83,0xe0,0xfb,0x74,0x01,0x2e,0x24,0x00,0xfe,0xe4} }, | ||
180 | { 14, 0x0694, 0, {0x34,0x17,0xff,0x8e,0x82,0x8f,0x83,0xe0,0xfe,0x90,0x7f,0xe9,0xe0,0xff} }, | ||
181 | { 3, 0x06a2, 0, {0xbf,0x81,0x0a} }, | ||
182 | { 10, 0x06a5, 0, {0x90,0x7f,0x00,0xeb,0xf0,0x90,0x7f,0x01,0xee,0xf0} }, | ||
183 | { 8, 0x06af, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x82,0x1a} }, | ||
184 | { 3, 0x06b7, 0, {0xba,0x01,0x0c} }, | ||
185 | { 12, 0x06ba, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} }, | ||
186 | { 11, 0x06c6, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0xb5,0xf0} }, | ||
187 | { 8, 0x06d1, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x83,0x1b} }, | ||
188 | { 3, 0x06d9, 0, {0xba,0x01,0x0d} }, | ||
189 | { 13, 0x06dc, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} }, | ||
190 | { 11, 0x06e9, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0x12,0xf0} }, | ||
191 | { 8, 0x06f4, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x84,0x1c} }, | ||
192 | { 3, 0x06fc, 0, {0xba,0x01,0x0d} }, | ||
193 | { 13, 0x06ff, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0c} }, | ||
194 | { 12, 0x070c, 0, {0x90,0x7f,0x00,0x74,0x80,0xf0,0x90,0x7f,0x01,0x74,0x01,0xf0} }, | ||
195 | { 5, 0x0718, 0, {0x90,0x7f,0xb5,0xec,0xf0} }, | ||
196 | { 1, 0x071d, 0, {0x22} }, | ||
197 | { 12, 0x071e, 0, {0x75,0x36,0x0d,0x90,0x88,0x00,0x74,0x1d,0xf0,0x75,0x6b,0x80} }, | ||
198 | { 10, 0x072a, 0, {0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} }, | ||
199 | { 9, 0x0734, 0, {0x6c,0x0f,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} }, | ||
200 | { 9, 0x073d, 0, {0x6c,0x06,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} }, | ||
201 | { 7, 0x0746, 0, {0x6c,0x01,0x12,0x10,0xe2,0x7a,0x00} }, | ||
202 | { 3, 0x074d, 0, {0xba,0xff,0x00} }, | ||
203 | { 2, 0x0750, 0, {0x50,0x0a} }, | ||
204 | { 10, 0x0752, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} }, | ||
205 | { 10, 0x075c, 0, {0x75,0x6b,0x80,0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75} }, | ||
206 | { 8, 0x0766, 0, {0x6b,0x80,0x75,0x6c,0x0f,0x12,0x10,0xe2} }, | ||
207 | { 1, 0x076e, 0, {0x22} }, | ||
208 | { 14, 0x076f, 0, {0x90,0x7f,0xa1,0xe4,0xf0,0x90,0x7f,0xaf,0x74,0x01,0xf0,0x90,0x7f,0x92} }, | ||
209 | { 14, 0x077d, 0, {0x74,0x02,0xf0,0x75,0x8e,0x31,0x75,0x89,0x21,0x75,0x88,0x00,0x75,0xc8} }, | ||
210 | { 14, 0x078b, 0, {0x00,0x75,0x8d,0x40,0x75,0x98,0x40,0x75,0xc0,0x40,0x75,0x87,0x00,0x75} }, | ||
211 | { 9, 0x0799, 0, {0x20,0x00,0x75,0x21,0x00,0x75,0x22,0x00,0x75} }, | ||
212 | { 5, 0x07a2, 0, {0x23,0x00,0x75,0x47,0x00} }, | ||
213 | { 7, 0x07a7, 0, {0xc3,0xe5,0x47,0x94,0x20,0x50,0x11} }, | ||
214 | { 13, 0x07ae, 0, {0xe5,0x47,0x24,0x00,0xf5,0x82,0xe4,0x34,0x17,0xf5,0x83,0xe4,0xf0} }, | ||
215 | { 4, 0x07bb, 0, {0x05,0x47,0x80,0xe8} }, | ||
216 | { 9, 0x07bf, 0, {0xe4,0xf5,0x40,0xf5,0x3f,0xe4,0xf5,0x3c,0xf5} }, | ||
217 | { 7, 0x07c8, 0, {0x3b,0xe4,0xf5,0x3e,0xf5,0x3d,0x75} }, | ||
218 | { 11, 0x07cf, 0, {0x32,0x00,0x75,0x37,0x00,0x75,0x39,0x00,0x90,0x7f,0x93} }, | ||
219 | { 14, 0x07da, 0, {0x74,0x3c,0xf0,0x90,0x7f,0x9c,0x74,0xff,0xf0,0x90,0x7f,0x96,0x74,0x80} }, | ||
220 | { 14, 0x07e8, 0, {0xf0,0x90,0x7f,0x94,0x74,0x70,0xf0,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} }, | ||
221 | { 14, 0x07f6, 0, {0x7f,0x97,0xe4,0xf0,0x90,0x7f,0x95,0x74,0xc2,0xf0,0x90,0x7f,0x98,0x74} }, | ||
222 | { 14, 0x0804, 0, {0x28,0xf0,0x90,0x7f,0x9e,0x74,0x28,0xf0,0x90,0x7f,0xf0,0xe4,0xf0,0x90} }, | ||
223 | { 14, 0x0812, 0, {0x7f,0xf1,0xe4,0xf0,0x90,0x7f,0xf2,0xe4,0xf0,0x90,0x7f,0xf3,0xe4,0xf0} }, | ||
224 | { 14, 0x0820, 0, {0x90,0x7f,0xf4,0xe4,0xf0,0x90,0x7f,0xf5,0xe4,0xf0,0x90,0x7f,0xf6,0xe4} }, | ||
225 | { 14, 0x082e, 0, {0xf0,0x90,0x7f,0xf7,0xe4,0xf0,0x90,0x7f,0xf8,0xe4,0xf0,0x90,0x7f,0xf9} }, | ||
226 | { 14, 0x083c, 0, {0x74,0x38,0xf0,0x90,0x7f,0xfa,0x74,0xa0,0xf0,0x90,0x7f,0xfb,0x74,0xa0} }, | ||
227 | { 14, 0x084a, 0, {0xf0,0x90,0x7f,0xfc,0x74,0xa0,0xf0,0x90,0x7f,0xfd,0x74,0xa0,0xf0,0x90} }, | ||
228 | { 14, 0x0858, 0, {0x7f,0xfe,0x74,0xa0,0xf0,0x90,0x7f,0xff,0x74,0xa0,0xf0,0x90,0x7f,0xe0} }, | ||
229 | { 14, 0x0866, 0, {0x74,0x03,0xf0,0x90,0x7f,0xe1,0x74,0x01,0xf0,0x90,0x7f,0xdd,0x74,0x80} }, | ||
230 | { 11, 0x0874, 0, {0xf0,0x12,0x12,0x43,0x12,0x07,0x1e,0x7a,0x00,0x7b,0x00} }, | ||
231 | { 9, 0x087f, 0, {0xc3,0xea,0x94,0x1e,0xeb,0x94,0x00,0x50,0x17} }, | ||
232 | { 12, 0x0888, 0, {0x90,0x88,0x00,0xe0,0xf5,0x47,0x90,0x88,0x0b,0xe0,0xf5,0x47} }, | ||
233 | { 9, 0x0894, 0, {0x90,0x7f,0x68,0xf0,0x0a,0xba,0x00,0x01,0x0b} }, | ||
234 | { 2, 0x089d, 0, {0x80,0xe0} }, | ||
235 | { 12, 0x089f, 0, {0x12,0x03,0xe1,0x90,0x7f,0xd6,0xe4,0xf0,0x7a,0x00,0x7b,0x00} }, | ||
236 | { 13, 0x08ab, 0, {0x8a,0x04,0x8b,0x05,0xc3,0xea,0x94,0xe0,0xeb,0x94,0x2e,0x50,0x1a} }, | ||
237 | { 14, 0x08b8, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} }, | ||
238 | { 10, 0x08c6, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} }, | ||
239 | { 2, 0x08d0, 0, {0x80,0xd9} }, | ||
240 | { 13, 0x08d2, 0, {0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0,0x90} }, | ||
241 | { 14, 0x08df, 0, {0x7f,0xde,0x74,0x05,0xf0,0x90,0x7f,0xdf,0x74,0x05,0xf0,0x90,0x7f,0xac} }, | ||
242 | { 14, 0x08ed, 0, {0xe4,0xf0,0x90,0x7f,0xad,0x74,0x05,0xf0,0x75,0xa8,0x80,0x75,0xf8,0x10} }, | ||
243 | { 13, 0x08fb, 0, {0x90,0x7f,0xae,0x74,0x0b,0xf0,0x90,0x7f,0xe2,0x74,0x88,0xf0,0x90} }, | ||
244 | { 12, 0x0908, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0xe8,0x11,0x75,0x32,0x01,0x75} }, | ||
245 | { 12, 0x0914, 0, {0x31,0x00,0x75,0x30,0x00,0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7} }, | ||
246 | { 10, 0x0920, 0, {0xd0,0x05,0xd0,0x04,0x75,0x34,0x00,0x75,0x35,0x01} }, | ||
247 | { 13, 0x092a, 0, {0x90,0x7f,0xae,0x74,0x03,0xf0,0x8c,0x02,0xba,0x00,0x02,0x80,0x03} }, | ||
248 | { 3, 0x0937, 0, {0x02,0x0a,0x3f} }, | ||
249 | { 12, 0x093a, 0, {0x85,0x33,0x34,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90,0x7f,0x97} }, | ||
250 | { 14, 0x0946, 0, {0x74,0x08,0xf0,0x90,0x7f,0x9d,0x74,0x88,0xf0,0x90,0x7f,0x9a,0xe0,0xfa} }, | ||
251 | { 12, 0x0954, 0, {0x74,0x05,0x5a,0xf5,0x33,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} }, | ||
252 | { 13, 0x0960, 0, {0x7f,0x97,0x74,0x02,0xf0,0x90,0x7f,0x9d,0x74,0x82,0xf0,0xe5,0x33} }, | ||
253 | { 13, 0x096d, 0, {0x25,0xe0,0xfa,0x90,0x7f,0x9a,0xe0,0x54,0x05,0xfb,0x4a,0xf5,0x33} }, | ||
254 | { 2, 0x097a, 0, {0x60,0x0c} }, | ||
255 | { 12, 0x097c, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x4a,0xf0} }, | ||
256 | { 11, 0x0988, 0, {0x75,0x6e,0x00,0x75,0x6f,0x00,0xc0,0x04,0xc0,0x05,0x12} }, | ||
257 | { 14, 0x0993, 0, {0x11,0x44,0xd0,0x05,0xd0,0x04,0x90,0x17,0x13,0xe0,0xfa,0x74,0x80,0x2a} }, | ||
258 | { 6, 0x09a1, 0, {0xfa,0xe5,0x33,0xb4,0x04,0x29} }, | ||
259 | { 3, 0x09a7, 0, {0xba,0xa0,0x00} }, | ||
260 | { 2, 0x09aa, 0, {0x50,0x24} }, | ||
261 | { 13, 0x09ac, 0, {0x90,0x17,0x13,0xe0,0x04,0xfb,0x0b,0x90,0x17,0x13,0xeb,0xf0,0x90} }, | ||
262 | { 14, 0x09b9, 0, {0x17,0x13,0xe0,0xfb,0x90,0x17,0x15,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05} }, | ||
263 | { 9, 0x09c7, 0, {0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02} }, | ||
264 | { 5, 0x09d0, 0, {0xe5,0x33,0xb4,0x02,0x26} }, | ||
265 | { 6, 0x09d5, 0, {0xc3,0x74,0x04,0x9a,0x50,0x20} }, | ||
266 | { 13, 0x09db, 0, {0x90,0x17,0x13,0xe0,0xfa,0x1a,0x1a,0x90,0x17,0x13,0xea,0xf0,0x90} }, | ||
267 | { 13, 0x09e8, 0, {0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xf0,0xc0,0x04,0xc0,0x05,0x12} }, | ||
268 | { 6, 0x09f5, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04} }, | ||
269 | { 5, 0x09fb, 0, {0xe5,0x33,0xb4,0x08,0x1d} }, | ||
270 | { 4, 0x0a00, 0, {0xe5,0x34,0x70,0x19} }, | ||
271 | { 10, 0x0a04, 0, {0x74,0x01,0x25,0x35,0x54,0x0f,0xf5,0x35,0x85,0x35} }, | ||
272 | { 12, 0x0a0e, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} }, | ||
273 | { 3, 0x0a1a, 0, {0x05,0xd0,0x04} }, | ||
274 | { 5, 0x0a1d, 0, {0xe5,0x33,0xb4,0x01,0x1d} }, | ||
275 | { 4, 0x0a22, 0, {0xe5,0x34,0x70,0x19} }, | ||
276 | { 10, 0x0a26, 0, {0xe5,0x35,0x24,0xff,0x54,0x0f,0xf5,0x35,0x85,0x35} }, | ||
277 | { 12, 0x0a30, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} }, | ||
278 | { 3, 0x0a3c, 0, {0x05,0xd0,0x04} }, | ||
279 | { 14, 0x0a3f, 0, {0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0,0x04,0x90,0x7f,0x96} }, | ||
280 | { 14, 0x0a4d, 0, {0xe0,0xfa,0x90,0x7f,0x96,0x74,0x7f,0x5a,0xf0,0x90,0x7f,0x97,0x74,0x08} }, | ||
281 | { 10, 0x0a5b, 0, {0xf0,0xc3,0xec,0x94,0x00,0xed,0x94,0x02,0x40,0x08} }, | ||
282 | { 8, 0x0a65, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x20,0xe6,0x08} }, | ||
283 | { 8, 0x0a6d, 0, {0xc3,0xe4,0x9c,0x74,0x08,0x9d,0x50,0x13} }, | ||
284 | { 14, 0x0a75, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x40,0x65,0x02,0xf0,0x7c} }, | ||
285 | { 5, 0x0a83, 0, {0x00,0x7d,0x00,0x80,0x05} }, | ||
286 | { 5, 0x0a88, 0, {0x0c,0xbc,0x00,0x01,0x0d} }, | ||
287 | { 5, 0x0a8d, 0, {0xe5,0x38,0xb4,0x01,0x0e} }, | ||
288 | { 13, 0x0a92, 0, {0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0x75,0x38} }, | ||
289 | { 1, 0x0a9f, 0, {0x00} }, | ||
290 | { 7, 0x0aa0, 0, {0xe5,0x31,0x70,0x03,0x02,0x09,0x2a} }, | ||
291 | { 10, 0x0aa7, 0, {0x90,0x7f,0xc9,0xe0,0xfa,0x70,0x03,0x02,0x0c,0x2d} }, | ||
292 | { 14, 0x0ab1, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} }, | ||
293 | { 9, 0x0abf, 0, {0x7d,0xc0,0xe0,0xfa,0xba,0x2c,0x02,0x80,0x03} }, | ||
294 | { 3, 0x0ac8, 0, {0x02,0x0b,0x36} }, | ||
295 | { 5, 0x0acb, 0, {0x75,0x32,0x00,0x7b,0x00} }, | ||
296 | { 3, 0x0ad0, 0, {0xbb,0x64,0x00} }, | ||
297 | { 2, 0x0ad3, 0, {0x50,0x1c} }, | ||
298 | { 14, 0x0ad5, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} }, | ||
299 | { 13, 0x0ae3, 0, {0x04,0xd0,0x03,0xd0,0x02,0x90,0x88,0x0f,0xe0,0xf5,0x47,0x0b,0x80} }, | ||
300 | { 1, 0x0af0, 0, {0xdf} }, | ||
301 | { 13, 0x0af1, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x07,0x1e,0x12,0x03,0xe1,0x12} }, | ||
302 | { 12, 0x0afe, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x75,0x6e,0x00,0x75} }, | ||
303 | { 13, 0x0b0a, 0, {0x6f,0x01,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0x44,0xd0,0x05} }, | ||
304 | { 9, 0x0b17, 0, {0xd0,0x04,0xd0,0x02,0x75,0x70,0x4d,0x75,0x71} }, | ||
305 | { 11, 0x0b20, 0, {0x0c,0x75,0x72,0x02,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} }, | ||
306 | { 11, 0x0b2b, 0, {0x11,0x75,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x02,0x0c,0x2d} }, | ||
307 | { 3, 0x0b36, 0, {0xba,0x2a,0x3b} }, | ||
308 | { 13, 0x0b39, 0, {0x90,0x7f,0x98,0x74,0x20,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} }, | ||
309 | { 14, 0x0b46, 0, {0x01,0xdd,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x90,0x7f,0x98,0x74,0x28,0xf0} }, | ||
310 | { 2, 0x0b54, 0, {0x7b,0x00} }, | ||
311 | { 3, 0x0b56, 0, {0xbb,0x0a,0x00} }, | ||
312 | { 5, 0x0b59, 0, {0x40,0x03,0x02,0x0c,0x2d} }, | ||
313 | { 14, 0x0b5e, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} }, | ||
314 | { 8, 0x0b6c, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0b,0x80,0xe2} }, | ||
315 | { 3, 0x0b74, 0, {0xba,0x2b,0x1a} }, | ||
316 | { 8, 0x0b77, 0, {0x90,0x7f,0xc9,0xe0,0xfb,0xbb,0x40,0x12} }, | ||
317 | { 14, 0x0b7f, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x12,0x05,0xd0,0x05,0xd0,0x04,0xd0} }, | ||
318 | { 4, 0x0b8d, 0, {0x02,0x02,0x0c,0x2d} }, | ||
319 | { 3, 0x0b91, 0, {0xba,0x10,0x1f} }, | ||
320 | { 14, 0x0b94, 0, {0x90,0x7f,0x96,0xe0,0xfb,0x90,0x7f,0x96,0x74,0x80,0x65,0x03,0xf0,0xc0} }, | ||
321 | { 14, 0x0ba2, 0, {0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x3d,0xd0,0x05,0xd0,0x04,0xd0,0x02} }, | ||
322 | { 3, 0x0bb0, 0, {0x02,0x0c,0x2d} }, | ||
323 | { 3, 0x0bb3, 0, {0xba,0x11,0x12} }, | ||
324 | { 14, 0x0bb6, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x6a,0xd0,0x05,0xd0,0x04,0xd0} }, | ||
325 | { 4, 0x0bc4, 0, {0x02,0x02,0x0c,0x2d} }, | ||
326 | { 3, 0x0bc8, 0, {0xba,0x12,0x12} }, | ||
327 | { 14, 0x0bcb, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x8f,0xd0,0x05,0xd0,0x04,0xd0} }, | ||
328 | { 4, 0x0bd9, 0, {0x02,0x02,0x0c,0x2d} }, | ||
329 | { 3, 0x0bdd, 0, {0xba,0x13,0x0b} }, | ||
330 | { 11, 0x0be0, 0, {0x90,0x7d,0xc1,0xe0,0xfb,0x90,0x88,0x00,0xf0,0x80,0x42} }, | ||
331 | { 3, 0x0beb, 0, {0xba,0x14,0x11} }, | ||
332 | { 14, 0x0bee, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0xdd,0xd0,0x05,0xd0,0x04,0xd0} }, | ||
333 | { 3, 0x0bfc, 0, {0x02,0x80,0x2e} }, | ||
334 | { 3, 0x0bff, 0, {0xba,0x15,0x1d} }, | ||
335 | { 12, 0x0c02, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x75,0x90,0x7d,0xc2,0xe0,0xf5,0x76} }, | ||
336 | { 14, 0x0c0e, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0,0x05,0xd0,0x04,0xd0} }, | ||
337 | { 3, 0x0c1c, 0, {0x02,0x80,0x0e} }, | ||
338 | { 3, 0x0c1f, 0, {0xba,0x16,0x0b} }, | ||
339 | { 11, 0x0c22, 0, {0xc0,0x04,0xc0,0x05,0x12,0x13,0xa3,0xd0,0x05,0xd0,0x04} }, | ||
340 | { 11, 0x0c2d, 0, {0x90,0x7f,0xc9,0xe4,0xf0,0x75,0x31,0x00,0x02,0x09,0x2a} }, | ||
341 | { 1, 0x0c38, 0, {0x22} }, | ||
342 | { 7, 0x0c39, 0, {0x53,0x55,0x50,0x45,0x4e,0x44,0x00} }, | ||
343 | { 7, 0x0c40, 0, {0x52,0x45,0x53,0x55,0x4d,0x45,0x00} }, | ||
344 | { 6, 0x0c47, 0, {0x20,0x56,0x6f,0x6c,0x20,0x00} }, | ||
345 | { 13, 0x0c4d, 0, {0x44,0x41,0x42,0x55,0x53,0x42,0x20,0x76,0x31,0x2e,0x30,0x30,0x00} }, | ||
346 | { 14, 0x0c5a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} }, | ||
347 | { 14, 0x0c68, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} }, | ||
348 | { 13, 0x0c76, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} }, | ||
349 | { 14, 0x0c83, 0, {0x7f,0xab,0x74,0x01,0xf0,0x90,0x7f,0xe8,0xe0,0xfa,0x90,0x7f,0xe9,0xe0} }, | ||
350 | { 6, 0x0c91, 0, {0xfb,0xbb,0x00,0x02,0x80,0x03} }, | ||
351 | { 3, 0x0c97, 0, {0x02,0x0d,0x38} }, | ||
352 | { 3, 0x0c9a, 0, {0xba,0x80,0x14} }, | ||
353 | { 14, 0x0c9d, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5} }, | ||
354 | { 6, 0x0cab, 0, {0x74,0x02,0xf0,0x02,0x0e,0xcd} }, | ||
355 | { 5, 0x0cb1, 0, {0xba,0x82,0x02,0x80,0x03} }, | ||
356 | { 3, 0x0cb6, 0, {0x02,0x0d,0x1d} }, | ||
357 | { 8, 0x0cb9, 0, {0x90,0x7f,0xec,0xe0,0xfc,0xbc,0x01,0x00} }, | ||
358 | { 2, 0x0cc1, 0, {0x40,0x21} }, | ||
359 | { 6, 0x0cc3, 0, {0xc3,0x74,0x07,0x9c,0x40,0x1b} }, | ||
360 | { 14, 0x0cc9, 0, {0xec,0x24,0xff,0x25,0xe0,0xfd,0x24,0xc6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} }, | ||
361 | { 13, 0x0cd7, 0, {0x83,0xe0,0xfd,0x53,0x05,0x01,0x90,0x7f,0x00,0xed,0xf0,0x80,0x2b} }, | ||
362 | { 3, 0x0ce4, 0, {0xbc,0x81,0x00} }, | ||
363 | { 2, 0x0ce7, 0, {0x40,0x21} }, | ||
364 | { 6, 0x0ce9, 0, {0xc3,0x74,0x87,0x9c,0x40,0x1b} }, | ||
365 | { 14, 0x0cef, 0, {0xec,0x24,0x7f,0x25,0xe0,0xfc,0x24,0xb6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} }, | ||
366 | { 13, 0x0cfd, 0, {0x83,0xe0,0xfc,0x53,0x04,0x01,0x90,0x7f,0x00,0xec,0xf0,0x80,0x05} }, | ||
367 | { 5, 0x0d0a, 0, {0x90,0x7f,0x00,0xe4,0xf0} }, | ||
368 | { 14, 0x0d0f, 0, {0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74,0x02,0xf0,0x02,0x0e,0xcd} }, | ||
369 | { 5, 0x0d1d, 0, {0xba,0x81,0x02,0x80,0x03} }, | ||
370 | { 3, 0x0d22, 0, {0x02,0x0e,0xc5} }, | ||
371 | { 14, 0x0d25, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74} }, | ||
372 | { 5, 0x0d33, 0, {0x02,0xf0,0x02,0x0e,0xcd} }, | ||
373 | { 3, 0x0d38, 0, {0xbb,0x01,0x2d} }, | ||
374 | { 6, 0x0d3b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} }, | ||
375 | { 3, 0x0d41, 0, {0xba,0x02,0x11} }, | ||
376 | { 13, 0x0d44, 0, {0x75,0x59,0x00,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} }, | ||
377 | { 4, 0x0d51, 0, {0x02,0x02,0x0e,0xcd} }, | ||
378 | { 5, 0x0d55, 0, {0xba,0x21,0x02,0x80,0x03} }, | ||
379 | { 3, 0x0d5a, 0, {0x02,0x0e,0xcd} }, | ||
380 | { 11, 0x0d5d, 0, {0x75,0x37,0x01,0x90,0x7f,0xc5,0xe4,0xf0,0x02,0x0e,0xcd} }, | ||
381 | { 3, 0x0d68, 0, {0xbb,0x03,0x1f} }, | ||
382 | { 6, 0x0d6b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} }, | ||
383 | { 5, 0x0d71, 0, {0xba,0x02,0x02,0x80,0x03} }, | ||
384 | { 3, 0x0d76, 0, {0x02,0x0e,0xcd} }, | ||
385 | { 13, 0x0d79, 0, {0x75,0x59,0x01,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} }, | ||
386 | { 4, 0x0d86, 0, {0x02,0x02,0x0e,0xcd} }, | ||
387 | { 3, 0x0d8a, 0, {0xbb,0x06,0x54} }, | ||
388 | { 5, 0x0d8d, 0, {0xba,0x80,0x02,0x80,0x03} }, | ||
389 | { 3, 0x0d92, 0, {0x02,0x0e,0xc5} }, | ||
390 | { 8, 0x0d95, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x01,0x15} }, | ||
391 | { 12, 0x0d9d, 0, {0x7c,0xfb,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} }, | ||
392 | { 9, 0x0da9, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} }, | ||
393 | { 10, 0x0db2, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x02,0x02,0x80,0x03} }, | ||
394 | { 3, 0x0dbc, 0, {0x02,0x0e,0xc5} }, | ||
395 | { 10, 0x0dbf, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x02,0x80,0x03} }, | ||
396 | { 3, 0x0dc9, 0, {0x02,0x0e,0xc5} }, | ||
397 | { 12, 0x0dcc, 0, {0x7c,0x3b,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} }, | ||
398 | { 9, 0x0dd8, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} }, | ||
399 | { 6, 0x0de1, 0, {0xbb,0x07,0x03,0x02,0x0e,0xc5} }, | ||
400 | { 3, 0x0de7, 0, {0xbb,0x08,0x10} }, | ||
401 | { 13, 0x0dea, 0, {0xac,0x48,0x90,0x7f,0x00,0xec,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} }, | ||
402 | { 3, 0x0df7, 0, {0x02,0x0e,0xcd} }, | ||
403 | { 3, 0x0dfa, 0, {0xbb,0x09,0x31} }, | ||
404 | { 5, 0x0dfd, 0, {0xba,0x00,0x02,0x80,0x03} }, | ||
405 | { 3, 0x0e02, 0, {0x02,0x0e,0xc5} }, | ||
406 | { 14, 0x0e05, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xc3,0x74,0x01,0x9c,0x50,0x03,0x02,0x0e,0xc5} }, | ||
407 | { 8, 0x0e13, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x0a} }, | ||
408 | { 10, 0x0e1b, 0, {0x90,0x17,0x21,0xe4,0xf0,0x90,0x17,0x22,0xe4,0xf0} }, | ||
409 | { 9, 0x0e25, 0, {0x90,0x7f,0xea,0xe0,0xf5,0x48,0x02,0x0e,0xcd} }, | ||
410 | { 3, 0x0e2e, 0, {0xbb,0x0a,0x27} }, | ||
411 | { 5, 0x0e31, 0, {0xba,0x81,0x02,0x80,0x03} }, | ||
412 | { 3, 0x0e36, 0, {0x02,0x0e,0xc5} }, | ||
413 | { 14, 0x0e39, 0, {0x90,0x7f,0xec,0xe0,0xfa,0x24,0x20,0xfa,0xe4,0x34,0x17,0xfc,0x8a,0x82} }, | ||
414 | { 14, 0x0e47, 0, {0x8c,0x83,0xe0,0xfa,0x90,0x7f,0x00,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} }, | ||
415 | { 3, 0x0e55, 0, {0x02,0x0e,0xcd} }, | ||
416 | { 5, 0x0e58, 0, {0xbb,0x0b,0x02,0x80,0x03} }, | ||
417 | { 3, 0x0e5d, 0, {0x02,0x0e,0xa9} }, | ||
418 | { 13, 0x0e60, 0, {0x90,0x17,0x20,0xe4,0xf0,0x90,0x7f,0xec,0xe0,0xfa,0xba,0x01,0x1a} }, | ||
419 | { 8, 0x0e6d, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x12} }, | ||
420 | { 14, 0x0e75, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x90,0x17,0x21,0xf0,0xc0,0x03,0x12,0x04,0xe2} }, | ||
421 | { 4, 0x0e83, 0, {0xd0,0x03,0x80,0x46} }, | ||
422 | { 8, 0x0e87, 0, {0x90,0x7f,0xec,0xe0,0xfa,0xba,0x02,0x3e} }, | ||
423 | { 8, 0x0e8f, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x36} }, | ||
424 | { 13, 0x0e97, 0, {0xc0,0x03,0x12,0x04,0xef,0xd0,0x03,0x90,0x7f,0xea,0xe0,0xfa,0x90} }, | ||
425 | { 5, 0x0ea4, 0, {0x17,0x22,0xf0,0x80,0x24} }, | ||
426 | { 5, 0x0ea9, 0, {0xbb,0x12,0x02,0x80,0x17} }, | ||
427 | { 5, 0x0eae, 0, {0xbb,0x81,0x02,0x80,0x0d} }, | ||
428 | { 5, 0x0eb3, 0, {0xbb,0x83,0x02,0x80,0x08} }, | ||
429 | { 5, 0x0eb8, 0, {0xbb,0x82,0x02,0x80,0x03} }, | ||
430 | { 3, 0x0ebd, 0, {0xbb,0x84,0x05} }, | ||
431 | { 5, 0x0ec0, 0, {0x12,0x06,0x4e,0x80,0x08} }, | ||
432 | { 8, 0x0ec5, 0, {0x90,0x7f,0xb4,0x74,0x03,0xf0,0x80,0x06} }, | ||
433 | { 6, 0x0ecd, 0, {0x90,0x7f,0xb4,0x74,0x02,0xf0} }, | ||
434 | { 2, 0x0ed3, 0, {0xd0,0x86} }, | ||
435 | { 14, 0x0ed5, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} }, | ||
436 | { 13, 0x0ee3, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, | ||
437 | { 11, 0x0ef0, 0, {0x90,0x7f,0xec,0xe0,0xf5,0x5a,0xc3,0x94,0x01,0x40,0x1d} }, | ||
438 | { 7, 0x0efb, 0, {0xc3,0x74,0x07,0x95,0x5a,0x40,0x16} }, | ||
439 | { 13, 0x0f02, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xc6,0xf5,0x82,0xe4,0x34} }, | ||
440 | { 9, 0x0f0f, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0,0x80,0x22} }, | ||
441 | { 7, 0x0f18, 0, {0xc3,0xe5,0x5a,0x94,0x81,0x40,0x1b} }, | ||
442 | { 7, 0x0f1f, 0, {0xc3,0x74,0x87,0x95,0x5a,0x40,0x14} }, | ||
443 | { 13, 0x0f26, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xb6,0xf5,0x82,0xe4,0x34} }, | ||
444 | { 7, 0x0f33, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0} }, | ||
445 | { 1, 0x0f3a, 0, {0x22} }, | ||
446 | { 14, 0x0f3b, 0, {0x09,0x02,0xba,0x00,0x03,0x01,0x00,0x40,0x00,0x09,0x04,0x00,0x00,0x00} }, | ||
447 | { 14, 0x0f49, 0, {0x01,0x01,0x00,0x00,0x09,0x24,0x01,0x00,0x01,0x3d,0x00,0x01,0x01,0x0c} }, | ||
448 | { 14, 0x0f57, 0, {0x24,0x02,0x01,0x10,0x07,0x00,0x02,0x03,0x00,0x00,0x00,0x0d,0x24,0x06} }, | ||
449 | { 14, 0x0f65, 0, {0x03,0x01,0x02,0x15,0x00,0x03,0x00,0x03,0x00,0x00,0x09,0x24,0x03,0x02} }, | ||
450 | { 14, 0x0f73, 0, {0x01,0x01,0x00,0x01,0x00,0x09,0x24,0x03,0x04,0x02,0x03,0x00,0x03,0x00} }, | ||
451 | { 14, 0x0f81, 0, {0x09,0x24,0x03,0x05,0x03,0x06,0x00,0x01,0x00,0x09,0x04,0x01,0x00,0x00} }, | ||
452 | { 14, 0x0f8f, 0, {0x01,0x02,0x00,0x00,0x09,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00,0x07} }, | ||
453 | { 14, 0x0f9d, 0, {0x24,0x01,0x02,0x01,0x01,0x00,0x0b,0x24,0x02,0x01,0x02,0x02,0x10,0x01} }, | ||
454 | { 14, 0x0fab, 0, {0x80,0xbb,0x00,0x09,0x05,0x88,0x05,0x00,0x01,0x01,0x00,0x00,0x07,0x25} }, | ||
455 | { 14, 0x0fb9, 0, {0x01,0x00,0x00,0x00,0x00,0x09,0x04,0x02,0x00,0x02,0x00,0x00,0x00,0x00} }, | ||
456 | { 14, 0x0fc7, 0, {0x07,0x05,0x82,0x02,0x40,0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00} }, | ||
457 | { 14, 0x0fd5, 0, {0x09,0x04,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x07,0x05,0x82,0x02,0x40} }, | ||
458 | { 14, 0x0fe3, 0, {0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00,0x09,0x05,0x89,0x05,0xa0} }, | ||
459 | { 10, 0x0ff1, 0, {0x01,0x01,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00} }, | ||
460 | { 14, 0x0ffb, 0, {0x12,0x01,0x00,0x01,0x00,0x00,0x00,0x40,0x47,0x05,0x99,0x99,0x00,0x01} }, | ||
461 | { 14, 0x1009, 0, {0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x02,0xba} }, | ||
462 | { 4, 0x1017, 0, {0x00,0x03,0x01,0x00} }, | ||
463 | { 2, 0x101b, 0, {0x7a,0x00} }, | ||
464 | { 3, 0x101d, 0, {0xba,0x05,0x00} }, | ||
465 | { 2, 0x1020, 0, {0x50,0x17} }, | ||
466 | { 8, 0x1022, 0, {0x90,0x7f,0xa5,0xe0,0xfb,0x30,0xe0,0x05} }, | ||
467 | { 5, 0x102a, 0, {0x90,0x00,0x01,0x80,0x0d} }, | ||
468 | { 10, 0x102f, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xe4} }, | ||
469 | { 3, 0x1039, 0, {0x90,0x00,0x01} }, | ||
470 | { 1, 0x103c, 0, {0x22} }, | ||
471 | { 14, 0x103d, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0x00,0x7d} }, | ||
472 | { 4, 0x104b, 0, {0x7e,0xeb,0x60,0x12} }, | ||
473 | { 14, 0x104f, 0, {0x89,0x82,0x8a,0x83,0xe0,0xa3,0xa9,0x82,0xaa,0x83,0x8c,0x82,0x8d,0x83} }, | ||
474 | { 4, 0x105d, 0, {0xf0,0x0c,0xdb,0xee} }, | ||
475 | { 8, 0x1061, 0, {0x90,0x7d,0xc3,0xe0,0x90,0x7f,0xb9,0xf0} }, | ||
476 | { 1, 0x1069, 0, {0x22} }, | ||
477 | { 14, 0x106a, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0xc4,0x7d} }, | ||
478 | { 4, 0x1078, 0, {0x7d,0xeb,0x60,0xe5} }, | ||
479 | { 14, 0x107c, 0, {0x8c,0x82,0x8d,0x83,0xe0,0x0c,0x89,0x82,0x8a,0x83,0xf0,0xa3,0xa9,0x82} }, | ||
480 | { 4, 0x108a, 0, {0xaa,0x83,0xdb,0xee} }, | ||
481 | { 1, 0x108e, 0, {0x22} }, | ||
482 | { 14, 0x108f, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x05,0x86,0x90,0x7d,0xc1,0xe0,0x05,0x86} }, | ||
483 | { 14, 0x109d, 0, {0xa3,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0x05,0x86,0xa3,0xa3,0xe0,0xf9} }, | ||
484 | { 5, 0x10ab, 0, {0x60,0x16,0xa3,0x05,0x86} }, | ||
485 | { 13, 0x10b0, 0, {0x90,0x7f,0xa6,0x05,0x86,0xe0,0xa3,0x05,0x86,0xf0,0xc0,0x01,0x12} }, | ||
486 | { 6, 0x10bd, 0, {0x10,0x1b,0xd0,0x01,0xd9,0xed} }, | ||
487 | { 6, 0x10c3, 0, {0x90,0x7f,0xa5,0x74,0x40,0xf0} }, | ||
488 | { 1, 0x10c9, 0, {0x22} }, | ||
489 | { 8, 0x10ca, 0, {0x90,0x88,0x02,0x74,0x01,0xf0,0x7a,0x00} }, | ||
490 | { 3, 0x10d2, 0, {0xba,0xff,0x00} }, | ||
491 | { 2, 0x10d5, 0, {0x50,0x0a} }, | ||
492 | { 10, 0x10d7, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} }, | ||
493 | { 1, 0x10e1, 0, {0x22} }, | ||
494 | { 5, 0x10e2, 0, {0xe5,0x6b,0xb4,0xc0,0x08} }, | ||
495 | { 8, 0x10e7, 0, {0x90,0x88,0x03,0xe5,0x6c,0xf0,0x80,0x06} }, | ||
496 | { 6, 0x10ef, 0, {0x90,0x88,0x02,0xe5,0x6c,0xf0} }, | ||
497 | { 4, 0x10f5, 0, {0x7a,0x00,0x7b,0x00} }, | ||
498 | { 11, 0x10f9, 0, {0xc3,0xea,0x94,0x32,0xeb,0x64,0x80,0x94,0x80,0x50,0x07} }, | ||
499 | { 5, 0x1104, 0, {0x0a,0xba,0x00,0x01,0x0b} }, | ||
500 | { 2, 0x1109, 0, {0x80,0xee} }, | ||
501 | { 1, 0x110b, 0, {0x22} }, | ||
502 | { 10, 0x110c, 0, {0x90,0x88,0x03,0xe5,0x6d,0xf0,0x05,0x39,0x7a,0x00} }, | ||
503 | { 3, 0x1116, 0, {0xba,0x28,0x00} }, | ||
504 | { 2, 0x1119, 0, {0x50,0x03} }, | ||
505 | { 3, 0x111b, 0, {0x0a,0x80,0xf8} }, | ||
506 | { 5, 0x111e, 0, {0xe5,0x39,0xb4,0x10,0x08} }, | ||
507 | { 8, 0x1123, 0, {0x90,0x88,0x02,0x74,0xc0,0xf0,0x80,0x0e} }, | ||
508 | { 5, 0x112b, 0, {0xe5,0x39,0xb4,0x20,0x09} }, | ||
509 | { 9, 0x1130, 0, {0x90,0x88,0x02,0x74,0x80,0xf0,0x75,0x39,0x00} }, | ||
510 | { 2, 0x1139, 0, {0x7a,0x00} }, | ||
511 | { 3, 0x113b, 0, {0xba,0x28,0x00} }, | ||
512 | { 2, 0x113e, 0, {0x50,0x03} }, | ||
513 | { 3, 0x1140, 0, {0x0a,0x80,0xf8} }, | ||
514 | { 1, 0x1143, 0, {0x22} }, | ||
515 | { 4, 0x1144, 0, {0xe5,0x6f,0x60,0x02} }, | ||
516 | { 2, 0x1148, 0, {0x80,0x07} }, | ||
517 | { 7, 0x114a, 0, {0x7a,0x00,0x75,0x39,0x00,0x80,0x05} }, | ||
518 | { 5, 0x1151, 0, {0x7a,0x40,0x75,0x39,0x10} }, | ||
519 | { 9, 0x1156, 0, {0xe5,0x6e,0x2a,0xfa,0xe5,0x6e,0x25,0x39,0xf5} }, | ||
520 | { 10, 0x115f, 0, {0x39,0x90,0x88,0x02,0x74,0x80,0x2a,0xf0,0x7a,0x00} }, | ||
521 | { 8, 0x1169, 0, {0xc3,0xea,0x64,0x80,0x94,0xa8,0x50,0x03} }, | ||
522 | { 3, 0x1171, 0, {0x0a,0x80,0xf5} }, | ||
523 | { 1, 0x1174, 0, {0x22} }, | ||
524 | { 6, 0x1175, 0, {0xaa,0x70,0xab,0x71,0xac,0x72} }, | ||
525 | { 12, 0x117b, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x12,0x14,0xee,0xfd,0x60,0x18} }, | ||
526 | { 13, 0x1187, 0, {0x8d,0x6d,0xc0,0x02,0xc0,0x03,0xc0,0x04,0x12,0x11,0x0c,0xd0,0x04} }, | ||
527 | { 9, 0x1194, 0, {0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} }, | ||
528 | { 2, 0x119d, 0, {0x80,0xdc} }, | ||
529 | { 1, 0x119f, 0, {0x22} }, | ||
530 | { 13, 0x11a0, 0, {0xe5,0x73,0xc4,0x54,0x0f,0xfa,0x53,0x02,0x0f,0xc3,0x74,0x09,0x9a} }, | ||
531 | { 2, 0x11ad, 0, {0x50,0x06} }, | ||
532 | { 6, 0x11af, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} }, | ||
533 | { 4, 0x11b5, 0, {0x74,0x30,0x2a,0xfb} }, | ||
534 | { 12, 0x11b9, 0, {0x8b,0x6d,0xc0,0x03,0x12,0x11,0x0c,0xd0,0x03,0xaa,0x73,0x53} }, | ||
535 | { 8, 0x11c5, 0, {0x02,0x0f,0xc3,0x74,0x09,0x9a,0x50,0x06} }, | ||
536 | { 6, 0x11cd, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} }, | ||
537 | { 4, 0x11d3, 0, {0x74,0x30,0x2a,0xfb} }, | ||
538 | { 5, 0x11d7, 0, {0x8b,0x6d,0x12,0x11,0x0c} }, | ||
539 | { 1, 0x11dc, 0, {0x22} }, | ||
540 | { 7, 0x11dd, 0, {0x90,0x7d,0xc3,0xe0,0xfa,0x60,0x0f} }, | ||
541 | { 12, 0x11e4, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x6e,0x90,0x7d,0xc2,0xe0,0xf5,0x6f} }, | ||
542 | { 3, 0x11f0, 0, {0x12,0x11,0x44} }, | ||
543 | { 12, 0x11f3, 0, {0x90,0x7d,0xff,0xe4,0xf0,0x75,0x70,0xc4,0x75,0x71,0x7d,0x75} }, | ||
544 | { 5, 0x11ff, 0, {0x72,0x01,0x12,0x11,0x75} }, | ||
545 | { 1, 0x1204, 0, {0x22} }, | ||
546 | { 2, 0x1205, 0, {0x7a,0x04} }, | ||
547 | { 3, 0x1207, 0, {0xba,0x40,0x00} }, | ||
548 | { 2, 0x120a, 0, {0x50,0x36} }, | ||
549 | { 14, 0x120c, 0, {0xea,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfb,0x7c,0x00} }, | ||
550 | { 3, 0x121a, 0, {0xbc,0x08,0x00} }, | ||
551 | { 2, 0x121d, 0, {0x50,0x20} }, | ||
552 | { 6, 0x121f, 0, {0x8b,0x05,0xed,0x30,0xe7,0x0b} }, | ||
553 | { 11, 0x1225, 0, {0x90,0x7f,0x96,0x74,0x42,0xf0,0x74,0xc3,0xf0,0x80,0x08} }, | ||
554 | { 8, 0x1230, 0, {0x90,0x7f,0x96,0xe4,0xf0,0x74,0x81,0xf0} }, | ||
555 | { 7, 0x1238, 0, {0xeb,0x25,0xe0,0xfb,0x0c,0x80,0xdb} }, | ||
556 | { 3, 0x123f, 0, {0x0a,0x80,0xc5} }, | ||
557 | { 1, 0x1242, 0, {0x22} }, | ||
558 | { 4, 0x1243, 0, {0x7a,0x00,0x7b,0xef} }, | ||
559 | { 3, 0x1247, 0, {0xba,0x10,0x00} }, | ||
560 | { 2, 0x124a, 0, {0x50,0x20} }, | ||
561 | { 14, 0x124c, 0, {0x74,0x11,0x2b,0xfb,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0x8c,0x82,0x8d} }, | ||
562 | { 14, 0x125a, 0, {0x83,0xe4,0xf0,0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe4} }, | ||
563 | { 4, 0x1268, 0, {0xf0,0x0a,0x80,0xdb} }, | ||
564 | { 1, 0x126c, 0, {0x22} }, | ||
565 | { 14, 0x126d, 0, {0x74,0xf8,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, | ||
566 | { 14, 0x127b, 0, {0x74,0xf9,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, | ||
567 | { 14, 0x1289, 0, {0x74,0xfa,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, | ||
568 | { 14, 0x1297, 0, {0x74,0xfb,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, | ||
569 | { 14, 0x12a5, 0, {0x74,0xff,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, | ||
570 | { 1, 0x12b3, 0, {0x22} }, | ||
571 | { 14, 0x12b4, 0, {0x12,0x03,0xcb,0x12,0x12,0x6d,0x7a,0xc0,0x7b,0x87,0x7c,0x01,0x74,0x01} }, | ||
572 | { 14, 0x12c2, 0, {0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74} }, | ||
573 | { 14, 0x12d0, 0, {0x01,0x12,0x14,0xbf,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e} }, | ||
574 | { 14, 0x12de, 0, {0x83,0x8f,0xf0,0x74,0x06,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b} }, | ||
575 | { 14, 0x12ec, 0, {0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74} }, | ||
576 | { 14, 0x12fa, 0, {0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0} }, | ||
577 | { 14, 0x1308, 0, {0x74,0x0b,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07} }, | ||
578 | { 14, 0x1316, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74,0x08,0x12,0x14,0xbf,0x74,0x01,0x2d} }, | ||
579 | { 14, 0x1324, 0, {0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x01} }, | ||
580 | { 14, 0x1332, 0, {0x12,0x14,0xbf,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83} }, | ||
581 | { 14, 0x1340, 0, {0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74,0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f} }, | ||
582 | { 14, 0x134e, 0, {0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x03,0x12,0x14,0xbf,0x7d,0x00} }, | ||
583 | { 3, 0x135c, 0, {0xbd,0x06,0x00} }, | ||
584 | { 2, 0x135f, 0, {0x50,0x12} }, | ||
585 | { 11, 0x1361, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x0a,0xba,0x00,0x01,0x0b} }, | ||
586 | { 7, 0x136c, 0, {0xe4,0x12,0x14,0xbf,0x0d,0x80,0xe9} }, | ||
587 | { 13, 0x1373, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe5,0x74,0x12,0x14,0xbf,0x74,0xf9} }, | ||
588 | { 14, 0x1380, 0, {0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x0f,0xf0,0x74} }, | ||
589 | { 14, 0x138e, 0, {0xfe,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x01,0xf0} }, | ||
590 | { 6, 0x139c, 0, {0x12,0x03,0xe1,0x12,0x04,0xf7} }, | ||
591 | { 1, 0x13a2, 0, {0x22} }, | ||
592 | { 13, 0x13a3, 0, {0x90,0x7d,0xc1,0xe0,0xfa,0x24,0x00,0xfb,0xe4,0x34,0x19,0xfc,0x90} }, | ||
593 | { 14, 0x13b0, 0, {0x7d,0xc2,0xe0,0xfd,0x8b,0x82,0x8c,0x83,0xf0,0x75,0xf0,0x11,0xea,0xa4} }, | ||
594 | { 3, 0x13be, 0, {0xfa,0x7b,0x00} }, | ||
595 | { 3, 0x13c1, 0, {0xbb,0x10,0x00} }, | ||
596 | { 2, 0x13c4, 0, {0x50,0x24} }, | ||
597 | { 14, 0x13c6, 0, {0xea,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0xeb,0x2c,0xfc,0xe4,0x3d,0xfd} }, | ||
598 | { 14, 0x13d4, 0, {0x74,0x04,0x2b,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfe} }, | ||
599 | { 8, 0x13e2, 0, {0x8c,0x82,0x8d,0x83,0xf0,0x0b,0x80,0xd7} }, | ||
600 | { 14, 0x13ea, 0, {0xea,0x24,0x00,0xfa,0xe4,0x34,0x18,0xfb,0x74,0x10,0x2a,0xf5,0x82,0xe4} }, | ||
601 | { 5, 0x13f8, 0, {0x3b,0xf5,0x83,0xe4,0xf0} }, | ||
602 | { 1, 0x13fd, 0, {0x22} }, | ||
603 | { 4, 0x13fe, 0, {0xe5,0x76,0x60,0x02} }, | ||
604 | { 2, 0x1402, 0, {0x80,0x16} }, | ||
605 | { 12, 0x1404, 0, {0x74,0x0f,0x55,0x75,0xfa,0x8a,0x75,0x24,0x00,0xf5,0x82,0xe4} }, | ||
606 | { 10, 0x1410, 0, {0x34,0x19,0xf5,0x83,0xe0,0xf5,0x74,0x12,0x12,0xb4} }, | ||
607 | { 10, 0x141a, 0, {0x12,0x10,0xca,0x75,0x6e,0x00,0x75,0x6f,0x00,0x12} }, | ||
608 | { 6, 0x1424, 0, {0x11,0x44,0x75,0x70,0xb9,0x75} }, | ||
609 | { 6, 0x142a, 0, {0x71,0x14,0x75,0x72,0x02,0x12} }, | ||
610 | { 11, 0x1430, 0, {0x11,0x75,0xe5,0x76,0xb4,0x02,0x04,0x74,0x01,0x80,0x01} }, | ||
611 | { 1, 0x143b, 0, {0xe4} }, | ||
612 | { 3, 0x143c, 0, {0xfa,0x70,0x0f} }, | ||
613 | { 12, 0x143f, 0, {0x74,0x01,0x25,0x75,0xf5,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0} }, | ||
614 | { 3, 0x144b, 0, {0x02,0x80,0x0a} }, | ||
615 | { 10, 0x144e, 0, {0x85,0x75,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0,0x02} }, | ||
616 | { 12, 0x1458, 0, {0x75,0x6e,0x00,0x75,0x6f,0x01,0xc0,0x02,0x12,0x11,0x44,0xd0} }, | ||
617 | { 4, 0x1464, 0, {0x02,0xea,0x70,0x1a} }, | ||
618 | { 13, 0x1468, 0, {0x75,0xf0,0x11,0xe5,0x75,0xa4,0xfa,0x24,0x00,0xfa,0xe4,0x34,0x18} }, | ||
619 | { 9, 0x1475, 0, {0xfb,0x8a,0x70,0x8b,0x71,0x75,0x72,0x01,0x12} }, | ||
620 | { 4, 0x147e, 0, {0x11,0x75,0x80,0x36} }, | ||
621 | { 2, 0x1482, 0, {0x7a,0x00} }, | ||
622 | { 3, 0x1484, 0, {0xba,0x10,0x00} }, | ||
623 | { 2, 0x1487, 0, {0x50,0x2f} }, | ||
624 | { 13, 0x1489, 0, {0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe0,0xfb,0xe5} }, | ||
625 | { 4, 0x1496, 0, {0x75,0xb5,0x03,0x1b} }, | ||
626 | { 14, 0x149a, 0, {0x75,0xf0,0x11,0xea,0xa4,0xfb,0x24,0x00,0xfb,0xe4,0x34,0x18,0xfc,0x8b} }, | ||
627 | { 9, 0x14a8, 0, {0x70,0x8c,0x71,0x75,0x72,0x01,0xc0,0x02,0x12} }, | ||
628 | { 4, 0x14b1, 0, {0x11,0x75,0xd0,0x02} }, | ||
629 | { 3, 0x14b5, 0, {0x0a,0x80,0xcc} }, | ||
630 | { 1, 0x14b8, 0, {0x22} }, | ||
631 | { 6, 0x14b9, 0, {0x50,0x72,0x6f,0x67,0x20,0x00} }, | ||
632 | { 14, 0x14bf, 0, {0xc8,0xc0,0xe0,0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0b,0x14,0x60,0x0f,0x14} }, | ||
633 | { 7, 0x14cd, 0, {0x60,0x11,0x14,0x60,0x12,0x80,0x15} }, | ||
634 | { 7, 0x14d4, 0, {0xd0,0xe0,0xa8,0x82,0xf6,0x80,0x0e} }, | ||
635 | { 5, 0x14db, 0, {0xd0,0xe0,0xf0,0x80,0x09} }, | ||
636 | { 4, 0x14e0, 0, {0xd0,0xe0,0x80,0x05} }, | ||
637 | { 5, 0x14e4, 0, {0xd0,0xe0,0xa8,0x82,0xf2} }, | ||
638 | { 4, 0x14e9, 0, {0xc8,0xd0,0xe0,0xc8} }, | ||
639 | { 1, 0x14ed, 0, {0x22} }, | ||
640 | { 14, 0x14ee, 0, {0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0d,0x14,0x60,0x0f,0x14,0x60,0x0f,0x14} }, | ||
641 | { 6, 0x14fc, 0, {0x60,0x10,0x74,0xff,0x80,0x0f} }, | ||
642 | { 5, 0x1502, 0, {0xa8,0x82,0xe6,0x80,0x0a} }, | ||
643 | { 3, 0x1507, 0, {0xe0,0x80,0x07} }, | ||
644 | { 4, 0x150a, 0, {0xe4,0x93,0x80,0x03} }, | ||
645 | { 3, 0x150e, 0, {0xa8,0x82,0xe2} }, | ||
646 | { 4, 0x1511, 0, {0xf8,0xd0,0xe0,0xc8} }, | ||
647 | { 1, 0x1515, 0, {0x22} }, | ||
648 | { 0, 0x0000, 1, {0} } | ||
649 | |||
650 | }; | ||
651 | |||
652 | static unsigned char bitstream[] = { | ||
653 | |||
654 | 0x00,0x09,0x0F,0xF0,0x0F,0xF0,0x0F,0xF0, 0x0F,0xF0,0x00,0x00,0x01,0x61,0x00,0x0D, | ||
655 | 0x64,0x61,0x62,0x75,0x73,0x62,0x74,0x72, 0x2E,0x6E,0x63,0x64,0x00,0x62,0x00,0x0B, | ||
656 | 0x73,0x31,0x30,0x78,0x6C,0x76,0x71,0x31, 0x30,0x30,0x00,0x63,0x00,0x0B,0x31,0x39, | ||
657 | 0x39,0x39,0x2F,0x30,0x39,0x2F,0x32,0x34, 0x00,0x64,0x00,0x09,0x31,0x30,0x3A,0x34, | ||
658 | 0x32,0x3A,0x34,0x36,0x00,0x65,0x00,0x00, 0x2E,0xC0,0xFF,0x20,0x17,0x5F,0x9F,0x5B, | ||
659 | 0xFE,0xFB,0xBB,0xB7,0xBB,0xBB,0xFB,0xBF, 0xAF,0xEF,0xFB,0xDF,0xB7,0xFB,0xFB,0x7F, | ||
660 | 0xBF,0xB7,0xEF,0xF2,0xFF,0xFB,0xFE,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xBF,0xFF,0xFF, | ||
661 | 0xFF,0xFF,0xAF,0xFF,0xFA,0xFF,0xFF,0xFF, 0xC9,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xFF, | ||
662 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xA3,0xFF,0xFB, | ||
663 | 0xFE,0xFF,0xBF,0xEF,0xE3,0xFE,0xFF,0xBF, 0xE3,0xFE,0xFF,0xBF,0x6F,0xFB,0xF6,0xFF, | ||
664 | 0xBF,0xFF,0x47,0xFF,0xFF,0x9F,0xEE,0xF9, 0xFE,0xCF,0x9F,0xEF,0xFB,0xCF,0x9B,0xEE, | ||
665 | 0xF8,0xFE,0xEF,0x8F,0xEE,0xFB,0xFE,0x0B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
666 | 0xFF,0xFF,0xBF,0xFF,0xFF,0xFB,0xFF,0xFF, 0xBF,0xFF,0xFF,0xFC,0x17,0xFF,0xFF,0xFF, | ||
667 | 0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFB,0xFF,0xFF,0x7F,0xFF,0xFF, | ||
668 | 0xFC,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF, | ||
669 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x5F,0xFF, 0xFF,0xFD,0xFF,0xFF,0xDB,0xFF,0xFD,0xFF, | ||
670 | 0x77,0xFF,0xFD,0xFF,0xFF,0xDF,0xFE,0xFD, 0xFF,0xFF,0xF2,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
671 | 0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE1, | ||
672 | 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF, | ||
673 | 0xFF,0xFF,0xFF,0xFF,0xE3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF, | ||
674 | 0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x67,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
675 | 0x7F,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,0x2F,0xFF, | ||
676 | 0xF3,0xFD,0xFF,0x7F,0xDE,0xF7,0xFD,0xFF, 0x7F,0xF7,0x7D,0xFF,0x7F,0xDF,0xF7,0xBD, | ||
677 | 0xFF,0x7F,0xFF,0x1F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xEF,0xFB, | ||
678 | 0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF, 0x3F,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F, | ||
679 | 0x9F,0xE7,0xFA,0x7F,0x9F,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xFF,0xFC,0x7F,0xBF,0xBF, | ||
680 | 0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xB7, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, | ||
681 | 0xFF,0xE0,0xFD,0xF9,0xFE,0x7F,0x9F,0xE7, 0xF9,0xFE,0x7F,0x9D,0xF9,0xFE,0x7D,0x9D, | ||
682 | 0xE7,0xF9,0xFE,0x7F,0x9F,0xED,0xED,0xFF, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F, | ||
683 | 0xDF,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF, 0x7F,0xDF,0xFF,0x9B,0xFF,0xEF,0xFB,0xFE, | ||
684 | 0xFB,0xBF,0xEF,0xBB,0xFE,0xFF,0xAF,0xBB, 0xBE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF, | ||
685 | 0xB7,0xBF,0xDB,0xF6,0xBD,0xBF,0x6B,0xDB, 0xF6,0xF9,0xBF,0x5B,0xD6,0xF9,0xBF,0x6F, | ||
686 | 0xDB,0xF6,0xFD,0xBF,0xFF,0x0E,0xFF,0xFF, 0xFF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0x7F, | ||
687 | 0xF7,0xBD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xDF,0x9F,0xFF,0xFF,0xFF,0xFE,0xFF, | ||
688 | 0xFF,0xEF,0xFE,0xFE,0xFF,0xFF,0x77,0xFF, 0xFB,0xFB,0xFF,0xFF,0xFF,0xFF,0xF8,0x3F, | ||
689 | 0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
690 | 0xFF,0xFF,0xFF,0xF4,0x7F,0xFF,0xFE,0xFD, 0xBE,0xFF,0xDF,0xFE,0xFF,0xFF,0xEF,0x7F, | ||
691 | 0xFF,0xCF,0xFF,0xCF,0xFF,0xFF,0xFF,0xDF, 0xE6,0xFF,0xFF,0x7F,0xDF,0xF7,0xDD,0x7F, | ||
692 | 0x7F,0xDF,0xF7,0xFF,0x7F,0xDF,0xD7,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFF,0xCD,0xFF,0xF2, | ||
693 | 0xFF,0xFF,0x4F,0x7F,0xF4,0xFF,0xFF,0xFF, 0xE7,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
694 | 0xFF,0xFF,0xBB,0xFF,0xEF,0xFF,0xFE,0xFF, 0xFF,0xFF,0xEF,0xFF,0xFF,0xEF,0xFF,0xFB, | ||
695 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x65, 0xEF,0xFF,0xFF,0x7F,0xFF,0xFD,0xEF,0xFF, | ||
696 | 0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xCF,0xDF,0xFE,0xFF, | ||
697 | 0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xF3,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
698 | 0xFE,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
699 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF,0xFF, | ||
700 | 0xFF,0xFF,0xEF,0xEB,0xFF,0xFE,0xBF,0xFF, 0xEB,0xFF,0xFC,0x7F,0xFF,0xFF,0xFF,0xEE, | ||
701 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xD6,0xFF,0xFD,0xBF,0xFF,0xFB,0xFF,0xFE, | ||
702 | 0xFD,0xFF,0xFF,0xFD,0xEF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xDE,0xFF,0xFF,0xFF,0xFF, | ||
703 | 0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0x7F,0xBF, 0xFF,0x5F,0xDF,0xFF,0xFF,0xBF,0x77,0xFF, | ||
704 | 0xFF,0xFF,0x7F,0xD7,0xFF,0xFF,0xFF,0xFF, 0xFF,0xC3,0xFF,0xFF,0xFF,0xFF,0xDF,0xEF, | ||
705 | 0xFF,0xFF,0xFE,0xFB,0xFF,0xFF,0xDF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xB7,0xFF, | ||
706 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
707 | 0xFF,0xFF,0xFF,0xAF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
708 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xBF,0xDF,0xF3,0xFD,0xFB,0xFF,0x5B, | ||
709 | 0xFD,0xFF,0xBF,0xEF,0xF7,0xFF,0xFF,0x7D, 0xFF,0xFF,0xFF,0xFF,0xF8,0x3B,0xFF,0xBF, | ||
710 | 0x6F,0xFF,0xFE,0xFF,0xBF,0xFF,0xEB,0x7D, 0xFF,0xEF,0xFB,0xFE,0xFF,0xFF,0xFF,0xFF, | ||
711 | 0xFF,0xF2,0x7F,0xFC,0xFF,0x3F,0xDF,0xED, 0xFE,0xFF,0xFF,0xFF,0xFF,0xEF,0x5F,0xF7, | ||
712 | 0xB5,0xFF,0xEF,0xFF,0xFF,0xFF,0xE0,0x3F, 0x9F,0x9E,0xFF,0xFF,0xEF,0xFF,0xDF,0xFF, | ||
713 | 0xBF,0x5F,0xBF,0xCF,0xF3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x69,0xAF,0x33,0xFD,0xFF, | ||
714 | 0xFB,0xFF,0xFF,0xFF,0xFF,0xFC,0xFF,0x7F, 0xD9,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xF5, | ||
715 | 0xA3,0xDF,0x6E,0xDE,0xFF,0xFF,0xBD,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFE,0xE7,0xFD, | ||
716 | 0xFF,0xFF,0xFF,0xF9,0xEF,0xC6,0xFE,0xB7, 0xAD,0xE5,0xF9,0xFF,0xFF,0xFF,0xCF,0xFF, | ||
717 | 0xFF,0xFF,0xCD,0xFB,0x7F,0xFF,0xFF,0xFF, 0xF9,0xF6,0x0F,0xDF,0xEC,0xCF,0x7F,0xFF, | ||
718 | 0xFB,0x7F,0xFF,0xFF,0xFF,0xFD,0xFF,0xFE, 0xF9,0xFD,0x7F,0xFF,0x7F,0xFF,0xF9,0x5B, | ||
719 | 0xFF,0x73,0xDC,0xFD,0x7B,0xDF,0xFF,0xFF, 0xFF,0x7B,0xFF,0xFF,0xF7,0x53,0xD6,0xFF, | ||
720 | 0xFF,0xFF,0xFF,0xD8,0x9F,0xFE,0xFF,0xEF, 0x7F,0xEE,0xFF,0xFF,0xFF,0xFB,0xED,0xED, | ||
721 | 0xFD,0xFF,0xFE,0xFF,0xFF,0xFB,0x7F,0xFF, 0xE2,0x7F,0xFF,0x6F,0xD8,0x57,0xF7,0xFF, | ||
722 | 0xFF,0xFF,0xDF,0xFF,0xE8,0xFF,0xFF,0xFD, 0xFF,0xFF,0xFC,0x7F,0xFF,0xE4,0xFF,0xFB, | ||
723 | 0xEF,0xFB,0xFE,0xDF,0xB7,0xED,0xFF,0xFE, 0xDF,0x7F,0xFF,0xFE,0x7F,0xB7,0xFF,0xFF, | ||
724 | 0xFF,0xFF,0x89,0xFF,0xFF,0xCF,0xF3,0xFE, 0x7F,0xFF,0xEF,0xFF,0xFE,0x7E,0x7F,0xFB, | ||
725 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF1, 0xFF,0xEB,0x7A,0xD5,0xBF,0x6F,0xDB,0xBE, | ||
726 | 0xFD,0xB7,0xD8,0xF6,0xE5,0xBF,0x6F,0xFB, 0xFE,0xF5,0xBD,0x7E,0x06,0xFF,0xDF,0xF7, | ||
727 | 0xFB,0xF6,0xFF,0x3F,0xFF,0xDB,0xFF,0xFF, 0x6F,0xFB,0xF7,0xFF,0xFF,0xFF,0xFB,0xFE, | ||
728 | 0xF7,0xAF,0xFF,0xB7,0xED,0xEF,0xF7,0xFE, 0xFF,0xFF,0xDF,0xFF,0xFE,0xFF,0xEF,0xFF, | ||
729 | 0xFF,0xFF,0xFF,0xBF,0xF7,0xFC,0x1F,0xEE, 0xFB,0xFE,0xBD,0xFF,0x7F,0x5F,0xD7,0xFD, | ||
730 | 0xFB,0x43,0xFF,0xFF,0xFD,0xFF,0x5F,0xFF, 0xF7,0xFF,0xF9,0x3F,0xFF,0xCF,0xF3,0xFD, | ||
731 | 0xF7,0x7E,0xEF,0xA7,0xF9,0xFE,0x8F,0xA7, 0xE9,0xF3,0x7E,0x9F,0xFB,0xF8,0xFF,0xFF, | ||
732 | 0x3F,0xFD,0x7F,0x5F,0xDF,0xFD,0xFF,0xFF, 0x5F,0xFF,0xFD,0x5F,0xFF,0xFF,0x7F,0xFD, | ||
733 | 0x7F,0xFD,0x9F,0xFF,0xE0,0xFF,0xFA,0xF8, 0xBE,0x6F,0x9F,0xE6,0xF8,0xBE,0x3F,0x9A, | ||
734 | 0xF9,0xBE,0x6F,0x9F,0xE2,0xF9,0xFE,0x6F, 0x9F,0xF9,0xFF,0xF5,0xFD,0x7F,0xCF,0xDF, | ||
735 | 0xFD,0xFD,0x7F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xF7,0xF5,0xFD,0x0F,0xDB,0xFF,0xD3,0xFF, | ||
736 | 0xEB,0xFA,0xFF,0xFF,0xBF,0xFF,0xFA,0xFF, 0xFF,0xCB,0xFB,0xFE,0xFF,0xFF,0xEB,0xFA, | ||
737 | 0xFE,0xFF,0xFF,0xB7,0xFF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xDF,0xF5,0xFF,0xFF,0xD7,0xFF, | ||
738 | 0xFF,0xFF,0xDF,0xD7,0xF5,0xFF,0x7F,0xFE, 0x4F,0xFF,0xFD,0xFF,0x7F,0x7F,0xFF,0xAD, | ||
739 | 0xEB,0xFB,0xFF,0xAD,0xFF,0xFF,0xFF,0xFF, 0xAF,0xEB,0xFB,0xFF,0xFC,0x0D,0xFF,0xFF, | ||
740 | 0xDF,0xD2,0xFD,0xFF,0xFF,0xFD,0xF6,0xFF, 0xFF,0x7F,0xFF,0xFF,0x1F,0xFF,0xFF,0xFF, | ||
741 | 0xFF,0xFB,0x3F,0x7D,0xEB,0x32,0xFE,0xBF, 0x2F,0xEB,0xFA,0xAE,0xBD,0xE0,0xFA,0x7E, | ||
742 | 0xBF,0xAD,0xEB,0xFA,0xFE,0xBF,0xF5,0x7F, 0xFF,0xDE,0xFE,0xE3,0xFB,0xFF,0xFF,0xFF, | ||
743 | 0xDF,0xEF,0x4F,0xDF,0xFF,0x7F,0xDF,0xFF, 0xF7,0xFF,0xFF,0xF8,0x7F,0xFF,0xFF,0xEF, | ||
744 | 0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xFF,0xDF, 0xED,0xFB,0xDF,0xFF,0xBF,0xFF,0xFF,0xFF, | ||
745 | 0x81,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFF,0xFE,0xDD,0xFE,0xEF,0xFD,0xFF, | ||
746 | 0xFF,0xFB,0xFE,0xF7,0xFF,0x93,0xFD,0xFB, 0x7E,0xFF,0xFE,0x87,0xE9,0xFF,0x7F,0xB3, | ||
747 | 0x9F,0xFE,0xFE,0xFF,0xAF,0xFD,0xFE,0x7E, 0x3F,0xFE,0x67,0xFF,0xFF,0xF7,0xFF,0xFF, | ||
748 | 0xFC,0xF7,0xDF,0xFD,0xFF,0x7F,0xFF,0xFF, 0x7F,0x6D,0xFF,0xFF,0xFE,0xFF,0xFF,0x2F, | ||
749 | 0xFF,0xBF,0xFF,0xFF,0xEE,0xFF,0xBE,0xFF, 0xFF,0xFE,0xFF,0xEF,0xFF,0xFF,0xFE,0xFF, | ||
750 | 0xEF,0xFF,0xFF,0xFA,0x5F,0xFF,0xFF,0xFB, 0xFF,0xFF,0xEF,0xFF,0xFB,0xFE,0xFD,0xFF, | ||
751 | 0xFE,0xFF,0xFB,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFE,0xBF,0xDF,0xFF,0xFB,0xFF,0xFF,0xF7, | ||
752 | 0xFC,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF2,0x7F,0xFF, | ||
753 | 0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xF3,0xFF,0xFF,0xFF,0xEF,0xFB,0xFF,0xFF, | ||
754 | 0xFF,0xDF,0xE2,0xFF,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xE7,0xFF,0xFD, | ||
755 | 0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xED, 0xEF,0xFD,0xFF,0xFF,0xDF,0xD7,0xF5,0xFD, | ||
756 | 0x7F,0x5D,0xFD,0xFF,0x7F,0xDF,0x97,0xF4, 0xFD,0x7B,0x5F,0xFF,0xC9,0xFF,0xFB,0xFE, | ||
757 | 0xFF,0xBF,0xFF,0x5F,0xFF,0xFF,0xF7,0xFF, 0xEF,0xFD,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF, | ||
758 | 0xFF,0xF7,0xFF,0xD7,0xFD,0x7D,0x7F,0xFF, 0xFF,0xFF,0xFF,0xEF,0xDF,0xF7,0xFD,0xFF, | ||
759 | 0xBB,0xFF,0xFF,0x7F,0xFF,0xFE,0xE3,0xFF, 0xF9,0xFE,0x7F,0xBF,0xEF,0xFB,0xFE,0xFF, | ||
760 | 0xBF,0xF9,0xFE,0xFF,0x9F,0xEF,0xF9,0xFE, 0xFF,0xBF,0xF3,0xDA,0xFF,0x37,0xCD,0xF3, | ||
761 | 0x7C,0xDF,0x37,0xCD,0xF3,0x7F,0x37,0xCD, 0xF3,0x7C,0xDF,0x37,0xCC,0xF3,0x7F,0x5A, | ||
762 | 0xBD,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFD, 0xBF,0x6F,0xDE,0xFD,0xBF,0x6F,0xDB,0xF6, | ||
763 | 0xFD,0xBF,0x6F,0xFE,0xF1,0x6F,0xEB,0x7A, 0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7,0xAF, | ||
764 | 0x7A,0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7, 0xFF,0x7E,0xFF,0xFE,0xCD,0xB3,0x6C,0xDB, | ||
765 | 0x36,0xCD,0xB3,0x6C,0xDE,0xCD,0xB3,0x6C, 0xDB,0x36,0xCD,0xB3,0x6C,0xDF,0xC9,0xBF, | ||
766 | 0xF7,0xBD,0xEF,0x7A,0x9E,0xA7,0xA9,0xEA, 0x7A,0xB7,0xBD,0xEA,0x7B,0xDE,0xA7,0xBD, | ||
767 | 0xCA,0x72,0x8D,0x91,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xF7,0xEF,0xFB, | ||
768 | 0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFE, 0x87,0xFF,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6, | ||
769 | 0xFD,0xBF,0x6F,0xF6,0xFD,0xBF,0x6F,0xDB, 0xF6,0xFD,0xBF,0x6F,0xFE,0x4F,0xFF,0xBF, | ||
770 | 0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB,0xEF, 0xBE,0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB, | ||
771 | 0xEF,0xFC,0x5F,0xFF,0xFF,0xFF,0x3F,0xCF, 0xF3,0xFC,0xFF,0x3F,0xCF,0xFC,0xFF,0x3F, | ||
772 | 0xCF,0xF3,0xFC,0xFF,0x3F,0xCF,0xFD,0x9F, 0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF, | ||
773 | 0xEB,0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFF,0xE1,0x6F,0xFD,0xFF,0x7F, | ||
774 | 0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFD,0xFF, 0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF, | ||
775 | 0x7A,0xBF,0xFB,0xFE,0xDF,0xB7,0xED,0xFB, 0x7E,0xDF,0xB7,0xFB,0x7E,0xDF,0xB7,0xED, | ||
776 | 0xFB,0x7E,0xDF,0xB7,0xFF,0xC9,0xFF,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, | ||
777 | 0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEE, 0xFB,0xFE,0xBB,0xFF,0xFE,0xFF,0xBF,0xEF, | ||
778 | 0xFB,0xFE,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0x3F,0xCF,0xFF,0xE7, | ||
779 | 0xFE,0xFF,0xF5,0xFD,0x77,0x5D,0xD7,0x35, 0xDD,0x77,0xD7,0xF5,0xCD,0x7B,0x5D,0xD7, | ||
780 | 0xF5,0xDD,0x77,0xFE,0x27,0xFF,0xFF,0x8B, 0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9,0xAF, | ||
781 | 0x8B,0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9, 0xFE,0x1F,0xFF,0x5F,0xD7,0xF5,0xFD,0x7F, | ||
782 | 0x5F,0xD7,0xF5,0xFF,0x5F,0xD7,0xF5,0xFD, 0x7F,0x5F,0xD7,0xF5,0xFF,0xFA,0x3F,0xFE, | ||
783 | 0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xEB, 0xEC,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF, | ||
784 | 0xEB,0xFF,0xFE,0x7F,0xFD,0x7F,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
785 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE6, 0xFF,0xFA,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF, | ||
786 | 0xF7,0xFC,0xFF,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFD,0xFF,0xF5,0xFF,0xFF,0xFF, | ||
787 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
788 | 0xFF,0x02,0xFF,0xFE,0xBF,0xAB,0xEB,0xFA, 0xBE,0xBF,0x23,0xEB,0xDE,0x1F,0xAF,0xEA, | ||
789 | 0xFA,0xFE,0xAF,0xAF,0xEB,0xFD,0x97,0xFF, 0xF3,0xFC,0x7B,0x1F,0xCF,0xF1,0xFC,0x7F, | ||
790 | 0x1F,0xF1,0xFC,0x77,0x1F,0xCD,0xF1,0xFC, 0xFF,0x1F,0xFE,0x87,0xFF,0xAF,0xEF,0xFA, | ||
791 | 0xFE,0xFF,0xAF,0xEF,0xFA,0xFD,0xBF,0x2B, 0xFB,0x7E,0xBF,0xBF,0xEB,0xFB,0xFB,0xFB, | ||
792 | 0xDF,0xFF,0xFB,0xF7,0xFF,0xFF,0x7F,0xF7, 0xF7,0xFF,0xFD,0xDF,0xFE,0xFC,0xDF,0xFF, | ||
793 | 0xDF,0xFF,0xFD,0xFF,0xDA,0xBF,0xFF,0xBB, 0xEF,0xFB,0xF9,0xFF,0xBE,0xEF,0xFB,0xFB, | ||
794 | 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xF7,0x7F,0xFD,0xD7,0xFF,0xFF,0x7F, | ||
795 | 0xFF,0xFF,0xFF,0xFE,0xF7,0xFF,0xFE,0xFF, 0xF7,0xFF,0xFF,0x7F,0xFF,0xFF,0xEC,0xFF, | ||
796 | 0xFF,0xFE,0xDF,0xBF,0xFF,0xFB,0xFE,0xFF, 0xBB,0x68,0xAE,0x1F,0xAE,0xFB,0xFB,0xFF, | ||
797 | 0xFF,0xBF,0xFF,0xD5,0xFF,0x7F,0xFF,0xFF, 0xF7,0xFE,0xFE,0xFF,0xBF,0xEF,0x9F,0xFD, | ||
798 | 0x7F,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF,0xFF, 0xBB,0xF7,0xBF,0xFF,0xFF,0xFF,0xFF,0xDF, | ||
799 | 0xFF,0xBF,0xFB,0xFF,0xFF,0xFF,0xDE,0x3F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xA7,0xFF,0xFF, | ||
800 | 0xFF,0xFF,0xEF,0xFF,0x7F,0xFB,0xFD,0xFB, 0x7F,0xFF,0xFF,0xFF,0xFF,0xCF,0xF3,0x7C, | ||
801 | 0xFF,0x7F,0x8D,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFB,0xFF,0xF7,0xFB,0xFE,0xFD,0xFF,0xFF, | ||
802 | 0xFF,0xFF,0xF7,0xFD,0xFF,0x7F,0xFD,0x1F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xBF,0xDF,0xFF, | ||
803 | 0xFF,0xFE,0x5C,0xFF,0x6D,0xFF,0x7F,0xAB, 0xE7,0xF1,0xFF,0xFD,0x9F,0xFF,0xFF,0xAD, | ||
804 | 0xEB,0x7A,0x3F,0x1F,0xFF,0xFF,0xFE,0xBF, 0xAF,0xF3,0xDE,0xF5,0xFF,0x8F,0xFB,0xDF, | ||
805 | 0xE6,0x7F,0xFF,0xDF,0xF3,0xFD,0xFF,0x7E, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xF7,0xF3, | ||
806 | 0x7F,0xDF,0xF7,0xEF,0xFF,0xF6,0x3F,0x9F, 0xDF,0xFF,0xFF,0xEE,0xFF,0xFF,0xEF,0xFB, | ||
807 | 0xFF,0xFF,0xF9,0xFB,0xFE,0x4F,0xBF,0xEF, 0xBB,0xFF,0x69,0xAF,0xAF,0xFC,0xFF,0x3F, | ||
808 | 0xDD,0xFF,0xFC,0xBF,0x8F,0xFF,0xFD,0xF3, 0xBF,0xED,0x9E,0xFC,0xBF,0x6F,0xF5,0xD3, | ||
809 | 0xDF,0xFF,0xDB,0xD6,0xF5,0xEF,0xFD,0xFE, 0xFF,0xB9,0xFF,0x1F,0xD2,0xA9,0xAF,0xFF, | ||
810 | 0xDB,0xF7,0xBF,0xEF,0x46,0xFF,0xFF,0xAD, 0xEB,0x7A,0xDF,0xEF,0xF7,0xFF,0x7F,0xF7, | ||
811 | 0x9F,0xED,0xFF,0x7F,0xFF,0xAD,0xEB,0x7F, 0xF5,0x6F,0xFF,0xFD,0xFB,0xD6,0xF4,0xF7, | ||
812 | 0xFB,0xF9,0x7E,0x7F,0xFF,0x5F,0xC2,0xFE, 0xBF,0xFD,0xFB,0x33,0xDF,0xF9,0x5B,0xFF, | ||
813 | 0xFF,0xDD,0x67,0x7D,0xCF,0xEF,0xDB,0xEC, 0xFF,0x77,0xDD,0xF7,0xFD,0xFF,0xFF,0xDE, | ||
814 | 0xA7,0xBF,0xD4,0x9F,0xFF,0xFF,0xBF,0xEF, 0xFE,0xFF,0xDF,0xEF,0xBB,0xFF,0xFF,0xEF, | ||
815 | 0xEB,0xFA,0xFF,0xEF,0xBD,0xFB,0xFF,0xE2, 0x7F,0xFF,0xDF,0xDF,0xF7,0xFD,0xBF,0xBB, | ||
816 | 0x73,0xF7,0xFD,0x7F,0xDF,0xDE,0xF7,0xBF, 0xEA,0xDB,0xF6,0xFF,0xD6,0xFF,0xFF,0x66, | ||
817 | 0xFF,0xBE,0xFF,0xBF,0x6B,0xD9,0xF6,0xDF, 0xFF,0xFB,0x7E,0x7F,0xB7,0x7E,0xFF,0xFE, | ||
818 | 0xFF,0xCD,0xFF,0xFE,0x7F,0xFF,0xFC,0xFD, 0x3F,0xFB,0xFB,0xF7,0xFF,0xFF,0xFB,0xF6, | ||
819 | 0x7D,0xFE,0x7F,0xFF,0xFC,0xFF,0xB9,0xFF, 0xF9,0xFA,0xFE,0xBF,0xAF,0x5B,0xD6,0xED, | ||
820 | 0xAD,0x7B,0xF6,0xF9,0xBF,0xEF,0xF8,0xFA, 0xFE,0xBF,0xFE,0xE6,0xFF,0xFF,0xF7,0xFD, | ||
821 | 0xFF,0x7F,0xBF,0xEF,0xF3,0xFF,0xFF,0x6F, 0xF7,0xFE,0xFF,0xFF,0xF7,0xFD,0xFE,0xF7, | ||
822 | 0xEF,0xFF,0xFB,0xEF,0xFB,0x7E,0xDE,0xFE, 0xFF,0xBF,0xFF,0xFE,0xFF,0xFF,0xFB,0xFF, | ||
823 | 0xFF,0xEF,0xFB,0x6F,0xFC,0x1F,0xFE,0xE7, 0xFF,0xFF,0xFF,0xEF,0xFF,0xD3,0xB4,0xBB, | ||
824 | 0xFF,0xFF,0xFD,0xBF,0x6F,0xE3,0xFE,0xFF, 0xBF,0xFC,0xBF,0xF7,0xCF,0xF7,0xFD,0xFF, | ||
825 | 0x2F,0xDF,0xAB,0xEA,0xFF,0xDF,0xE7,0xEA, 0x9A,0xAF,0xEF,0xFB,0xFE,0xFF,0xF5,0x3F, | ||
826 | 0xFD,0x7E,0xFF,0xD7,0xF5,0xFB,0xFF,0xFD, 0xF7,0xFF,0x7F,0xFE,0xF7,0xFD,0xFF,0xD7, | ||
827 | 0xFF,0xD7,0x7F,0xEE,0x7F,0xFA,0x79,0xFE, 0x2F,0x8B,0xE6,0xF9,0xFE,0x3F,0x9E,0xF9, | ||
828 | 0xBE,0x2F,0x0B,0xE7,0xF9,0xFE,0x2F,0x9F, 0xFD,0xFF,0xFE,0x7D,0x7F,0x5F,0xD7,0xFF, | ||
829 | 0xFF,0x7F,0xFF,0xFD,0xFF,0x7F,0x5F,0x97, 0xFF,0xFD,0x7F,0x5F,0xFF,0xE3,0xFF,0xFF, | ||
830 | 0xFA,0xFE,0xBF,0xAF,0xFB,0xFB,0xFF,0xFF, 0xCF,0xEB,0xFE,0xBF,0xAF,0xFF,0xFA,0xFE, | ||
831 | 0xBF,0xFF,0x87,0xFF,0xFF,0xF5,0xFF,0xFF, 0xFF,0xFF,0xFD,0xFF,0x7F,0xFF,0xFF,0xFF, | ||
832 | 0xFB,0xFF,0xFF,0xF5,0xFF,0xFF,0xFE,0x0F, 0xFF,0xFD,0xEB,0xFF,0xFF,0xF7,0xFF,0xEF, | ||
833 | 0x7B,0xDF,0xFE,0xFF,0xFF,0xDF,0xF7,0xFD, 0xEB,0x7F,0xDF,0xFF,0x5F,0xFF,0xFF,0xFF, | ||
834 | 0xFF,0xFD,0xBF,0xFF,0x7E,0xFA,0xBF,0xC7, 0xDB,0xF7,0xBD,0x3F,0xFB,0xFF,0xF6,0xFF, | ||
835 | 0xFA,0xAF,0xFF,0xEB,0xFA,0xFE,0x3F,0x2F, 0xEA,0xFA,0x3E,0xAD,0xC9,0xBA,0xF6,0xAD, | ||
836 | 0xAF,0xEB,0xFA,0xF6,0xBF,0xFE,0x7F,0xFF, 0xFF,0xFD,0xFF,0xF1,0x7F,0x3F,0xCF,0xF1, | ||
837 | 0xEF,0xFF,0x7F,0xFF,0xBC,0xDF,0xDF,0xF7, 0xDD,0xFF,0xE0,0x7F,0xFF,0xFF,0xFE,0xFF, | ||
838 | 0xFA,0xEC,0xBB,0x7F,0x5F,0xFF,0xFB,0xEC, 0xFF,0xEF,0xB7,0xFF,0xF7,0xFF,0xFF,0xB5, | ||
839 | 0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xEE,0xDF, 0x5F,0xDF,0xDE,0xFF,0xAE,0xE7,0x77,0xFF, | ||
840 | 0xFF,0xDF,0xF7,0xFF,0xE3,0xFF,0xFA,0xBB, 0xFE,0xFF,0xAF,0xFD,0xFB,0xFE,0xBF,0xAB, | ||
841 | 0xF9,0xFE,0xFF,0xBF,0x7F,0xBF,0xFE,0xBD, 0xFE,0xD7,0xFF,0x9F,0xFD,0xFF,0xBE,0xEF, | ||
842 | 0xFF,0xEE,0xFD,0xBB,0x5B,0xEF,0xFF,0x7F, 0xEF,0xFF,0xEF,0xFF,0x7F,0xFF,0x4F,0xFF, | ||
843 | 0xEF,0xFB,0xBC,0xFC,0xFF,0xFF,0xFF,0xFE, 0xFE,0xFD,0xFA,0xFE,0xFB,0xFF,0xFD,0xF3, | ||
844 | 0xFB,0xFF,0xF8,0x5F,0xFF,0xFF,0xD7,0xF5, 0xFD,0xDF,0xEF,0xFF,0xF3,0xDC,0x5F,0xCE, | ||
845 | 0xF5,0xBD,0xFF,0xFF,0xD7,0xFF,0xFF,0xF9, 0x3F,0xFF,0xDF,0xF7,0xFF,0xFE,0xFF,0xFD, | ||
846 | 0xFF,0xFB,0xFF,0xF7,0xB9,0x7D,0xFE,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF9,0x7F,0xFF,0xFE, | ||
847 | 0xFF,0xFF,0x7F,0xFF,0xFE,0xFF,0xFF,0xF7, 0xF6,0xFF,0xBF,0xF1,0xF8,0xFF,0xFF,0xFF, | ||
848 | 0xFF,0xE0,0xFF,0xFF,0xFF,0xFF,0xF9,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEF,0xEF,0xFF,0xFF, | ||
849 | 0x9B,0xFB,0x7F,0xFF,0xFF,0xFF,0xC1,0xFF, 0xDF,0xFF,0x3F,0x5F,0xD7,0xBF,0xEF,0xBB, | ||
850 | 0xDE,0xEE,0xFF,0x7F,0xDF,0xFF,0xFE,0xF5, 0x7F,0xDF,0xFF,0x99,0xFF,0xFF,0xFA,0xFF, | ||
851 | 0xBF,0xFD,0xEB,0x7A,0xFF,0xB7,0xFE,0xFE, 0xFF,0xFF,0xEF,0xFF,0xFF,0xFD,0xBF,0xFF, | ||
852 | 0x97,0xFF,0xFD,0xF7,0xFF,0x7F,0xF7,0xFF, 0xFF,0xFD,0x5F,0xFE,0xF3,0xF9,0xDF,0xDF, | ||
853 | 0xFF,0xFF,0xFC,0xFF,0xFF,0x83,0xFF,0xFF, 0xFE,0xFF,0x9E,0xEC,0xFB,0xEE,0xFF,0x9F, | ||
854 | 0xBF,0xEF,0xFF,0xFE,0xED,0x7B,0xFF,0xFF, 0xFF,0xF1,0x5A,0xFF,0xFF,0xFD,0xFF,0x7C, | ||
855 | 0x69,0x3B,0xDF,0xFF,0x7F,0x1F,0xDF,0xFF, 0xFD,0xBA,0xFF,0xFF,0xFB,0xFF,0x5B,0xBD, | ||
856 | 0xFF,0xFF,0xFF,0xFF,0xD7,0xB6,0xED,0xE9, 0xFF,0xD6,0xBD,0x6F,0x5F,0xFB,0xFF,0xEF, | ||
857 | 0xFF,0x5F,0xFE,0xF6,0x6F,0xFF,0xFF,0xFF, 0xFF,0xF7,0xEB,0x7A,0xDF,0xFF,0x9F,0x7F, | ||
858 | 0x7F,0xFF,0xB7,0xFF,0xFF,0xFE,0xDF,0xFF, 0x6C,0xFF,0xFB,0xFF,0xBB,0x6F,0xEB,0xFE, | ||
859 | 0xCC,0xF7,0xA5,0xFA,0x5C,0xF5,0x75,0xBB, 0xB7,0xDF,0xFE,0x6F,0x5F,0xC5,0xBF,0xFD, | ||
860 | 0x7B,0xFE,0xFF,0x95,0xE7,0x29,0xCF,0x4F, 0xF5,0x91,0xEE,0x6B,0xDF,0xEF,0xFD,0x54, | ||
861 | 0xF5,0xBD,0xB1,0xFF,0xEF,0xEE,0xFB,0xBE, 0xBF,0xAF,0xFE,0xDE,0xBD,0x6F,0xDA,0xF2, | ||
862 | 0xFF,0xAF,0xBE,0xFF,0xFF,0xFD,0x7E,0xA7, 0xFF,0xF7,0xFF,0xBF,0xEF,0x7B,0xF6,0xFD, | ||
863 | 0xBD,0x4A,0xF2,0x85,0x85,0xBF,0x5B,0xFE, 0xB5,0xFD,0xFA,0xFF,0x4F,0xFF,0xFE,0xDF, | ||
864 | 0xFF,0xED,0xFF,0xBF,0xFF,0xBF,0x7F,0xFE, 0xFF,0xB7,0x6D,0xFF,0xF7,0xBF,0xBF,0xEF, | ||
865 | 0xFD,0x1F,0xFF,0xFE,0x7D,0xFF,0x67,0xFF, 0xFF,0xFF,0x3F,0x7F,0xFE,0xBF,0xFF,0xE7, | ||
866 | 0xDF,0xE7,0xFF,0xEF,0x6B,0xFC,0x1F,0xFF, 0xBF,0xEF,0xFB,0xFE,0xDE,0xBF,0xAF,0xFA, | ||
867 | 0xFF,0xB6,0xEF,0xF9,0xFE,0xFF,0x8F,0xEF, 0xDB,0xEF,0xAB,0x6F,0xFB,0xFE,0xFF,0xFF, | ||
868 | 0xEF,0xFD,0xFF,0x7F,0xFF,0xFF,0xDE,0xFF, 0xFF,0xEF,0xFF,0xFF,0xFF,0x3F,0xFF,0x6C, | ||
869 | 0xFF,0xBF,0xFB,0xFF,0xFE,0xFF,0xFB,0xFE, 0xDF,0xFF,0xFF,0xEF,0xFF,0xFF,0xBF,0xFF, | ||
870 | 0xFF,0xFE,0xFB,0xFF,0xD5,0x7F,0xFF,0xFF, 0xEF,0xFB,0xFF,0xFF,0xBF,0xEF,0x43,0xB5, | ||
871 | 0xFD,0x6F,0xCF,0xD6,0xBE,0x3F,0x7F,0xDB, 0xFE,0xC3,0xFF,0xFD,0xFF,0xAF,0xEB,0xFB, | ||
872 | 0xFC,0xFF,0x3E,0xEF,0xE8,0xFA,0xBD,0xCD, 0xAA,0xFE,0xFE,0x7D,0xCF,0xFF,0xB7,0xFF, | ||
873 | 0xF7,0xFF,0xFF,0xFF,0xFD,0xFF,0x75,0xCD, 0x52,0xD7,0xFD,0xFB,0xF7,0xDD,0xFB,0xEF, | ||
874 | 0xEB,0xFF,0xFF,0x4F,0xFF,0xBF,0x9F,0xE7, 0xF9,0xFC,0x7F,0x8B,0xC3,0xF9,0xAF,0x8F, | ||
875 | 0xE7,0xE9,0xBE,0x7F,0x9F,0xE6,0xF9,0xFC, 0x5F,0xFF,0xFF,0xF7,0xFD,0xFF,0x7A,0x5F, | ||
876 | 0xD7,0xED,0xFF,0xFF,0xD7,0xFF,0xDD,0x7F, 0xE7,0xFF,0xFC,0xFF,0xFC,0x3F,0xFF,0xFF, | ||
877 | 0xFF,0xFB,0xFF,0xFE,0xBF,0xAF,0xFF,0xFD, 0xFF,0xEF,0xFF,0xEB,0xFF,0xFF,0xFF,0xFF, | ||
878 | 0xFF,0xF7,0x7F,0xFF,0x7F,0xDF,0xFF,0xFD, 0xFD,0x7F,0xFE,0xF7,0xFD,0x7F,0xDF,0xFF, | ||
879 | 0xFD,0xFF,0xFF,0xDF,0xFB,0xFF,0xEE,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7A,0xDF,0xF5, | ||
880 | 0xFD,0xFA,0xDF,0xF7,0xFC,0xFF,0x7F,0xDF, 0xBF,0xED,0xFF,0xC9,0xFF,0xDF,0xFF,0xBF, | ||
881 | 0x2F,0xFB,0xFF,0xBC,0xAD,0xFF,0xF7,0xFF, 0xFF,0xEF,0xD3,0xFF,0x7D,0xBF,0x6F,0xFF, | ||
882 | 0xFA,0xFF,0xFE,0xBF,0xAE,0xEA,0xFA,0xBE, 0xAD,0xA5,0xEB,0xCE,0xBF,0xA7,0xEB,0x5A, | ||
883 | 0xDE,0xBD,0xAF,0x6B,0xFD,0x57,0xFF,0xFF, 0xF4,0x7F,0x1F,0x7F,0xFD,0xFF,0x7F,0x36, | ||
884 | 0xF0,0xDF,0x79,0xFF,0xFF,0xFF,0xF7,0xFD, 0xBF,0xFF,0x87,0xFF,0xFB,0xF3,0xFC,0xFF, | ||
885 | 0xFF,0xFF,0xFF,0x7E,0xFF,0xBF,0xDF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xF8,0x9F, | ||
886 | 0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFD, 0xF7,0xFC,0xBD,0xFF,0xFE,0xFF,0xFF,0xFF, | ||
887 | 0xFF,0xFF,0xFB,0xF9,0xBF,0xFF,0xFF,0xEB, 0xE2,0xFE,0xFF,0xBF,0xEF,0xA9,0xBA,0x2F, | ||
888 | 0xEB,0xF9,0xFE,0x77,0xDF,0xF7,0xFF,0xFF, 0xF9,0x7F,0xFF,0xFF,0x7F,0xEF,0xD7,0xFF, | ||
889 | 0xFD,0xFF,0xFB,0xF5,0xFF,0xBF,0x6F,0xDF, 0xFF,0xFF,0xFD,0xFF,0xFF,0xF0,0xFF,0xFF, | ||
890 | 0xFF,0x3F,0xCF,0xFF,0xBA,0xEE,0x9B,0xBF, 0xEE,0xD7,0xFE,0xCD,0xEF,0xFF,0xDF,0xBF, | ||
891 | 0xFF,0xFF,0xC5,0xFF,0xFF,0xFD,0x7F,0x4F, 0xFD,0xF6,0xD9,0xFF,0x4F,0xD6,0xFD,0xBF, | ||
892 | 0x6E,0xFF,0xFF,0xF4,0x7F,0xFF,0x7F,0x8B, 0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xF9,0xFE, | ||
893 | 0x37,0xFF,0xD9,0xFB,0xF5,0xAF,0xFD,0xFF, 0xFF,0xFB,0xFF,0xFF,0x07,0xFF,0xFF,0xFF, | ||
894 | 0xFB,0xF7,0xFF,0xFD,0xFF,0x7C,0xFA,0x7E, 0x4F,0xFC,0xDF,0x1D,0xC7,0xFF,0xFF,0xFF, | ||
895 | 0xFF,0xAE,0xFF,0xFF,0xFF,0xFF,0xFD,0xFB, 0xFF,0xFF,0xFE,0xFE,0xFC,0xFF,0x7F,0x7F, | ||
896 | 0xBF,0xEF,0xFE,0xFF,0xFF,0xFF,0x5F,0xFD, 0xFF,0xFF,0xFF,0xFD,0x6F,0x5A,0xD7,0x7B, | ||
897 | 0xBE,0x5F,0xFE,0x39,0xFF,0xF7,0xFF,0xF7, 0xFD,0xFE,0xAA,0x1F,0xFF,0xFF,0xFF,0xFF, | ||
898 | 0xFE,0xFE,0xAB,0xAF,0xFD,0xFE,0xBF,0xFF, 0xF7,0xFF,0x7F,0xFE,0x8F,0xE3,0xFB,0xEE, | ||
899 | 0x7F,0xFF,0xFF,0xFF,0xFF,0xEB,0xFB,0xFF, 0xFD,0xBF,0xEF,0xDF,0xFF,0xFF,0xFF,0xFF, | ||
900 | 0xFF,0xFF,0xFF,0xFB,0xE4,0x3F,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF3,0xEF,0xBB,0xFB, | ||
901 | 0xBF,0xEF,0xBB,0xFF,0xD7,0xBF,0xFF,0xFF, 0xFF,0x29,0xAF,0xF7,0xFF,0xFF,0xFB,0xFF, | ||
902 | 0xFB,0xE6,0xFF,0x0F,0xFB,0x3F,0xDF,0x0F, 0xFF,0xAF,0xFF,0xFF,0xFF,0xF5,0xC3,0xDF, | ||
903 | 0x5F,0xFF,0xFF,0xFF,0xFE,0x6B,0xCA,0xBE, 0xBC,0xFF,0x9F,0xF2,0xBF,0xFF,0xFE,0xFA, | ||
904 | 0xFF,0xFF,0xEF,0x16,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFC,0xDF,0x97,0xFD,0x79,0xFF,0x37, | ||
905 | 0xE7,0x7F,0xFF,0xFF,0xB5,0xFF,0xFF,0xF6, 0x2F,0xFF,0xFD,0xFB,0xFE,0xFF,0xFF,0xFD, | ||
906 | 0x5F,0x57,0x5F,0xFF,0xDB,0x52,0xDF,0xFF, 0xFD,0xBF,0xFF,0xFF,0xFC,0xDB,0xFF,0x7B, | ||
907 | 0xB5,0xFD,0x7F,0xFF,0x71,0x9C,0x6E,0xFF, 0xF6,0x35,0xA5,0x9B,0xFF,0xFF,0xFD,0xFF, | ||
908 | 0xFF,0xDB,0x9E,0x7F,0xFE,0xEF,0xFB,0xFF, 0xFF,0xBD,0xEF,0xFF,0xDE,0xB7,0xF9,0x4B, | ||
909 | 0xFF,0xF5,0xEF,0xFF,0xFF,0xFF,0xE8,0x7E, 0xFF,0xEA,0xDF,0xF7,0xFF,0xFD,0x69,0x5B, | ||
910 | 0xFC,0x9F,0xEF,0x78,0xD6,0xFF,0xEB,0xEF, 0xFF,0xFF,0xFF,0xE8,0xFF,0xFF,0xED,0xFF, | ||
911 | 0xFF,0xFF,0xFF,0xE3,0xF9,0xF6,0xBF,0xFF, 0xFF,0xFE,0xDF,0xFF,0x7F,0xFF,0xFF,0xFF, | ||
912 | 0xD1,0xFF,0xFF,0xE7,0xFF,0xFF,0xFF,0xFF, 0xE7,0xF9,0xFF,0xBF,0x7F,0xD9,0xFF,0xFD, | ||
913 | 0xFE,0x7F,0xFF,0xFE,0xFF,0xF9,0xFF,0xFB, 0xD6,0xDF,0xBF,0xEF,0x5B,0xD6,0xFF,0xBF, | ||
914 | 0xFB,0xF6,0xFF,0xBF,0xEF,0xF8,0xF6,0xDD, 0xBE,0xFE,0x16,0xFF,0xBF,0xEF,0xFF,0xFE, | ||
915 | 0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0x6F,0xFB, 0xFF,0xFF,0xFF,0x6F,0xF3,0xFF,0xF7,0xEF, | ||
916 | 0xFB,0xFF,0xBF,0xFF,0xEF,0xFE,0xFF,0xBF, 0xFF,0xFF,0xFF,0xBE,0xBF,0xFF,0xEF,0xFF, | ||
917 | 0x7F,0xEF,0xFF,0xFD,0x17,0xFB,0x7B,0xFF, 0xFF,0xFD,0x7F,0xDB,0xF6,0xF4,0x7F,0xFA, | ||
918 | 0xFE,0xF5,0xBF,0xEB,0xE3,0xF7,0xFF,0xFF, 0xE9,0xBF,0xFF,0xAF,0xF7,0xFD,0xF3,0x7E, | ||
919 | 0x8F,0xA3,0xEA,0xFF,0xCB,0xF3,0xEE,0xFF, 0xBF,0xEF,0xF7,0xF9,0xFF,0xFE,0x7F,0xFF, | ||
920 | 0xFF,0xFF,0xFF,0xF5,0xFB,0xF6,0xFF,0xF5, 0x2F,0xFE,0xFB,0xD7,0xBF,0xFF,0xBE,0xDF, | ||
921 | 0x9F,0xFF,0xF0,0xFF,0xFF,0xF9,0xFE,0x7F, 0x8F,0xA3,0xF8,0xFE,0x6F,0x9F,0xF9,0xF6, | ||
922 | 0x2F,0x9F,0xE7,0xF9,0xFE,0x2F,0x9F,0xE1, 0xFF,0xFF,0xFF,0x7F,0xDF,0xF7,0xF5,0xFD, | ||
923 | 0x7F,0x7F,0xF5,0xFF,0x9F,0x5F,0xFB,0xFE, 0xFF,0x7F,0xFF,0xFF,0xCB,0xFF,0xFF,0xFB, | ||
924 | 0xFE,0xFF,0xBF,0xAF,0xFB,0xFE,0xFF,0xDF, 0xFE,0xFE,0xBF,0xF7,0xFF,0xFF,0xFF,0xFF, | ||
925 | 0xFF,0xC7,0xFF,0xFF,0xFD,0xFF,0x7F,0xDD, 0xF7,0xFD,0xFF,0xFF,0xD7,0xFF,0xFD,0x7F, | ||
926 | 0xFF,0xFB,0xFD,0xFF,0xFF,0xFE,0xEF,0x7F, 0xFD,0xEF,0xFB,0xFE,0xFB,0xFD,0xFF,0x7F, | ||
927 | 0xDF,0xFD,0xFF,0x7A,0xDF,0xF7,0xFD,0xFF, 0xFF,0xFF,0xFF,0x1F,0xFF,0xFF,0xD3,0xF7, | ||
928 | 0xFF,0xFF,0x6F,0xDB,0xFF,0xFF,0xEF,0xCB, 0xF4,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, | ||
929 | 0x29,0xFF,0xE8,0xDA,0x76,0x9F,0xAF,0x6A, 0xDA,0xFE,0x35,0xEB,0xDA,0xD6,0xBF,0xAB, | ||
930 | 0xEB,0x7A,0xDE,0xBF,0xD7,0x7F,0xFF,0xFE, 0xFF,0xBF,0xEF,0xFD,0xDF,0x77,0xBF,0xFD, | ||
931 | 0x37,0xEF,0xFF,0xEF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFE,0x7F,0xFF,0xFF,0xFF,0xF7,0x7E, | ||
932 | 0xDF,0xFF,0xFF,0xFF,0xFA,0xB7,0x7F,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0x89,0xFF, | ||
933 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x9F,0xFB,0xFF,0xFF,0xFF,0xE7,0xFF, | ||
934 | 0xFF,0xFF,0xFF,0xAA,0xFF,0xAB,0xFB,0xFA, 0xEF,0xBF,0xFF,0xDF,0xFA,0x7B,0xB9,0xFE, | ||
935 | 0xFE,0xFF,0xFD,0xFF,0xF7,0xFE,0x3F,0xFF, 0xB7,0xFF,0xF7,0xEE,0xFF,0x7F,0xEF,0xFF, | ||
936 | 0xFF,0x7F,0xFF,0x1F,0xFB,0xFF,0xBF,0xFB, 0xFE,0xFF,0xBD,0xFF,0xFF,0x2F,0xFF,0xBF, | ||
937 | 0xFF,0x7F,0xDF,0xFA,0xFF,0xFF,0xFC,0xEE, 0xF5,0xF3,0xBE,0xFB,0x0F,0xEF,0xF3,0xBE, | ||
938 | 0xEF,0xFC,0x5F,0xFF,0x5A,0xFF,0xF7,0xDF, 0xFF,0xFF,0xFE,0xD5,0xFC,0x5F,0xFB,0xF2, | ||
939 | 0xFF,0xFF,0x2F,0xBB,0xF3,0xFF,0xFF,0xBF, 0xFF,0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF, | ||
940 | 0xBF,0xFF,0xFF,0xFD,0x7B,0xFF,0xDF,0xB9, 0xFF,0xFB,0xFF,0xD8,0x7F,0xFF,0xFF,0xFF, | ||
941 | 0xFB,0xFF,0xFC,0x7F,0x1F,0xBF,0xE0,0xDF, 0xF7,0xEF,0xFF,0xFD,0x7F,0xFE,0xDF,0xFF, | ||
942 | 0xE0,0xFF,0xFF,0xFD,0xEF,0xFB,0xFF,0xFE, 0xF7,0xDF,0xFF,0xEB,0x5F,0xFF,0xF7,0xFF, | ||
943 | 0xFF,0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0xFD, 0xFF,0xFF,0xFF,0xF7,0xFD,0xFF,0x3B,0xDC, | ||
944 | 0xFD,0x6D,0x7B,0x5F,0x57,0xF5,0xFD,0x7F, 0x5F,0xFF,0xB1,0xFF,0xEB,0xFF,0xFF,0xFF, | ||
945 | 0xFB,0xFB,0xFE,0xFF,0xBF,0xFB,0xBE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xAF,0xFE,0xF7, | ||
946 | 0xDF,0xDF,0xFF,0xFF,0xFF,0x7F,0xCF,0xF3, 0xF8,0xFF,0xD7,0xFB,0xFF,0x5F,0xBF,0xF7, | ||
947 | 0xFB,0xFF,0x7F,0xFE,0x23,0xFF,0xFF,0xFE, 0x7F,0xF3,0xFF,0xFB,0xFE,0xFF,0xFF,0xF3, | ||
948 | 0xFF,0xFF,0xF5,0xF9,0xFF,0x3F,0xFF,0xFF, 0xF0,0x9A,0xFF,0xBE,0x7F,0xFF,0xFC,0xF9, | ||
949 | 0xFF,0xFD,0xAF,0xEB,0xFE,0xBF,0xFF,0xCF, 0xF3,0xFE,0x7F,0xFF,0xFF,0x5B,0xBD,0xFF, | ||
950 | 0xBC,0xEB,0xFF,0xD7,0xD4,0xAF,0xAF,0xFD, 0xFF,0xCF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, | ||
951 | 0xFD,0xFE,0xFF,0x6F,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFD,0x7F,0x5E,0xFD,0xBF,0xDB,0xF6, | ||
952 | 0xFD,0xBF,0x6F,0xFB,0xEE,0xFD,0xFF,0x7A, 0xFF,0xFA,0xFB,0xFF,0x3F,0xFB,0xB7,0x5F, | ||
953 | 0xD6,0xF7,0x1F,0x71,0xDC,0x77,0x1D,0xC7, 0x31,0xDC,0x77,0xDF,0xF9,0xBF,0xF5,0x5B, | ||
954 | 0xF4,0xD7,0x9D,0xAE,0xFF,0xBF,0xFD,0xBF, 0xDB,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFE, | ||
955 | 0x3D,0x81,0xFF,0xEB,0xFE,0xFE,0xFE,0xFF, 0xEB,0x7A,0xDF,0x7D,0x77,0x7D,0xF5,0x79, | ||
956 | 0xDF,0x57,0xDD,0xF5,0x7D,0x7E,0xE6,0xFF, 0xD6,0x3F,0xBF,0x7F,0xFF,0xD4,0xF5,0x3F, | ||
957 | 0xBF,0xFB,0xBE,0xEF,0xB3,0xEE,0xFB,0x9E, 0xEF,0xBB,0xFE,0x8B,0xFF,0xFE,0xDF,0xB7, | ||
958 | 0xED,0xFF,0xF7,0xFD,0xFE,0xFF,0xEF,0xBB, 0xEE,0xFF,0xBE,0xEF,0xBB,0xEE,0xEB,0xFC, | ||
959 | 0x1F,0xFF,0xFF,0xFD,0xFF,0xE7,0xFF,0xF7, 0xFD,0xFF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB, | ||
960 | 0xFE,0xFF,0xBF,0xEB,0xFA,0x1F,0xFF,0xB7, 0xEF,0x5B,0xFE,0xFF,0xAF,0xEB,0xDD,0xE7, | ||
961 | 0xDE,0x77,0x9D,0xE7,0x79,0xDE,0x77,0x9D, 0xBF,0xE6,0x6F,0xFF,0xFE,0xFF,0xBF,0xEF, | ||
962 | 0xFB,0xFE,0xFD,0xBF,0x6F,0xF6,0xFD,0xBF, 0x6F,0xDB,0xF6,0xFD,0xBF,0xFF,0x7E,0xFF, | ||
963 | 0xFF,0xFB,0xFE,0xFE,0xFF,0xEF,0xFB,0xFD, 0xEF,0x7E,0xF7,0xBD,0xEF,0x7B,0xDE,0xF7, | ||
964 | 0xBD,0xEF,0xFF,0xD5,0xFF,0xBF,0xFF,0xEF, 0xFE,0xFF,0xFC,0x3F,0x0F,0xE7,0xFE,0x7F, | ||
965 | 0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFE, 0xF3,0xFF,0xFE,0xDF,0xAD,0xDF,0x67,0xEE, | ||
966 | 0xFB,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFF,0x23,0xFF,0xFF, | ||
967 | 0xFF,0xFF,0x7F,0xFF,0xF3,0xBC,0xDB,0xFE, 0xFB,0xFF,0xFB,0xBE,0xF7,0xFB,0xFF,0x7F, | ||
968 | 0xDF,0xFF,0xCF,0xFB,0xFF,0x9F,0xE3,0xF9, 0xBE,0x3F,0x8F,0xE7,0x79,0xFF,0x9D,0xE7, | ||
969 | 0xF9,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x5F, 0xFF,0xCF,0xF7,0xFF,0xFF,0xFF,0xDF,0xF7, | ||
970 | 0xFE,0x7F,0xE7,0xF9,0xFE,0x7F,0xFF,0xFF, 0xFB,0xFE,0xFF,0xFF,0xBF,0xFF,0xBF,0xBF, | ||
971 | 0xFF,0xFE,0xFF,0xBF,0xEF,0xFF,0xFD,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFD,0xFF, | ||
972 | 0xFF,0x3F,0xFF,0xBF,0xFF,0xF7,0xFF,0xFF, 0x7F,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
973 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xE8,0xEF,0xFF, 0x5F,0xF7,0xBF,0xF9,0xFE,0xDF,0xB7,0xFD, | ||
974 | 0xFF,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xDD,0xFF,0xF2,0xFF,0xBF,0xFF, | ||
975 | 0xFF,0xBF,0xFF,0xFF,0x2F,0xF2,0xFF,0xBF, 0x2F,0x7B,0xD2,0xF7,0xBF,0x2F,0xFF,0xBB, | ||
976 | 0xFF,0xEE,0x8F,0xAF,0xEB,0xFA,0xFE,0x3F, 0xA7,0x69,0xCE,0x8F,0xA4,0xEA,0xFA,0xEE, | ||
977 | 0xB7,0xAE,0xEB,0xFD,0xC7,0xFF,0xF7,0xF7, 0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x3E,0xF3, | ||
978 | 0x74,0xFF,0x3F,0x4F,0xFF,0xE7,0xFF,0x3F, 0xFE,0xA7,0xFF,0xFF,0xDF,0xF7,0xB7,0xFF, | ||
979 | 0xF7,0xFF,0xBA,0xEF,0x37,0xEB,0xFB,0xFE, 0xBF,0xFB,0xFE,0xF3,0xFF,0xF9,0xDF,0xFF, | ||
980 | 0xBF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFD,0xDF,0xFF,0xFD,0xFF,0xFF,0xFB,0xFE, | ||
981 | 0xFD,0xFF,0xFB,0xBF,0xFE,0x3F,0xED,0xFF, 0xDF,0xBE,0x3D,0xA7,0xFB,0xFA,0x3F,0xE6, | ||
982 | 0xE1,0xFE,0xFE,0x3F,0xEF,0xE3,0xDF,0xF5, 0x7F,0xFE,0xFF,0x7E,0xFF,0xFF,0xFF,0xFF, | ||
983 | 0xEF,0x6F,0xF6,0xFF,0x7D,0xEF,0xD7,0xDE, 0xFF,0x7D,0xEF,0xFF,0xF2,0xFF,0xFF,0xFF, | ||
984 | 0xFF,0xFF,0xFF,0x7B,0xDE,0xFB,0xE6,0xEE, 0xEF,0x37,0x6E,0xF3,0x7E,0xEB,0x37,0xEF, | ||
985 | 0xFF,0xC1,0xFF,0xFE,0xFF,0xF7,0xEF,0xFF, 0xFF,0xFF,0xBF,0x3F,0xD2,0xDF,0xBF,0x2F, | ||
986 | 0x7B,0xE2,0xFF,0xFE,0x3B,0xBD,0xDB,0xFF, 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFE, | ||
987 | 0xFF,0xFB,0xFF,0xFF,0xBF,0xFF,0xFB,0xDF, 0xFF,0xBF,0xFF,0xB7,0xFF,0xFF,0xBF,0xEF, | ||
988 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF, 0x7F,0xFF,0x1F,0xEF,0xF1,0xFD,0xFF,0xF6, | ||
989 | 0xAF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF, 0xFF,0xFF,0xFE,0x9F,0xFF,0xFF,0xFF,0x77, | ||
990 | 0xEF,0xF7,0xFB,0xFF,0xFE,0x5F,0xFF,0xFF, 0xBF,0xCF,0xFB,0xF7,0xDD,0xF7,0xF5,0xFF, | ||
991 | 0x5F,0xD5,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5, 0xFF,0xFB,0x0F,0xFF,0xFF,0xA9,0xEA,0x7A, | ||
992 | 0xFF,0xAF,0x8F,0xFE,0xDF,0xAF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFB,0xDF,0xE5,0x5F, | ||
993 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xBD,0x57,0xFF, 0xFF,0x6F,0x77,0xBF,0xF7,0xFB,0xFF,0x7F, | ||
994 | 0xBF,0xF7,0xFF,0xFC,0xBF,0xFF,0x9F,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF,0x1F, | ||
995 | 0xCF,0xFF,0xFC,0xFF,0xFF,0xFF,0xFF,0xFB, 0x65,0xAF,0xF3,0x7C,0xFF,0x3F,0xDF,0xFF, | ||
996 | 0xFD,0xE9,0xFE,0x7F,0xE7,0xFF,0xFE,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFD,0xE3,0xDF,0xFB, | ||
997 | 0xDB,0xF6,0xFD,0xEF,0x5B,0xFB,0xFF,0xDF, 0xFC,0xFF,0x3F,0xDF,0xF3,0xFD,0xFF,0x7F, | ||
998 | 0xDF,0xEF,0x66,0xFF,0xDF,0xAD,0xEB,0x7A, 0xDE,0xF7,0xF7,0xE7,0xD9,0xFD,0x9F,0x67, | ||
999 | 0xD9,0xF6,0x7D,0x9F,0xE7,0xDF,0xF5,0x47, 0xFD,0x65,0x5B,0xD6,0xF4,0xFE,0xFF,0xEF, | ||
1000 | 0xFF,0x6D,0xF6,0xDD,0xB7,0x6D,0xDB,0x76, 0xDC,0xB7,0x7D,0xFA,0x9B,0xF6,0x6D,0x9D, | ||
1001 | 0x67,0x59,0xDF,0xF7,0xDD,0xFF,0xEB,0xFE, 0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xE3, | ||
1002 | 0xD1,0x9F,0xFF,0xBD,0xBF,0xEF,0xFE,0xF7, 0xBF,0xBF,0xF7,0xD7,0x7F,0xDD,0xF7,0x9D, | ||
1003 | 0xDF,0x7F,0xDF,0xF7,0xFF,0xE0,0x7F,0xFD, 0xC1,0xDF,0xF7,0xFD,0xC7,0x7F,0x7F,0xFB, | ||
1004 | 0xFF,0xBB,0xEC,0xFB,0x3E,0xFF,0xBF,0xEC, 0xFB,0xFF,0xD8,0x7F,0xBF,0x6C,0xFF,0xBE, | ||
1005 | 0xFF,0xBF,0xED,0xFF,0xEF,0xFE,0xFB,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEE,0xFF,0xC5, | ||
1006 | 0xFF,0xAF,0x6F,0xFF,0xFC,0xFD,0x3F,0xE7, 0xFF,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF, | ||
1007 | 0xEF,0xFB,0xFE,0xBF,0x89,0xFE,0xFA,0xBA, 0xFE,0xBF,0xAF,0xFB,0xF6,0xF5,0xD9,0x7D, | ||
1008 | 0x97,0x65,0xD9,0x74,0x5D,0x97,0x65,0xD3, 0xFE,0xD6,0xFF,0xBF,0xF7,0xFD,0xFF,0x7F, | ||
1009 | 0xBF,0xCF,0xFB,0xFE,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFF,0xF6,0x8F,0xFB, | ||
1010 | 0xFF,0xEF,0xFB,0x7E,0xDB,0xFE,0xFF,0xBE, 0xEF,0xEE,0xFB,0xBE,0xEF,0xBB,0xEE,0xFB, | ||
1011 | 0xBE,0xFF,0xFF,0xDF,0xFF,0x43,0xFF,0xFF, 0xFB,0xEF,0x5F,0xB7,0xFE,0x7F,0xE7,0xF9, | ||
1012 | 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xF9, 0xBF,0xFE,0xAF,0x77,0xFD,0xFF,0x2F,0xAF, | ||
1013 | 0xA7,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xF1,0x7F,0xEF,0xDF, | ||
1014 | 0xFF,0x97,0xF5,0xEF,0xFF,0xDF,0xFF,0xFF, 0xBF,0xFF,0xBF,0xFF,0xFF,0xFE,0xFF,0xFF, | ||
1015 | 0xFF,0xE0,0xFF,0xFF,0xF9,0xFE,0x2F,0x8B, 0xE3,0xF8,0xBE,0x77,0x9F,0xF9,0xDA,0x77, | ||
1016 | 0x9D,0xE7,0x79,0xDE,0x77,0x9F,0xDD,0xFF, 0xFD,0xFD,0x7F,0x5F,0xD7,0xFD,0xFF,0x7F, | ||
1017 | 0xE7,0xFE,0x7F,0x97,0xE7,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFF,0xAB,0xFF,0xEF,0xFA,0xFE, | ||
1018 | 0xBF,0xAF,0xFF,0xFA,0xFF,0xFF,0xDF,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF, | ||
1019 | 0x67,0xFF,0xF7,0xF5,0xFF,0xFF,0xFF,0xDF, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
1020 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF,0xBD, 0xEB,0xFF,0xFF,0xF7,0xAD,0xEB,0xFF,0xDF, | ||
1021 | 0xFD,0xFF,0x3F,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0xFD, | ||
1022 | 0xBF,0xFF,0xCB,0xF4,0xFF,0x7F,0xD3,0xF7, 0xFD,0x3F,0x7F,0xD3,0xF7,0xFF,0xFC,0x3F, | ||
1023 | 0xFF,0xEA,0xFA,0xBE,0xAF,0xAB,0xEB,0xBA, 0xF4,0x95,0x6B,0x52,0xD4,0xAD,0x2F,0x4A, | ||
1024 | 0xD2,0xF6,0xBF,0xD2,0x7F,0xF7,0x3F,0xFF, 0xFF,0xF3,0x7F,0xFF,0xFF,0xF7,0xFF,0xBA, | ||
1025 | 0xDF,0xFB,0xFD,0xFF,0xBF,0xFF,0xFB,0xFF, 0xF8,0x7F,0xEA,0xFF,0xFE,0xFE,0xDF,0xFF, | ||
1026 | 0xF7,0xFF,0x7F,0xBB,0xFF,0xFF,0xBF,0xDF, 0xFB,0xFF,0xFF,0xBF,0xFF,0xB1,0x7F,0xFF, | ||
1027 | 0xFB,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF, 0xCF,0xFE,0xFF,0xFF,0xEF,0xFF,0xF7,0xFF, | ||
1028 | 0xFF,0xFF,0xF1,0xFF,0x69,0xBE,0xFA,0xBF, 0xAF,0xE2,0xFF,0xFE,0xFD,0xAF,0xF3,0xFE, | ||
1029 | 0xFF,0xBF,0xEF,0xFB,0xFC,0xFF,0xFF,0x07, 0xFD,0x95,0xDB,0xDF,0x7F,0xDF,0xAF,0xFF, | ||
1030 | 0xF7,0xAF,0x36,0xFE,0xBF,0x65,0xEB,0xF6, 0xFE,0x9F,0x6F,0xFE,0x07,0xFF,0xCF,0xFF, | ||
1031 | 0xF8,0xFE,0xFF,0xCF,0xFF,0xF6,0xFA,0xE7, 0xFB,0xFE,0xFF,0xBB,0xED,0xF9,0xFF,0xFF, | ||
1032 | 0xFF,0x5F,0xFF,0xFF,0xFF,0x75,0xFF,0xEF, 0x7E,0xFD,0xE0,0xE8,0x5E,0xD3,0xE5,0xF9, | ||
1033 | 0x3E,0x5F,0xD7,0xF7,0xFF,0xFA,0x2F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0x7F, | ||
1034 | 0x7F,0xD7,0xF5,0x7D,0x5F,0x57,0xD5,0xF5, 0xEF,0xFF,0xF3,0x7F,0xFC,0x7F,0xFF,0xC7, | ||
1035 | 0xF1,0xFF,0xFF,0x1F,0xCF,0xB0,0xFF,0x3F, 0xCF,0xF3,0xFC,0xFF,0x3F,0xCE,0xFF,0xE4, | ||
1036 | 0xFF,0xDF,0x7F,0xFE,0xF7,0xBB,0xFF,0xFF, 0xDF,0xEF,0xEE,0xFF,0xBF,0xEF,0xFB,0xFE, | ||
1037 | 0xBF,0xBF,0xEF,0xFF,0xD1,0xFF,0xFF,0xFF, 0xFD,0xFB,0xFF,0xFD,0xFF,0xFB,0x9F,0xE9, | ||
1038 | 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xBF, 0xFF,0xB3,0xFF,0xFF,0xF7,0xFF,0xFF,0xAF, | ||
1039 | 0xF7,0xFF,0xB6,0x3F,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFA,0xFE,0xBF,0xFE,0xA7,0xFF, | ||
1040 | 0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF, 0xFE,0x9F,0xF7,0xF9,0xFF,0x7F,0x9F,0xE7, | ||
1041 | 0xFF,0xFF,0xFE,0xAF,0x6F,0xFF,0xFF,0xFF, 0x9F,0xFF,0xDF,0xFF,0x7D,0x5F,0xDD,0xFF, | ||
1042 | 0xFB,0xBF,0xE7,0xBB,0xFF,0xFB,0xDF,0x6D, 0x5F,0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
1043 | 0xEB,0xF7,0xFF,0xE7,0xEF,0xF7,0xFF,0xFF, 0x7F,0xFF,0xF7,0xFF,0xFC,0x8F,0xFF,0xEF, | ||
1044 | 0xFD,0xFE,0xFF,0xBE,0xF4,0xF2,0x7D,0xD7, 0xCF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
1045 | 0xFF,0xCF,0x6B,0xFF,0xBF,0x3F,0xFB,0xF2, 0xFC,0x7F,0xEB,0xFF,0x9F,0xFA,0xFF,0xFF, | ||
1046 | 0x3F,0xFF,0xF3,0xFF,0xFF,0xFD,0x70,0xF7, 0xFF,0xFF,0xBF,0xFF,0xFB,0xD7,0xFE,0xF5, | ||
1047 | 0x77,0xFF,0x15,0xDD,0x77,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFB,0xCD,0xBF,0xFF,0xFD,0xFF, | ||
1048 | 0xFF,0xDF,0x37,0xCD,0xF9,0xEC,0xFE,0xEF, 0xBB,0xF4,0xFB,0x3F,0x4F,0xB3,0xFF,0xFD, | ||
1049 | 0xCB,0xFF,0xE9,0x7E,0x54,0x9F,0xE5,0x4B, 0xB7,0xFF,0xDD,0x7D,0xC7,0x71,0xDD,0x77, | ||
1050 | 0x5D,0xD7,0x75,0xCD,0x7F,0xD6,0xFF,0xD3, 0xF6,0xF9,0x3F,0x6D,0x95,0xAF,0x7F,0xFE, | ||
1051 | 0xFF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xF6,0xC7,0xFF,0xAD,0x7B,0xCA,0xFF, | ||
1052 | 0xBF,0xBF,0xEF,0xFD,0xE3,0xDF,0xB7,0xED, 0xFB,0x7E,0xDF,0x37,0xED,0xE3,0xFB,0xDF, | ||
1053 | 0xFF,0x52,0x5C,0x15,0xFD,0xCF,0x7F,0xDF, 0xFE,0xEF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEC, | ||
1054 | 0x7B,0xFE,0xFF,0xFE,0x3E,0x7F,0xDA,0xF7, 0xFD,0xFF,0x7F,0xFF,0xFF,0xFB,0xEF,0xBB, | ||
1055 | 0x6F,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF, 0xF7,0x7D,0xFF,0xD8,0xFF,0xFD,0xBF,0x7F, | ||
1056 | 0xFB,0xFF,0xFF,0x9F,0xFB,0xFE,0x7F,0x9F, 0xE7,0xF9,0xFE,0x7F,0x9F,0xEA,0x7F,0xF6, | ||
1057 | 0xBF,0xBD,0x6A,0x5A,0xF6,0xE5,0xBF,0x77, 0x5F,0x6D,0xDD,0x77,0x5D,0xD7,0x75,0xDD, | ||
1058 | 0x77,0xFF,0xA5,0xBF,0xCF,0xFB,0xFF,0xFF, 0xBF,0xCF,0xFB,0xFD,0xFF,0xBF,0xF3,0xFE, | ||
1059 | 0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD,0xAB, 0xFF,0xBF,0xBF,0xFF,0xFB,0xFF,0x7F,0xEF, | ||
1060 | 0xFF,0xBE,0xFB,0xEE,0xFB,0xBE,0xEF,0xBB, 0xEE,0xFB,0xBF,0xFF,0xB5,0xFF,0xD0,0xBC, | ||
1061 | 0xFD,0x2F,0x4B,0xF7,0xFF,0xFF,0x9F,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x9F, | ||
1062 | 0xFA,0x8F,0xFD,0xAB,0xFA,0xDA,0xBF,0xAF, 0xB3,0xFD,0xFF,0xBF,0xFB,0xFE,0xFF,0xBF, | ||
1063 | 0xEF,0xFB,0xFE,0xF7,0xBF,0xFF,0x9F,0xFF, 0x77,0xF7,0xBD,0xFD,0x77,0xDF,0xFF,0x7E, | ||
1064 | 0xDF,0xED,0xBB,0xFE,0xFF,0xBE,0xEF,0xFB, 0xFE,0xFF,0xFA,0x3F,0xFF,0xBE,0x6F,0x8F, | ||
1065 | 0xE6,0xF9,0xFE,0x7F,0x9F,0xC7,0xFE,0x7F, 0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFB, | ||
1066 | 0x7F,0xFF,0x7F,0xCF,0xFF,0xFD,0xFF,0xFF, 0xDF,0xFB,0xAF,0xBF,0xEF,0xFF,0xFE,0xFF, | ||
1067 | 0x9F,0xEF,0xFB,0xFF,0xFC,0xFF,0xFB,0xFE, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xF7, | ||
1068 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF5,0xFF,0xFF,0xFF,0x3F,0xDF,0xF7, | ||
1069 | 0xFF,0xFF,0x7F,0xEF,0xFE,0xFF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xEF,0xFF,0xB3,0x7F, | ||
1070 | 0xFF,0x7B,0x5E,0xF7,0xFD,0xFF,0x7B,0x7F, 0xF7,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F, | ||
1071 | 0xDF,0xF7,0xFF,0x17,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xDD,0xF6,0xFC,0xBF,0xCB,0xF2, | ||
1072 | 0xBC,0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xFE, 0x8F,0xFF,0xFA,0x7E,0xBF,0xA7,0xEB,0xDA, | ||
1073 | 0xFC,0xBF,0xAF,0x7A,0xFE,0xBF,0xAF,0xEA, 0xFA,0xFE,0xBF,0xAF,0xF4,0xDF,0xFE,0xFF, | ||
1074 | 0xF3,0x3C,0x7F,0x3E,0xFF,0xCF,0xF8,0xBF, 0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xE7,0xE8, | ||
1075 | 0xFF,0xFC,0x9F,0xFF,0xFF,0xCF,0xEB,0xB3, 0xE7,0xFB,0x7B,0xF3,0xFE,0xFF,0xCF,0xDB, | ||
1076 | 0xFB,0xFB,0xBF,0x6F,0x6F,0xDF,0xEC,0x7F, 0xFF,0xFF,0xF7,0xFD,0xFD,0xFF,0xFF,0xFF, | ||
1077 | 0xFF,0xB2,0xBF,0xFF,0xDE,0xFD,0xBD,0xEF, 0xFB,0xF6,0xDF,0xEA,0xE7,0xDB,0xFE,0xBB, | ||
1078 | 0xFF,0xEB,0xFB,0xBF,0x9F,0x8F,0xE8,0xFE, 0x3F,0x8F,0xA3,0xF8,0xFE,0x3F,0x8F,0xFF, | ||
1079 | 0xF8,0x7E,0xFD,0xFD,0x7F,0xFF,0xFB,0xCD, 0xFF,0xFD,0xFF,0x5F,0xEF,0xFD,0xFF,0xFF, | ||
1080 | 0xDF,0xF7,0xFD,0xFF,0xBE,0x90,0xFF,0xFF, 0xEE,0xFF,0x3F,0xBF,0xF3,0xBB,0xFE,0xB7, | ||
1081 | 0xAB,0xFA,0xFE,0xAF,0xAD,0xEA,0xFA,0xDE, 0xAB,0xFF,0x63,0xFF,0xFE,0xF2,0xFF,0xB3, | ||
1082 | 0xFF,0xDF,0xEE,0x7D,0xFF,0x03,0xF1,0xF4, 0x3F,0x1F,0xC3,0xF1,0xEC,0x7F,0xFE,0x6F, | ||
1083 | 0xFF,0xFB,0xFB,0xFF,0x9F,0xFF,0xBF,0xFF, 0x7B,0x5F,0xFD,0xFF,0xDF,0xF7,0xFD,0xFD, | ||
1084 | 0x7F,0x7F,0xDF,0xFE,0xCF,0xFB,0xFF,0xFF, 0xAF,0xFB,0xFF,0x1F,0xEF,0xA5,0xFD,0xBF, | ||
1085 | 0xDF,0xFB,0x7D,0xFF,0xBF,0xDF,0xFB,0xFF, 0xFD,0x3B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, | ||
1086 | 0xAF,0xF3,0xFF,0xFB,0x7F,0xBF,0xD7,0xFB, 0xBF,0x7F,0xBB,0xF7,0xFF,0xF8,0x7F,0xFF, | ||
1087 | 0xFA,0x5F,0xD7,0xFF,0xDF,0x7F,0xEF,0xFF, 0xFF,0x7F,0xDB,0xF7,0xFD,0xFF,0x7F,0xDF, | ||
1088 | 0xB7,0xFB,0xEC,0xFF,0xFF,0xF7,0xBF,0xEF, 0xFD,0xFC,0xFB,0xFF,0xEF,0xF0,0xFE,0x3F, | ||
1089 | 0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xEF,0x8D, 0xFF,0xFF,0xEF,0x7F,0xBF,0xFF,0xFB,0xFF, | ||
1090 | 0xDB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0xD8,0xFF,0x2E,0x7F, | ||
1091 | 0xBE,0xEF,0xFE,0x6E,0xFF,0xBF,0xF9,0xFF, 0xFF,0xF3,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
1092 | 0xFC,0x66,0xBE,0x47,0xF3,0x7F,0xDF,0xFE, 0x87,0x9F,0xFF,0xFF,0xFF,0xFF,0xE7,0xFF, | ||
1093 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xD6,0x6F,0x7C, 0xFB,0x4F,0xD2,0xFF,0xFD,0x2B,0xFE,0xFF, | ||
1094 | 0xFF,0xFD,0x5F,0xD7,0xD5,0xF5,0x7D,0xFF, 0xFF,0xFF,0xBF,0x9B,0xFF,0xFF,0xDF,0xB7, | ||
1095 | 0xFF,0xFF,0xDF,0xFF,0x3F,0xCF,0xFE,0x7F, 0xBF,0xEF,0xFB,0xFC,0xFF,0x3F,0xFF,0xD9, | ||
1096 | 0xBF,0xFE,0x97,0xEC,0x8F,0xB7,0xFE,0x9B, 0x7D,0xFD,0xB7,0xDD,0x77,0x1D,0xC7,0x71, | ||
1097 | 0xDD,0x77,0x5D,0xD7,0xF3,0x6F,0xFD,0x3F, 0x73,0xDD,0xAF,0xFD,0x7A,0xFF,0xFF,0xAF, | ||
1098 | 0xFE,0xFD,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0x66,0x7F,0xFF,0xFF,0xBF,0xBF,0xFF, | ||
1099 | 0xFB,0xFF,0xF7,0xDF,0xFD,0xFB,0x7D,0xDF, 0xB7,0xCD,0xF3,0x7C,0x5F,0x3F,0x91,0x3F, | ||
1100 | 0xFF,0x3D,0xEF,0x7B,0xFF,0xFC,0xFF,0xCA, 0xEF,0xFE,0xFF,0xBD,0xEF,0xFB,0x1E,0xE7, | ||
1101 | 0xBB,0xEC,0x7F,0xB3,0xFF,0xFD,0x9F,0xFF, 0xFF,0xFE,0xFF,0xFF,0x7F,0xBF,0xFB,0xFE, | ||
1102 | 0xFF,0xBF,0xEF,0xFB,0xEE,0xFB,0xBF,0xDF, 0x67,0xFF,0xFF,0xBF,0xEF,0xDB,0xFF,0xBC, | ||
1103 | 0xFE,0x7F,0xFB,0xFF,0x9F,0xEF,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x87,0xFF,0xEE, | ||
1104 | 0xFB,0xBE,0xE5,0xBF,0xEF,0xF9,0xD7,0x65, 0xF7,0xDD,0xE7,0x7D,0xDF,0x77,0x5D,0xD7, | ||
1105 | 0x7F,0xF8,0x9B,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xBF,0xEF,0xFB,0xFF,0x7F,0xCF, | ||
1106 | 0xF3,0xFC,0xFF,0xBF,0xEF,0xFF,0xDB,0x3F, 0xEF,0xFB,0xFE,0xFF,0xDF,0xFF,0xFE,0xFB, | ||
1107 | 0xBB,0xEF,0xBF,0xEF,0xBB,0xEE,0xFB,0xBE, 0xEF,0xBB,0xFF,0xFC,0x7F,0xFD,0x3B,0x5B, | ||
1108 | 0xD6,0xE5,0xFD,0x4F,0xC3,0xFB,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF, | ||
1109 | 0xB4,0xFF,0xFA,0xBC,0x8F,0xB2,0xE9,0xD2, 0x2E,0xCF,0xFB,0xFF,0xBF,0xEF,0xFB,0xFE, | ||
1110 | 0xFF,0xBF,0xEF,0xFB,0xFF,0xEC,0xFF,0xFD, 0xFD,0x7F,0xDF,0xF7,0xE4,0xDF,0x5F,0xFF, | ||
1111 | 0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xC3,0xFF,0xEF,0xE6,0xF8,0xFE, | ||
1112 | 0x3F,0x8B,0x83,0xF9,0xFE,0x7F,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x17, | ||
1113 | 0xFD,0xFF,0xFF,0xFF,0x7F,0x5F,0xF7,0x2C, 0xFF,0xFF,0xFF,0xFE,0x7F,0xFF,0xE7,0xF9, | ||
1114 | 0xFE,0x7F,0x9F,0xFE,0x2F,0xFF,0xFF,0xEF, 0xFF,0xFE,0xBF,0xEF,0xAD,0xFF,0xFF,0x7F, | ||
1115 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFE,0xDF,0xFF,0xDF,0xFF,0xFD,0xFD,0x7F, | ||
1116 | 0xDF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0x3F,0xFE, | ||
1117 | 0xF7,0xFD,0xEF,0x7A,0xFF,0xB1,0xBD,0xFF, 0x7F,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD, | ||
1118 | 0xFF,0x7F,0xF3,0x27,0xFF,0xDF,0xFF,0xDD, 0xFF,0xFC,0x9B,0xFF,0xCB,0xFC,0xBF,0x2F, | ||
1119 | 0xCB,0xF2,0xFC,0xBF,0x2F,0xC9,0xFF,0xDE, 0xFF,0xDF,0xAF,0xEB,0xDA,0xFE,0xBB,0xAF, | ||
1120 | 0xEB,0xF8,0xF7,0xAF,0xE8,0xFA,0xFE,0xBF, 0xAF,0xEB,0xF2,0xFF,0xFD,0xFF,0xFF,0xEF, | ||
1121 | 0xBD,0xD7,0xBF,0xFF,0xFF,0xDE,0x8F,0xB8, 0xDE,0x37,0x8D,0xA3,0x78,0xDA,0x3F,0x8F, | ||
1122 | 0xFF,0xA1,0xFF,0xFF,0xFB,0xFB,0xFF,0xFF, 0xFF,0xFF,0xA7,0xBD,0xFB,0x76,0xFD,0xBF, | ||
1123 | 0xEF,0xDB,0xFE,0xBB,0xBF,0xFE,0x27,0x7F, 0xFF,0xFE,0xFE,0xFD,0xF5,0xFF,0xEF,0xF5, | ||
1124 | 0xDF,0x1F,0xE7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xFF,0xCD,0xFD,0xAE,0xFF,0xFA, | ||
1125 | 0x3E,0x3F,0xAB,0xFD,0xF8,0x7E,0x8F,0xE3, 0xF8,0xFE,0x3E,0x8F,0xE3,0xF8,0xFF,0xFE, | ||
1126 | 0x1F,0xEF,0xDF,0xBF,0xFE,0xDE,0xDF,0xD9, 0xFF,0xDF,0xBC,0xFF,0xFF,0x7F,0xFF,0xEF, | ||
1127 | 0xFD,0x7F,0xDF,0xF7,0xF9,0x3F,0xFE,0xFF, 0xFF,0x6F,0xFE,0xDE,0xBF,0xF7,0xED,0xEA, | ||
1128 | 0xFD,0x8F,0x83,0xF8,0xEA,0x3F,0x8F,0xEF, 0xFF,0xF4,0x7F,0xFF,0xEF,0xEF,0x7B,0xF3, | ||
1129 | 0xF1,0x5F,0xFF,0xFF,0xF1,0x3B,0x7F,0xDF, 0xF7,0xFD,0xFF,0xFF,0xFF,0xFF,0xE0,0xFF, | ||
1130 | 0xFF,0xFF,0xF7,0xFF,0x6F,0xFF,0x7F,0xFF, 0xFF,0xF7,0xDE,0xF7,0xBF,0xEF,0xFB,0xF7, | ||
1131 | 0xFD,0xFF,0xFF,0xF5,0xFA,0xFF,0xFF,0xFB, 0xE7,0xFF,0xF3,0xF8,0x7F,0xF3,0xDF,0xFF, | ||
1132 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0xEF, 0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, | ||
1133 | 0xFF,0x7F,0xFF,0x9F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xCF,0xFF,0x37,0xFF,0xFF, | ||
1134 | 0x7F,0xDF,0x77,0x5D,0xE7,0xFC,0xFF,0xBF, 0xF7,0xF5,0xFB,0xFF,0xFF,0xD7,0xF5,0xFB, | ||
1135 | 0xFF,0xFF,0x45,0xFD,0x7F,0xEA,0xFD,0xBE, 0xBF,0xDF,0xF7,0xFF,0xFF,0xDB,0xFB,0xFE, | ||
1136 | 0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0xFB,0x5F, 0x7F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
1137 | 0xFF,0xFE,0xFF,0xEF,0xFD,0xFF,0x7F,0xDF, 0xFF,0xEF,0xFB,0xF8,0x0F,0xF3,0xFF,0xF9, | ||
1138 | 0x2E,0xFB,0xFE,0xFC,0xF3,0xEF,0xFF,0xFF, 0xBF,0xFF,0xFB,0xE7,0xFF,0xFE,0x7E,0xFF, | ||
1139 | 0xC0,0x6B,0xCF,0xFF,0x34,0xDF,0xF1,0xFD, 0xFF,0xEF,0xFF,0xFF,0xFF,0xDF,0xF7,0xFD, | ||
1140 | 0xCF,0x7F,0x9C,0xFD,0xFD,0x6C,0xF7,0xFF, 0xF6,0xFD,0xEB,0x2B,0x9F,0xFF,0xFC,0xFE, | ||
1141 | 0x7E,0xFF,0xFF,0xFF,0xFF,0xD7,0xF3,0xF7, 0xFF,0xFB,0xE1,0xBF,0xFF,0xEB,0x7A,0xDE, | ||
1142 | 0xD7,0xFB,0xFF,0xF9,0xFE,0xFF,0xFF,0xF3, 0xDE,0x7F,0xFD,0xE7,0x7F,0xFF,0xFD,0xBB, | ||
1143 | 0xFF,0xFF,0x7E,0xCC,0xF6,0xAF,0x5F,0x7F, 0xFE,0xF4,0x7D,0xF7,0xFD,0xBB,0x6E,0xDB, | ||
1144 | 0xB7,0xFF,0xF7,0xDF,0x66,0xFF,0xFF,0xF7, 0x3D,0xCF,0xDE,0xBD,0xFF,0xFF,0xDE,0xDB, | ||
1145 | 0x8D,0xF7,0x7E,0xDF,0xB7,0xEF,0x7F,0xFF, 0xF6,0x87,0xFF,0xFF,0xEF,0xFE,0xDE,0xBF, | ||
1146 | 0xFF,0xFF,0xFF,0xBB,0xEF,0xFD,0xFF,0x7B, 0xDE,0xF7,0x3F,0xFF,0xBF,0xFB,0xDB,0xFF, | ||
1147 | 0xF2,0xB6,0xFD,0xBD,0x7F,0xE7,0xFF,0xFF, 0xFF,0x6F,0xF7,0xFF,0xFF,0xFF,0xFE,0x77, | ||
1148 | 0xFF,0xBF,0xF8,0xAF,0xFF,0xDF,0xBF,0xFF, 0xBF,0x7F,0xFB,0xFF,0xFF,0xFF,0xDB,0xFE, | ||
1149 | 0xFF,0xBF,0xFF,0xFA,0xFF,0xFD,0xFF,0xF6, 0x7F,0xFF,0x9F,0xFF,0xFF,0x3F,0xEF,0xF8, | ||
1150 | 0xEE,0x7E,0x9F,0xBA,0xFE,0xBF,0x8F,0xEF, 0xFE,0xFE,0xF9,0xFF,0xFA,0x7F,0xFE,0x7E, | ||
1151 | 0xBF,0xAF,0xFB,0x96,0xFD,0x9F,0xEF,0x5E, 0x65,0xBE,0xEF,0x5B,0xB6,0xFF,0xBE,0xE3, | ||
1152 | 0xFF,0xB5,0xBF,0xFF,0xFD,0xFF,0x7F,0xFF, 0xEF,0xDF,0xFE,0xFF,0xBF,0xFB,0xFE,0xFF, | ||
1153 | 0xBF,0xCF,0xFF,0xFF,0xFF,0xFD,0x9B,0xFF, 0xFE,0xFB,0xFE,0xDF,0xFF,0x7F,0xFF,0xF7, | ||
1154 | 0xFE,0xFF,0xDF,0xFB,0xFB,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xB7,0xFE,0xFA,0xFF,0xAB, | ||
1155 | 0xEF,0xFF,0xFD,0xB5,0x7B,0x7F,0xFB,0xF7, 0xFD,0xFF,0xFF,0xDD,0xFF,0xEF,0x8F,0xFF, | ||
1156 | 0x2F,0xFF,0xFB,0x7C,0xFF,0x3F,0xDF,0x73, 0xEB,0xFE,0x3F,0xFF,0xEF,0xFB,0xFE,0xFF, | ||
1157 | 0xEF,0xFD,0xFF,0xBF,0xFD,0x0F,0xFF,0xFF, 0xFF,0xF5,0xF9,0xFF,0x7F,0xD7,0xFD,0xFF, | ||
1158 | 0xDF,0xFF,0xF7,0xFB,0xFF,0x7F,0xBF,0xFF, 0xFF,0xF0,0x9F,0xFF,0xFE,0x7F,0x8B,0xE3, | ||
1159 | 0xF9,0xDE,0x27,0x9B,0xE6,0xBE,0x7F,0x9B, 0xC3,0xF8,0xDE,0x7F,0x9D,0xE7,0xFE,0x7F, | ||
1160 | 0xFF,0xFF,0x5F,0xD7,0xFF,0xFF,0xFF,0x4F, 0xFB,0xFF,0xFF,0x7F,0xFF,0xAF,0xFF,0x9F, | ||
1161 | 0x7F,0xFB,0xFF,0xE8,0xFF,0xFF,0xFE,0xBF, 0xAF,0xFF,0xFF,0xFE,0xBF,0xEF,0xF7,0xFF, | ||
1162 | 0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFC,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF, | ||
1163 | 0xFD,0x3F,0xCF,0xFF,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFD,0x7F,0xFF,0xFF,0x93,0xFF,0xFF, | ||
1164 | 0x7A,0xDF,0xF7,0xFF,0xFF,0x7B,0x7F,0xB7, 0xEF,0xFF,0xFF,0xFD,0xBF,0xFD,0xFB,0xFF, | ||
1165 | 0xF7,0xFF,0xD7,0xFF,0xFF,0xFF,0xFC,0x9F, 0x6F,0xCB,0xFF,0xF4,0xBB,0xDF,0xD6,0xFD, | ||
1166 | 0xBF,0x2F,0xD3,0xF7,0xFF,0xDF,0xFF,0xCF, 0xFF,0xFA,0xBE,0xBD,0xAF,0x6A,0xDA,0xBE, | ||
1167 | 0xBB,0xAB,0x3A,0xBE,0x2D,0xAE,0xEB,0xDA, 0xF6,0x3F,0xAD,0xF5,0xDD,0xFF,0xCF,0xF1, | ||
1168 | 0xFF,0xF9,0x7F,0xFF,0x73,0xFE,0xFF,0xCF, 0xC3,0xF4,0xF7,0x2F,0xF3,0xFF,0xFC,0xFF, | ||
1169 | 0x7C,0x1F,0xFF,0x3F,0x4F,0xFF,0x7E,0xFF, 0xEF,0xBD,0xF6,0xFE,0xFF,0x2B,0xEF,0xDC, | ||
1170 | 0xFB,0xFD,0xFF,0xFB,0xFF,0xEA,0x7B,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xF7,0xDF,0xFF, | ||
1171 | 0xE3,0x7D,0xFF,0xB7,0xFF,0xBF,0xFF,0xFF, 0xDF,0xFF,0xF8,0xFF,0xBF,0xFF,0xBF,0xEB, | ||
1172 | 0xE7,0xFA,0xFE,0x3D,0xBF,0xE9,0xFC,0xBF, 0xFF,0xFA,0xFB,0xFE,0xFF,0xFF,0xFF,0xD9, | ||
1173 | 0xFF,0xFF,0xFF,0xF6,0x7F,0xFF,0xF6,0x7D, 0xFF,0xDF,0xCF,0xFD,0xBF,0xFB,0xEF,0x7E, | ||
1174 | 0xFF,0x7F,0xFF,0xFF,0xD3,0xFF,0xFD,0xFB, 0xFF,0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xBF, | ||
1175 | 0xFE,0xFF,0xF7,0xEF,0xFF,0xFF,0xFF,0xFB, 0xFF,0x87,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF, | ||
1176 | 0x7B,0xFE,0xFF,0xFE,0x3B,0xF7,0xF7,0xFF, 0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF, | ||
1177 | 0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFF,0xAD,0xFF,0xFE,0xF7,0xFF,0xFF, | ||
1178 | 0x5F,0xFF,0xFF,0xDF,0xFF,0xFD,0xFF,0xF5, 0xFF,0xDF,0xFF,0xBD,0xFF,0xE9,0xFF,0xC7, | ||
1179 | 0xF3,0xFF,0xFF,0xF7,0xFF,0xF3,0xFF,0xF8, 0x3B,0xFF,0xFF,0x7B,0xDF,0xBF,0xFB,0xEF, | ||
1180 | 0xFB,0xFF,0xFB,0xF7,0xF7,0xBB,0xFF,0xFF, 0xFF,0xFF,0xFB,0xFF,0xFE,0x7F,0xF3,0x7F, | ||
1181 | 0x5E,0xB7,0xBF,0xFD,0x7F,0xFF,0xF9,0x7F, 0xFB,0xFF,0xEB,0xFD,0x7F,0x7F,0xFF,0xEF, | ||
1182 | 0xFB,0xE0,0x3F,0xFE,0xBF,0xBF,0xDF,0xFF, 0x7E,0xFF,0xF7,0xFF,0xFF,0xFE,0xBF,0xFF, | ||
1183 | 0xDB,0x78,0xFF,0xFF,0xFF,0xEE,0xA1,0xBF, 0xF5,0xDE,0xFB,0xF7,0xFF,0xFB,0xFF,0xFF, | ||
1184 | 0xFF,0xFF,0xFB,0xFF,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xEF,0xF0,0xFF,0xFF,0xFF,0xF3, | ||
1185 | 0xF7,0xFF,0xEF,0xFF,0xE7,0xCF,0xFF,0xFB, 0xFF,0xEF,0xFF,0xFF,0x9F,0x9F,0xEF,0xFC, | ||
1186 | 0x16,0xBF,0xFE,0xF3,0xE4,0xFF,0xFF,0xC6, 0xFF,0xE7,0xFF,0xFF,0xFD,0xFF,0xBF,0xFF, | ||
1187 | 0xFF,0x3F,0xFF,0xBF,0xD6,0xAF,0x7F,0xFE, 0x6B,0x7E,0x7F,0xFF,0xAF,0xFF,0xFF,0xBF, | ||
1188 | 0xFF,0x5F,0xFF,0xFE,0xFF,0xFF,0xFE,0xFF, 0xFF,0xBD,0xDB,0xFF,0xFE,0x5F,0xF2,0xFF, | ||
1189 | 0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xEF,0x7F,0xFF,0xFF,0xFF,0xFF,0xDE,0xBF, | ||
1190 | 0xFF,0xFF,0xEF,0xFB,0x77,0xFE,0xBD,0x7F, 0x5F,0xFF,0xFF,0xFF,0xDF,0x6F,0xED,0xFF, | ||
1191 | 0xFD,0xFF,0x7F,0xFD,0x6F,0xFF,0xFF,0x77, 0xDA,0xCF,0xFD,0x5F,0xFF,0xBF,0xFF,0xFF, | ||
1192 | 0xDF,0x7F,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF, 0x66,0x7F,0xFF,0xFE,0xBF,0xE7,0xBF,0xFA, | ||
1193 | 0xFF,0xFE,0xFF,0xFF,0xFF,0xDF,0xFF,0x59, 0xEF,0xFF,0xEF,0xFB,0x7F,0x89,0xFF,0xFF, | ||
1194 | 0xE9,0xFF,0x6F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xFF,0xFF,0x7F,0xF2,0xF7,0xFF,0xFF,0xEF, | ||
1195 | 0xF8,0x7F,0xFB,0xFF,0xFD,0xFF,0xFF,0xD9, 0xFF,0xEF,0xBB,0xFF,0xFF,0xFF,0xBF,0xEF, | ||
1196 | 0xDE,0xFF,0xFF,0x9F,0x7F,0xDF,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xAF, | ||
1197 | 0xFF,0xFF,0xF7,0x3F,0xEB,0x9F,0xFE,0x7F, 0x9E,0x7F,0x9F,0xFE,0x87,0xFF,0xED,0xDB, | ||
1198 | 0x56,0xFF,0xBF,0xAF,0x0B,0xD2,0xFF,0xEF, 0xDB,0x6E,0x7D,0xBD,0x6F,0xF8,0xFE,0x3F, | ||
1199 | 0xFA,0x5B,0xFF,0xFD,0xBF,0xEF,0xFF,0xBF, 0x6F,0xDB,0xE6,0xFF,0xFF,0x3F,0xFF,0xDF, | ||
1200 | 0xFE,0xFF,0xFF,0xFF,0xFF,0xDA,0x3F,0xFF, 0xFB,0xFE,0xFE,0xFF,0xFF,0xDF,0xF7,0xBD, | ||
1201 | 0xFF,0xFD,0xFF,0xFE,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xF1,0x5F,0xFD,0x9F,0xDF,0xFD, | ||
1202 | 0xFF,0xFD,0x7F,0xFF,0xFF,0xFF,0xFF,0x76, 0xFA,0xFF,0xFF,0x7F,0xE3,0xF8,0xFF,0xAE, | ||
1203 | 0xFF,0xFB,0x7E,0x9D,0x73,0xFF,0xFA,0x7F, 0xDF,0xFF,0xFF,0x7F,0xFF,0xFB,0xCD,0xFF, | ||
1204 | 0x7F,0xEF,0xFB,0xFF,0xFD,0xFF,0xF7,0x7F, 0x7F,0xEF,0xFF,0xED,0xFF,0xFF,0xFF,0xB5, | ||
1205 | 0xFF,0xBF,0xFF,0xBF,0xFD,0xEF,0xDB,0xF7, 0xFF,0x93,0xFF,0xEF,0xE2,0xF9,0xBE,0x7F, | ||
1206 | 0x8B,0xE7,0xF9,0xFE,0x6B,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x47,0xFF, | ||
1207 | 0xFF,0xFD,0xFF,0x9F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xF5,0xFF,0x9F,0xFF,0xF7,0xFE, | ||
1208 | 0xFF,0xBF,0xFE,0x6F,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xAF,0xFF,0xFF,0xFF,0x7F,0xFB, | ||
1209 | 0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xDF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF,0xDF, | ||
1210 | 0xFF,0xFF,0xFF,0x5F,0xFF,0xFF,0xFF,0xFF, 0x5F,0xFB,0xFE,0xFF,0xF8,0x37,0xFF,0xFF, | ||
1211 | 0xEF,0xFF,0x7F,0xFE,0xBF,0xFF,0xFF,0xFE, 0xBF,0xFF,0xFF,0x7F,0xFF,0xBF,0xFD,0xFF, | ||
1212 | 0x7F,0xFA,0x7F,0xFF,0xFF,0x6F,0xFF,0xFF, 0x7D,0xFF,0xCF,0xFF,0xFF,0xFF,0x4F,0xFF, | ||
1213 | 0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0xBF, 0xFF,0xAE,0xEB,0xFA,0xFE,0xBB,0xAD,0xEB, | ||
1214 | 0xFA,0xF7,0xAF,0x6B,0xFA,0xF6,0xBF,0x25, 0xE9,0xF2,0x7F,0x45,0xFF,0xFF,0xFD,0xF7, | ||
1215 | 0xF7,0xBF,0xFF,0xDF,0xFF,0xFF,0xBF,0xFB, 0xFF,0xDF,0xF3,0xFF,0xF7,0x3F,0xCF,0xFF, | ||
1216 | 0xA1,0xFF,0xFF,0xBF,0xE7,0xFF,0xFF,0x7F, 0xFF,0x3D,0xFF,0xFF,0xFF,0xF7,0xFF,0x2F, | ||
1217 | 0xFF,0xFB,0xF5,0x7F,0xFE,0x57,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7, | ||
1218 | 0x3F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD,0xFE, 0xF7,0xEE,0xAF,0xFE,0xEE,0xE7,0xFA,0xFF, | ||
1219 | 0xFE,0x9D,0xF9,0x5E,0xFE,0xFF,0xEB,0xFF, 0xFF,0xDF,0xA7,0xFF,0xFF,0xFF,0xFC,0xDB, | ||
1220 | 0xFF,0xFF,0xFF,0x7E,0xFB,0xFF,0xFF,0xEF, 0xFB,0xFD,0xFF,0xDB,0xFF,0xFF,0xFF,0xEF, | ||
1221 | 0xFF,0xFF,0xFF,0xFD,0xBF,0xFE,0xBF,0xFF, 0x6F,0x7F,0xFF,0xF7,0xFF,0xFF,0xF9,0xFF, | ||
1222 | 0xF7,0xFF,0xBF,0xDE,0xF7,0xFF,0xFF,0xFF, 0xFA,0x7F,0xFD,0xBF,0x5F,0xFF,0xFF,0xBF, | ||
1223 | 0xFF,0xED,0xFF,0xF7,0xBF,0xFF,0xFF,0xEF, 0xFF,0xDF,0xFF,0xFF,0xFF,0xE6,0xFF,0xFB, | ||
1224 | 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEB,0xFF, | ||
1225 | 0xFD,0xFF,0xF5,0xFF,0xF6,0x7F,0xDF,0xBD, 0xCF,0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF, | ||
1226 | 0xFF,0xF9,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3, 0xFF,0xEE,0xBF,0xFF,0x7D,0xEF,0xFE,0xFF, | ||
1227 | 0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFE, 0xFF,0xFF,0xFF,0xFF,0xE7,0xFF,0xB5,0xAE, | ||
1228 | 0xFF,0xFF,0xB6,0xFE,0xBF,0xFF,0xFF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
1229 | 0xFF,0x27,0xFF,0xEF,0xFE,0x7F,0xDF,0xFF, 0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
1230 | 0xFF,0xFF,0xFD,0xFF,0xF7,0xF9,0x9F,0xFF, 0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, | ||
1231 | 0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x0F,0xFF,0xE7,0xBF,0xFE, | ||
1232 | 0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFC,0xBF, 0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xC4, | ||
1233 | 0x6B,0xFF,0x29,0x1F,0xFB,0xAF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0x1B,0xFE,0xFF,0xFC, | ||
1234 | 0x6F,0xFF,0xFF,0xFD,0x6A,0xF7,0xD7,0xF5, 0xBF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
1235 | 0xFE,0xBF,0xFF,0xFF,0xFA,0xFF,0xFF,0xF7, 0xFB,0xDD,0xBF,0xFF,0xE7,0xFF,0xFF,0xFF, | ||
1236 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0x7F,0xFF, 0xFF,0xF5,0xFF,0xFF,0xF7,0xFD,0xB3,0xEF, | ||
1237 | 0xFD,0x7E,0x5D,0xFF,0xFD,0xFF,0xFF,0xFF, 0xFD,0x7F,0xD2,0xF5,0xFB,0x7E,0xCB,0xB7, | ||
1238 | 0xFF,0xFF,0xFF,0xC6,0xFF,0xFD,0xEE,0x63, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xFD,0x65, | ||
1239 | 0x5B,0xDF,0xFF,0xD5,0xFF,0xFF,0xFF,0xF6, 0xE7,0xBF,0xF7,0xA9,0xFF,0xFF,0xED,0xFF, | ||
1240 | 0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFF,0xFF, 0xAF,0xFF,0xFF,0xFF,0xF8,0x1B,0xFF,0xE3, | ||
1241 | 0xD0,0xBF,0xFF,0xE1,0xFF,0xFF,0xFF,0xFF, 0xFF,0xD7,0xFF,0xFF,0xFF,0x5F,0xFF,0xFF, | ||
1242 | 0xFF,0xFF,0xAF,0xFF,0xDB,0x76,0xBF,0xFF, 0x7F,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF, | ||
1243 | 0xFB,0xFE,0xFF,0xFF,0xFF,0xBF,0xF2,0x7F, 0xFF,0x9F,0xFE,0xBD,0xFE,0x7F,0xFF,0xFF, | ||
1244 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF7,0x3F,0xEC,0x7F,0xF6,0x95,0xBB, | ||
1245 | 0xEF,0xF8,0xFE,0xFC,0xBF,0x2F,0xDA,0xFC, 0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xEF,0xFF, | ||
1246 | 0xA9,0xBF,0xCF,0xFB,0xFF,0xFF,0xFF,0xFE, 0xDD,0xB7,0x6D,0xF6,0xD9,0xB6,0x6D,0x9B, | ||
1247 | 0x76,0xD9,0xBF,0xFB,0xFD,0xA3,0xFF,0xBF, 0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0x7F,0xDF, | ||
1248 | 0xFD,0xEF,0x7B,0xDE,0xF7,0xFD,0xEF,0x7F, 0xFF,0xFF,0x05,0xFF,0xFA,0xFE,0x7F,0xEF, | ||
1249 | 0xE3,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF, 0xFF,0x5F,0xFF,0xFF,0xFD,0x7F,0xFB,0xAF, | ||
1250 | 0xFF,0x63,0xC8,0xFF,0xBF,0xEF,0xFF,0xFF, 0xFA,0x7F,0xFF,0xFF,0xFF,0xFE,0x9F,0xF7, | ||
1251 | 0xFF,0xFA,0xBF,0xFE,0x9F,0xFB,0x7F,0xFF, 0xFF,0xEF,0xD7,0xFF,0xFF,0xF5,0xFF,0xFF, | ||
1252 | 0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xBF,0xFF, 0xF9,0xBF,0xFF,0xBE,0x27,0x9F,0xE7,0xF9, | ||
1253 | 0xFE,0x7F,0x8B,0xE7,0xFE,0x7F,0x9F,0xE2, 0xF9,0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF, | ||
1254 | 0xFF,0xFF,0xFB,0xFE,0xFF,0xFF,0xFF,0xD7, 0xFF,0xFF,0xFF,0xFF,0xF5,0xFF,0xFF,0xFF, | ||
1255 | 0xD7,0xFF,0xFA,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF,0xAF,0xF7,0xFF,0xFF, | ||
1256 | 0xFF,0xEB,0xFF,0xFF,0xFF,0xAF,0xFF,0xC4, 0xFF,0xF7,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF, | ||
1257 | 0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xD7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFB,0x7A, | ||
1258 | 0xDF,0xF7,0xFD,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0x7F,0xFF,0xAF,0xFF,0xFF,0xFF,0xF7, | ||
1259 | 0xEF,0xE3,0xFF,0xDD,0xD2,0xFF,0xDF,0xFF, 0xFF,0xF2,0xFC,0xBF,0xCB,0xF6,0xFD,0xBF, | ||
1260 | 0x2F,0xCB,0xFF,0x7F,0xDF,0xDE,0xAF,0xFF, 0xDA,0xEE,0xBF,0xAF,0xE9,0xFA,0xF4,0xBD, | ||
1261 | 0xAF,0x5A,0xAE,0xBB,0xAB,0x6B,0xDA,0xDE, 0xBF,0xAD,0xD7,0x5E,0xFF,0xFF,0xBF,0xFC, | ||
1262 | 0xFF,0xDF,0xFD,0xFF,0xFF,0xFF,0xFF,0xDF, 0xF7,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFA, | ||
1263 | 0x1F,0xFF,0xFE,0xFB,0xEF,0xBF,0xFD,0xFF, 0xFD,0xBD,0x77,0xFF,0xFF,0xFF,0xFF,0x9D, | ||
1264 | 0xEF,0xFF,0xFF,0xFF,0xEF,0x7D,0xFF,0xFB, 0xFE,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7, | ||
1265 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEE, 0xBF,0xE4,0xFB,0xFF,0xFE,0x3F,0xFE,0xFF, | ||
1266 | 0xFF,0xFF,0xFF,0xAF,0xEA,0xFE,0xBF,0xAF, 0xEB,0xFA,0xFE,0xFF,0xFF,0xFF,0x55,0xF6, | ||
1267 | 0xFF,0xFE,0xF7,0xFF,0x7F,0xFF,0xEB,0xF7, 0x5F,0xC5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF, | ||
1268 | 0x6F,0xFB,0xFF,0x8A,0xFF,0xFF,0xFF,0xFF, 0xEB,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0xBF, | ||
1269 | 0xEF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0x77,0xDF,0xFB,0xFF,0xFD,0x7F,0xEF,0xFF, | ||
1270 | 0xFF,0xFF,0xBF,0x7F,0xFF,0xDF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xFF,0xFE,0xEF,0xDF,0xFF, | ||
1271 | 0xFE,0xFF,0x9F,0xEF,0x7D,0xFF,0xF7,0xFF, 0x7F,0xFF,0xFF,0xDF,0xF7,0xFD,0xFF,0xEF, | ||
1272 | 0xDF,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFB, | ||
1273 | 0xFD,0xFF,0xBF,0xDF,0xD1,0xFF,0xF8,0x3B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
1274 | 0x7E,0xDB,0xFD,0xFF,0x77,0xDB,0xB7,0x7D, 0xBF,0xFB,0xFF,0xF8,0x7F,0xED,0x7B,0x5E, | ||
1275 | 0xFF,0xFE,0xFF,0xFF,0x4F,0xD7,0xFD,0x7F, 0xDF,0xD7,0xF5,0xFF,0x7F,0xFF,0xFF,0xFF, | ||
1276 | 0xF2,0x3F,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFF,0xBF,0xEF,0xFE,0xFF,0x3B,0xEE,0xFF, | ||
1277 | 0xFC,0xEF,0xFF,0xFF,0xFF,0x85,0xFF,0xFD, 0xFE,0xFF,0xF5,0xFF,0xFF,0xFE,0xFF,0xDF, | ||
1278 | 0xFB,0xFF,0x5F,0xBF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xA8,0xFF,0xFF,0x9F,0x9E,0xFF, | ||
1279 | 0xFF,0xFF,0x7F,0xF3,0xFF,0xFF,0xCF,0xFF, 0xF7,0xFD,0xFF,0x7F,0xFF,0xFF,0xFC,0x16, | ||
1280 | 0xBF,0xCF,0xA3,0xE5,0xEF,0x7F,0xFF,0xF3, 0xE4,0xFF,0xCF,0x93,0xFC,0xFF,0x3F,0xCF, | ||
1281 | 0xFF,0xFF,0xFF,0xD6,0x0F,0x7D,0xBF,0x6E, 0xFB,0xF4,0xFC,0xAF,0x6D,0xDB,0x77,0xB7, | ||
1282 | 0x6D,0xDB,0xF6,0xFD,0xBF,0xFF,0xFF,0xFF, 0xBF,0x9B,0xFA,0xDE,0xB7,0xB7,0xED,0xF9, | ||
1283 | 0x7E,0xB7,0xAC,0xEB,0xD6,0xB3,0xAD,0xEB, 0x7A,0xDF,0xFF,0xFF,0xFF,0xD8,0xBF,0xFF, | ||
1284 | 0xB7,0xED,0x9F,0x6F,0xDD,0xF7,0x68,0xDB, 0x37,0xB3,0x6C,0xDB,0x36,0xCD,0xB3,0x7F, | ||
1285 | 0xFF,0x7F,0xF5,0x6F,0xFD,0xEF,0x79,0x3D, 0xF7,0x93,0xE4,0x7A,0x9E,0xAD,0xEA,0x7A, | ||
1286 | 0x9E,0xF7,0xBD,0xEF,0xFF,0xFF,0xFF,0x76, 0x7F,0xFB,0xC6,0xFF,0xBB,0xEF,0xDA,0xFE, | ||
1287 | 0xFD,0xBF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xFB,0xFF,0xA5,0xFF,0xFD,0xAB, | ||
1288 | 0x6F,0x78,0xDE,0x17,0x8F,0x79,0xDF,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xFF,0xFB, | ||
1289 | 0xFF,0xFB,0xFF,0xEF,0xFB,0xEF,0xFB,0xFE, 0xFF,0xBB,0xDA,0xF3,0xEF,0x3B,0xCE,0xF3, | ||
1290 | 0xBC,0xEF,0x3F,0xCF,0xDF,0xFF,0xB7,0xFF, 0xFF,0xFF,0xCF,0x73,0xFF,0xBF,0xEF,0xFF, | ||
1291 | 0xF3,0xFF,0x3F,0xCF,0xF3,0xFC,0xFF,0x3D, 0xCF,0x9F,0xFE,0x07,0xFF,0xAF,0xEB,0xFE, | ||
1292 | 0xFD,0xBF,0xEF,0xEB,0xFA,0xFF,0xAF,0xEB, 0xFA,0xFE,0xBF,0xAF,0xFB,0xFE,0x3F,0xFB, | ||
1293 | 0x9B,0xFF,0x7F,0xDF,0xFF,0xF3,0xFE,0xFF, 0xDE,0xF7,0xBF,0x7B,0xDE,0xF7,0xBD,0xEF, | ||
1294 | 0x7B,0xFE,0xFF,0xFF,0xDF,0x3F,0xFE,0xFF, 0xB7,0xFF,0xEF,0xF7,0xFF,0xBF,0xED,0xFE, | ||
1295 | 0xDF,0xB7,0xED,0xFB,0x7E,0xDF,0xFF,0xFF, 0xFF,0xFD,0x5F,0xEF,0xEB,0xFA,0xFE,0xF5, | ||
1296 | 0xBF,0x6F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xF8,0xFF,0xA8,0xFF, | ||
1297 | 0xFF,0xBF,0xEF,0xFB,0x6A,0xFB,0xB7,0xEF, 0xFB,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF, | ||
1298 | 0xEF,0xFB,0xFF,0xE0,0xFF,0xFF,0xFD,0x7F, 0x5C,0xD7,0x7D,0xDF,0xF3,0x5C,0xF5,0xCD, | ||
1299 | 0x73,0x5E,0xD7,0xB5,0xFD,0x7F,0xEF,0xFF, 0xDB,0xFF,0xFF,0xE2,0xF8,0xBE,0x2F,0x8F, | ||
1300 | 0xE7,0xF8,0xBE,0x6B,0xE2,0xF8,0xBE,0x2F, 0x8B,0xE2,0xF9,0xFE,0x7F,0xE7,0xFF,0xD7, | ||
1301 | 0xF5,0xFD,0x7F,0xFF,0xF7,0xF5,0xFD,0x7F, 0xD7,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF, | ||
1302 | 0xFF,0xFF,0x8F,0xFF,0xAF,0xEB,0xFA,0xFF, 0xFF,0xBF,0xEB,0xFA,0xFF,0x2F,0xEB,0xFA, | ||
1303 | 0xFE,0xBF,0xAF,0xEB,0xFF,0xFF,0xFE,0x5F, 0xFF,0x5F,0xFF,0xFF,0xFD,0xFF,0xFF,0xD7, | ||
1304 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFE,0xB7,0xFD, | ||
1305 | 0xFF,0x7E,0xDF,0xF7,0xAD,0xFF,0x7F,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F, | ||
1306 | 0xF6,0x7F,0xFF,0xFF,0xFF,0xDB,0xF6,0xFC, 0xAF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF, | ||
1307 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xEC,0xBF,0xFF, 0xAF,0xEB,0xFA,0xF6,0xAB,0x8F,0xEB,0xFA, | ||
1308 | 0xF7,0xA5,0xEB,0xFA,0xBE,0xBF,0xAF,0xEB, 0xFA,0xFF,0x6D,0xFF,0xFF,0x7F,0xDF,0x33, | ||
1309 | 0xDD,0xFF,0x7F,0xFE,0xF7,0xFC,0x7F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xA9, | ||
1310 | 0xFF,0xFD,0xFF,0xFF,0xFE,0xFF,0xFF,0xDF, 0xFF,0xFF,0xEF,0xEF,0xFD,0xFF,0x7F,0xFF, | ||
1311 | 0xFF,0xFF,0xFF,0xFE,0xA7,0xFF,0xFF,0xFF, 0x77,0xDF,0xF7,0xFD,0x9F,0x7F,0xFE,0x77, | ||
1312 | 0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xAF,0xBF,0xAF,0xFF,0xF9,0xBE,0xBF, | ||
1313 | 0x8F,0xFB,0xFE,0xFE,0xEF,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFF,0xFF,0xFD,0xDF,0x6F, | ||
1314 | 0xEF,0xFF,0x7F,0xFF,0xBF,0xBF,0xDF,0xFF, 0xFC,0xFF,0xDF,0xF7,0xFD,0xEF,0x7F,0xDF, | ||
1315 | 0xFF,0xFF,0xFF,0x3F,0xF6,0xFF,0xCF,0xFF, 0xDB,0xFB,0xF7,0xFF,0xEB,0x7A,0xFF,0xFF, | ||
1316 | 0xFF,0xBF,0xEF,0xFB,0xFF,0xFF,0xFF,0xFE, 0x6D,0xFD,0xFF,0x5F,0xFB,0xFF,0xFF,0xF7, | ||
1317 | 0xFF,0x5F,0xF5,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xF8,0xFF,0xFB,0xFF, | ||
1318 | 0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xE7,0xF6, 0xBF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xFF, | ||
1319 | 0xFF,0xC9,0xFF,0xFF,0xFF,0xBD,0xFF,0xBF, 0xAF,0xEF,0xEF,0x3F,0xD1,0xFC,0x7F,0xFB, | ||
1320 | 0xC7,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3,0xFF, 0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0x77,0xFF, | ||
1321 | 0xDF,0xB7,0xFD,0xF7,0xFD,0xF7,0xFF,0xFF, 0xFF,0xFF,0xFF,0x57,0xFF,0xF7,0xA5,0xFD, | ||
1322 | 0x3F,0xDF,0xBF,0xBF,0xFE,0x7F,0xFF,0xFF, 0xFF,0xDF,0xFA,0xFD,0xFF,0xFF,0xFF,0xFE, | ||
1323 | 0x87,0xFF,0xE9,0xFF,0xFE,0xEF,0xBF,0xEF, 0xFE,0xFE,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF, | ||
1324 | 0xFF,0xFF,0xFF,0xFF,0xFA,0x9F,0xFF,0x3F, 0xFF,0xFD,0xFD,0x57,0xDF,0xFD,0xF3,0xFF, | ||
1325 | 0xDF,0xFD,0xFF,0x5F,0xDF,0xF5,0xFD,0xFF, 0xFF,0xF9,0x8F,0xFF,0xFF,0xFF,0xEE,0x7F, | ||
1326 | 0xFF,0xFF,0xBF,0x5E,0xFE,0xEC,0xFB,0x3F, 0x7F,0x9F,0xEF,0xF9,0xFF,0xFF,0xCD,0x6B, | ||
1327 | 0xFF,0xFF,0xFF,0xC5,0xF3,0xFC,0xFA,0x38, 0xFF,0xAF,0x3F,0xEE,0x7F,0x9F,0xFF,0xD9, | ||
1328 | 0xFF,0xFF,0xFD,0x7A,0xF7,0xFF,0xF3,0xFF, 0xAF,0x6F,0xDB,0xF2,0xB9,0xE9,0xFB,0xFF, | ||
1329 | 0xFF,0xFF,0xFE,0xFF,0xFF,0xEF,0xFF,0xFB, 0xC5,0xBF,0xFF,0xEF,0xFF,0x5E,0xB7,0xAD, | ||
1330 | 0xCD,0x79,0x7C,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0x93,0xFF,0xEF, | ||
1331 | 0xEA,0xFE,0xBF,0xEF,0x5B,0xD2,0xCD,0xF5, 0x6D,0x77,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF, | ||
1332 | 0xFF,0xFF,0x66,0xFF,0xD5,0x65,0x7D,0x5F, 0x75,0x9D,0x65,0x7F,0xD6,0xFB,0x4F,0xFF, | ||
1333 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xC7, 0xFF,0xBF,0xEF,0xFA,0xFE,0xFF,0xBF,0xEB, | ||
1334 | 0xFF,0xDF,0xFF,0x7E,0xFF,0xFF,0xEF,0xFD, 0x7E,0xD7,0xFF,0x78,0xDF,0xFF,0x5F,0xDF, | ||
1335 | 0xF5,0xBF,0x7F,0xDF,0xC5,0xFF,0x3F,0xF6, 0x7E,0xFF,0x0F,0xEF,0xF2,0x3E,0xBF,0xFF, | ||
1336 | 0xFB,0x3F,0xFF,0xFB,0x7F,0xFF,0xB3,0xFE, 0xFB,0xF6,0xFD,0xFF,0xDA,0xF7,0xFD,0xFF, | ||
1337 | 0x7F,0xDF,0xF7,0xBF,0xFF,0xFA,0x7F,0xFF, 0xFF,0xFF,0xFF,0x9F,0xFF,0xF3,0xDC,0xF9, | ||
1338 | 0xBF,0xCE,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7, 0xFF,0xFF,0xE2,0x7F,0xFE,0xFF,0xBF,0xEF, | ||
1339 | 0xEB,0xFA,0xFF,0x9F,0x67,0x1E,0xFF,0x8F, 0xE7,0xF8,0xFE,0x7F,0x8F,0xEF,0xFF,0xBD, | ||
1340 | 0xBF,0xFF,0xFB,0xFF,0xFF,0xDF,0xF7,0xFF, 0xFC,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
1341 | 0xFF,0xFF,0xFF,0xFD,0xB3,0xFF,0xFF,0xEF, 0xFF,0xFF,0xBF,0xED,0xFF,0xFB,0xEE,0xFE, | ||
1342 | 0xFF,0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFF,0xB5,0xFF,0xB7,0xFD,0xFD,0x6E,0xFF, | ||
1343 | 0xFF,0xFE,0xFD,0x2F,0xD8,0xFE,0xBF,0x8F, 0xEB,0xF9,0xFE,0x3F,0xFF,0xFA,0xCF,0xFF, | ||
1344 | 0xE7,0xD9,0xFA,0xBF,0xDF,0x77,0xFC,0xFB, 0x3F,0xAB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFE, | ||
1345 | 0xFF,0xFF,0xEE,0x1F,0xFF,0xDF,0xF7,0xFF, 0xFF,0xFF,0x5F,0x97,0x35,0xBF,0x5E,0xFE, | ||
1346 | 0xBF,0xEF,0xFF,0xF7,0xFD,0xFF,0xFF,0xFA, 0xBF,0xFF,0xBE,0x6F,0x9F,0xE7,0xF8,0xBE, | ||
1347 | 0x2F,0x8B,0x66,0x94,0x7D,0x9D,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF,0xFF, | ||
1348 | 0xFF,0xF7,0xF5,0xFD,0x7F,0x5F,0xFB,0xFD, 0x9E,0xFF,0xFB,0xFE,0xFF,0xFF,0xEF,0xFF, | ||
1349 | 0xFF,0xA0,0xFF,0xFF,0xFF,0xBF,0xEF,0xEB, 0xFA,0xFE,0xBF,0xB7,0xF7,0xF7,0xFF,0xFF, | ||
1350 | 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xFD,0xFF,0xFF,0xFF,0xD7,0xFF,0xFF,0xFF, | ||
1351 | 0x7F,0xF5,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xFF,0xAB,0xFE,0xFB,0xFE,0xFF, | ||
1352 | 0xF7,0xAF,0xFF,0xFF,0xDE,0xF7,0xEB,0x5F, 0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,0xFF, | ||
1353 | 0xB3,0xFF,0xC9,0xFE,0xFF,0xFF,0xFF,0xFF, 0xD6,0xFF,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF, | ||
1354 | 0xFF,0xFF,0xFF,0xFF,0xFC,0x8F,0xFF,0xBA, 0xBE,0xBF,0xAF,0xEB,0x78,0xFE,0xB7,0xAD, | ||
1355 | 0x3A,0xFE,0xB7,0xAF,0xEB,0x7A,0xFE,0xBF, 0xAF,0xFF,0x9F,0xFF,0xFF,0xDF,0xFC,0xFF, | ||
1356 | 0xFF,0xFE,0xC3,0xFE,0xFF,0xFF,0x33,0xFC, 0xFF,0xBF,0xDF,0xF3,0xFF,0xFF,0xBB,0x9F, | ||
1357 | 0xFF,0xFF,0xFF,0xEB,0xDF,0xFF,0xFF,0xAF, 0xF7,0x6F,0xF9,0xBF,0xEF,0xFD,0xFF,0xFF, | ||
1358 | 0xFF,0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xFD,0xFB,0xF7,0xFF, | ||
1359 | 0xDF,0xF7,0xFF,0xFE,0xEF,0x5F,0xBD,0xFF, 0xFA,0xFF,0xF8,0xFF,0xBF,0xAF,0xFB,0xFE, | ||
1360 | 0xFE,0x3F,0xEF,0xE8,0xFF,0xDF,0xF3,0xFD, 0xFF,0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xFB, | ||
1361 | 0xFD,0xFF,0xAF,0xFF,0xFF,0xFE,0xFE,0xBF, 0xDB,0xFF,0xFF,0xFF,0xBF,0xFF,0xDF,0xFF, | ||
1362 | 0xFD,0xFF,0xCB,0xFF,0xFF,0xFF,0xFF,0xFF, 0xBF,0x6F,0xFF,0x7F,0xB7,0xB3,0xFF,0xFF, | ||
1363 | 0xDF,0xFF,0xFB,0xEF,0xFF,0xFF,0xFF,0x07, 0xFF,0xFB,0xFF,0xFF,0xFF,0xED,0xFF,0xF5, | ||
1364 | 0x7C,0xFF,0x7F,0xFE,0xFF,0xFF,0xEF,0xCF, 0xFF,0xFB,0xFF,0xFF,0x2F,0xFF,0xFF,0xFF, | ||
1365 | 0xFF,0xF3,0xFF,0xFB,0xFF,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF, | ||
1366 | 0xFD,0x1B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFE,0x7C,0xFF,0xFF,0xFF,0xFF, | ||
1367 | 0xEF,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0x7F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
1368 | 0xDB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xFF,0xFF,0xF0,0x7F,0xFF,0xFF,0xFF,0xFF, | ||
1369 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xFE, | ||
1370 | 0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xEF,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF, | ||
1371 | 0xFF,0xFF,0xEF,0xFA,0xB5,0xFF,0xFF,0xFF, 0xF7,0xF7,0xFF,0xFF,0xFF,0xFF,0xDF,0xFB, | ||
1372 | 0xFC,0xFF,0xFF,0xFE,0xFF,0x7F,0xDF,0xBF, 0xFF,0xCB,0xBF,0xF9,0xFE,0x7F,0x9F,0xE7, | ||
1373 | 0xF9,0xFE,0x7F,0x97,0xE1,0xFE,0x79,0x9F, 0xE7,0xFD,0xFE,0x7F,0xDF,0xFE,0x37,0xFF, | ||
1374 | 0xFB,0xDE,0xDE,0xBD,0xEF,0xF3,0xFE,0xFB, 0xAF,0xEB,0xFE,0xFF,0xFF,0xCF,0xFF,0xFE, | ||
1375 | 0xFF,0xBF,0xFF,0x8F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xE7,0xF9,0x5E,0x7F,0xEF,0xFB, | ||
1376 | 0xDA,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD, 0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDF, | ||
1377 | 0xFF,0xFF,0x7F,0xFF,0xFF,0xF7,0xFB,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFC,0x3F,0xFF,0xBF, | ||
1378 | 0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0x7B,0x7F, 0xBF,0xEF,0xFB,0xFE,0xFF,0xB5,0xEF,0xFB, | ||
1379 | 0xBF,0xFA,0x7F,0xFC,0xFF,0x3F,0xCF,0xF3, 0xFC,0xFF,0x3F,0xCF,0xBC,0xFF,0x3F,0xEF, | ||
1380 | 0xF3,0xFC,0xFE,0x3F,0xCF,0xFF,0xEE,0xEF, 0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0x6A,0xD7, | ||
1381 | 0xB7,0xFB,0xF8,0xFF,0xB7,0xEF,0xBA,0xFE, 0xFF,0xBF,0x7F,0xE9,0xFF,0xF9,0x7E,0x5F, | ||
1382 | 0x97,0xE5,0xF9,0xFE,0x7F,0xBF,0xF9,0x7E, 0x5F,0x9F,0xE5,0xFB,0xFE,0x5F,0xB7,0xFF, | ||
1383 | 0xA3,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0x5E,0xF7,0x7D,0xFF,0x77,0xDF, | ||
1384 | 0xF7,0xFD,0xFF,0x7F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xDF,0xFB,0x7F, | ||
1385 | 0xFF,0xFF,0xEF,0xFF,0xFE,0xFB,0xFF,0xFF, 0xBF,0xFE,0x8F,0xFF,0xDF,0xF7,0xFD,0xFD, | ||
1386 | 0x7F,0xDF,0xF7,0xFD,0x3E,0xDF,0xF5,0xBD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xF7,0xFF,0x9F, | ||
1387 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xBE,0xFF,0xFF,0xFF,0xFF, | ||
1388 | 0xFF,0xFF,0xFF,0xFD,0x3F,0xFF,0xDF,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xCF, | ||
1389 | 0x77,0xFC,0xFF,0x5F,0xDF,0xF7,0xFD,0xFF, 0xF4,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
1390 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xFF,0xFF,0xEE,0xFF,0xFF, | ||
1391 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xED,0xFB,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF, | ||
1392 | 0xFF,0xFF,0xE9,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFB,0xFF,0xFF,0xFF,0xD3,0xFF,0xFF, | ||
1393 | 0xBF,0x3F,0xFB,0xFF,0xFF,0xFF,0xFB,0xF3, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
1394 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0x17,0xFF,0xFF,0xFF, | ||
1395 | 0xDF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xDF,0xFF,0xFD,0xFF,0xFF,0xDF,0xF7, | ||
1396 | 0xFF,0x4F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD, | ||
1397 | 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0x9F,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, | ||
1398 | 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFF,0xFF,0x7A,0x3F,0xFF,0xFF,0xFF,0xFF, | ||
1399 | 0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF2, | ||
1400 | 0x7F,0xFF,0xFB,0xFE,0xFF,0xBF,0xEF,0xF8, 0xFE,0xFF,0xBF,0xFB,0xFE,0xFF,0x8F,0xEC, | ||
1401 | 0xFB,0xFE,0xFF,0xBF,0xF8,0xF7,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFD,0xBF,0xCF,0xEC, | ||
1402 | 0xFF,0x3F,0xEF,0xDB,0xF8,0xFF,0xBF,0xCF, 0xFF,0xF9,0xFF,0xFF,0xBF,0xFF,0xFB,0xFF, | ||
1403 | 0xFF,0xFF,0xEF,0xFB,0xDF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xBB,0xFF, | ||
1404 | 0xEF,0xFB,0xFE,0xEF,0xBF,0xEE,0xEB,0xFB, 0xFE,0xFF,0xEF,0xFE,0xEE,0xBF,0xFE,0xEB, | ||
1405 | 0xFF,0xEF,0xFF,0x17,0xFF,0x7E,0xEB,0xBB, 0xFE,0xBF,0xBE,0xFB,0xEF,0x5B,0xF7,0xBD, | ||
1406 | 0xFB,0xCF,0xBF,0xBF,0xBB,0xFB,0x7E,0xCC, 0xEF,0xFF | ||
1407 | |||
1408 | }; | ||
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c new file mode 100644 index 000000000000..1774ab7a40d2 --- /dev/null +++ b/drivers/media/video/dabusb.c | |||
@@ -0,0 +1,874 @@ | |||
1 | /*****************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * dabusb.c -- dab usb driver. | ||
5 | * | ||
6 | * Copyright (C) 1999 Deti Fliegl (deti@fliegl.de) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | * | ||
23 | * | ||
24 | * $Id: dabusb.c,v 1.54 2000/07/24 21:39:39 deti Exp $ | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | /*****************************************************************************/ | ||
29 | |||
30 | #include <linux/module.h> | ||
31 | #include <linux/socket.h> | ||
32 | #include <linux/list.h> | ||
33 | #include <linux/vmalloc.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <asm/uaccess.h> | ||
37 | #include <asm/atomic.h> | ||
38 | #include <linux/delay.h> | ||
39 | #include <linux/usb.h> | ||
40 | #include <linux/smp_lock.h> | ||
41 | #include <linux/mutex.h> | ||
42 | |||
43 | #include "dabusb.h" | ||
44 | #include "dabfirmware.h" | ||
45 | |||
46 | /* | ||
47 | * Version Information | ||
48 | */ | ||
49 | #define DRIVER_VERSION "v1.54" | ||
50 | #define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de" | ||
51 | #define DRIVER_DESC "DAB-USB Interface Driver for Linux (c)1999" | ||
52 | |||
53 | /* --------------------------------------------------------------------- */ | ||
54 | |||
55 | #ifdef CONFIG_USB_DYNAMIC_MINORS | ||
56 | #define NRDABUSB 256 | ||
57 | #else | ||
58 | #define NRDABUSB 4 | ||
59 | #endif | ||
60 | |||
61 | /*-------------------------------------------------------------------*/ | ||
62 | |||
63 | static dabusb_t dabusb[NRDABUSB]; | ||
64 | static int buffers = 256; | ||
65 | static struct usb_driver dabusb_driver; | ||
66 | |||
67 | /*-------------------------------------------------------------------*/ | ||
68 | |||
69 | static int dabusb_add_buf_tail (pdabusb_t s, struct list_head *dst, struct list_head *src) | ||
70 | { | ||
71 | unsigned long flags; | ||
72 | struct list_head *tmp; | ||
73 | int ret = 0; | ||
74 | |||
75 | spin_lock_irqsave (&s->lock, flags); | ||
76 | |||
77 | if (list_empty (src)) { | ||
78 | // no elements in source buffer | ||
79 | ret = -1; | ||
80 | goto err; | ||
81 | } | ||
82 | tmp = src->next; | ||
83 | list_move_tail (tmp, dst); | ||
84 | |||
85 | err: spin_unlock_irqrestore (&s->lock, flags); | ||
86 | return ret; | ||
87 | } | ||
88 | /*-------------------------------------------------------------------*/ | ||
89 | #ifdef DEBUG | ||
90 | static void dump_urb (struct urb *urb) | ||
91 | { | ||
92 | dbg("urb :%p", urb); | ||
93 | dbg("dev :%p", urb->dev); | ||
94 | dbg("pipe :%08X", urb->pipe); | ||
95 | dbg("status :%d", urb->status); | ||
96 | dbg("transfer_flags :%08X", urb->transfer_flags); | ||
97 | dbg("transfer_buffer :%p", urb->transfer_buffer); | ||
98 | dbg("transfer_buffer_length:%d", urb->transfer_buffer_length); | ||
99 | dbg("actual_length :%d", urb->actual_length); | ||
100 | dbg("setup_packet :%p", urb->setup_packet); | ||
101 | dbg("start_frame :%d", urb->start_frame); | ||
102 | dbg("number_of_packets :%d", urb->number_of_packets); | ||
103 | dbg("interval :%d", urb->interval); | ||
104 | dbg("error_count :%d", urb->error_count); | ||
105 | dbg("context :%p", urb->context); | ||
106 | dbg("complete :%p", urb->complete); | ||
107 | } | ||
108 | #endif | ||
109 | /*-------------------------------------------------------------------*/ | ||
110 | static int dabusb_cancel_queue (pdabusb_t s, struct list_head *q) | ||
111 | { | ||
112 | unsigned long flags; | ||
113 | pbuff_t b; | ||
114 | |||
115 | dbg("dabusb_cancel_queue"); | ||
116 | |||
117 | spin_lock_irqsave (&s->lock, flags); | ||
118 | |||
119 | list_for_each_entry(b, q, buff_list) { | ||
120 | #ifdef DEBUG | ||
121 | dump_urb(b->purb); | ||
122 | #endif | ||
123 | usb_unlink_urb (b->purb); | ||
124 | } | ||
125 | spin_unlock_irqrestore (&s->lock, flags); | ||
126 | return 0; | ||
127 | } | ||
128 | /*-------------------------------------------------------------------*/ | ||
129 | static int dabusb_free_queue (struct list_head *q) | ||
130 | { | ||
131 | struct list_head *tmp; | ||
132 | struct list_head *p; | ||
133 | pbuff_t b; | ||
134 | |||
135 | dbg("dabusb_free_queue"); | ||
136 | for (p = q->next; p != q;) { | ||
137 | b = list_entry (p, buff_t, buff_list); | ||
138 | |||
139 | #ifdef DEBUG | ||
140 | dump_urb(b->purb); | ||
141 | #endif | ||
142 | kfree(b->purb->transfer_buffer); | ||
143 | usb_free_urb(b->purb); | ||
144 | tmp = p->next; | ||
145 | list_del (p); | ||
146 | kfree (b); | ||
147 | p = tmp; | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | /*-------------------------------------------------------------------*/ | ||
153 | static int dabusb_free_buffers (pdabusb_t s) | ||
154 | { | ||
155 | unsigned long flags; | ||
156 | dbg("dabusb_free_buffers"); | ||
157 | |||
158 | spin_lock_irqsave(&s->lock, flags); | ||
159 | |||
160 | dabusb_free_queue (&s->free_buff_list); | ||
161 | dabusb_free_queue (&s->rec_buff_list); | ||
162 | |||
163 | spin_unlock_irqrestore(&s->lock, flags); | ||
164 | |||
165 | s->got_mem = 0; | ||
166 | return 0; | ||
167 | } | ||
168 | /*-------------------------------------------------------------------*/ | ||
169 | static void dabusb_iso_complete (struct urb *purb, struct pt_regs *regs) | ||
170 | { | ||
171 | pbuff_t b = purb->context; | ||
172 | pdabusb_t s = b->s; | ||
173 | int i; | ||
174 | int len; | ||
175 | int dst = 0; | ||
176 | void *buf = purb->transfer_buffer; | ||
177 | |||
178 | dbg("dabusb_iso_complete"); | ||
179 | |||
180 | // process if URB was not killed | ||
181 | if (purb->status != -ENOENT) { | ||
182 | unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE); | ||
183 | int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe)); | ||
184 | for (i = 0; i < purb->number_of_packets; i++) | ||
185 | if (!purb->iso_frame_desc[i].status) { | ||
186 | len = purb->iso_frame_desc[i].actual_length; | ||
187 | if (len <= pipesize) { | ||
188 | memcpy (buf + dst, buf + purb->iso_frame_desc[i].offset, len); | ||
189 | dst += len; | ||
190 | } | ||
191 | else | ||
192 | err("dabusb_iso_complete: invalid len %d", len); | ||
193 | } | ||
194 | else | ||
195 | warn("dabusb_iso_complete: corrupted packet status: %d", purb->iso_frame_desc[i].status); | ||
196 | if (dst != purb->actual_length) | ||
197 | err("dst!=purb->actual_length:%d!=%d", dst, purb->actual_length); | ||
198 | } | ||
199 | |||
200 | if (atomic_dec_and_test (&s->pending_io) && !s->remove_pending && s->state != _stopped) { | ||
201 | s->overruns++; | ||
202 | err("overrun (%d)", s->overruns); | ||
203 | } | ||
204 | wake_up (&s->wait); | ||
205 | } | ||
206 | /*-------------------------------------------------------------------*/ | ||
207 | static int dabusb_alloc_buffers (pdabusb_t s) | ||
208 | { | ||
209 | int buffers = 0; | ||
210 | pbuff_t b; | ||
211 | unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE); | ||
212 | int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe)); | ||
213 | int packets = _ISOPIPESIZE / pipesize; | ||
214 | int transfer_buffer_length = packets * pipesize; | ||
215 | int i; | ||
216 | |||
217 | dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d", | ||
218 | pipesize, packets, transfer_buffer_length); | ||
219 | |||
220 | while (buffers < (s->total_buffer_size << 10)) { | ||
221 | b = (pbuff_t) kzalloc (sizeof (buff_t), GFP_KERNEL); | ||
222 | if (!b) { | ||
223 | err("kzalloc(sizeof(buff_t))==NULL"); | ||
224 | goto err; | ||
225 | } | ||
226 | b->s = s; | ||
227 | b->purb = usb_alloc_urb(packets, GFP_KERNEL); | ||
228 | if (!b->purb) { | ||
229 | err("usb_alloc_urb == NULL"); | ||
230 | kfree (b); | ||
231 | goto err; | ||
232 | } | ||
233 | |||
234 | b->purb->transfer_buffer = kmalloc (transfer_buffer_length, GFP_KERNEL); | ||
235 | if (!b->purb->transfer_buffer) { | ||
236 | kfree (b->purb); | ||
237 | kfree (b); | ||
238 | err("kmalloc(%d)==NULL", transfer_buffer_length); | ||
239 | goto err; | ||
240 | } | ||
241 | |||
242 | b->purb->transfer_buffer_length = transfer_buffer_length; | ||
243 | b->purb->number_of_packets = packets; | ||
244 | b->purb->complete = dabusb_iso_complete; | ||
245 | b->purb->context = b; | ||
246 | b->purb->dev = s->usbdev; | ||
247 | b->purb->pipe = pipe; | ||
248 | b->purb->transfer_flags = URB_ISO_ASAP; | ||
249 | |||
250 | for (i = 0; i < packets; i++) { | ||
251 | b->purb->iso_frame_desc[i].offset = i * pipesize; | ||
252 | b->purb->iso_frame_desc[i].length = pipesize; | ||
253 | } | ||
254 | |||
255 | buffers += transfer_buffer_length; | ||
256 | list_add_tail (&b->buff_list, &s->free_buff_list); | ||
257 | } | ||
258 | s->got_mem = buffers; | ||
259 | |||
260 | return 0; | ||
261 | |||
262 | err: | ||
263 | dabusb_free_buffers (s); | ||
264 | return -ENOMEM; | ||
265 | } | ||
266 | /*-------------------------------------------------------------------*/ | ||
267 | static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb) | ||
268 | { | ||
269 | int ret; | ||
270 | unsigned int pipe; | ||
271 | int actual_length; | ||
272 | |||
273 | dbg("dabusb_bulk"); | ||
274 | |||
275 | if (!pb->pipe) | ||
276 | pipe = usb_rcvbulkpipe (s->usbdev, 2); | ||
277 | else | ||
278 | pipe = usb_sndbulkpipe (s->usbdev, 2); | ||
279 | |||
280 | ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 100); | ||
281 | if(ret<0) { | ||
282 | err("dabusb: usb_bulk_msg failed(%d)",ret); | ||
283 | |||
284 | if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) { | ||
285 | err("set_interface failed"); | ||
286 | return -EINVAL; | ||
287 | } | ||
288 | |||
289 | } | ||
290 | |||
291 | if( ret == -EPIPE ) { | ||
292 | warn("CLEAR_FEATURE request to remove STALL condition."); | ||
293 | if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe))) | ||
294 | err("request failed"); | ||
295 | } | ||
296 | |||
297 | pb->size = actual_length; | ||
298 | return ret; | ||
299 | } | ||
300 | /* --------------------------------------------------------------------- */ | ||
301 | static int dabusb_writemem (pdabusb_t s, int pos, unsigned char *data, int len) | ||
302 | { | ||
303 | int ret; | ||
304 | unsigned char *transfer_buffer = kmalloc (len, GFP_KERNEL); | ||
305 | |||
306 | if (!transfer_buffer) { | ||
307 | err("dabusb_writemem: kmalloc(%d) failed.", len); | ||
308 | return -ENOMEM; | ||
309 | } | ||
310 | |||
311 | memcpy (transfer_buffer, data, len); | ||
312 | |||
313 | ret=usb_control_msg(s->usbdev, usb_sndctrlpipe( s->usbdev, 0 ), 0xa0, 0x40, pos, 0, transfer_buffer, len, 300); | ||
314 | |||
315 | kfree (transfer_buffer); | ||
316 | return ret; | ||
317 | } | ||
318 | /* --------------------------------------------------------------------- */ | ||
319 | static int dabusb_8051_reset (pdabusb_t s, unsigned char reset_bit) | ||
320 | { | ||
321 | dbg("dabusb_8051_reset: %d",reset_bit); | ||
322 | return dabusb_writemem (s, CPUCS_REG, &reset_bit, 1); | ||
323 | } | ||
324 | /* --------------------------------------------------------------------- */ | ||
325 | static int dabusb_loadmem (pdabusb_t s, const char *fname) | ||
326 | { | ||
327 | int ret; | ||
328 | PINTEL_HEX_RECORD ptr = firmware; | ||
329 | |||
330 | dbg("Enter dabusb_loadmem (internal)"); | ||
331 | |||
332 | ret = dabusb_8051_reset (s, 1); | ||
333 | while (ptr->Type == 0) { | ||
334 | |||
335 | dbg("dabusb_writemem: %04X %p %d)", ptr->Address, ptr->Data, ptr->Length); | ||
336 | |||
337 | ret = dabusb_writemem (s, ptr->Address, ptr->Data, ptr->Length); | ||
338 | if (ret < 0) { | ||
339 | err("dabusb_writemem failed (%d %04X %p %d)", ret, ptr->Address, ptr->Data, ptr->Length); | ||
340 | break; | ||
341 | } | ||
342 | ptr++; | ||
343 | } | ||
344 | ret = dabusb_8051_reset (s, 0); | ||
345 | |||
346 | dbg("dabusb_loadmem: exit"); | ||
347 | |||
348 | return ret; | ||
349 | } | ||
350 | /* --------------------------------------------------------------------- */ | ||
351 | static int dabusb_fpga_clear (pdabusb_t s, pbulk_transfer_t b) | ||
352 | { | ||
353 | b->size = 4; | ||
354 | b->data[0] = 0x2a; | ||
355 | b->data[1] = 0; | ||
356 | b->data[2] = 0; | ||
357 | b->data[3] = 0; | ||
358 | |||
359 | dbg("dabusb_fpga_clear"); | ||
360 | |||
361 | return dabusb_bulk (s, b); | ||
362 | } | ||
363 | /* --------------------------------------------------------------------- */ | ||
364 | static int dabusb_fpga_init (pdabusb_t s, pbulk_transfer_t b) | ||
365 | { | ||
366 | b->size = 4; | ||
367 | b->data[0] = 0x2c; | ||
368 | b->data[1] = 0; | ||
369 | b->data[2] = 0; | ||
370 | b->data[3] = 0; | ||
371 | |||
372 | dbg("dabusb_fpga_init"); | ||
373 | |||
374 | return dabusb_bulk (s, b); | ||
375 | } | ||
376 | /* --------------------------------------------------------------------- */ | ||
377 | static int dabusb_fpga_download (pdabusb_t s, const char *fname) | ||
378 | { | ||
379 | pbulk_transfer_t b = kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL); | ||
380 | unsigned int blen, n; | ||
381 | int ret; | ||
382 | unsigned char *buf = bitstream; | ||
383 | |||
384 | dbg("Enter dabusb_fpga_download (internal)"); | ||
385 | |||
386 | if (!b) { | ||
387 | err("kmalloc(sizeof(bulk_transfer_t))==NULL"); | ||
388 | return -ENOMEM; | ||
389 | } | ||
390 | |||
391 | b->pipe = 1; | ||
392 | ret = dabusb_fpga_clear (s, b); | ||
393 | mdelay (10); | ||
394 | blen = buf[73] + (buf[72] << 8); | ||
395 | |||
396 | dbg("Bitstream len: %i", blen); | ||
397 | |||
398 | b->data[0] = 0x2b; | ||
399 | b->data[1] = 0; | ||
400 | b->data[2] = 0; | ||
401 | b->data[3] = 60; | ||
402 | |||
403 | for (n = 0; n <= blen + 60; n += 60) { | ||
404 | // some cclks for startup | ||
405 | b->size = 64; | ||
406 | memcpy (b->data + 4, buf + 74 + n, 60); | ||
407 | ret = dabusb_bulk (s, b); | ||
408 | if (ret < 0) { | ||
409 | err("dabusb_bulk failed."); | ||
410 | break; | ||
411 | } | ||
412 | mdelay (1); | ||
413 | } | ||
414 | |||
415 | ret = dabusb_fpga_init (s, b); | ||
416 | kfree (b); | ||
417 | |||
418 | dbg("exit dabusb_fpga_download"); | ||
419 | |||
420 | return ret; | ||
421 | } | ||
422 | |||
423 | static int dabusb_stop (pdabusb_t s) | ||
424 | { | ||
425 | dbg("dabusb_stop"); | ||
426 | |||
427 | s->state = _stopped; | ||
428 | dabusb_cancel_queue (s, &s->rec_buff_list); | ||
429 | |||
430 | dbg("pending_io: %d", s->pending_io.counter); | ||
431 | |||
432 | s->pending_io.counter = 0; | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static int dabusb_startrek (pdabusb_t s) | ||
437 | { | ||
438 | if (!s->got_mem && s->state != _started) { | ||
439 | |||
440 | dbg("dabusb_startrek"); | ||
441 | |||
442 | if (dabusb_alloc_buffers (s) < 0) | ||
443 | return -ENOMEM; | ||
444 | dabusb_stop (s); | ||
445 | s->state = _started; | ||
446 | s->readptr = 0; | ||
447 | } | ||
448 | |||
449 | if (!list_empty (&s->free_buff_list)) { | ||
450 | pbuff_t end; | ||
451 | int ret; | ||
452 | |||
453 | while (!dabusb_add_buf_tail (s, &s->rec_buff_list, &s->free_buff_list)) { | ||
454 | |||
455 | dbg("submitting: end:%p s->rec_buff_list:%p", s->rec_buff_list.prev, &s->rec_buff_list); | ||
456 | |||
457 | end = list_entry (s->rec_buff_list.prev, buff_t, buff_list); | ||
458 | |||
459 | ret = usb_submit_urb (end->purb, GFP_KERNEL); | ||
460 | if (ret) { | ||
461 | err("usb_submit_urb returned:%d", ret); | ||
462 | if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list)) | ||
463 | err("startrek: dabusb_add_buf_tail failed"); | ||
464 | break; | ||
465 | } | ||
466 | else | ||
467 | atomic_inc (&s->pending_io); | ||
468 | } | ||
469 | dbg("pending_io: %d",s->pending_io.counter); | ||
470 | } | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, loff_t * ppos) | ||
476 | { | ||
477 | pdabusb_t s = (pdabusb_t) file->private_data; | ||
478 | unsigned long flags; | ||
479 | unsigned ret = 0; | ||
480 | int rem; | ||
481 | int cnt; | ||
482 | pbuff_t b; | ||
483 | struct urb *purb = NULL; | ||
484 | |||
485 | dbg("dabusb_read"); | ||
486 | |||
487 | if (*ppos) | ||
488 | return -ESPIPE; | ||
489 | |||
490 | if (s->remove_pending) | ||
491 | return -EIO; | ||
492 | |||
493 | |||
494 | if (!s->usbdev) | ||
495 | return -EIO; | ||
496 | |||
497 | while (count > 0) { | ||
498 | dabusb_startrek (s); | ||
499 | |||
500 | spin_lock_irqsave (&s->lock, flags); | ||
501 | |||
502 | if (list_empty (&s->rec_buff_list)) { | ||
503 | |||
504 | spin_unlock_irqrestore(&s->lock, flags); | ||
505 | |||
506 | err("error: rec_buf_list is empty"); | ||
507 | goto err; | ||
508 | } | ||
509 | |||
510 | b = list_entry (s->rec_buff_list.next, buff_t, buff_list); | ||
511 | purb = b->purb; | ||
512 | |||
513 | spin_unlock_irqrestore(&s->lock, flags); | ||
514 | |||
515 | if (purb->status == -EINPROGRESS) { | ||
516 | if (file->f_flags & O_NONBLOCK) // return nonblocking | ||
517 | { | ||
518 | if (!ret) | ||
519 | ret = -EAGAIN; | ||
520 | goto err; | ||
521 | } | ||
522 | |||
523 | interruptible_sleep_on (&s->wait); | ||
524 | |||
525 | if (signal_pending (current)) { | ||
526 | if (!ret) | ||
527 | ret = -ERESTARTSYS; | ||
528 | goto err; | ||
529 | } | ||
530 | |||
531 | spin_lock_irqsave (&s->lock, flags); | ||
532 | |||
533 | if (list_empty (&s->rec_buff_list)) { | ||
534 | spin_unlock_irqrestore(&s->lock, flags); | ||
535 | err("error: still no buffer available."); | ||
536 | goto err; | ||
537 | } | ||
538 | spin_unlock_irqrestore(&s->lock, flags); | ||
539 | s->readptr = 0; | ||
540 | } | ||
541 | if (s->remove_pending) { | ||
542 | ret = -EIO; | ||
543 | goto err; | ||
544 | } | ||
545 | |||
546 | rem = purb->actual_length - s->readptr; // set remaining bytes to copy | ||
547 | |||
548 | if (count >= rem) | ||
549 | cnt = rem; | ||
550 | else | ||
551 | cnt = count; | ||
552 | |||
553 | dbg("copy_to_user:%p %p %d",buf, purb->transfer_buffer + s->readptr, cnt); | ||
554 | |||
555 | if (copy_to_user (buf, purb->transfer_buffer + s->readptr, cnt)) { | ||
556 | err("read: copy_to_user failed"); | ||
557 | if (!ret) | ||
558 | ret = -EFAULT; | ||
559 | goto err; | ||
560 | } | ||
561 | |||
562 | s->readptr += cnt; | ||
563 | count -= cnt; | ||
564 | buf += cnt; | ||
565 | ret += cnt; | ||
566 | |||
567 | if (s->readptr == purb->actual_length) { | ||
568 | // finished, take next buffer | ||
569 | if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list)) | ||
570 | err("read: dabusb_add_buf_tail failed"); | ||
571 | s->readptr = 0; | ||
572 | } | ||
573 | } | ||
574 | err: //mutex_unlock(&s->mutex); | ||
575 | return ret; | ||
576 | } | ||
577 | |||
578 | static int dabusb_open (struct inode *inode, struct file *file) | ||
579 | { | ||
580 | int devnum = iminor(inode); | ||
581 | pdabusb_t s; | ||
582 | |||
583 | if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB)) | ||
584 | return -EIO; | ||
585 | |||
586 | s = &dabusb[devnum - DABUSB_MINOR]; | ||
587 | |||
588 | dbg("dabusb_open"); | ||
589 | mutex_lock(&s->mutex); | ||
590 | |||
591 | while (!s->usbdev || s->opened) { | ||
592 | mutex_unlock(&s->mutex); | ||
593 | |||
594 | if (file->f_flags & O_NONBLOCK) { | ||
595 | return -EBUSY; | ||
596 | } | ||
597 | msleep_interruptible(500); | ||
598 | |||
599 | if (signal_pending (current)) { | ||
600 | return -EAGAIN; | ||
601 | } | ||
602 | mutex_lock(&s->mutex); | ||
603 | } | ||
604 | if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) { | ||
605 | mutex_unlock(&s->mutex); | ||
606 | err("set_interface failed"); | ||
607 | return -EINVAL; | ||
608 | } | ||
609 | s->opened = 1; | ||
610 | mutex_unlock(&s->mutex); | ||
611 | |||
612 | file->f_pos = 0; | ||
613 | file->private_data = s; | ||
614 | |||
615 | return nonseekable_open(inode, file); | ||
616 | } | ||
617 | |||
618 | static int dabusb_release (struct inode *inode, struct file *file) | ||
619 | { | ||
620 | pdabusb_t s = (pdabusb_t) file->private_data; | ||
621 | |||
622 | dbg("dabusb_release"); | ||
623 | |||
624 | mutex_lock(&s->mutex); | ||
625 | dabusb_stop (s); | ||
626 | dabusb_free_buffers (s); | ||
627 | mutex_unlock(&s->mutex); | ||
628 | |||
629 | if (!s->remove_pending) { | ||
630 | if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) | ||
631 | err("set_interface failed"); | ||
632 | } | ||
633 | else | ||
634 | wake_up (&s->remove_ok); | ||
635 | |||
636 | s->opened = 0; | ||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
641 | { | ||
642 | pdabusb_t s = (pdabusb_t) file->private_data; | ||
643 | pbulk_transfer_t pbulk; | ||
644 | int ret = 0; | ||
645 | int version = DABUSB_VERSION; | ||
646 | |||
647 | dbg("dabusb_ioctl"); | ||
648 | |||
649 | if (s->remove_pending) | ||
650 | return -EIO; | ||
651 | |||
652 | mutex_lock(&s->mutex); | ||
653 | |||
654 | if (!s->usbdev) { | ||
655 | mutex_unlock(&s->mutex); | ||
656 | return -EIO; | ||
657 | } | ||
658 | |||
659 | switch (cmd) { | ||
660 | |||
661 | case IOCTL_DAB_BULK: | ||
662 | pbulk = (pbulk_transfer_t) kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL); | ||
663 | |||
664 | if (!pbulk) { | ||
665 | ret = -ENOMEM; | ||
666 | break; | ||
667 | } | ||
668 | |||
669 | if (copy_from_user (pbulk, (void __user *) arg, sizeof (bulk_transfer_t))) { | ||
670 | ret = -EFAULT; | ||
671 | kfree (pbulk); | ||
672 | break; | ||
673 | } | ||
674 | |||
675 | ret=dabusb_bulk (s, pbulk); | ||
676 | if(ret==0) | ||
677 | if (copy_to_user((void __user *)arg, pbulk, | ||
678 | sizeof(bulk_transfer_t))) | ||
679 | ret = -EFAULT; | ||
680 | kfree (pbulk); | ||
681 | break; | ||
682 | |||
683 | case IOCTL_DAB_OVERRUNS: | ||
684 | ret = put_user (s->overruns, (unsigned int __user *) arg); | ||
685 | break; | ||
686 | |||
687 | case IOCTL_DAB_VERSION: | ||
688 | ret = put_user (version, (unsigned int __user *) arg); | ||
689 | break; | ||
690 | |||
691 | default: | ||
692 | ret = -ENOIOCTLCMD; | ||
693 | break; | ||
694 | } | ||
695 | mutex_unlock(&s->mutex); | ||
696 | return ret; | ||
697 | } | ||
698 | |||
699 | static struct file_operations dabusb_fops = | ||
700 | { | ||
701 | .owner = THIS_MODULE, | ||
702 | .llseek = no_llseek, | ||
703 | .read = dabusb_read, | ||
704 | .ioctl = dabusb_ioctl, | ||
705 | .open = dabusb_open, | ||
706 | .release = dabusb_release, | ||
707 | }; | ||
708 | |||
709 | static struct usb_class_driver dabusb_class = { | ||
710 | .name = "dabusb%d", | ||
711 | .fops = &dabusb_fops, | ||
712 | .minor_base = DABUSB_MINOR, | ||
713 | }; | ||
714 | |||
715 | |||
716 | /* --------------------------------------------------------------------- */ | ||
717 | static int dabusb_probe (struct usb_interface *intf, | ||
718 | const struct usb_device_id *id) | ||
719 | { | ||
720 | struct usb_device *usbdev = interface_to_usbdev(intf); | ||
721 | int retval; | ||
722 | pdabusb_t s; | ||
723 | |||
724 | dbg("dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d", | ||
725 | le16_to_cpu(usbdev->descriptor.idVendor), | ||
726 | le16_to_cpu(usbdev->descriptor.idProduct), | ||
727 | intf->altsetting->desc.bInterfaceNumber); | ||
728 | |||
729 | /* We don't handle multiple configurations */ | ||
730 | if (usbdev->descriptor.bNumConfigurations != 1) | ||
731 | return -ENODEV; | ||
732 | |||
733 | if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF && | ||
734 | le16_to_cpu(usbdev->descriptor.idProduct) == 0x9999) | ||
735 | return -ENODEV; | ||
736 | |||
737 | |||
738 | |||
739 | s = &dabusb[intf->minor]; | ||
740 | |||
741 | mutex_lock(&s->mutex); | ||
742 | s->remove_pending = 0; | ||
743 | s->usbdev = usbdev; | ||
744 | s->devnum = intf->minor; | ||
745 | |||
746 | if (usb_reset_configuration (usbdev) < 0) { | ||
747 | err("reset_configuration failed"); | ||
748 | goto reject; | ||
749 | } | ||
750 | if (le16_to_cpu(usbdev->descriptor.idProduct) == 0x2131) { | ||
751 | dabusb_loadmem (s, NULL); | ||
752 | goto reject; | ||
753 | } | ||
754 | else { | ||
755 | dabusb_fpga_download (s, NULL); | ||
756 | |||
757 | if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) { | ||
758 | err("set_interface failed"); | ||
759 | goto reject; | ||
760 | } | ||
761 | } | ||
762 | dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber); | ||
763 | usb_set_intfdata (intf, s); | ||
764 | mutex_unlock(&s->mutex); | ||
765 | |||
766 | retval = usb_register_dev(intf, &dabusb_class); | ||
767 | if (retval) { | ||
768 | usb_set_intfdata (intf, NULL); | ||
769 | return -ENOMEM; | ||
770 | } | ||
771 | |||
772 | return 0; | ||
773 | |||
774 | reject: | ||
775 | mutex_unlock(&s->mutex); | ||
776 | s->usbdev = NULL; | ||
777 | return -ENODEV; | ||
778 | } | ||
779 | |||
780 | static void dabusb_disconnect (struct usb_interface *intf) | ||
781 | { | ||
782 | wait_queue_t __wait; | ||
783 | pdabusb_t s = usb_get_intfdata (intf); | ||
784 | |||
785 | dbg("dabusb_disconnect"); | ||
786 | |||
787 | init_waitqueue_entry(&__wait, current); | ||
788 | |||
789 | usb_set_intfdata (intf, NULL); | ||
790 | if (s) { | ||
791 | usb_deregister_dev (intf, &dabusb_class); | ||
792 | s->remove_pending = 1; | ||
793 | wake_up (&s->wait); | ||
794 | add_wait_queue(&s->remove_ok, &__wait); | ||
795 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
796 | if (s->state == _started) | ||
797 | schedule(); | ||
798 | current->state = TASK_RUNNING; | ||
799 | remove_wait_queue(&s->remove_ok, &__wait); | ||
800 | |||
801 | s->usbdev = NULL; | ||
802 | s->overruns = 0; | ||
803 | } | ||
804 | } | ||
805 | |||
806 | static struct usb_device_id dabusb_ids [] = { | ||
807 | // { USB_DEVICE(0x0547, 0x2131) }, /* An2131 chip, no boot ROM */ | ||
808 | { USB_DEVICE(0x0547, 0x9999) }, | ||
809 | { } /* Terminating entry */ | ||
810 | }; | ||
811 | |||
812 | MODULE_DEVICE_TABLE (usb, dabusb_ids); | ||
813 | |||
814 | static struct usb_driver dabusb_driver = { | ||
815 | .name = "dabusb", | ||
816 | .probe = dabusb_probe, | ||
817 | .disconnect = dabusb_disconnect, | ||
818 | .id_table = dabusb_ids, | ||
819 | }; | ||
820 | |||
821 | /* --------------------------------------------------------------------- */ | ||
822 | |||
823 | static int __init dabusb_init (void) | ||
824 | { | ||
825 | int retval; | ||
826 | unsigned u; | ||
827 | |||
828 | /* initialize struct */ | ||
829 | for (u = 0; u < NRDABUSB; u++) { | ||
830 | pdabusb_t s = &dabusb[u]; | ||
831 | memset (s, 0, sizeof (dabusb_t)); | ||
832 | mutex_init (&s->mutex); | ||
833 | s->usbdev = NULL; | ||
834 | s->total_buffer_size = buffers; | ||
835 | init_waitqueue_head (&s->wait); | ||
836 | init_waitqueue_head (&s->remove_ok); | ||
837 | spin_lock_init (&s->lock); | ||
838 | INIT_LIST_HEAD (&s->free_buff_list); | ||
839 | INIT_LIST_HEAD (&s->rec_buff_list); | ||
840 | } | ||
841 | |||
842 | /* register misc device */ | ||
843 | retval = usb_register(&dabusb_driver); | ||
844 | if (retval) | ||
845 | goto out; | ||
846 | |||
847 | dbg("dabusb_init: driver registered"); | ||
848 | |||
849 | info(DRIVER_VERSION ":" DRIVER_DESC); | ||
850 | |||
851 | out: | ||
852 | return retval; | ||
853 | } | ||
854 | |||
855 | static void __exit dabusb_cleanup (void) | ||
856 | { | ||
857 | dbg("dabusb_cleanup"); | ||
858 | |||
859 | usb_deregister (&dabusb_driver); | ||
860 | } | ||
861 | |||
862 | /* --------------------------------------------------------------------- */ | ||
863 | |||
864 | MODULE_AUTHOR( DRIVER_AUTHOR ); | ||
865 | MODULE_DESCRIPTION( DRIVER_DESC ); | ||
866 | MODULE_LICENSE("GPL"); | ||
867 | |||
868 | module_param(buffers, int, 0); | ||
869 | MODULE_PARM_DESC (buffers, "Number of buffers (default=256)"); | ||
870 | |||
871 | module_init (dabusb_init); | ||
872 | module_exit (dabusb_cleanup); | ||
873 | |||
874 | /* --------------------------------------------------------------------- */ | ||
diff --git a/drivers/media/video/dabusb.h b/drivers/media/video/dabusb.h new file mode 100644 index 000000000000..96b03e4af8b9 --- /dev/null +++ b/drivers/media/video/dabusb.h | |||
@@ -0,0 +1,85 @@ | |||
1 | #define _BULK_DATA_LEN 64 | ||
2 | typedef struct | ||
3 | { | ||
4 | unsigned char data[_BULK_DATA_LEN]; | ||
5 | unsigned int size; | ||
6 | unsigned int pipe; | ||
7 | }bulk_transfer_t,*pbulk_transfer_t; | ||
8 | |||
9 | #define DABUSB_MINOR 240 /* some unassigned USB minor */ | ||
10 | #define DABUSB_VERSION 0x1000 | ||
11 | #define IOCTL_DAB_BULK _IOWR('d', 0x30, bulk_transfer_t) | ||
12 | #define IOCTL_DAB_OVERRUNS _IOR('d', 0x15, int) | ||
13 | #define IOCTL_DAB_VERSION _IOR('d', 0x3f, int) | ||
14 | |||
15 | #ifdef __KERNEL__ | ||
16 | |||
17 | typedef enum { _stopped=0, _started } driver_state_t; | ||
18 | |||
19 | typedef struct | ||
20 | { | ||
21 | struct mutex mutex; | ||
22 | struct usb_device *usbdev; | ||
23 | wait_queue_head_t wait; | ||
24 | wait_queue_head_t remove_ok; | ||
25 | spinlock_t lock; | ||
26 | atomic_t pending_io; | ||
27 | driver_state_t state; | ||
28 | int remove_pending; | ||
29 | int got_mem; | ||
30 | int total_buffer_size; | ||
31 | unsigned int overruns; | ||
32 | int readptr; | ||
33 | int opened; | ||
34 | int devnum; | ||
35 | struct list_head free_buff_list; | ||
36 | struct list_head rec_buff_list; | ||
37 | } dabusb_t,*pdabusb_t; | ||
38 | |||
39 | typedef struct | ||
40 | { | ||
41 | pdabusb_t s; | ||
42 | struct urb *purb; | ||
43 | struct list_head buff_list; | ||
44 | } buff_t,*pbuff_t; | ||
45 | |||
46 | typedef struct | ||
47 | { | ||
48 | wait_queue_head_t wait; | ||
49 | } bulk_completion_context_t, *pbulk_completion_context_t; | ||
50 | |||
51 | |||
52 | #define _DABUSB_IF 2 | ||
53 | #define _DABUSB_ISOPIPE 0x09 | ||
54 | #define _ISOPIPESIZE 16384 | ||
55 | |||
56 | #define _BULK_DATA_LEN 64 | ||
57 | // Vendor specific request code for Anchor Upload/Download | ||
58 | // This one is implemented in the core | ||
59 | #define ANCHOR_LOAD_INTERNAL 0xA0 | ||
60 | |||
61 | // EZ-USB Control and Status Register. Bit 0 controls 8051 reset | ||
62 | #define CPUCS_REG 0x7F92 | ||
63 | #define _TOTAL_BUFFERS 384 | ||
64 | |||
65 | #define MAX_INTEL_HEX_RECORD_LENGTH 16 | ||
66 | |||
67 | #ifndef _BYTE_DEFINED | ||
68 | #define _BYTE_DEFINED | ||
69 | typedef unsigned char BYTE; | ||
70 | #endif // !_BYTE_DEFINED | ||
71 | |||
72 | #ifndef _WORD_DEFINED | ||
73 | #define _WORD_DEFINED | ||
74 | typedef unsigned short WORD; | ||
75 | #endif // !_WORD_DEFINED | ||
76 | |||
77 | typedef struct _INTEL_HEX_RECORD | ||
78 | { | ||
79 | BYTE Length; | ||
80 | WORD Address; | ||
81 | BYTE Type; | ||
82 | BYTE Data[MAX_INTEL_HEX_RECORD_LENGTH]; | ||
83 | } INTEL_HEX_RECORD, *PINTEL_HEX_RECORD; | ||
84 | |||
85 | #endif | ||
diff --git a/drivers/media/video/dsbr100.c b/drivers/media/video/dsbr100.c new file mode 100644 index 000000000000..25646804d5be --- /dev/null +++ b/drivers/media/video/dsbr100.c | |||
@@ -0,0 +1,429 @@ | |||
1 | /* A driver for the D-Link DSB-R100 USB radio. The R100 plugs | ||
2 | into both the USB and an analog audio input, so this thing | ||
3 | only deals with initialisation and frequency setting, the | ||
4 | audio data has to be handled by a sound driver. | ||
5 | |||
6 | Major issue: I can't find out where the device reports the signal | ||
7 | strength, and indeed the windows software appearantly just looks | ||
8 | at the stereo indicator as well. So, scanning will only find | ||
9 | stereo stations. Sad, but I can't help it. | ||
10 | |||
11 | Also, the windows program sends oodles of messages over to the | ||
12 | device, and I couldn't figure out their meaning. My suspicion | ||
13 | is that they don't have any:-) | ||
14 | |||
15 | You might find some interesting stuff about this module at | ||
16 | http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr | ||
17 | |||
18 | Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de> | ||
19 | |||
20 | This program is free software; you can redistribute it and/or modify | ||
21 | it under the terms of the GNU General Public License as published by | ||
22 | the Free Software Foundation; either version 2 of the License, or | ||
23 | (at your option) any later version. | ||
24 | |||
25 | This program is distributed in the hope that it will be useful, | ||
26 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
27 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
28 | GNU General Public License for more details. | ||
29 | |||
30 | You should have received a copy of the GNU General Public License | ||
31 | along with this program; if not, write to the Free Software | ||
32 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
33 | |||
34 | History: | ||
35 | |||
36 | Version 0.40: | ||
37 | Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing | ||
38 | |||
39 | Version 0.30: | ||
40 | Markus: Updates for 2.5.x kernel and more ISO compliant source | ||
41 | |||
42 | Version 0.25: | ||
43 | PSL and Markus: Cleanup, radio now doesn't stop on device close | ||
44 | |||
45 | Version 0.24: | ||
46 | Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally | ||
47 | right. Some minor cleanup, improved standalone compilation | ||
48 | |||
49 | Version 0.23: | ||
50 | Markus: Sign extension bug fixed by declaring transfer_buffer unsigned | ||
51 | |||
52 | Version 0.22: | ||
53 | Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, | ||
54 | thanks to Mike Cox for pointing the problem out. | ||
55 | |||
56 | Version 0.21: | ||
57 | Markus: Minor cleanup, warnings if something goes wrong, lame attempt | ||
58 | to adhere to Documentation/CodingStyle | ||
59 | |||
60 | Version 0.2: | ||
61 | Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module | ||
62 | Markus: Copyright clarification | ||
63 | |||
64 | Version 0.01: Markus: initial release | ||
65 | |||
66 | */ | ||
67 | |||
68 | |||
69 | #include <linux/kernel.h> | ||
70 | #include <linux/module.h> | ||
71 | #include <linux/init.h> | ||
72 | #include <linux/slab.h> | ||
73 | #include <linux/input.h> | ||
74 | #include <linux/videodev.h> | ||
75 | #include <linux/usb.h> | ||
76 | #include <linux/smp_lock.h> | ||
77 | |||
78 | /* | ||
79 | * Version Information | ||
80 | */ | ||
81 | #define DRIVER_VERSION "v0.40" | ||
82 | #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>" | ||
83 | #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver" | ||
84 | |||
85 | #define DSB100_VENDOR 0x04b4 | ||
86 | #define DSB100_PRODUCT 0x1002 | ||
87 | |||
88 | /* Commands the device appears to understand */ | ||
89 | #define DSB100_TUNE 1 | ||
90 | #define DSB100_ONOFF 2 | ||
91 | |||
92 | #define TB_LEN 16 | ||
93 | |||
94 | /* Frequency limits in MHz -- these are European values. For Japanese | ||
95 | devices, that would be 76 and 91. */ | ||
96 | #define FREQ_MIN 87.5 | ||
97 | #define FREQ_MAX 108.0 | ||
98 | #define FREQ_MUL 16000 | ||
99 | |||
100 | |||
101 | static int usb_dsbr100_probe(struct usb_interface *intf, | ||
102 | const struct usb_device_id *id); | ||
103 | static void usb_dsbr100_disconnect(struct usb_interface *intf); | ||
104 | static int usb_dsbr100_ioctl(struct inode *inode, struct file *file, | ||
105 | unsigned int cmd, unsigned long arg); | ||
106 | static int usb_dsbr100_open(struct inode *inode, struct file *file); | ||
107 | static int usb_dsbr100_close(struct inode *inode, struct file *file); | ||
108 | |||
109 | static int radio_nr = -1; | ||
110 | module_param(radio_nr, int, 0); | ||
111 | |||
112 | /* Data for one (physical) device */ | ||
113 | typedef struct { | ||
114 | struct usb_device *usbdev; | ||
115 | struct video_device *videodev; | ||
116 | unsigned char transfer_buffer[TB_LEN]; | ||
117 | int curfreq; | ||
118 | int stereo; | ||
119 | int users; | ||
120 | int removed; | ||
121 | } dsbr100_device; | ||
122 | |||
123 | |||
124 | /* File system interface */ | ||
125 | static struct file_operations usb_dsbr100_fops = { | ||
126 | .owner = THIS_MODULE, | ||
127 | .open = usb_dsbr100_open, | ||
128 | .release = usb_dsbr100_close, | ||
129 | .ioctl = usb_dsbr100_ioctl, | ||
130 | .compat_ioctl = v4l_compat_ioctl32, | ||
131 | .llseek = no_llseek, | ||
132 | }; | ||
133 | |||
134 | /* V4L interface */ | ||
135 | static struct video_device dsbr100_videodev_template= | ||
136 | { | ||
137 | .owner = THIS_MODULE, | ||
138 | .name = "D-Link DSB-R 100", | ||
139 | .type = VID_TYPE_TUNER, | ||
140 | .hardware = VID_HARDWARE_AZTECH, | ||
141 | .fops = &usb_dsbr100_fops, | ||
142 | .release = video_device_release, | ||
143 | }; | ||
144 | |||
145 | static struct usb_device_id usb_dsbr100_device_table [] = { | ||
146 | { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, | ||
147 | { } /* Terminating entry */ | ||
148 | }; | ||
149 | |||
150 | MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table); | ||
151 | |||
152 | /* USB subsystem interface */ | ||
153 | static struct usb_driver usb_dsbr100_driver = { | ||
154 | .name = "dsbr100", | ||
155 | .probe = usb_dsbr100_probe, | ||
156 | .disconnect = usb_dsbr100_disconnect, | ||
157 | .id_table = usb_dsbr100_device_table, | ||
158 | }; | ||
159 | |||
160 | /* Low-level device interface begins here */ | ||
161 | |||
162 | /* switch on radio */ | ||
163 | static int dsbr100_start(dsbr100_device *radio) | ||
164 | { | ||
165 | if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
166 | USB_REQ_GET_STATUS, | ||
167 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
168 | 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 || | ||
169 | usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
170 | DSB100_ONOFF, | ||
171 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
172 | 0x01, 0x00, radio->transfer_buffer, 8, 300)<0) | ||
173 | return -1; | ||
174 | return (radio->transfer_buffer)[0]; | ||
175 | } | ||
176 | |||
177 | |||
178 | /* switch off radio */ | ||
179 | static int dsbr100_stop(dsbr100_device *radio) | ||
180 | { | ||
181 | if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
182 | USB_REQ_GET_STATUS, | ||
183 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
184 | 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 || | ||
185 | usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
186 | DSB100_ONOFF, | ||
187 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
188 | 0x00, 0x00, radio->transfer_buffer, 8, 300)<0) | ||
189 | return -1; | ||
190 | return (radio->transfer_buffer)[0]; | ||
191 | } | ||
192 | |||
193 | /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ | ||
194 | static int dsbr100_setfreq(dsbr100_device *radio, int freq) | ||
195 | { | ||
196 | freq = (freq/16*80)/1000+856; | ||
197 | if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
198 | DSB100_TUNE, | ||
199 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
200 | (freq>>8)&0x00ff, freq&0xff, | ||
201 | radio->transfer_buffer, 8, 300)<0 || | ||
202 | usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
203 | USB_REQ_GET_STATUS, | ||
204 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
205 | 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 || | ||
206 | usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
207 | USB_REQ_GET_STATUS, | ||
208 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
209 | 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) { | ||
210 | radio->stereo = -1; | ||
211 | return -1; | ||
212 | } | ||
213 | radio->stereo = ! ((radio->transfer_buffer)[0]&0x01); | ||
214 | return (radio->transfer_buffer)[0]; | ||
215 | } | ||
216 | |||
217 | /* return the device status. This is, in effect, just whether it | ||
218 | sees a stereo signal or not. Pity. */ | ||
219 | static void dsbr100_getstat(dsbr100_device *radio) | ||
220 | { | ||
221 | if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), | ||
222 | USB_REQ_GET_STATUS, | ||
223 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
224 | 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0) | ||
225 | radio->stereo = -1; | ||
226 | else | ||
227 | radio->stereo = ! (radio->transfer_buffer[0]&0x01); | ||
228 | } | ||
229 | |||
230 | |||
231 | /* USB subsystem interface begins here */ | ||
232 | |||
233 | /* check if the device is present and register with v4l and | ||
234 | usb if it is */ | ||
235 | static int usb_dsbr100_probe(struct usb_interface *intf, | ||
236 | const struct usb_device_id *id) | ||
237 | { | ||
238 | dsbr100_device *radio; | ||
239 | |||
240 | if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL))) | ||
241 | return -ENOMEM; | ||
242 | if (!(radio->videodev = video_device_alloc())) { | ||
243 | kfree(radio); | ||
244 | return -ENOMEM; | ||
245 | } | ||
246 | memcpy(radio->videodev, &dsbr100_videodev_template, | ||
247 | sizeof(dsbr100_videodev_template)); | ||
248 | radio->removed = 0; | ||
249 | radio->users = 0; | ||
250 | radio->usbdev = interface_to_usbdev(intf); | ||
251 | radio->curfreq = FREQ_MIN*FREQ_MUL; | ||
252 | video_set_drvdata(radio->videodev, radio); | ||
253 | if (video_register_device(radio->videodev, VFL_TYPE_RADIO, | ||
254 | radio_nr)) { | ||
255 | warn("Could not register video device"); | ||
256 | video_device_release(radio->videodev); | ||
257 | kfree(radio); | ||
258 | return -EIO; | ||
259 | } | ||
260 | usb_set_intfdata(intf, radio); | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | /* handle unplugging of the device, release data structures | ||
265 | if nothing keeps us from doing it. If something is still | ||
266 | keeping us busy, the release callback of v4l will take care | ||
267 | of releasing it. stv680.c does not relase its private | ||
268 | data, so I don't do this here either. Checking out the | ||
269 | code I'd expect I better did that, but if there's a memory | ||
270 | leak here it's tiny (~50 bytes per disconnect) */ | ||
271 | static void usb_dsbr100_disconnect(struct usb_interface *intf) | ||
272 | { | ||
273 | dsbr100_device *radio = usb_get_intfdata(intf); | ||
274 | |||
275 | usb_set_intfdata (intf, NULL); | ||
276 | if (radio) { | ||
277 | video_unregister_device(radio->videodev); | ||
278 | radio->videodev = NULL; | ||
279 | if (radio->users) { | ||
280 | kfree(radio); | ||
281 | } else { | ||
282 | radio->removed = 1; | ||
283 | } | ||
284 | } | ||
285 | } | ||
286 | |||
287 | |||
288 | /* Video for Linux interface */ | ||
289 | |||
290 | static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file, | ||
291 | unsigned int cmd, void *arg) | ||
292 | { | ||
293 | dsbr100_device *radio=video_get_drvdata(video_devdata(file)); | ||
294 | |||
295 | if (!radio) | ||
296 | return -EIO; | ||
297 | |||
298 | switch(cmd) { | ||
299 | case VIDIOCGCAP: { | ||
300 | struct video_capability *v = arg; | ||
301 | |||
302 | memset(v, 0, sizeof(*v)); | ||
303 | v->type = VID_TYPE_TUNER; | ||
304 | v->channels = 1; | ||
305 | v->audios = 1; | ||
306 | strcpy(v->name, "D-Link R-100 USB FM Radio"); | ||
307 | return 0; | ||
308 | } | ||
309 | case VIDIOCGTUNER: { | ||
310 | struct video_tuner *v = arg; | ||
311 | |||
312 | dsbr100_getstat(radio); | ||
313 | if(v->tuner) /* Only 1 tuner */ | ||
314 | return -EINVAL; | ||
315 | v->rangelow = FREQ_MIN*FREQ_MUL; | ||
316 | v->rangehigh = FREQ_MAX*FREQ_MUL; | ||
317 | v->flags = VIDEO_TUNER_LOW; | ||
318 | v->mode = VIDEO_MODE_AUTO; | ||
319 | v->signal = radio->stereo*0x7000; | ||
320 | /* Don't know how to get signal strength */ | ||
321 | v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo; | ||
322 | strcpy(v->name, "DSB R-100"); | ||
323 | return 0; | ||
324 | } | ||
325 | case VIDIOCSTUNER: { | ||
326 | struct video_tuner *v = arg; | ||
327 | |||
328 | if(v->tuner!=0) | ||
329 | return -EINVAL; | ||
330 | /* Only 1 tuner so no setting needed ! */ | ||
331 | return 0; | ||
332 | } | ||
333 | case VIDIOCGFREQ: { | ||
334 | int *freq = arg; | ||
335 | |||
336 | if (radio->curfreq==-1) | ||
337 | return -EINVAL; | ||
338 | *freq = radio->curfreq; | ||
339 | return 0; | ||
340 | } | ||
341 | case VIDIOCSFREQ: { | ||
342 | int *freq = arg; | ||
343 | |||
344 | radio->curfreq = *freq; | ||
345 | if (dsbr100_setfreq(radio, radio->curfreq)==-1) | ||
346 | warn("Set frequency failed"); | ||
347 | return 0; | ||
348 | } | ||
349 | case VIDIOCGAUDIO: { | ||
350 | struct video_audio *v = arg; | ||
351 | |||
352 | memset(v, 0, sizeof(*v)); | ||
353 | v->flags |= VIDEO_AUDIO_MUTABLE; | ||
354 | v->mode = VIDEO_SOUND_STEREO; | ||
355 | v->volume = 1; | ||
356 | v->step = 1; | ||
357 | strcpy(v->name, "Radio"); | ||
358 | return 0; | ||
359 | } | ||
360 | case VIDIOCSAUDIO: { | ||
361 | struct video_audio *v = arg; | ||
362 | |||
363 | if (v->audio) | ||
364 | return -EINVAL; | ||
365 | if (v->flags&VIDEO_AUDIO_MUTE) { | ||
366 | if (dsbr100_stop(radio)==-1) | ||
367 | warn("Radio did not respond properly"); | ||
368 | } | ||
369 | else | ||
370 | if (dsbr100_start(radio)==-1) | ||
371 | warn("Radio did not respond properly"); | ||
372 | return 0; | ||
373 | } | ||
374 | default: | ||
375 | return -ENOIOCTLCMD; | ||
376 | } | ||
377 | } | ||
378 | |||
379 | static int usb_dsbr100_ioctl(struct inode *inode, struct file *file, | ||
380 | unsigned int cmd, unsigned long arg) | ||
381 | { | ||
382 | return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl); | ||
383 | } | ||
384 | |||
385 | static int usb_dsbr100_open(struct inode *inode, struct file *file) | ||
386 | { | ||
387 | dsbr100_device *radio=video_get_drvdata(video_devdata(file)); | ||
388 | |||
389 | radio->users = 1; | ||
390 | if (dsbr100_start(radio)<0) { | ||
391 | warn("Radio did not start up properly"); | ||
392 | radio->users = 0; | ||
393 | return -EIO; | ||
394 | } | ||
395 | dsbr100_setfreq(radio, radio->curfreq); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static int usb_dsbr100_close(struct inode *inode, struct file *file) | ||
400 | { | ||
401 | dsbr100_device *radio=video_get_drvdata(video_devdata(file)); | ||
402 | |||
403 | if (!radio) | ||
404 | return -ENODEV; | ||
405 | radio->users = 0; | ||
406 | if (radio->removed) { | ||
407 | kfree(radio); | ||
408 | } | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | static int __init dsbr100_init(void) | ||
413 | { | ||
414 | int retval = usb_register(&usb_dsbr100_driver); | ||
415 | info(DRIVER_VERSION ":" DRIVER_DESC); | ||
416 | return retval; | ||
417 | } | ||
418 | |||
419 | static void __exit dsbr100_exit(void) | ||
420 | { | ||
421 | usb_deregister(&usb_dsbr100_driver); | ||
422 | } | ||
423 | |||
424 | module_init (dsbr100_init); | ||
425 | module_exit (dsbr100_exit); | ||
426 | |||
427 | MODULE_AUTHOR( DRIVER_AUTHOR ); | ||
428 | MODULE_DESCRIPTION( DRIVER_DESC ); | ||
429 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/video/et61x251/Makefile b/drivers/media/video/et61x251/Makefile new file mode 100644 index 000000000000..2ff4db9ec882 --- /dev/null +++ b/drivers/media/video/et61x251/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | et61x251-objs := et61x251_core.o et61x251_tas5130d1b.o | ||
2 | |||
3 | obj-$(CONFIG_USB_ET61X251) += et61x251.o | ||
4 | |||
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h new file mode 100644 index 000000000000..eee8afc9be72 --- /dev/null +++ b/drivers/media/video/et61x251/et61x251.h | |||
@@ -0,0 +1,234 @@ | |||
1 | /*************************************************************************** | ||
2 | * V4L2 driver for ET61X[12]51 PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program is distributed in the hope that it will be useful, * | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #ifndef _ET61X251_H_ | ||
22 | #define _ET61X251_H_ | ||
23 | |||
24 | #include <linux/version.h> | ||
25 | #include <linux/usb.h> | ||
26 | #include <linux/videodev2.h> | ||
27 | #include <media/v4l2-common.h> | ||
28 | #include <linux/device.h> | ||
29 | #include <linux/list.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/time.h> | ||
32 | #include <linux/wait.h> | ||
33 | #include <linux/types.h> | ||
34 | #include <linux/param.h> | ||
35 | #include <linux/rwsem.h> | ||
36 | #include <linux/mutex.h> | ||
37 | #include <linux/stddef.h> | ||
38 | #include <linux/string.h> | ||
39 | |||
40 | #include "et61x251_sensor.h" | ||
41 | |||
42 | /*****************************************************************************/ | ||
43 | |||
44 | #define ET61X251_DEBUG | ||
45 | #define ET61X251_DEBUG_LEVEL 2 | ||
46 | #define ET61X251_MAX_DEVICES 64 | ||
47 | #define ET61X251_PRESERVE_IMGSCALE 0 | ||
48 | #define ET61X251_FORCE_MUNMAP 0 | ||
49 | #define ET61X251_MAX_FRAMES 32 | ||
50 | #define ET61X251_COMPRESSION_QUALITY 0 | ||
51 | #define ET61X251_URBS 2 | ||
52 | #define ET61X251_ISO_PACKETS 7 | ||
53 | #define ET61X251_ALTERNATE_SETTING 13 | ||
54 | #define ET61X251_URB_TIMEOUT msecs_to_jiffies(2 * ET61X251_ISO_PACKETS) | ||
55 | #define ET61X251_CTRL_TIMEOUT 100 | ||
56 | #define ET61X251_FRAME_TIMEOUT 2 | ||
57 | |||
58 | /*****************************************************************************/ | ||
59 | |||
60 | static const struct usb_device_id et61x251_id_table[] = { | ||
61 | { USB_DEVICE(0x102c, 0x6151), }, | ||
62 | { USB_DEVICE(0x102c, 0x6251), }, | ||
63 | { USB_DEVICE(0x102c, 0x6253), }, | ||
64 | { USB_DEVICE(0x102c, 0x6254), }, | ||
65 | { USB_DEVICE(0x102c, 0x6255), }, | ||
66 | { USB_DEVICE(0x102c, 0x6256), }, | ||
67 | { USB_DEVICE(0x102c, 0x6257), }, | ||
68 | { USB_DEVICE(0x102c, 0x6258), }, | ||
69 | { USB_DEVICE(0x102c, 0x6259), }, | ||
70 | { USB_DEVICE(0x102c, 0x625a), }, | ||
71 | { USB_DEVICE(0x102c, 0x625b), }, | ||
72 | { USB_DEVICE(0x102c, 0x625c), }, | ||
73 | { USB_DEVICE(0x102c, 0x625d), }, | ||
74 | { USB_DEVICE(0x102c, 0x625e), }, | ||
75 | { USB_DEVICE(0x102c, 0x625f), }, | ||
76 | { USB_DEVICE(0x102c, 0x6260), }, | ||
77 | { USB_DEVICE(0x102c, 0x6261), }, | ||
78 | { USB_DEVICE(0x102c, 0x6262), }, | ||
79 | { USB_DEVICE(0x102c, 0x6263), }, | ||
80 | { USB_DEVICE(0x102c, 0x6264), }, | ||
81 | { USB_DEVICE(0x102c, 0x6265), }, | ||
82 | { USB_DEVICE(0x102c, 0x6266), }, | ||
83 | { USB_DEVICE(0x102c, 0x6267), }, | ||
84 | { USB_DEVICE(0x102c, 0x6268), }, | ||
85 | { USB_DEVICE(0x102c, 0x6269), }, | ||
86 | { } | ||
87 | }; | ||
88 | |||
89 | ET61X251_SENSOR_TABLE | ||
90 | |||
91 | /*****************************************************************************/ | ||
92 | |||
93 | enum et61x251_frame_state { | ||
94 | F_UNUSED, | ||
95 | F_QUEUED, | ||
96 | F_GRABBING, | ||
97 | F_DONE, | ||
98 | F_ERROR, | ||
99 | }; | ||
100 | |||
101 | struct et61x251_frame_t { | ||
102 | void* bufmem; | ||
103 | struct v4l2_buffer buf; | ||
104 | enum et61x251_frame_state state; | ||
105 | struct list_head frame; | ||
106 | unsigned long vma_use_count; | ||
107 | }; | ||
108 | |||
109 | enum et61x251_dev_state { | ||
110 | DEV_INITIALIZED = 0x01, | ||
111 | DEV_DISCONNECTED = 0x02, | ||
112 | DEV_MISCONFIGURED = 0x04, | ||
113 | }; | ||
114 | |||
115 | enum et61x251_io_method { | ||
116 | IO_NONE, | ||
117 | IO_READ, | ||
118 | IO_MMAP, | ||
119 | }; | ||
120 | |||
121 | enum et61x251_stream_state { | ||
122 | STREAM_OFF, | ||
123 | STREAM_INTERRUPT, | ||
124 | STREAM_ON, | ||
125 | }; | ||
126 | |||
127 | struct et61x251_sysfs_attr { | ||
128 | u8 reg, i2c_reg; | ||
129 | }; | ||
130 | |||
131 | struct et61x251_module_param { | ||
132 | u8 force_munmap; | ||
133 | u16 frame_timeout; | ||
134 | }; | ||
135 | |||
136 | static DEFINE_MUTEX(et61x251_sysfs_lock); | ||
137 | static DECLARE_RWSEM(et61x251_disconnect); | ||
138 | |||
139 | struct et61x251_device { | ||
140 | struct video_device* v4ldev; | ||
141 | |||
142 | struct et61x251_sensor sensor; | ||
143 | |||
144 | struct usb_device* usbdev; | ||
145 | struct urb* urb[ET61X251_URBS]; | ||
146 | void* transfer_buffer[ET61X251_URBS]; | ||
147 | u8* control_buffer; | ||
148 | |||
149 | struct et61x251_frame_t *frame_current, frame[ET61X251_MAX_FRAMES]; | ||
150 | struct list_head inqueue, outqueue; | ||
151 | u32 frame_count, nbuffers, nreadbuffers; | ||
152 | |||
153 | enum et61x251_io_method io; | ||
154 | enum et61x251_stream_state stream; | ||
155 | |||
156 | struct v4l2_jpegcompression compression; | ||
157 | |||
158 | struct et61x251_sysfs_attr sysfs; | ||
159 | struct et61x251_module_param module_param; | ||
160 | |||
161 | enum et61x251_dev_state state; | ||
162 | u8 users; | ||
163 | |||
164 | struct mutex dev_mutex, fileop_mutex; | ||
165 | spinlock_t queue_lock; | ||
166 | wait_queue_head_t open, wait_frame, wait_stream; | ||
167 | }; | ||
168 | |||
169 | /*****************************************************************************/ | ||
170 | |||
171 | struct et61x251_device* | ||
172 | et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id) | ||
173 | { | ||
174 | if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id)) | ||
175 | return cam; | ||
176 | |||
177 | return NULL; | ||
178 | } | ||
179 | |||
180 | |||
181 | void | ||
182 | et61x251_attach_sensor(struct et61x251_device* cam, | ||
183 | struct et61x251_sensor* sensor) | ||
184 | { | ||
185 | memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor)); | ||
186 | } | ||
187 | |||
188 | /*****************************************************************************/ | ||
189 | |||
190 | #undef DBG | ||
191 | #undef KDBG | ||
192 | #ifdef ET61X251_DEBUG | ||
193 | # define DBG(level, fmt, args...) \ | ||
194 | do { \ | ||
195 | if (debug >= (level)) { \ | ||
196 | if ((level) == 1) \ | ||
197 | dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ | ||
198 | else if ((level) == 2) \ | ||
199 | dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ | ||
200 | else if ((level) >= 3) \ | ||
201 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | ||
202 | __FUNCTION__, __LINE__ , ## args); \ | ||
203 | } \ | ||
204 | } while (0) | ||
205 | # define KDBG(level, fmt, args...) \ | ||
206 | do { \ | ||
207 | if (debug >= (level)) { \ | ||
208 | if ((level) == 1 || (level) == 2) \ | ||
209 | pr_info("et61x251: " fmt "\n", ## args); \ | ||
210 | else if ((level) == 3) \ | ||
211 | pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \ | ||
212 | __LINE__ , ## args); \ | ||
213 | } \ | ||
214 | } while (0) | ||
215 | # define V4LDBG(level, name, cmd) \ | ||
216 | do { \ | ||
217 | if (debug >= (level)) \ | ||
218 | v4l_print_ioctl(name, cmd); \ | ||
219 | } while (0) | ||
220 | #else | ||
221 | # define DBG(level, fmt, args...) do {;} while(0) | ||
222 | # define KDBG(level, fmt, args...) do {;} while(0) | ||
223 | # define V4LDBG(level, name, cmd) do {;} while(0) | ||
224 | #endif | ||
225 | |||
226 | #undef PDBG | ||
227 | #define PDBG(fmt, args...) \ | ||
228 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | ||
229 | __FUNCTION__, __LINE__ , ## args) | ||
230 | |||
231 | #undef PDBGG | ||
232 | #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ | ||
233 | |||
234 | #endif /* _ET61X251_H_ */ | ||
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c new file mode 100644 index 000000000000..7cc01b828b3d --- /dev/null +++ b/drivers/media/video/et61x251/et61x251_core.c | |||
@@ -0,0 +1,2630 @@ | |||
1 | /*************************************************************************** | ||
2 | * V4L2 driver for ET61X[12]51 PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program is distributed in the hope that it will be useful, * | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/param.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | #include <linux/errno.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/device.h> | ||
29 | #include <linux/fs.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/compiler.h> | ||
32 | #include <linux/ioctl.h> | ||
33 | #include <linux/poll.h> | ||
34 | #include <linux/stat.h> | ||
35 | #include <linux/mm.h> | ||
36 | #include <linux/vmalloc.h> | ||
37 | #include <linux/page-flags.h> | ||
38 | #include <linux/byteorder/generic.h> | ||
39 | #include <asm/page.h> | ||
40 | #include <asm/uaccess.h> | ||
41 | |||
42 | #include "et61x251.h" | ||
43 | |||
44 | /*****************************************************************************/ | ||
45 | |||
46 | #define ET61X251_MODULE_NAME "V4L2 driver for ET61X[12]51 " \ | ||
47 | "PC Camera Controllers" | ||
48 | #define ET61X251_MODULE_AUTHOR "(C) 2006 Luca Risolia" | ||
49 | #define ET61X251_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" | ||
50 | #define ET61X251_MODULE_LICENSE "GPL" | ||
51 | #define ET61X251_MODULE_VERSION "1:1.02" | ||
52 | #define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 2) | ||
53 | |||
54 | /*****************************************************************************/ | ||
55 | |||
56 | MODULE_DEVICE_TABLE(usb, et61x251_id_table); | ||
57 | |||
58 | MODULE_AUTHOR(ET61X251_MODULE_AUTHOR " " ET61X251_AUTHOR_EMAIL); | ||
59 | MODULE_DESCRIPTION(ET61X251_MODULE_NAME); | ||
60 | MODULE_VERSION(ET61X251_MODULE_VERSION); | ||
61 | MODULE_LICENSE(ET61X251_MODULE_LICENSE); | ||
62 | |||
63 | static short video_nr[] = {[0 ... ET61X251_MAX_DEVICES-1] = -1}; | ||
64 | module_param_array(video_nr, short, NULL, 0444); | ||
65 | MODULE_PARM_DESC(video_nr, | ||
66 | "\n<-1|n[,...]> Specify V4L2 minor mode number." | ||
67 | "\n -1 = use next available (default)" | ||
68 | "\n n = use minor number n (integer >= 0)" | ||
69 | "\nYou can specify up to " | ||
70 | __MODULE_STRING(ET61X251_MAX_DEVICES) " cameras this way." | ||
71 | "\nFor example:" | ||
72 | "\nvideo_nr=-1,2,-1 would assign minor number 2 to" | ||
73 | "\nthe second registered camera and use auto for the first" | ||
74 | "\none and for every other camera." | ||
75 | "\n"); | ||
76 | |||
77 | static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] = | ||
78 | ET61X251_FORCE_MUNMAP}; | ||
79 | module_param_array(force_munmap, bool, NULL, 0444); | ||
80 | MODULE_PARM_DESC(force_munmap, | ||
81 | "\n<0|1[,...]> Force the application to unmap previously" | ||
82 | "\nmapped buffer memory before calling any VIDIOC_S_CROP or" | ||
83 | "\nVIDIOC_S_FMT ioctl's. Not all the applications support" | ||
84 | "\nthis feature. This parameter is specific for each" | ||
85 | "\ndetected camera." | ||
86 | "\n 0 = do not force memory unmapping" | ||
87 | "\n 1 = force memory unmapping (save memory)" | ||
88 | "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." | ||
89 | "\n"); | ||
90 | |||
91 | static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] = | ||
92 | ET61X251_FRAME_TIMEOUT}; | ||
93 | module_param_array(frame_timeout, uint, NULL, 0644); | ||
94 | MODULE_PARM_DESC(frame_timeout, | ||
95 | "\n<n[,...]> Timeout for a video frame in seconds." | ||
96 | "\nThis parameter is specific for each detected camera." | ||
97 | "\nDefault value is " | ||
98 | __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"." | ||
99 | "\n"); | ||
100 | |||
101 | #ifdef ET61X251_DEBUG | ||
102 | static unsigned short debug = ET61X251_DEBUG_LEVEL; | ||
103 | module_param(debug, ushort, 0644); | ||
104 | MODULE_PARM_DESC(debug, | ||
105 | "\n<n> Debugging information level, from 0 to 3:" | ||
106 | "\n0 = none (use carefully)" | ||
107 | "\n1 = critical errors" | ||
108 | "\n2 = significant informations" | ||
109 | "\n3 = more verbose messages" | ||
110 | "\nLevel 3 is useful for testing only, when only " | ||
111 | "one device is used." | ||
112 | "\nDefault value is "__MODULE_STRING(ET61X251_DEBUG_LEVEL)"." | ||
113 | "\n"); | ||
114 | #endif | ||
115 | |||
116 | /*****************************************************************************/ | ||
117 | |||
118 | static u32 | ||
119 | et61x251_request_buffers(struct et61x251_device* cam, u32 count, | ||
120 | enum et61x251_io_method io) | ||
121 | { | ||
122 | struct v4l2_pix_format* p = &(cam->sensor.pix_format); | ||
123 | struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); | ||
124 | const size_t imagesize = cam->module_param.force_munmap || | ||
125 | io == IO_READ ? | ||
126 | (p->width * p->height * p->priv) / 8 : | ||
127 | (r->width * r->height * p->priv) / 8; | ||
128 | void* buff = NULL; | ||
129 | u32 i; | ||
130 | |||
131 | if (count > ET61X251_MAX_FRAMES) | ||
132 | count = ET61X251_MAX_FRAMES; | ||
133 | |||
134 | cam->nbuffers = count; | ||
135 | while (cam->nbuffers > 0) { | ||
136 | if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize)))) | ||
137 | break; | ||
138 | cam->nbuffers--; | ||
139 | } | ||
140 | |||
141 | for (i = 0; i < cam->nbuffers; i++) { | ||
142 | cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); | ||
143 | cam->frame[i].buf.index = i; | ||
144 | cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); | ||
145 | cam->frame[i].buf.length = imagesize; | ||
146 | cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
147 | cam->frame[i].buf.sequence = 0; | ||
148 | cam->frame[i].buf.field = V4L2_FIELD_NONE; | ||
149 | cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; | ||
150 | cam->frame[i].buf.flags = 0; | ||
151 | } | ||
152 | |||
153 | return cam->nbuffers; | ||
154 | } | ||
155 | |||
156 | |||
157 | static void et61x251_release_buffers(struct et61x251_device* cam) | ||
158 | { | ||
159 | if (cam->nbuffers) { | ||
160 | vfree(cam->frame[0].bufmem); | ||
161 | cam->nbuffers = 0; | ||
162 | } | ||
163 | cam->frame_current = NULL; | ||
164 | } | ||
165 | |||
166 | |||
167 | static void et61x251_empty_framequeues(struct et61x251_device* cam) | ||
168 | { | ||
169 | u32 i; | ||
170 | |||
171 | INIT_LIST_HEAD(&cam->inqueue); | ||
172 | INIT_LIST_HEAD(&cam->outqueue); | ||
173 | |||
174 | for (i = 0; i < ET61X251_MAX_FRAMES; i++) { | ||
175 | cam->frame[i].state = F_UNUSED; | ||
176 | cam->frame[i].buf.bytesused = 0; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | |||
181 | static void et61x251_requeue_outqueue(struct et61x251_device* cam) | ||
182 | { | ||
183 | struct et61x251_frame_t *i; | ||
184 | |||
185 | list_for_each_entry(i, &cam->outqueue, frame) { | ||
186 | i->state = F_QUEUED; | ||
187 | list_add(&i->frame, &cam->inqueue); | ||
188 | } | ||
189 | |||
190 | INIT_LIST_HEAD(&cam->outqueue); | ||
191 | } | ||
192 | |||
193 | |||
194 | static void et61x251_queue_unusedframes(struct et61x251_device* cam) | ||
195 | { | ||
196 | unsigned long lock_flags; | ||
197 | u32 i; | ||
198 | |||
199 | for (i = 0; i < cam->nbuffers; i++) | ||
200 | if (cam->frame[i].state == F_UNUSED) { | ||
201 | cam->frame[i].state = F_QUEUED; | ||
202 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
203 | list_add_tail(&cam->frame[i].frame, &cam->inqueue); | ||
204 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | /*****************************************************************************/ | ||
209 | |||
210 | int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index) | ||
211 | { | ||
212 | struct usb_device* udev = cam->usbdev; | ||
213 | u8* buff = cam->control_buffer; | ||
214 | int res; | ||
215 | |||
216 | *buff = value; | ||
217 | |||
218 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, | ||
219 | 0, index, buff, 1, ET61X251_CTRL_TIMEOUT); | ||
220 | if (res < 0) { | ||
221 | DBG(3, "Failed to write a register (value 0x%02X, index " | ||
222 | "0x%02X, error %d)", value, index, res); | ||
223 | return -1; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | |||
230 | int et61x251_read_reg(struct et61x251_device* cam, u16 index) | ||
231 | { | ||
232 | struct usb_device* udev = cam->usbdev; | ||
233 | u8* buff = cam->control_buffer; | ||
234 | int res; | ||
235 | |||
236 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, | ||
237 | 0, index, buff, 1, ET61X251_CTRL_TIMEOUT); | ||
238 | if (res < 0) | ||
239 | DBG(3, "Failed to read a register (index 0x%02X, error %d)", | ||
240 | index, res); | ||
241 | |||
242 | return (res >= 0) ? (int)(*buff) : -1; | ||
243 | } | ||
244 | |||
245 | |||
246 | static int | ||
247 | et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor) | ||
248 | { | ||
249 | int i, r; | ||
250 | |||
251 | for (i = 1; i <= 8; i++) { | ||
252 | if (sensor->interface == ET61X251_I2C_3WIRES) { | ||
253 | r = et61x251_read_reg(cam, 0x8e); | ||
254 | if (!(r & 0x02) && (r >= 0)) | ||
255 | return 0; | ||
256 | } else { | ||
257 | r = et61x251_read_reg(cam, 0x8b); | ||
258 | if (!(r & 0x01) && (r >= 0)) | ||
259 | return 0; | ||
260 | } | ||
261 | if (r < 0) | ||
262 | return -EIO; | ||
263 | udelay(8*8); /* minimum for sensors at 400kHz */ | ||
264 | } | ||
265 | |||
266 | return -EBUSY; | ||
267 | } | ||
268 | |||
269 | |||
270 | int | ||
271 | et61x251_i2c_try_read(struct et61x251_device* cam, | ||
272 | struct et61x251_sensor* sensor, u8 address) | ||
273 | { | ||
274 | struct usb_device* udev = cam->usbdev; | ||
275 | u8* data = cam->control_buffer; | ||
276 | int err = 0, res; | ||
277 | |||
278 | data[0] = address; | ||
279 | data[1] = cam->sensor.i2c_slave_id; | ||
280 | data[2] = cam->sensor.rsta | 0x10; | ||
281 | data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02); | ||
282 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, | ||
283 | 0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT); | ||
284 | if (res < 0) | ||
285 | err += res; | ||
286 | |||
287 | err += et61x251_i2c_wait(cam, sensor); | ||
288 | |||
289 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, | ||
290 | 0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT); | ||
291 | if (res < 0) | ||
292 | err += res; | ||
293 | |||
294 | if (err) | ||
295 | DBG(3, "I2C read failed for %s image sensor", sensor->name); | ||
296 | |||
297 | PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]); | ||
298 | |||
299 | return err ? -1 : (int)data[0]; | ||
300 | } | ||
301 | |||
302 | |||
303 | int | ||
304 | et61x251_i2c_try_write(struct et61x251_device* cam, | ||
305 | struct et61x251_sensor* sensor, u8 address, u8 value) | ||
306 | { | ||
307 | struct usb_device* udev = cam->usbdev; | ||
308 | u8* data = cam->control_buffer; | ||
309 | int err = 0, res; | ||
310 | |||
311 | data[0] = address; | ||
312 | data[1] = cam->sensor.i2c_slave_id; | ||
313 | data[2] = cam->sensor.rsta | 0x12; | ||
314 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, | ||
315 | 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); | ||
316 | if (res < 0) | ||
317 | err += res; | ||
318 | |||
319 | data[0] = value; | ||
320 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, | ||
321 | 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT); | ||
322 | if (res < 0) | ||
323 | err += res; | ||
324 | |||
325 | err += et61x251_i2c_wait(cam, sensor); | ||
326 | |||
327 | if (err) | ||
328 | DBG(3, "I2C write failed for %s image sensor", sensor->name); | ||
329 | |||
330 | PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value); | ||
331 | |||
332 | return err ? -1 : 0; | ||
333 | } | ||
334 | |||
335 | |||
336 | int | ||
337 | et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, | ||
338 | u8 data3, u8 data4, u8 data5, u8 data6, u8 data7, | ||
339 | u8 data8, u8 address) | ||
340 | { | ||
341 | struct usb_device* udev = cam->usbdev; | ||
342 | u8* data = cam->control_buffer; | ||
343 | int err = 0, res; | ||
344 | |||
345 | data[0] = data2; | ||
346 | data[1] = data3; | ||
347 | data[2] = data4; | ||
348 | data[3] = data5; | ||
349 | data[4] = data6; | ||
350 | data[5] = data7; | ||
351 | data[6] = data8; | ||
352 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, | ||
353 | 0, 0x81, data, n-1, ET61X251_CTRL_TIMEOUT); | ||
354 | if (res < 0) | ||
355 | err += res; | ||
356 | |||
357 | data[0] = address; | ||
358 | data[1] = cam->sensor.i2c_slave_id; | ||
359 | data[2] = cam->sensor.rsta | 0x02 | (n << 4); | ||
360 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, | ||
361 | 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); | ||
362 | if (res < 0) | ||
363 | err += res; | ||
364 | |||
365 | /* Start writing through the serial interface */ | ||
366 | data[0] = data1; | ||
367 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, | ||
368 | 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT); | ||
369 | if (res < 0) | ||
370 | err += res; | ||
371 | |||
372 | err += et61x251_i2c_wait(cam, &cam->sensor); | ||
373 | |||
374 | if (err) | ||
375 | DBG(3, "I2C raw write failed for %s image sensor", | ||
376 | cam->sensor.name); | ||
377 | |||
378 | PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, " | ||
379 | "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X," | ||
380 | " data6 = 0x%02X, data7 = 0x%02X, data8 = 0x%02X", n, address, | ||
381 | data1, data2, data3, data4, data5, data6, data7, data8); | ||
382 | |||
383 | return err ? -1 : 0; | ||
384 | |||
385 | } | ||
386 | |||
387 | |||
388 | int et61x251_i2c_read(struct et61x251_device* cam, u8 address) | ||
389 | { | ||
390 | return et61x251_i2c_try_read(cam, &cam->sensor, address); | ||
391 | } | ||
392 | |||
393 | |||
394 | int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value) | ||
395 | { | ||
396 | return et61x251_i2c_try_write(cam, &cam->sensor, address, value); | ||
397 | } | ||
398 | |||
399 | /*****************************************************************************/ | ||
400 | |||
401 | static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs) | ||
402 | { | ||
403 | struct et61x251_device* cam = urb->context; | ||
404 | struct et61x251_frame_t** f; | ||
405 | size_t imagesize; | ||
406 | u8 i; | ||
407 | int err = 0; | ||
408 | |||
409 | if (urb->status == -ENOENT) | ||
410 | return; | ||
411 | |||
412 | f = &cam->frame_current; | ||
413 | |||
414 | if (cam->stream == STREAM_INTERRUPT) { | ||
415 | cam->stream = STREAM_OFF; | ||
416 | if ((*f)) | ||
417 | (*f)->state = F_QUEUED; | ||
418 | DBG(3, "Stream interrupted"); | ||
419 | wake_up(&cam->wait_stream); | ||
420 | } | ||
421 | |||
422 | if (cam->state & DEV_DISCONNECTED) | ||
423 | return; | ||
424 | |||
425 | if (cam->state & DEV_MISCONFIGURED) { | ||
426 | wake_up_interruptible(&cam->wait_frame); | ||
427 | return; | ||
428 | } | ||
429 | |||
430 | if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) | ||
431 | goto resubmit_urb; | ||
432 | |||
433 | if (!(*f)) | ||
434 | (*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t, | ||
435 | frame); | ||
436 | |||
437 | imagesize = (cam->sensor.pix_format.width * | ||
438 | cam->sensor.pix_format.height * | ||
439 | cam->sensor.pix_format.priv) / 8; | ||
440 | |||
441 | for (i = 0; i < urb->number_of_packets; i++) { | ||
442 | unsigned int len, status; | ||
443 | void *pos; | ||
444 | u8* b1, * b2, sof; | ||
445 | const u8 VOID_BYTES = 6; | ||
446 | size_t imglen; | ||
447 | |||
448 | len = urb->iso_frame_desc[i].actual_length; | ||
449 | status = urb->iso_frame_desc[i].status; | ||
450 | pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; | ||
451 | |||
452 | if (status) { | ||
453 | DBG(3, "Error in isochronous frame"); | ||
454 | (*f)->state = F_ERROR; | ||
455 | continue; | ||
456 | } | ||
457 | |||
458 | b1 = pos++; | ||
459 | b2 = pos++; | ||
460 | sof = ((*b1 & 0x3f) == 63); | ||
461 | imglen = ((*b1 & 0xc0) << 2) | *b2; | ||
462 | |||
463 | PDBGG("Isochrnous frame: length %u, #%u i, image length %zu", | ||
464 | len, i, imglen); | ||
465 | |||
466 | if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) | ||
467 | start_of_frame: | ||
468 | if (sof) { | ||
469 | (*f)->state = F_GRABBING; | ||
470 | (*f)->buf.bytesused = 0; | ||
471 | do_gettimeofday(&(*f)->buf.timestamp); | ||
472 | pos += 22; | ||
473 | DBG(3, "SOF detected: new video frame"); | ||
474 | } | ||
475 | |||
476 | if ((*f)->state == F_GRABBING) { | ||
477 | if (sof && (*f)->buf.bytesused) { | ||
478 | if (cam->sensor.pix_format.pixelformat == | ||
479 | V4L2_PIX_FMT_ET61X251) | ||
480 | goto end_of_frame; | ||
481 | else { | ||
482 | DBG(3, "Not expected SOF detected " | ||
483 | "after %lu bytes", | ||
484 | (unsigned long)(*f)->buf.bytesused); | ||
485 | (*f)->state = F_ERROR; | ||
486 | continue; | ||
487 | } | ||
488 | } | ||
489 | |||
490 | if ((*f)->buf.bytesused + imglen > imagesize) { | ||
491 | DBG(3, "Video frame size exceeded"); | ||
492 | (*f)->state = F_ERROR; | ||
493 | continue; | ||
494 | } | ||
495 | |||
496 | pos += VOID_BYTES; | ||
497 | |||
498 | memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, imglen); | ||
499 | (*f)->buf.bytesused += imglen; | ||
500 | |||
501 | if ((*f)->buf.bytesused == imagesize) { | ||
502 | u32 b; | ||
503 | end_of_frame: | ||
504 | b = (*f)->buf.bytesused; | ||
505 | (*f)->state = F_DONE; | ||
506 | (*f)->buf.sequence= ++cam->frame_count; | ||
507 | spin_lock(&cam->queue_lock); | ||
508 | list_move_tail(&(*f)->frame, &cam->outqueue); | ||
509 | if (!list_empty(&cam->inqueue)) | ||
510 | (*f) = list_entry(cam->inqueue.next, | ||
511 | struct et61x251_frame_t, | ||
512 | frame); | ||
513 | else | ||
514 | (*f) = NULL; | ||
515 | spin_unlock(&cam->queue_lock); | ||
516 | DBG(3, "Video frame captured: : %lu bytes", | ||
517 | (unsigned long)(b)); | ||
518 | |||
519 | if (!(*f)) | ||
520 | goto resubmit_urb; | ||
521 | |||
522 | if (sof && | ||
523 | cam->sensor.pix_format.pixelformat == | ||
524 | V4L2_PIX_FMT_ET61X251) | ||
525 | goto start_of_frame; | ||
526 | } | ||
527 | } | ||
528 | } | ||
529 | |||
530 | resubmit_urb: | ||
531 | urb->dev = cam->usbdev; | ||
532 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
533 | if (err < 0 && err != -EPERM) { | ||
534 | cam->state |= DEV_MISCONFIGURED; | ||
535 | DBG(1, "usb_submit_urb() failed"); | ||
536 | } | ||
537 | |||
538 | wake_up_interruptible(&cam->wait_frame); | ||
539 | } | ||
540 | |||
541 | |||
542 | static int et61x251_start_transfer(struct et61x251_device* cam) | ||
543 | { | ||
544 | struct usb_device *udev = cam->usbdev; | ||
545 | struct urb* urb; | ||
546 | const unsigned int wMaxPacketSize[] = {0, 256, 384, 512, 640, 768, 832, | ||
547 | 864, 896, 920, 956, 980, 1000, | ||
548 | 1022}; | ||
549 | const unsigned int psz = wMaxPacketSize[ET61X251_ALTERNATE_SETTING]; | ||
550 | s8 i, j; | ||
551 | int err = 0; | ||
552 | |||
553 | for (i = 0; i < ET61X251_URBS; i++) { | ||
554 | cam->transfer_buffer[i] = kzalloc(ET61X251_ISO_PACKETS * psz, | ||
555 | GFP_KERNEL); | ||
556 | if (!cam->transfer_buffer[i]) { | ||
557 | err = -ENOMEM; | ||
558 | DBG(1, "Not enough memory"); | ||
559 | goto free_buffers; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | for (i = 0; i < ET61X251_URBS; i++) { | ||
564 | urb = usb_alloc_urb(ET61X251_ISO_PACKETS, GFP_KERNEL); | ||
565 | cam->urb[i] = urb; | ||
566 | if (!urb) { | ||
567 | err = -ENOMEM; | ||
568 | DBG(1, "usb_alloc_urb() failed"); | ||
569 | goto free_urbs; | ||
570 | } | ||
571 | urb->dev = udev; | ||
572 | urb->context = cam; | ||
573 | urb->pipe = usb_rcvisocpipe(udev, 1); | ||
574 | urb->transfer_flags = URB_ISO_ASAP; | ||
575 | urb->number_of_packets = ET61X251_ISO_PACKETS; | ||
576 | urb->complete = et61x251_urb_complete; | ||
577 | urb->transfer_buffer = cam->transfer_buffer[i]; | ||
578 | urb->transfer_buffer_length = psz * ET61X251_ISO_PACKETS; | ||
579 | urb->interval = 1; | ||
580 | for (j = 0; j < ET61X251_ISO_PACKETS; j++) { | ||
581 | urb->iso_frame_desc[j].offset = psz * j; | ||
582 | urb->iso_frame_desc[j].length = psz; | ||
583 | } | ||
584 | } | ||
585 | |||
586 | err = et61x251_write_reg(cam, 0x01, 0x03); | ||
587 | err = et61x251_write_reg(cam, 0x00, 0x03); | ||
588 | err = et61x251_write_reg(cam, 0x08, 0x03); | ||
589 | if (err) { | ||
590 | err = -EIO; | ||
591 | DBG(1, "I/O hardware error"); | ||
592 | goto free_urbs; | ||
593 | } | ||
594 | |||
595 | err = usb_set_interface(udev, 0, ET61X251_ALTERNATE_SETTING); | ||
596 | if (err) { | ||
597 | DBG(1, "usb_set_interface() failed"); | ||
598 | goto free_urbs; | ||
599 | } | ||
600 | |||
601 | cam->frame_current = NULL; | ||
602 | |||
603 | for (i = 0; i < ET61X251_URBS; i++) { | ||
604 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); | ||
605 | if (err) { | ||
606 | for (j = i-1; j >= 0; j--) | ||
607 | usb_kill_urb(cam->urb[j]); | ||
608 | DBG(1, "usb_submit_urb() failed, error %d", err); | ||
609 | goto free_urbs; | ||
610 | } | ||
611 | } | ||
612 | |||
613 | return 0; | ||
614 | |||
615 | free_urbs: | ||
616 | for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++) | ||
617 | usb_free_urb(cam->urb[i]); | ||
618 | |||
619 | free_buffers: | ||
620 | for (i = 0; (i < ET61X251_URBS) && cam->transfer_buffer[i]; i++) | ||
621 | kfree(cam->transfer_buffer[i]); | ||
622 | |||
623 | return err; | ||
624 | } | ||
625 | |||
626 | |||
627 | static int et61x251_stop_transfer(struct et61x251_device* cam) | ||
628 | { | ||
629 | struct usb_device *udev = cam->usbdev; | ||
630 | s8 i; | ||
631 | int err = 0; | ||
632 | |||
633 | if (cam->state & DEV_DISCONNECTED) | ||
634 | return 0; | ||
635 | |||
636 | for (i = ET61X251_URBS-1; i >= 0; i--) { | ||
637 | usb_kill_urb(cam->urb[i]); | ||
638 | usb_free_urb(cam->urb[i]); | ||
639 | kfree(cam->transfer_buffer[i]); | ||
640 | } | ||
641 | |||
642 | err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ | ||
643 | if (err) | ||
644 | DBG(3, "usb_set_interface() failed"); | ||
645 | |||
646 | return err; | ||
647 | } | ||
648 | |||
649 | |||
650 | static int et61x251_stream_interrupt(struct et61x251_device* cam) | ||
651 | { | ||
652 | long timeout; | ||
653 | |||
654 | cam->stream = STREAM_INTERRUPT; | ||
655 | timeout = wait_event_timeout(cam->wait_stream, | ||
656 | (cam->stream == STREAM_OFF) || | ||
657 | (cam->state & DEV_DISCONNECTED), | ||
658 | ET61X251_URB_TIMEOUT); | ||
659 | if (cam->state & DEV_DISCONNECTED) | ||
660 | return -ENODEV; | ||
661 | else if (cam->stream != STREAM_OFF) { | ||
662 | cam->state |= DEV_MISCONFIGURED; | ||
663 | DBG(1, "URB timeout reached. The camera is misconfigured. To " | ||
664 | "use it, close and open /dev/video%d again.", | ||
665 | cam->v4ldev->minor); | ||
666 | return -EIO; | ||
667 | } | ||
668 | |||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | /*****************************************************************************/ | ||
673 | |||
674 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
675 | static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count) | ||
676 | { | ||
677 | char str[5]; | ||
678 | char* endp; | ||
679 | unsigned long val; | ||
680 | |||
681 | if (len < 4) { | ||
682 | strncpy(str, buff, len); | ||
683 | str[len+1] = '\0'; | ||
684 | } else { | ||
685 | strncpy(str, buff, 4); | ||
686 | str[4] = '\0'; | ||
687 | } | ||
688 | |||
689 | val = simple_strtoul(str, &endp, 0); | ||
690 | |||
691 | *count = 0; | ||
692 | if (val <= 0xff) | ||
693 | *count = (ssize_t)(endp - str); | ||
694 | if ((*count) && (len == *count+1) && (buff[*count] == '\n')) | ||
695 | *count += 1; | ||
696 | |||
697 | return (u8)val; | ||
698 | } | ||
699 | |||
700 | /* | ||
701 | NOTE 1: being inside one of the following methods implies that the v4l | ||
702 | device exists for sure (see kobjects and reference counters) | ||
703 | NOTE 2: buffers are PAGE_SIZE long | ||
704 | */ | ||
705 | |||
706 | static ssize_t et61x251_show_reg(struct class_device* cd, char* buf) | ||
707 | { | ||
708 | struct et61x251_device* cam; | ||
709 | ssize_t count; | ||
710 | |||
711 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
712 | return -ERESTARTSYS; | ||
713 | |||
714 | cam = video_get_drvdata(to_video_device(cd)); | ||
715 | if (!cam) { | ||
716 | mutex_unlock(&et61x251_sysfs_lock); | ||
717 | return -ENODEV; | ||
718 | } | ||
719 | |||
720 | count = sprintf(buf, "%u\n", cam->sysfs.reg); | ||
721 | |||
722 | mutex_unlock(&et61x251_sysfs_lock); | ||
723 | |||
724 | return count; | ||
725 | } | ||
726 | |||
727 | |||
728 | static ssize_t | ||
729 | et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) | ||
730 | { | ||
731 | struct et61x251_device* cam; | ||
732 | u8 index; | ||
733 | ssize_t count; | ||
734 | |||
735 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
736 | return -ERESTARTSYS; | ||
737 | |||
738 | cam = video_get_drvdata(to_video_device(cd)); | ||
739 | if (!cam) { | ||
740 | mutex_unlock(&et61x251_sysfs_lock); | ||
741 | return -ENODEV; | ||
742 | } | ||
743 | |||
744 | index = et61x251_strtou8(buf, len, &count); | ||
745 | if (index > 0x8e || !count) { | ||
746 | mutex_unlock(&et61x251_sysfs_lock); | ||
747 | return -EINVAL; | ||
748 | } | ||
749 | |||
750 | cam->sysfs.reg = index; | ||
751 | |||
752 | DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg); | ||
753 | DBG(3, "Written bytes: %zd", count); | ||
754 | |||
755 | mutex_unlock(&et61x251_sysfs_lock); | ||
756 | |||
757 | return count; | ||
758 | } | ||
759 | |||
760 | |||
761 | static ssize_t et61x251_show_val(struct class_device* cd, char* buf) | ||
762 | { | ||
763 | struct et61x251_device* cam; | ||
764 | ssize_t count; | ||
765 | int val; | ||
766 | |||
767 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
768 | return -ERESTARTSYS; | ||
769 | |||
770 | cam = video_get_drvdata(to_video_device(cd)); | ||
771 | if (!cam) { | ||
772 | mutex_unlock(&et61x251_sysfs_lock); | ||
773 | return -ENODEV; | ||
774 | } | ||
775 | |||
776 | if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) { | ||
777 | mutex_unlock(&et61x251_sysfs_lock); | ||
778 | return -EIO; | ||
779 | } | ||
780 | |||
781 | count = sprintf(buf, "%d\n", val); | ||
782 | |||
783 | DBG(3, "Read bytes: %zd", count); | ||
784 | |||
785 | mutex_unlock(&et61x251_sysfs_lock); | ||
786 | |||
787 | return count; | ||
788 | } | ||
789 | |||
790 | |||
791 | static ssize_t | ||
792 | et61x251_store_val(struct class_device* cd, const char* buf, size_t len) | ||
793 | { | ||
794 | struct et61x251_device* cam; | ||
795 | u8 value; | ||
796 | ssize_t count; | ||
797 | int err; | ||
798 | |||
799 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
800 | return -ERESTARTSYS; | ||
801 | |||
802 | cam = video_get_drvdata(to_video_device(cd)); | ||
803 | if (!cam) { | ||
804 | mutex_unlock(&et61x251_sysfs_lock); | ||
805 | return -ENODEV; | ||
806 | } | ||
807 | |||
808 | value = et61x251_strtou8(buf, len, &count); | ||
809 | if (!count) { | ||
810 | mutex_unlock(&et61x251_sysfs_lock); | ||
811 | return -EINVAL; | ||
812 | } | ||
813 | |||
814 | err = et61x251_write_reg(cam, value, cam->sysfs.reg); | ||
815 | if (err) { | ||
816 | mutex_unlock(&et61x251_sysfs_lock); | ||
817 | return -EIO; | ||
818 | } | ||
819 | |||
820 | DBG(2, "Written ET61X[12]51 reg. 0x%02X, val. 0x%02X", | ||
821 | cam->sysfs.reg, value); | ||
822 | DBG(3, "Written bytes: %zd", count); | ||
823 | |||
824 | mutex_unlock(&et61x251_sysfs_lock); | ||
825 | |||
826 | return count; | ||
827 | } | ||
828 | |||
829 | |||
830 | static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) | ||
831 | { | ||
832 | struct et61x251_device* cam; | ||
833 | ssize_t count; | ||
834 | |||
835 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
836 | return -ERESTARTSYS; | ||
837 | |||
838 | cam = video_get_drvdata(to_video_device(cd)); | ||
839 | if (!cam) { | ||
840 | mutex_unlock(&et61x251_sysfs_lock); | ||
841 | return -ENODEV; | ||
842 | } | ||
843 | |||
844 | count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg); | ||
845 | |||
846 | DBG(3, "Read bytes: %zd", count); | ||
847 | |||
848 | mutex_unlock(&et61x251_sysfs_lock); | ||
849 | |||
850 | return count; | ||
851 | } | ||
852 | |||
853 | |||
854 | static ssize_t | ||
855 | et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) | ||
856 | { | ||
857 | struct et61x251_device* cam; | ||
858 | u8 index; | ||
859 | ssize_t count; | ||
860 | |||
861 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
862 | return -ERESTARTSYS; | ||
863 | |||
864 | cam = video_get_drvdata(to_video_device(cd)); | ||
865 | if (!cam) { | ||
866 | mutex_unlock(&et61x251_sysfs_lock); | ||
867 | return -ENODEV; | ||
868 | } | ||
869 | |||
870 | index = et61x251_strtou8(buf, len, &count); | ||
871 | if (!count) { | ||
872 | mutex_unlock(&et61x251_sysfs_lock); | ||
873 | return -EINVAL; | ||
874 | } | ||
875 | |||
876 | cam->sysfs.i2c_reg = index; | ||
877 | |||
878 | DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg); | ||
879 | DBG(3, "Written bytes: %zd", count); | ||
880 | |||
881 | mutex_unlock(&et61x251_sysfs_lock); | ||
882 | |||
883 | return count; | ||
884 | } | ||
885 | |||
886 | |||
887 | static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) | ||
888 | { | ||
889 | struct et61x251_device* cam; | ||
890 | ssize_t count; | ||
891 | int val; | ||
892 | |||
893 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
894 | return -ERESTARTSYS; | ||
895 | |||
896 | cam = video_get_drvdata(to_video_device(cd)); | ||
897 | if (!cam) { | ||
898 | mutex_unlock(&et61x251_sysfs_lock); | ||
899 | return -ENODEV; | ||
900 | } | ||
901 | |||
902 | if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) { | ||
903 | mutex_unlock(&et61x251_sysfs_lock); | ||
904 | return -ENOSYS; | ||
905 | } | ||
906 | |||
907 | if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { | ||
908 | mutex_unlock(&et61x251_sysfs_lock); | ||
909 | return -EIO; | ||
910 | } | ||
911 | |||
912 | count = sprintf(buf, "%d\n", val); | ||
913 | |||
914 | DBG(3, "Read bytes: %zd", count); | ||
915 | |||
916 | mutex_unlock(&et61x251_sysfs_lock); | ||
917 | |||
918 | return count; | ||
919 | } | ||
920 | |||
921 | |||
922 | static ssize_t | ||
923 | et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) | ||
924 | { | ||
925 | struct et61x251_device* cam; | ||
926 | u8 value; | ||
927 | ssize_t count; | ||
928 | int err; | ||
929 | |||
930 | if (mutex_lock_interruptible(&et61x251_sysfs_lock)) | ||
931 | return -ERESTARTSYS; | ||
932 | |||
933 | cam = video_get_drvdata(to_video_device(cd)); | ||
934 | if (!cam) { | ||
935 | mutex_unlock(&et61x251_sysfs_lock); | ||
936 | return -ENODEV; | ||
937 | } | ||
938 | |||
939 | if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) { | ||
940 | mutex_unlock(&et61x251_sysfs_lock); | ||
941 | return -ENOSYS; | ||
942 | } | ||
943 | |||
944 | value = et61x251_strtou8(buf, len, &count); | ||
945 | if (!count) { | ||
946 | mutex_unlock(&et61x251_sysfs_lock); | ||
947 | return -EINVAL; | ||
948 | } | ||
949 | |||
950 | err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value); | ||
951 | if (err) { | ||
952 | mutex_unlock(&et61x251_sysfs_lock); | ||
953 | return -EIO; | ||
954 | } | ||
955 | |||
956 | DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", | ||
957 | cam->sysfs.i2c_reg, value); | ||
958 | DBG(3, "Written bytes: %zd", count); | ||
959 | |||
960 | mutex_unlock(&et61x251_sysfs_lock); | ||
961 | |||
962 | return count; | ||
963 | } | ||
964 | |||
965 | |||
966 | static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, | ||
967 | et61x251_show_reg, et61x251_store_reg); | ||
968 | static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, | ||
969 | et61x251_show_val, et61x251_store_val); | ||
970 | static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, | ||
971 | et61x251_show_i2c_reg, et61x251_store_i2c_reg); | ||
972 | static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, | ||
973 | et61x251_show_i2c_val, et61x251_store_i2c_val); | ||
974 | |||
975 | |||
976 | static void et61x251_create_sysfs(struct et61x251_device* cam) | ||
977 | { | ||
978 | struct video_device *v4ldev = cam->v4ldev; | ||
979 | |||
980 | video_device_create_file(v4ldev, &class_device_attr_reg); | ||
981 | video_device_create_file(v4ldev, &class_device_attr_val); | ||
982 | if (cam->sensor.sysfs_ops) { | ||
983 | video_device_create_file(v4ldev, &class_device_attr_i2c_reg); | ||
984 | video_device_create_file(v4ldev, &class_device_attr_i2c_val); | ||
985 | } | ||
986 | } | ||
987 | #endif /* CONFIG_VIDEO_ADV_DEBUG */ | ||
988 | |||
989 | /*****************************************************************************/ | ||
990 | |||
991 | static int | ||
992 | et61x251_set_pix_format(struct et61x251_device* cam, | ||
993 | struct v4l2_pix_format* pix) | ||
994 | { | ||
995 | int r, err = 0; | ||
996 | |||
997 | if ((r = et61x251_read_reg(cam, 0x12)) < 0) | ||
998 | err += r; | ||
999 | if (pix->pixelformat == V4L2_PIX_FMT_ET61X251) | ||
1000 | err += et61x251_write_reg(cam, r & 0xfd, 0x12); | ||
1001 | else | ||
1002 | err += et61x251_write_reg(cam, r | 0x02, 0x12); | ||
1003 | |||
1004 | return err ? -EIO : 0; | ||
1005 | } | ||
1006 | |||
1007 | |||
1008 | static int | ||
1009 | et61x251_set_compression(struct et61x251_device* cam, | ||
1010 | struct v4l2_jpegcompression* compression) | ||
1011 | { | ||
1012 | int r, err = 0; | ||
1013 | |||
1014 | if ((r = et61x251_read_reg(cam, 0x12)) < 0) | ||
1015 | err += r; | ||
1016 | if (compression->quality == 0) | ||
1017 | err += et61x251_write_reg(cam, r & 0xfb, 0x12); | ||
1018 | else | ||
1019 | err += et61x251_write_reg(cam, r | 0x04, 0x12); | ||
1020 | |||
1021 | return err ? -EIO : 0; | ||
1022 | } | ||
1023 | |||
1024 | |||
1025 | static int et61x251_set_scale(struct et61x251_device* cam, u8 scale) | ||
1026 | { | ||
1027 | int r = 0, err = 0; | ||
1028 | |||
1029 | r = et61x251_read_reg(cam, 0x12); | ||
1030 | if (r < 0) | ||
1031 | err += r; | ||
1032 | |||
1033 | if (scale == 1) | ||
1034 | err += et61x251_write_reg(cam, r & ~0x01, 0x12); | ||
1035 | else if (scale == 2) | ||
1036 | err += et61x251_write_reg(cam, r | 0x01, 0x12); | ||
1037 | |||
1038 | if (err) | ||
1039 | return -EIO; | ||
1040 | |||
1041 | PDBGG("Scaling factor: %u", scale); | ||
1042 | |||
1043 | return 0; | ||
1044 | } | ||
1045 | |||
1046 | |||
1047 | static int | ||
1048 | et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect) | ||
1049 | { | ||
1050 | struct et61x251_sensor* s = &cam->sensor; | ||
1051 | u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left + | ||
1052 | s->active_pixel.left), | ||
1053 | fmw_sy = (u16)(rect->top - s->cropcap.bounds.top + | ||
1054 | s->active_pixel.top), | ||
1055 | fmw_length = (u16)(rect->width), | ||
1056 | fmw_height = (u16)(rect->height); | ||
1057 | int err = 0; | ||
1058 | |||
1059 | err += et61x251_write_reg(cam, fmw_sx & 0xff, 0x69); | ||
1060 | err += et61x251_write_reg(cam, fmw_sy & 0xff, 0x6a); | ||
1061 | err += et61x251_write_reg(cam, fmw_length & 0xff, 0x6b); | ||
1062 | err += et61x251_write_reg(cam, fmw_height & 0xff, 0x6c); | ||
1063 | err += et61x251_write_reg(cam, (fmw_sx >> 8) | ((fmw_sy & 0x300) >> 6) | ||
1064 | | ((fmw_length & 0x300) >> 4) | ||
1065 | | ((fmw_height & 0x300) >> 2), 0x6d); | ||
1066 | if (err) | ||
1067 | return -EIO; | ||
1068 | |||
1069 | PDBGG("fmw_sx, fmw_sy, fmw_length, fmw_height: %u %u %u %u", | ||
1070 | fmw_sx, fmw_sy, fmw_length, fmw_height); | ||
1071 | |||
1072 | return 0; | ||
1073 | } | ||
1074 | |||
1075 | |||
1076 | static int et61x251_init(struct et61x251_device* cam) | ||
1077 | { | ||
1078 | struct et61x251_sensor* s = &cam->sensor; | ||
1079 | struct v4l2_control ctrl; | ||
1080 | struct v4l2_queryctrl *qctrl; | ||
1081 | struct v4l2_rect* rect; | ||
1082 | u8 i = 0; | ||
1083 | int err = 0; | ||
1084 | |||
1085 | if (!(cam->state & DEV_INITIALIZED)) { | ||
1086 | init_waitqueue_head(&cam->open); | ||
1087 | qctrl = s->qctrl; | ||
1088 | rect = &(s->cropcap.defrect); | ||
1089 | cam->compression.quality = ET61X251_COMPRESSION_QUALITY; | ||
1090 | } else { /* use current values */ | ||
1091 | qctrl = s->_qctrl; | ||
1092 | rect = &(s->_rect); | ||
1093 | } | ||
1094 | |||
1095 | err += et61x251_set_scale(cam, rect->width / s->pix_format.width); | ||
1096 | err += et61x251_set_crop(cam, rect); | ||
1097 | if (err) | ||
1098 | return err; | ||
1099 | |||
1100 | if (s->init) { | ||
1101 | err = s->init(cam); | ||
1102 | if (err) { | ||
1103 | DBG(3, "Sensor initialization failed"); | ||
1104 | return err; | ||
1105 | } | ||
1106 | } | ||
1107 | |||
1108 | err += et61x251_set_compression(cam, &cam->compression); | ||
1109 | err += et61x251_set_pix_format(cam, &s->pix_format); | ||
1110 | if (s->set_pix_format) | ||
1111 | err += s->set_pix_format(cam, &s->pix_format); | ||
1112 | if (err) | ||
1113 | return err; | ||
1114 | |||
1115 | if (s->pix_format.pixelformat == V4L2_PIX_FMT_ET61X251) | ||
1116 | DBG(3, "Compressed video format is active, quality %d", | ||
1117 | cam->compression.quality); | ||
1118 | else | ||
1119 | DBG(3, "Uncompressed video format is active"); | ||
1120 | |||
1121 | if (s->set_crop) | ||
1122 | if ((err = s->set_crop(cam, rect))) { | ||
1123 | DBG(3, "set_crop() failed"); | ||
1124 | return err; | ||
1125 | } | ||
1126 | |||
1127 | if (s->set_ctrl) { | ||
1128 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
1129 | if (s->qctrl[i].id != 0 && | ||
1130 | !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { | ||
1131 | ctrl.id = s->qctrl[i].id; | ||
1132 | ctrl.value = qctrl[i].default_value; | ||
1133 | err = s->set_ctrl(cam, &ctrl); | ||
1134 | if (err) { | ||
1135 | DBG(3, "Set %s control failed", | ||
1136 | s->qctrl[i].name); | ||
1137 | return err; | ||
1138 | } | ||
1139 | DBG(3, "Image sensor supports '%s' control", | ||
1140 | s->qctrl[i].name); | ||
1141 | } | ||
1142 | } | ||
1143 | |||
1144 | if (!(cam->state & DEV_INITIALIZED)) { | ||
1145 | mutex_init(&cam->fileop_mutex); | ||
1146 | spin_lock_init(&cam->queue_lock); | ||
1147 | init_waitqueue_head(&cam->wait_frame); | ||
1148 | init_waitqueue_head(&cam->wait_stream); | ||
1149 | cam->nreadbuffers = 2; | ||
1150 | memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); | ||
1151 | memcpy(&(s->_rect), &(s->cropcap.defrect), | ||
1152 | sizeof(struct v4l2_rect)); | ||
1153 | cam->state |= DEV_INITIALIZED; | ||
1154 | } | ||
1155 | |||
1156 | DBG(2, "Initialization succeeded"); | ||
1157 | return 0; | ||
1158 | } | ||
1159 | |||
1160 | |||
1161 | static void et61x251_release_resources(struct et61x251_device* cam) | ||
1162 | { | ||
1163 | mutex_lock(&et61x251_sysfs_lock); | ||
1164 | |||
1165 | DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); | ||
1166 | video_set_drvdata(cam->v4ldev, NULL); | ||
1167 | video_unregister_device(cam->v4ldev); | ||
1168 | |||
1169 | usb_put_dev(cam->usbdev); | ||
1170 | |||
1171 | mutex_unlock(&et61x251_sysfs_lock); | ||
1172 | |||
1173 | kfree(cam->control_buffer); | ||
1174 | } | ||
1175 | |||
1176 | /*****************************************************************************/ | ||
1177 | |||
1178 | static int et61x251_open(struct inode* inode, struct file* filp) | ||
1179 | { | ||
1180 | struct et61x251_device* cam; | ||
1181 | int err = 0; | ||
1182 | |||
1183 | /* | ||
1184 | This is the only safe way to prevent race conditions with | ||
1185 | disconnect | ||
1186 | */ | ||
1187 | if (!down_read_trylock(&et61x251_disconnect)) | ||
1188 | return -ERESTARTSYS; | ||
1189 | |||
1190 | cam = video_get_drvdata(video_devdata(filp)); | ||
1191 | |||
1192 | if (mutex_lock_interruptible(&cam->dev_mutex)) { | ||
1193 | up_read(&et61x251_disconnect); | ||
1194 | return -ERESTARTSYS; | ||
1195 | } | ||
1196 | |||
1197 | if (cam->users) { | ||
1198 | DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); | ||
1199 | if ((filp->f_flags & O_NONBLOCK) || | ||
1200 | (filp->f_flags & O_NDELAY)) { | ||
1201 | err = -EWOULDBLOCK; | ||
1202 | goto out; | ||
1203 | } | ||
1204 | mutex_unlock(&cam->dev_mutex); | ||
1205 | err = wait_event_interruptible_exclusive(cam->open, | ||
1206 | cam->state & DEV_DISCONNECTED | ||
1207 | || !cam->users); | ||
1208 | if (err) { | ||
1209 | up_read(&et61x251_disconnect); | ||
1210 | return err; | ||
1211 | } | ||
1212 | if (cam->state & DEV_DISCONNECTED) { | ||
1213 | up_read(&et61x251_disconnect); | ||
1214 | return -ENODEV; | ||
1215 | } | ||
1216 | mutex_lock(&cam->dev_mutex); | ||
1217 | } | ||
1218 | |||
1219 | |||
1220 | if (cam->state & DEV_MISCONFIGURED) { | ||
1221 | err = et61x251_init(cam); | ||
1222 | if (err) { | ||
1223 | DBG(1, "Initialization failed again. " | ||
1224 | "I will retry on next open()."); | ||
1225 | goto out; | ||
1226 | } | ||
1227 | cam->state &= ~DEV_MISCONFIGURED; | ||
1228 | } | ||
1229 | |||
1230 | if ((err = et61x251_start_transfer(cam))) | ||
1231 | goto out; | ||
1232 | |||
1233 | filp->private_data = cam; | ||
1234 | cam->users++; | ||
1235 | cam->io = IO_NONE; | ||
1236 | cam->stream = STREAM_OFF; | ||
1237 | cam->nbuffers = 0; | ||
1238 | cam->frame_count = 0; | ||
1239 | et61x251_empty_framequeues(cam); | ||
1240 | |||
1241 | DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); | ||
1242 | |||
1243 | out: | ||
1244 | mutex_unlock(&cam->dev_mutex); | ||
1245 | up_read(&et61x251_disconnect); | ||
1246 | return err; | ||
1247 | } | ||
1248 | |||
1249 | |||
1250 | static int et61x251_release(struct inode* inode, struct file* filp) | ||
1251 | { | ||
1252 | struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1253 | |||
1254 | mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ | ||
1255 | |||
1256 | et61x251_stop_transfer(cam); | ||
1257 | |||
1258 | et61x251_release_buffers(cam); | ||
1259 | |||
1260 | if (cam->state & DEV_DISCONNECTED) { | ||
1261 | et61x251_release_resources(cam); | ||
1262 | mutex_unlock(&cam->dev_mutex); | ||
1263 | kfree(cam); | ||
1264 | return 0; | ||
1265 | } | ||
1266 | |||
1267 | cam->users--; | ||
1268 | wake_up_interruptible_nr(&cam->open, 1); | ||
1269 | |||
1270 | DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); | ||
1271 | |||
1272 | mutex_unlock(&cam->dev_mutex); | ||
1273 | |||
1274 | return 0; | ||
1275 | } | ||
1276 | |||
1277 | |||
1278 | static ssize_t | ||
1279 | et61x251_read(struct file* filp, char __user * buf, | ||
1280 | size_t count, loff_t* f_pos) | ||
1281 | { | ||
1282 | struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1283 | struct et61x251_frame_t* f, * i; | ||
1284 | unsigned long lock_flags; | ||
1285 | long timeout; | ||
1286 | int err = 0; | ||
1287 | |||
1288 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
1289 | return -ERESTARTSYS; | ||
1290 | |||
1291 | if (cam->state & DEV_DISCONNECTED) { | ||
1292 | DBG(1, "Device not present"); | ||
1293 | mutex_unlock(&cam->fileop_mutex); | ||
1294 | return -ENODEV; | ||
1295 | } | ||
1296 | |||
1297 | if (cam->state & DEV_MISCONFIGURED) { | ||
1298 | DBG(1, "The camera is misconfigured. Close and open it " | ||
1299 | "again."); | ||
1300 | mutex_unlock(&cam->fileop_mutex); | ||
1301 | return -EIO; | ||
1302 | } | ||
1303 | |||
1304 | if (cam->io == IO_MMAP) { | ||
1305 | DBG(3, "Close and open the device again to choose the read " | ||
1306 | "method"); | ||
1307 | mutex_unlock(&cam->fileop_mutex); | ||
1308 | return -EINVAL; | ||
1309 | } | ||
1310 | |||
1311 | if (cam->io == IO_NONE) { | ||
1312 | if (!et61x251_request_buffers(cam, cam->nreadbuffers, | ||
1313 | IO_READ)) { | ||
1314 | DBG(1, "read() failed, not enough memory"); | ||
1315 | mutex_unlock(&cam->fileop_mutex); | ||
1316 | return -ENOMEM; | ||
1317 | } | ||
1318 | cam->io = IO_READ; | ||
1319 | cam->stream = STREAM_ON; | ||
1320 | } | ||
1321 | |||
1322 | if (list_empty(&cam->inqueue)) { | ||
1323 | if (!list_empty(&cam->outqueue)) | ||
1324 | et61x251_empty_framequeues(cam); | ||
1325 | et61x251_queue_unusedframes(cam); | ||
1326 | } | ||
1327 | |||
1328 | if (!count) { | ||
1329 | mutex_unlock(&cam->fileop_mutex); | ||
1330 | return 0; | ||
1331 | } | ||
1332 | |||
1333 | if (list_empty(&cam->outqueue)) { | ||
1334 | if (filp->f_flags & O_NONBLOCK) { | ||
1335 | mutex_unlock(&cam->fileop_mutex); | ||
1336 | return -EAGAIN; | ||
1337 | } | ||
1338 | timeout = wait_event_interruptible_timeout | ||
1339 | ( cam->wait_frame, | ||
1340 | (!list_empty(&cam->outqueue)) || | ||
1341 | (cam->state & DEV_DISCONNECTED) || | ||
1342 | (cam->state & DEV_MISCONFIGURED), | ||
1343 | cam->module_param.frame_timeout * | ||
1344 | 1000 * msecs_to_jiffies(1) ); | ||
1345 | if (timeout < 0) { | ||
1346 | mutex_unlock(&cam->fileop_mutex); | ||
1347 | return timeout; | ||
1348 | } | ||
1349 | if (cam->state & DEV_DISCONNECTED) { | ||
1350 | mutex_unlock(&cam->fileop_mutex); | ||
1351 | return -ENODEV; | ||
1352 | } | ||
1353 | if (!timeout || (cam->state & DEV_MISCONFIGURED)) { | ||
1354 | mutex_unlock(&cam->fileop_mutex); | ||
1355 | return -EIO; | ||
1356 | } | ||
1357 | } | ||
1358 | |||
1359 | f = list_entry(cam->outqueue.prev, struct et61x251_frame_t, frame); | ||
1360 | |||
1361 | if (count > f->buf.bytesused) | ||
1362 | count = f->buf.bytesused; | ||
1363 | |||
1364 | if (copy_to_user(buf, f->bufmem, count)) { | ||
1365 | err = -EFAULT; | ||
1366 | goto exit; | ||
1367 | } | ||
1368 | *f_pos += count; | ||
1369 | |||
1370 | exit: | ||
1371 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
1372 | list_for_each_entry(i, &cam->outqueue, frame) | ||
1373 | i->state = F_UNUSED; | ||
1374 | INIT_LIST_HEAD(&cam->outqueue); | ||
1375 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
1376 | |||
1377 | et61x251_queue_unusedframes(cam); | ||
1378 | |||
1379 | PDBGG("Frame #%lu, bytes read: %zu", | ||
1380 | (unsigned long)f->buf.index, count); | ||
1381 | |||
1382 | mutex_unlock(&cam->fileop_mutex); | ||
1383 | |||
1384 | return err ? err : count; | ||
1385 | } | ||
1386 | |||
1387 | |||
1388 | static unsigned int et61x251_poll(struct file *filp, poll_table *wait) | ||
1389 | { | ||
1390 | struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1391 | struct et61x251_frame_t* f; | ||
1392 | unsigned long lock_flags; | ||
1393 | unsigned int mask = 0; | ||
1394 | |||
1395 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
1396 | return POLLERR; | ||
1397 | |||
1398 | if (cam->state & DEV_DISCONNECTED) { | ||
1399 | DBG(1, "Device not present"); | ||
1400 | goto error; | ||
1401 | } | ||
1402 | |||
1403 | if (cam->state & DEV_MISCONFIGURED) { | ||
1404 | DBG(1, "The camera is misconfigured. Close and open it " | ||
1405 | "again."); | ||
1406 | goto error; | ||
1407 | } | ||
1408 | |||
1409 | if (cam->io == IO_NONE) { | ||
1410 | if (!et61x251_request_buffers(cam, cam->nreadbuffers, | ||
1411 | IO_READ)) { | ||
1412 | DBG(1, "poll() failed, not enough memory"); | ||
1413 | goto error; | ||
1414 | } | ||
1415 | cam->io = IO_READ; | ||
1416 | cam->stream = STREAM_ON; | ||
1417 | } | ||
1418 | |||
1419 | if (cam->io == IO_READ) { | ||
1420 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
1421 | list_for_each_entry(f, &cam->outqueue, frame) | ||
1422 | f->state = F_UNUSED; | ||
1423 | INIT_LIST_HEAD(&cam->outqueue); | ||
1424 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
1425 | et61x251_queue_unusedframes(cam); | ||
1426 | } | ||
1427 | |||
1428 | poll_wait(filp, &cam->wait_frame, wait); | ||
1429 | |||
1430 | if (!list_empty(&cam->outqueue)) | ||
1431 | mask |= POLLIN | POLLRDNORM; | ||
1432 | |||
1433 | mutex_unlock(&cam->fileop_mutex); | ||
1434 | |||
1435 | return mask; | ||
1436 | |||
1437 | error: | ||
1438 | mutex_unlock(&cam->fileop_mutex); | ||
1439 | return POLLERR; | ||
1440 | } | ||
1441 | |||
1442 | |||
1443 | static void et61x251_vm_open(struct vm_area_struct* vma) | ||
1444 | { | ||
1445 | struct et61x251_frame_t* f = vma->vm_private_data; | ||
1446 | f->vma_use_count++; | ||
1447 | } | ||
1448 | |||
1449 | |||
1450 | static void et61x251_vm_close(struct vm_area_struct* vma) | ||
1451 | { | ||
1452 | /* NOTE: buffers are not freed here */ | ||
1453 | struct et61x251_frame_t* f = vma->vm_private_data; | ||
1454 | f->vma_use_count--; | ||
1455 | } | ||
1456 | |||
1457 | |||
1458 | static struct vm_operations_struct et61x251_vm_ops = { | ||
1459 | .open = et61x251_vm_open, | ||
1460 | .close = et61x251_vm_close, | ||
1461 | }; | ||
1462 | |||
1463 | |||
1464 | static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) | ||
1465 | { | ||
1466 | struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1467 | unsigned long size = vma->vm_end - vma->vm_start, | ||
1468 | start = vma->vm_start; | ||
1469 | void *pos; | ||
1470 | u32 i; | ||
1471 | |||
1472 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
1473 | return -ERESTARTSYS; | ||
1474 | |||
1475 | if (cam->state & DEV_DISCONNECTED) { | ||
1476 | DBG(1, "Device not present"); | ||
1477 | mutex_unlock(&cam->fileop_mutex); | ||
1478 | return -ENODEV; | ||
1479 | } | ||
1480 | |||
1481 | if (cam->state & DEV_MISCONFIGURED) { | ||
1482 | DBG(1, "The camera is misconfigured. Close and open it " | ||
1483 | "again."); | ||
1484 | mutex_unlock(&cam->fileop_mutex); | ||
1485 | return -EIO; | ||
1486 | } | ||
1487 | |||
1488 | if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || | ||
1489 | size != PAGE_ALIGN(cam->frame[0].buf.length)) { | ||
1490 | mutex_unlock(&cam->fileop_mutex); | ||
1491 | return -EINVAL; | ||
1492 | } | ||
1493 | |||
1494 | for (i = 0; i < cam->nbuffers; i++) { | ||
1495 | if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) | ||
1496 | break; | ||
1497 | } | ||
1498 | if (i == cam->nbuffers) { | ||
1499 | mutex_unlock(&cam->fileop_mutex); | ||
1500 | return -EINVAL; | ||
1501 | } | ||
1502 | |||
1503 | vma->vm_flags |= VM_IO; | ||
1504 | vma->vm_flags |= VM_RESERVED; | ||
1505 | |||
1506 | pos = cam->frame[i].bufmem; | ||
1507 | while (size > 0) { /* size is page-aligned */ | ||
1508 | if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { | ||
1509 | mutex_unlock(&cam->fileop_mutex); | ||
1510 | return -EAGAIN; | ||
1511 | } | ||
1512 | start += PAGE_SIZE; | ||
1513 | pos += PAGE_SIZE; | ||
1514 | size -= PAGE_SIZE; | ||
1515 | } | ||
1516 | |||
1517 | vma->vm_ops = &et61x251_vm_ops; | ||
1518 | vma->vm_private_data = &cam->frame[i]; | ||
1519 | |||
1520 | et61x251_vm_open(vma); | ||
1521 | |||
1522 | mutex_unlock(&cam->fileop_mutex); | ||
1523 | |||
1524 | return 0; | ||
1525 | } | ||
1526 | |||
1527 | /*****************************************************************************/ | ||
1528 | |||
1529 | static int | ||
1530 | et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg) | ||
1531 | { | ||
1532 | struct v4l2_capability cap = { | ||
1533 | .driver = "et61x251", | ||
1534 | .version = ET61X251_MODULE_VERSION_CODE, | ||
1535 | .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | | ||
1536 | V4L2_CAP_STREAMING, | ||
1537 | }; | ||
1538 | |||
1539 | strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); | ||
1540 | if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) | ||
1541 | strlcpy(cap.bus_info, cam->usbdev->dev.bus_id, | ||
1542 | sizeof(cap.bus_info)); | ||
1543 | |||
1544 | if (copy_to_user(arg, &cap, sizeof(cap))) | ||
1545 | return -EFAULT; | ||
1546 | |||
1547 | return 0; | ||
1548 | } | ||
1549 | |||
1550 | |||
1551 | static int | ||
1552 | et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg) | ||
1553 | { | ||
1554 | struct v4l2_input i; | ||
1555 | |||
1556 | if (copy_from_user(&i, arg, sizeof(i))) | ||
1557 | return -EFAULT; | ||
1558 | |||
1559 | if (i.index) | ||
1560 | return -EINVAL; | ||
1561 | |||
1562 | memset(&i, 0, sizeof(i)); | ||
1563 | strcpy(i.name, "Camera"); | ||
1564 | i.type = V4L2_INPUT_TYPE_CAMERA; | ||
1565 | |||
1566 | if (copy_to_user(arg, &i, sizeof(i))) | ||
1567 | return -EFAULT; | ||
1568 | |||
1569 | return 0; | ||
1570 | } | ||
1571 | |||
1572 | |||
1573 | static int | ||
1574 | et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg) | ||
1575 | { | ||
1576 | int index = 0; | ||
1577 | |||
1578 | if (copy_to_user(arg, &index, sizeof(index))) | ||
1579 | return -EFAULT; | ||
1580 | |||
1581 | return 0; | ||
1582 | } | ||
1583 | |||
1584 | |||
1585 | static int | ||
1586 | et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg) | ||
1587 | { | ||
1588 | int index; | ||
1589 | |||
1590 | if (copy_from_user(&index, arg, sizeof(index))) | ||
1591 | return -EFAULT; | ||
1592 | |||
1593 | if (index != 0) | ||
1594 | return -EINVAL; | ||
1595 | |||
1596 | return 0; | ||
1597 | } | ||
1598 | |||
1599 | |||
1600 | static int | ||
1601 | et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg) | ||
1602 | { | ||
1603 | struct et61x251_sensor* s = &cam->sensor; | ||
1604 | struct v4l2_queryctrl qc; | ||
1605 | u8 i; | ||
1606 | |||
1607 | if (copy_from_user(&qc, arg, sizeof(qc))) | ||
1608 | return -EFAULT; | ||
1609 | |||
1610 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
1611 | if (qc.id && qc.id == s->qctrl[i].id) { | ||
1612 | memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); | ||
1613 | if (copy_to_user(arg, &qc, sizeof(qc))) | ||
1614 | return -EFAULT; | ||
1615 | return 0; | ||
1616 | } | ||
1617 | |||
1618 | return -EINVAL; | ||
1619 | } | ||
1620 | |||
1621 | |||
1622 | static int | ||
1623 | et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg) | ||
1624 | { | ||
1625 | struct et61x251_sensor* s = &cam->sensor; | ||
1626 | struct v4l2_control ctrl; | ||
1627 | int err = 0; | ||
1628 | u8 i; | ||
1629 | |||
1630 | if (!s->get_ctrl && !s->set_ctrl) | ||
1631 | return -EINVAL; | ||
1632 | |||
1633 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
1634 | return -EFAULT; | ||
1635 | |||
1636 | if (!s->get_ctrl) { | ||
1637 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
1638 | if (ctrl.id == s->qctrl[i].id) { | ||
1639 | ctrl.value = s->_qctrl[i].default_value; | ||
1640 | goto exit; | ||
1641 | } | ||
1642 | return -EINVAL; | ||
1643 | } else | ||
1644 | err = s->get_ctrl(cam, &ctrl); | ||
1645 | |||
1646 | exit: | ||
1647 | if (copy_to_user(arg, &ctrl, sizeof(ctrl))) | ||
1648 | return -EFAULT; | ||
1649 | |||
1650 | return err; | ||
1651 | } | ||
1652 | |||
1653 | |||
1654 | static int | ||
1655 | et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg) | ||
1656 | { | ||
1657 | struct et61x251_sensor* s = &cam->sensor; | ||
1658 | struct v4l2_control ctrl; | ||
1659 | u8 i; | ||
1660 | int err = 0; | ||
1661 | |||
1662 | if (!s->set_ctrl) | ||
1663 | return -EINVAL; | ||
1664 | |||
1665 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
1666 | return -EFAULT; | ||
1667 | |||
1668 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
1669 | if (ctrl.id == s->qctrl[i].id) { | ||
1670 | if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) | ||
1671 | return -EINVAL; | ||
1672 | if (ctrl.value < s->qctrl[i].minimum || | ||
1673 | ctrl.value > s->qctrl[i].maximum) | ||
1674 | return -ERANGE; | ||
1675 | ctrl.value -= ctrl.value % s->qctrl[i].step; | ||
1676 | break; | ||
1677 | } | ||
1678 | |||
1679 | if ((err = s->set_ctrl(cam, &ctrl))) | ||
1680 | return err; | ||
1681 | |||
1682 | s->_qctrl[i].default_value = ctrl.value; | ||
1683 | |||
1684 | return 0; | ||
1685 | } | ||
1686 | |||
1687 | |||
1688 | static int | ||
1689 | et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg) | ||
1690 | { | ||
1691 | struct v4l2_cropcap* cc = &(cam->sensor.cropcap); | ||
1692 | |||
1693 | cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1694 | cc->pixelaspect.numerator = 1; | ||
1695 | cc->pixelaspect.denominator = 1; | ||
1696 | |||
1697 | if (copy_to_user(arg, cc, sizeof(*cc))) | ||
1698 | return -EFAULT; | ||
1699 | |||
1700 | return 0; | ||
1701 | } | ||
1702 | |||
1703 | |||
1704 | static int | ||
1705 | et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg) | ||
1706 | { | ||
1707 | struct et61x251_sensor* s = &cam->sensor; | ||
1708 | struct v4l2_crop crop = { | ||
1709 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
1710 | }; | ||
1711 | |||
1712 | memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); | ||
1713 | |||
1714 | if (copy_to_user(arg, &crop, sizeof(crop))) | ||
1715 | return -EFAULT; | ||
1716 | |||
1717 | return 0; | ||
1718 | } | ||
1719 | |||
1720 | |||
1721 | static int | ||
1722 | et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg) | ||
1723 | { | ||
1724 | struct et61x251_sensor* s = &cam->sensor; | ||
1725 | struct v4l2_crop crop; | ||
1726 | struct v4l2_rect* rect; | ||
1727 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
1728 | struct v4l2_pix_format* pix_format = &(s->pix_format); | ||
1729 | u8 scale; | ||
1730 | const enum et61x251_stream_state stream = cam->stream; | ||
1731 | const u32 nbuffers = cam->nbuffers; | ||
1732 | u32 i; | ||
1733 | int err = 0; | ||
1734 | |||
1735 | if (copy_from_user(&crop, arg, sizeof(crop))) | ||
1736 | return -EFAULT; | ||
1737 | |||
1738 | rect = &(crop.c); | ||
1739 | |||
1740 | if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1741 | return -EINVAL; | ||
1742 | |||
1743 | if (cam->module_param.force_munmap) | ||
1744 | for (i = 0; i < cam->nbuffers; i++) | ||
1745 | if (cam->frame[i].vma_use_count) { | ||
1746 | DBG(3, "VIDIOC_S_CROP failed. " | ||
1747 | "Unmap the buffers first."); | ||
1748 | return -EINVAL; | ||
1749 | } | ||
1750 | |||
1751 | /* Preserve R,G or B origin */ | ||
1752 | rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L; | ||
1753 | rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L; | ||
1754 | |||
1755 | if (rect->width < 4) | ||
1756 | rect->width = 4; | ||
1757 | if (rect->height < 4) | ||
1758 | rect->height = 4; | ||
1759 | if (rect->width > bounds->width) | ||
1760 | rect->width = bounds->width; | ||
1761 | if (rect->height > bounds->height) | ||
1762 | rect->height = bounds->height; | ||
1763 | if (rect->left < bounds->left) | ||
1764 | rect->left = bounds->left; | ||
1765 | if (rect->top < bounds->top) | ||
1766 | rect->top = bounds->top; | ||
1767 | if (rect->left + rect->width > bounds->left + bounds->width) | ||
1768 | rect->left = bounds->left+bounds->width - rect->width; | ||
1769 | if (rect->top + rect->height > bounds->top + bounds->height) | ||
1770 | rect->top = bounds->top+bounds->height - rect->height; | ||
1771 | |||
1772 | rect->width &= ~3L; | ||
1773 | rect->height &= ~3L; | ||
1774 | |||
1775 | if (ET61X251_PRESERVE_IMGSCALE) { | ||
1776 | /* Calculate the actual scaling factor */ | ||
1777 | u32 a, b; | ||
1778 | a = rect->width * rect->height; | ||
1779 | b = pix_format->width * pix_format->height; | ||
1780 | scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; | ||
1781 | } else | ||
1782 | scale = 1; | ||
1783 | |||
1784 | if (cam->stream == STREAM_ON) | ||
1785 | if ((err = et61x251_stream_interrupt(cam))) | ||
1786 | return err; | ||
1787 | |||
1788 | if (copy_to_user(arg, &crop, sizeof(crop))) { | ||
1789 | cam->stream = stream; | ||
1790 | return -EFAULT; | ||
1791 | } | ||
1792 | |||
1793 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
1794 | et61x251_release_buffers(cam); | ||
1795 | |||
1796 | err = et61x251_set_crop(cam, rect); | ||
1797 | if (s->set_crop) | ||
1798 | err += s->set_crop(cam, rect); | ||
1799 | err += et61x251_set_scale(cam, scale); | ||
1800 | |||
1801 | if (err) { /* atomic, no rollback in ioctl() */ | ||
1802 | cam->state |= DEV_MISCONFIGURED; | ||
1803 | DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " | ||
1804 | "use the camera, close and open /dev/video%d again.", | ||
1805 | cam->v4ldev->minor); | ||
1806 | return -EIO; | ||
1807 | } | ||
1808 | |||
1809 | s->pix_format.width = rect->width/scale; | ||
1810 | s->pix_format.height = rect->height/scale; | ||
1811 | memcpy(&(s->_rect), rect, sizeof(*rect)); | ||
1812 | |||
1813 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
1814 | nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { | ||
1815 | cam->state |= DEV_MISCONFIGURED; | ||
1816 | DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " | ||
1817 | "use the camera, close and open /dev/video%d again.", | ||
1818 | cam->v4ldev->minor); | ||
1819 | return -ENOMEM; | ||
1820 | } | ||
1821 | |||
1822 | if (cam->io == IO_READ) | ||
1823 | et61x251_empty_framequeues(cam); | ||
1824 | else if (cam->module_param.force_munmap) | ||
1825 | et61x251_requeue_outqueue(cam); | ||
1826 | |||
1827 | cam->stream = stream; | ||
1828 | |||
1829 | return 0; | ||
1830 | } | ||
1831 | |||
1832 | |||
1833 | static int | ||
1834 | et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg) | ||
1835 | { | ||
1836 | struct v4l2_fmtdesc fmtd; | ||
1837 | |||
1838 | if (copy_from_user(&fmtd, arg, sizeof(fmtd))) | ||
1839 | return -EFAULT; | ||
1840 | |||
1841 | if (fmtd.index == 0) { | ||
1842 | strcpy(fmtd.description, "bayer rgb"); | ||
1843 | fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8; | ||
1844 | } else if (fmtd.index == 1) { | ||
1845 | strcpy(fmtd.description, "compressed"); | ||
1846 | fmtd.pixelformat = V4L2_PIX_FMT_ET61X251; | ||
1847 | fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; | ||
1848 | } else | ||
1849 | return -EINVAL; | ||
1850 | |||
1851 | fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1852 | memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); | ||
1853 | |||
1854 | if (copy_to_user(arg, &fmtd, sizeof(fmtd))) | ||
1855 | return -EFAULT; | ||
1856 | |||
1857 | return 0; | ||
1858 | } | ||
1859 | |||
1860 | |||
1861 | static int | ||
1862 | et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg) | ||
1863 | { | ||
1864 | struct v4l2_format format; | ||
1865 | struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); | ||
1866 | |||
1867 | if (copy_from_user(&format, arg, sizeof(format))) | ||
1868 | return -EFAULT; | ||
1869 | |||
1870 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1871 | return -EINVAL; | ||
1872 | |||
1873 | pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251) | ||
1874 | ? 0 : (pfmt->width * pfmt->priv) / 8; | ||
1875 | pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); | ||
1876 | pfmt->field = V4L2_FIELD_NONE; | ||
1877 | memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); | ||
1878 | |||
1879 | if (copy_to_user(arg, &format, sizeof(format))) | ||
1880 | return -EFAULT; | ||
1881 | |||
1882 | return 0; | ||
1883 | } | ||
1884 | |||
1885 | |||
1886 | static int | ||
1887 | et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, | ||
1888 | void __user * arg) | ||
1889 | { | ||
1890 | struct et61x251_sensor* s = &cam->sensor; | ||
1891 | struct v4l2_format format; | ||
1892 | struct v4l2_pix_format* pix; | ||
1893 | struct v4l2_pix_format* pfmt = &(s->pix_format); | ||
1894 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
1895 | struct v4l2_rect rect; | ||
1896 | u8 scale; | ||
1897 | const enum et61x251_stream_state stream = cam->stream; | ||
1898 | const u32 nbuffers = cam->nbuffers; | ||
1899 | u32 i; | ||
1900 | int err = 0; | ||
1901 | |||
1902 | if (copy_from_user(&format, arg, sizeof(format))) | ||
1903 | return -EFAULT; | ||
1904 | |||
1905 | pix = &(format.fmt.pix); | ||
1906 | |||
1907 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1908 | return -EINVAL; | ||
1909 | |||
1910 | memcpy(&rect, &(s->_rect), sizeof(rect)); | ||
1911 | |||
1912 | { /* calculate the actual scaling factor */ | ||
1913 | u32 a, b; | ||
1914 | a = rect.width * rect.height; | ||
1915 | b = pix->width * pix->height; | ||
1916 | scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; | ||
1917 | } | ||
1918 | |||
1919 | rect.width = scale * pix->width; | ||
1920 | rect.height = scale * pix->height; | ||
1921 | |||
1922 | if (rect.width < 4) | ||
1923 | rect.width = 4; | ||
1924 | if (rect.height < 4) | ||
1925 | rect.height = 4; | ||
1926 | if (rect.width > bounds->left + bounds->width - rect.left) | ||
1927 | rect.width = bounds->left + bounds->width - rect.left; | ||
1928 | if (rect.height > bounds->top + bounds->height - rect.top) | ||
1929 | rect.height = bounds->top + bounds->height - rect.top; | ||
1930 | |||
1931 | rect.width &= ~3L; | ||
1932 | rect.height &= ~3L; | ||
1933 | |||
1934 | { /* adjust the scaling factor */ | ||
1935 | u32 a, b; | ||
1936 | a = rect.width * rect.height; | ||
1937 | b = pix->width * pix->height; | ||
1938 | scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; | ||
1939 | } | ||
1940 | |||
1941 | pix->width = rect.width / scale; | ||
1942 | pix->height = rect.height / scale; | ||
1943 | |||
1944 | if (pix->pixelformat != V4L2_PIX_FMT_ET61X251 && | ||
1945 | pix->pixelformat != V4L2_PIX_FMT_SBGGR8) | ||
1946 | pix->pixelformat = pfmt->pixelformat; | ||
1947 | pix->priv = pfmt->priv; /* bpp */ | ||
1948 | pix->colorspace = pfmt->colorspace; | ||
1949 | pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) | ||
1950 | ? 0 : (pix->width * pix->priv) / 8; | ||
1951 | pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); | ||
1952 | pix->field = V4L2_FIELD_NONE; | ||
1953 | |||
1954 | if (cmd == VIDIOC_TRY_FMT) { | ||
1955 | if (copy_to_user(arg, &format, sizeof(format))) | ||
1956 | return -EFAULT; | ||
1957 | return 0; | ||
1958 | } | ||
1959 | |||
1960 | if (cam->module_param.force_munmap) | ||
1961 | for (i = 0; i < cam->nbuffers; i++) | ||
1962 | if (cam->frame[i].vma_use_count) { | ||
1963 | DBG(3, "VIDIOC_S_FMT failed. " | ||
1964 | "Unmap the buffers first."); | ||
1965 | return -EINVAL; | ||
1966 | } | ||
1967 | |||
1968 | if (cam->stream == STREAM_ON) | ||
1969 | if ((err = et61x251_stream_interrupt(cam))) | ||
1970 | return err; | ||
1971 | |||
1972 | if (copy_to_user(arg, &format, sizeof(format))) { | ||
1973 | cam->stream = stream; | ||
1974 | return -EFAULT; | ||
1975 | } | ||
1976 | |||
1977 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
1978 | et61x251_release_buffers(cam); | ||
1979 | |||
1980 | err += et61x251_set_pix_format(cam, pix); | ||
1981 | err += et61x251_set_crop(cam, &rect); | ||
1982 | if (s->set_pix_format) | ||
1983 | err += s->set_pix_format(cam, pix); | ||
1984 | if (s->set_crop) | ||
1985 | err += s->set_crop(cam, &rect); | ||
1986 | err += et61x251_set_scale(cam, scale); | ||
1987 | |||
1988 | if (err) { /* atomic, no rollback in ioctl() */ | ||
1989 | cam->state |= DEV_MISCONFIGURED; | ||
1990 | DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " | ||
1991 | "use the camera, close and open /dev/video%d again.", | ||
1992 | cam->v4ldev->minor); | ||
1993 | return -EIO; | ||
1994 | } | ||
1995 | |||
1996 | memcpy(pfmt, pix, sizeof(*pix)); | ||
1997 | memcpy(&(s->_rect), &rect, sizeof(rect)); | ||
1998 | |||
1999 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
2000 | nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { | ||
2001 | cam->state |= DEV_MISCONFIGURED; | ||
2002 | DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " | ||
2003 | "use the camera, close and open /dev/video%d again.", | ||
2004 | cam->v4ldev->minor); | ||
2005 | return -ENOMEM; | ||
2006 | } | ||
2007 | |||
2008 | if (cam->io == IO_READ) | ||
2009 | et61x251_empty_framequeues(cam); | ||
2010 | else if (cam->module_param.force_munmap) | ||
2011 | et61x251_requeue_outqueue(cam); | ||
2012 | |||
2013 | cam->stream = stream; | ||
2014 | |||
2015 | return 0; | ||
2016 | } | ||
2017 | |||
2018 | |||
2019 | static int | ||
2020 | et61x251_vidioc_g_jpegcomp(struct et61x251_device* cam, void __user * arg) | ||
2021 | { | ||
2022 | if (copy_to_user(arg, &cam->compression, | ||
2023 | sizeof(cam->compression))) | ||
2024 | return -EFAULT; | ||
2025 | |||
2026 | return 0; | ||
2027 | } | ||
2028 | |||
2029 | |||
2030 | static int | ||
2031 | et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg) | ||
2032 | { | ||
2033 | struct v4l2_jpegcompression jc; | ||
2034 | const enum et61x251_stream_state stream = cam->stream; | ||
2035 | int err = 0; | ||
2036 | |||
2037 | if (copy_from_user(&jc, arg, sizeof(jc))) | ||
2038 | return -EFAULT; | ||
2039 | |||
2040 | if (jc.quality != 0 && jc.quality != 1) | ||
2041 | return -EINVAL; | ||
2042 | |||
2043 | if (cam->stream == STREAM_ON) | ||
2044 | if ((err = et61x251_stream_interrupt(cam))) | ||
2045 | return err; | ||
2046 | |||
2047 | err += et61x251_set_compression(cam, &jc); | ||
2048 | if (err) { /* atomic, no rollback in ioctl() */ | ||
2049 | cam->state |= DEV_MISCONFIGURED; | ||
2050 | DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " | ||
2051 | "problems. To use the camera, close and open " | ||
2052 | "/dev/video%d again.", cam->v4ldev->minor); | ||
2053 | return -EIO; | ||
2054 | } | ||
2055 | |||
2056 | cam->compression.quality = jc.quality; | ||
2057 | |||
2058 | cam->stream = stream; | ||
2059 | |||
2060 | return 0; | ||
2061 | } | ||
2062 | |||
2063 | |||
2064 | static int | ||
2065 | et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg) | ||
2066 | { | ||
2067 | struct v4l2_requestbuffers rb; | ||
2068 | u32 i; | ||
2069 | int err; | ||
2070 | |||
2071 | if (copy_from_user(&rb, arg, sizeof(rb))) | ||
2072 | return -EFAULT; | ||
2073 | |||
2074 | if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
2075 | rb.memory != V4L2_MEMORY_MMAP) | ||
2076 | return -EINVAL; | ||
2077 | |||
2078 | if (cam->io == IO_READ) { | ||
2079 | DBG(3, "Close and open the device again to choose the mmap " | ||
2080 | "I/O method"); | ||
2081 | return -EINVAL; | ||
2082 | } | ||
2083 | |||
2084 | for (i = 0; i < cam->nbuffers; i++) | ||
2085 | if (cam->frame[i].vma_use_count) { | ||
2086 | DBG(3, "VIDIOC_REQBUFS failed. " | ||
2087 | "Previous buffers are still mapped."); | ||
2088 | return -EINVAL; | ||
2089 | } | ||
2090 | |||
2091 | if (cam->stream == STREAM_ON) | ||
2092 | if ((err = et61x251_stream_interrupt(cam))) | ||
2093 | return err; | ||
2094 | |||
2095 | et61x251_empty_framequeues(cam); | ||
2096 | |||
2097 | et61x251_release_buffers(cam); | ||
2098 | if (rb.count) | ||
2099 | rb.count = et61x251_request_buffers(cam, rb.count, IO_MMAP); | ||
2100 | |||
2101 | if (copy_to_user(arg, &rb, sizeof(rb))) { | ||
2102 | et61x251_release_buffers(cam); | ||
2103 | cam->io = IO_NONE; | ||
2104 | return -EFAULT; | ||
2105 | } | ||
2106 | |||
2107 | cam->io = rb.count ? IO_MMAP : IO_NONE; | ||
2108 | |||
2109 | return 0; | ||
2110 | } | ||
2111 | |||
2112 | |||
2113 | static int | ||
2114 | et61x251_vidioc_querybuf(struct et61x251_device* cam, void __user * arg) | ||
2115 | { | ||
2116 | struct v4l2_buffer b; | ||
2117 | |||
2118 | if (copy_from_user(&b, arg, sizeof(b))) | ||
2119 | return -EFAULT; | ||
2120 | |||
2121 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
2122 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
2123 | return -EINVAL; | ||
2124 | |||
2125 | memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); | ||
2126 | |||
2127 | if (cam->frame[b.index].vma_use_count) | ||
2128 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
2129 | |||
2130 | if (cam->frame[b.index].state == F_DONE) | ||
2131 | b.flags |= V4L2_BUF_FLAG_DONE; | ||
2132 | else if (cam->frame[b.index].state != F_UNUSED) | ||
2133 | b.flags |= V4L2_BUF_FLAG_QUEUED; | ||
2134 | |||
2135 | if (copy_to_user(arg, &b, sizeof(b))) | ||
2136 | return -EFAULT; | ||
2137 | |||
2138 | return 0; | ||
2139 | } | ||
2140 | |||
2141 | |||
2142 | static int | ||
2143 | et61x251_vidioc_qbuf(struct et61x251_device* cam, void __user * arg) | ||
2144 | { | ||
2145 | struct v4l2_buffer b; | ||
2146 | unsigned long lock_flags; | ||
2147 | |||
2148 | if (copy_from_user(&b, arg, sizeof(b))) | ||
2149 | return -EFAULT; | ||
2150 | |||
2151 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
2152 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
2153 | return -EINVAL; | ||
2154 | |||
2155 | if (cam->frame[b.index].state != F_UNUSED) | ||
2156 | return -EINVAL; | ||
2157 | |||
2158 | cam->frame[b.index].state = F_QUEUED; | ||
2159 | |||
2160 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
2161 | list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); | ||
2162 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
2163 | |||
2164 | PDBGG("Frame #%lu queued", (unsigned long)b.index); | ||
2165 | |||
2166 | return 0; | ||
2167 | } | ||
2168 | |||
2169 | |||
2170 | static int | ||
2171 | et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp, | ||
2172 | void __user * arg) | ||
2173 | { | ||
2174 | struct v4l2_buffer b; | ||
2175 | struct et61x251_frame_t *f; | ||
2176 | unsigned long lock_flags; | ||
2177 | long timeout; | ||
2178 | |||
2179 | if (copy_from_user(&b, arg, sizeof(b))) | ||
2180 | return -EFAULT; | ||
2181 | |||
2182 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP) | ||
2183 | return -EINVAL; | ||
2184 | |||
2185 | if (list_empty(&cam->outqueue)) { | ||
2186 | if (cam->stream == STREAM_OFF) | ||
2187 | return -EINVAL; | ||
2188 | if (filp->f_flags & O_NONBLOCK) | ||
2189 | return -EAGAIN; | ||
2190 | timeout = wait_event_interruptible_timeout | ||
2191 | ( cam->wait_frame, | ||
2192 | (!list_empty(&cam->outqueue)) || | ||
2193 | (cam->state & DEV_DISCONNECTED) || | ||
2194 | (cam->state & DEV_MISCONFIGURED), | ||
2195 | cam->module_param.frame_timeout * | ||
2196 | 1000 * msecs_to_jiffies(1) ); | ||
2197 | if (timeout < 0) | ||
2198 | return timeout; | ||
2199 | if (cam->state & DEV_DISCONNECTED) | ||
2200 | return -ENODEV; | ||
2201 | if (!timeout || (cam->state & DEV_MISCONFIGURED)) | ||
2202 | return -EIO; | ||
2203 | } | ||
2204 | |||
2205 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
2206 | f = list_entry(cam->outqueue.next, struct et61x251_frame_t, frame); | ||
2207 | list_del(cam->outqueue.next); | ||
2208 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
2209 | |||
2210 | f->state = F_UNUSED; | ||
2211 | |||
2212 | memcpy(&b, &f->buf, sizeof(b)); | ||
2213 | if (f->vma_use_count) | ||
2214 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
2215 | |||
2216 | if (copy_to_user(arg, &b, sizeof(b))) | ||
2217 | return -EFAULT; | ||
2218 | |||
2219 | PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); | ||
2220 | |||
2221 | return 0; | ||
2222 | } | ||
2223 | |||
2224 | |||
2225 | static int | ||
2226 | et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg) | ||
2227 | { | ||
2228 | int type; | ||
2229 | |||
2230 | if (copy_from_user(&type, arg, sizeof(type))) | ||
2231 | return -EFAULT; | ||
2232 | |||
2233 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
2234 | return -EINVAL; | ||
2235 | |||
2236 | if (list_empty(&cam->inqueue)) | ||
2237 | return -EINVAL; | ||
2238 | |||
2239 | cam->stream = STREAM_ON; | ||
2240 | |||
2241 | DBG(3, "Stream on"); | ||
2242 | |||
2243 | return 0; | ||
2244 | } | ||
2245 | |||
2246 | |||
2247 | static int | ||
2248 | et61x251_vidioc_streamoff(struct et61x251_device* cam, void __user * arg) | ||
2249 | { | ||
2250 | int type, err; | ||
2251 | |||
2252 | if (copy_from_user(&type, arg, sizeof(type))) | ||
2253 | return -EFAULT; | ||
2254 | |||
2255 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
2256 | return -EINVAL; | ||
2257 | |||
2258 | if (cam->stream == STREAM_ON) | ||
2259 | if ((err = et61x251_stream_interrupt(cam))) | ||
2260 | return err; | ||
2261 | |||
2262 | et61x251_empty_framequeues(cam); | ||
2263 | |||
2264 | DBG(3, "Stream off"); | ||
2265 | |||
2266 | return 0; | ||
2267 | } | ||
2268 | |||
2269 | |||
2270 | static int | ||
2271 | et61x251_vidioc_g_parm(struct et61x251_device* cam, void __user * arg) | ||
2272 | { | ||
2273 | struct v4l2_streamparm sp; | ||
2274 | |||
2275 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
2276 | return -EFAULT; | ||
2277 | |||
2278 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2279 | return -EINVAL; | ||
2280 | |||
2281 | sp.parm.capture.extendedmode = 0; | ||
2282 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
2283 | |||
2284 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
2285 | return -EFAULT; | ||
2286 | |||
2287 | return 0; | ||
2288 | } | ||
2289 | |||
2290 | |||
2291 | static int | ||
2292 | et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg) | ||
2293 | { | ||
2294 | struct v4l2_streamparm sp; | ||
2295 | |||
2296 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
2297 | return -EFAULT; | ||
2298 | |||
2299 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2300 | return -EINVAL; | ||
2301 | |||
2302 | sp.parm.capture.extendedmode = 0; | ||
2303 | |||
2304 | if (sp.parm.capture.readbuffers == 0) | ||
2305 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
2306 | |||
2307 | if (sp.parm.capture.readbuffers > ET61X251_MAX_FRAMES) | ||
2308 | sp.parm.capture.readbuffers = ET61X251_MAX_FRAMES; | ||
2309 | |||
2310 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
2311 | return -EFAULT; | ||
2312 | |||
2313 | cam->nreadbuffers = sp.parm.capture.readbuffers; | ||
2314 | |||
2315 | return 0; | ||
2316 | } | ||
2317 | |||
2318 | |||
2319 | static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp, | ||
2320 | unsigned int cmd, void __user * arg) | ||
2321 | { | ||
2322 | struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); | ||
2323 | |||
2324 | switch (cmd) { | ||
2325 | |||
2326 | case VIDIOC_QUERYCAP: | ||
2327 | return et61x251_vidioc_querycap(cam, arg); | ||
2328 | |||
2329 | case VIDIOC_ENUMINPUT: | ||
2330 | return et61x251_vidioc_enuminput(cam, arg); | ||
2331 | |||
2332 | case VIDIOC_G_INPUT: | ||
2333 | return et61x251_vidioc_g_input(cam, arg); | ||
2334 | |||
2335 | case VIDIOC_S_INPUT: | ||
2336 | return et61x251_vidioc_s_input(cam, arg); | ||
2337 | |||
2338 | case VIDIOC_QUERYCTRL: | ||
2339 | return et61x251_vidioc_query_ctrl(cam, arg); | ||
2340 | |||
2341 | case VIDIOC_G_CTRL: | ||
2342 | return et61x251_vidioc_g_ctrl(cam, arg); | ||
2343 | |||
2344 | case VIDIOC_S_CTRL_OLD: | ||
2345 | case VIDIOC_S_CTRL: | ||
2346 | return et61x251_vidioc_s_ctrl(cam, arg); | ||
2347 | |||
2348 | case VIDIOC_CROPCAP_OLD: | ||
2349 | case VIDIOC_CROPCAP: | ||
2350 | return et61x251_vidioc_cropcap(cam, arg); | ||
2351 | |||
2352 | case VIDIOC_G_CROP: | ||
2353 | return et61x251_vidioc_g_crop(cam, arg); | ||
2354 | |||
2355 | case VIDIOC_S_CROP: | ||
2356 | return et61x251_vidioc_s_crop(cam, arg); | ||
2357 | |||
2358 | case VIDIOC_ENUM_FMT: | ||
2359 | return et61x251_vidioc_enum_fmt(cam, arg); | ||
2360 | |||
2361 | case VIDIOC_G_FMT: | ||
2362 | return et61x251_vidioc_g_fmt(cam, arg); | ||
2363 | |||
2364 | case VIDIOC_TRY_FMT: | ||
2365 | case VIDIOC_S_FMT: | ||
2366 | return et61x251_vidioc_try_s_fmt(cam, cmd, arg); | ||
2367 | |||
2368 | case VIDIOC_G_JPEGCOMP: | ||
2369 | return et61x251_vidioc_g_jpegcomp(cam, arg); | ||
2370 | |||
2371 | case VIDIOC_S_JPEGCOMP: | ||
2372 | return et61x251_vidioc_s_jpegcomp(cam, arg); | ||
2373 | |||
2374 | case VIDIOC_REQBUFS: | ||
2375 | return et61x251_vidioc_reqbufs(cam, arg); | ||
2376 | |||
2377 | case VIDIOC_QUERYBUF: | ||
2378 | return et61x251_vidioc_querybuf(cam, arg); | ||
2379 | |||
2380 | case VIDIOC_QBUF: | ||
2381 | return et61x251_vidioc_qbuf(cam, arg); | ||
2382 | |||
2383 | case VIDIOC_DQBUF: | ||
2384 | return et61x251_vidioc_dqbuf(cam, filp, arg); | ||
2385 | |||
2386 | case VIDIOC_STREAMON: | ||
2387 | return et61x251_vidioc_streamon(cam, arg); | ||
2388 | |||
2389 | case VIDIOC_STREAMOFF: | ||
2390 | return et61x251_vidioc_streamoff(cam, arg); | ||
2391 | |||
2392 | case VIDIOC_G_PARM: | ||
2393 | return et61x251_vidioc_g_parm(cam, arg); | ||
2394 | |||
2395 | case VIDIOC_S_PARM_OLD: | ||
2396 | case VIDIOC_S_PARM: | ||
2397 | return et61x251_vidioc_s_parm(cam, arg); | ||
2398 | |||
2399 | case VIDIOC_G_STD: | ||
2400 | case VIDIOC_S_STD: | ||
2401 | case VIDIOC_QUERYSTD: | ||
2402 | case VIDIOC_ENUMSTD: | ||
2403 | case VIDIOC_QUERYMENU: | ||
2404 | return -EINVAL; | ||
2405 | |||
2406 | default: | ||
2407 | return -EINVAL; | ||
2408 | |||
2409 | } | ||
2410 | } | ||
2411 | |||
2412 | |||
2413 | static int et61x251_ioctl(struct inode* inode, struct file* filp, | ||
2414 | unsigned int cmd, unsigned long arg) | ||
2415 | { | ||
2416 | struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); | ||
2417 | int err = 0; | ||
2418 | |||
2419 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
2420 | return -ERESTARTSYS; | ||
2421 | |||
2422 | if (cam->state & DEV_DISCONNECTED) { | ||
2423 | DBG(1, "Device not present"); | ||
2424 | mutex_unlock(&cam->fileop_mutex); | ||
2425 | return -ENODEV; | ||
2426 | } | ||
2427 | |||
2428 | if (cam->state & DEV_MISCONFIGURED) { | ||
2429 | DBG(1, "The camera is misconfigured. Close and open it " | ||
2430 | "again."); | ||
2431 | mutex_unlock(&cam->fileop_mutex); | ||
2432 | return -EIO; | ||
2433 | } | ||
2434 | |||
2435 | V4LDBG(3, "et61x251", cmd); | ||
2436 | |||
2437 | err = et61x251_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); | ||
2438 | |||
2439 | mutex_unlock(&cam->fileop_mutex); | ||
2440 | |||
2441 | return err; | ||
2442 | } | ||
2443 | |||
2444 | |||
2445 | static struct file_operations et61x251_fops = { | ||
2446 | .owner = THIS_MODULE, | ||
2447 | .open = et61x251_open, | ||
2448 | .release = et61x251_release, | ||
2449 | .ioctl = et61x251_ioctl, | ||
2450 | .read = et61x251_read, | ||
2451 | .poll = et61x251_poll, | ||
2452 | .mmap = et61x251_mmap, | ||
2453 | .llseek = no_llseek, | ||
2454 | }; | ||
2455 | |||
2456 | /*****************************************************************************/ | ||
2457 | |||
2458 | /* It exists a single interface only. We do not need to validate anything. */ | ||
2459 | static int | ||
2460 | et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | ||
2461 | { | ||
2462 | struct usb_device *udev = interface_to_usbdev(intf); | ||
2463 | struct et61x251_device* cam; | ||
2464 | static unsigned int dev_nr = 0; | ||
2465 | unsigned int i; | ||
2466 | int err = 0; | ||
2467 | |||
2468 | if (!(cam = kzalloc(sizeof(struct et61x251_device), GFP_KERNEL))) | ||
2469 | return -ENOMEM; | ||
2470 | |||
2471 | cam->usbdev = udev; | ||
2472 | |||
2473 | if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) { | ||
2474 | DBG(1, "kmalloc() failed"); | ||
2475 | err = -ENOMEM; | ||
2476 | goto fail; | ||
2477 | } | ||
2478 | |||
2479 | if (!(cam->v4ldev = video_device_alloc())) { | ||
2480 | DBG(1, "video_device_alloc() failed"); | ||
2481 | err = -ENOMEM; | ||
2482 | goto fail; | ||
2483 | } | ||
2484 | |||
2485 | mutex_init(&cam->dev_mutex); | ||
2486 | |||
2487 | DBG(2, "ET61X[12]51 PC Camera Controller detected " | ||
2488 | "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct); | ||
2489 | |||
2490 | for (i = 0; et61x251_sensor_table[i]; i++) { | ||
2491 | err = et61x251_sensor_table[i](cam); | ||
2492 | if (!err) | ||
2493 | break; | ||
2494 | } | ||
2495 | |||
2496 | if (!err) | ||
2497 | DBG(2, "%s image sensor detected", cam->sensor.name); | ||
2498 | else { | ||
2499 | DBG(1, "No supported image sensor detected"); | ||
2500 | err = -ENODEV; | ||
2501 | goto fail; | ||
2502 | } | ||
2503 | |||
2504 | if (et61x251_init(cam)) { | ||
2505 | DBG(1, "Initialization failed. I will retry on open()."); | ||
2506 | cam->state |= DEV_MISCONFIGURED; | ||
2507 | } | ||
2508 | |||
2509 | strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera"); | ||
2510 | cam->v4ldev->owner = THIS_MODULE; | ||
2511 | cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; | ||
2512 | cam->v4ldev->hardware = 0; | ||
2513 | cam->v4ldev->fops = &et61x251_fops; | ||
2514 | cam->v4ldev->minor = video_nr[dev_nr]; | ||
2515 | cam->v4ldev->release = video_device_release; | ||
2516 | video_set_drvdata(cam->v4ldev, cam); | ||
2517 | |||
2518 | mutex_lock(&cam->dev_mutex); | ||
2519 | |||
2520 | err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, | ||
2521 | video_nr[dev_nr]); | ||
2522 | if (err) { | ||
2523 | DBG(1, "V4L2 device registration failed"); | ||
2524 | if (err == -ENFILE && video_nr[dev_nr] == -1) | ||
2525 | DBG(1, "Free /dev/videoX node not found"); | ||
2526 | video_nr[dev_nr] = -1; | ||
2527 | dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
2528 | mutex_unlock(&cam->dev_mutex); | ||
2529 | goto fail; | ||
2530 | } | ||
2531 | |||
2532 | DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); | ||
2533 | |||
2534 | cam->module_param.force_munmap = force_munmap[dev_nr]; | ||
2535 | cam->module_param.frame_timeout = frame_timeout[dev_nr]; | ||
2536 | |||
2537 | dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
2538 | |||
2539 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
2540 | et61x251_create_sysfs(cam); | ||
2541 | DBG(2, "Optional device control through 'sysfs' interface ready"); | ||
2542 | #endif | ||
2543 | |||
2544 | usb_set_intfdata(intf, cam); | ||
2545 | |||
2546 | mutex_unlock(&cam->dev_mutex); | ||
2547 | |||
2548 | return 0; | ||
2549 | |||
2550 | fail: | ||
2551 | if (cam) { | ||
2552 | kfree(cam->control_buffer); | ||
2553 | if (cam->v4ldev) | ||
2554 | video_device_release(cam->v4ldev); | ||
2555 | kfree(cam); | ||
2556 | } | ||
2557 | return err; | ||
2558 | } | ||
2559 | |||
2560 | |||
2561 | static void et61x251_usb_disconnect(struct usb_interface* intf) | ||
2562 | { | ||
2563 | struct et61x251_device* cam = usb_get_intfdata(intf); | ||
2564 | |||
2565 | if (!cam) | ||
2566 | return; | ||
2567 | |||
2568 | down_write(&et61x251_disconnect); | ||
2569 | |||
2570 | mutex_lock(&cam->dev_mutex); | ||
2571 | |||
2572 | DBG(2, "Disconnecting %s...", cam->v4ldev->name); | ||
2573 | |||
2574 | wake_up_interruptible_all(&cam->open); | ||
2575 | |||
2576 | if (cam->users) { | ||
2577 | DBG(2, "Device /dev/video%d is open! Deregistration and " | ||
2578 | "memory deallocation are deferred on close.", | ||
2579 | cam->v4ldev->minor); | ||
2580 | cam->state |= DEV_MISCONFIGURED; | ||
2581 | et61x251_stop_transfer(cam); | ||
2582 | cam->state |= DEV_DISCONNECTED; | ||
2583 | wake_up_interruptible(&cam->wait_frame); | ||
2584 | wake_up(&cam->wait_stream); | ||
2585 | usb_get_dev(cam->usbdev); | ||
2586 | } else { | ||
2587 | cam->state |= DEV_DISCONNECTED; | ||
2588 | et61x251_release_resources(cam); | ||
2589 | } | ||
2590 | |||
2591 | mutex_unlock(&cam->dev_mutex); | ||
2592 | |||
2593 | if (!cam->users) | ||
2594 | kfree(cam); | ||
2595 | |||
2596 | up_write(&et61x251_disconnect); | ||
2597 | } | ||
2598 | |||
2599 | |||
2600 | static struct usb_driver et61x251_usb_driver = { | ||
2601 | .name = "et61x251", | ||
2602 | .id_table = et61x251_id_table, | ||
2603 | .probe = et61x251_usb_probe, | ||
2604 | .disconnect = et61x251_usb_disconnect, | ||
2605 | }; | ||
2606 | |||
2607 | /*****************************************************************************/ | ||
2608 | |||
2609 | static int __init et61x251_module_init(void) | ||
2610 | { | ||
2611 | int err = 0; | ||
2612 | |||
2613 | KDBG(2, ET61X251_MODULE_NAME " v" ET61X251_MODULE_VERSION); | ||
2614 | KDBG(3, ET61X251_MODULE_AUTHOR); | ||
2615 | |||
2616 | if ((err = usb_register(&et61x251_usb_driver))) | ||
2617 | KDBG(1, "usb_register() failed"); | ||
2618 | |||
2619 | return err; | ||
2620 | } | ||
2621 | |||
2622 | |||
2623 | static void __exit et61x251_module_exit(void) | ||
2624 | { | ||
2625 | usb_deregister(&et61x251_usb_driver); | ||
2626 | } | ||
2627 | |||
2628 | |||
2629 | module_init(et61x251_module_init); | ||
2630 | module_exit(et61x251_module_exit); | ||
diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h new file mode 100644 index 000000000000..56841ae8a207 --- /dev/null +++ b/drivers/media/video/et61x251/et61x251_sensor.h | |||
@@ -0,0 +1,116 @@ | |||
1 | /*************************************************************************** | ||
2 | * API for image sensors connected to ET61X[12]51 PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program is distributed in the hope that it will be useful, * | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #ifndef _ET61X251_SENSOR_H_ | ||
22 | #define _ET61X251_SENSOR_H_ | ||
23 | |||
24 | #include <linux/usb.h> | ||
25 | #include <linux/videodev.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/stddef.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <asm/types.h> | ||
30 | |||
31 | struct et61x251_device; | ||
32 | struct et61x251_sensor; | ||
33 | |||
34 | /*****************************************************************************/ | ||
35 | |||
36 | extern int et61x251_probe_tas5130d1b(struct et61x251_device* cam); | ||
37 | |||
38 | #define ET61X251_SENSOR_TABLE \ | ||
39 | /* Weak detections must go at the end of the list */ \ | ||
40 | static int (*et61x251_sensor_table[])(struct et61x251_device*) = { \ | ||
41 | &et61x251_probe_tas5130d1b, \ | ||
42 | NULL, \ | ||
43 | }; | ||
44 | |||
45 | extern struct et61x251_device* | ||
46 | et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id); | ||
47 | |||
48 | extern void | ||
49 | et61x251_attach_sensor(struct et61x251_device* cam, | ||
50 | struct et61x251_sensor* sensor); | ||
51 | |||
52 | /*****************************************************************************/ | ||
53 | |||
54 | extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index); | ||
55 | extern int et61x251_read_reg(struct et61x251_device*, u16 index); | ||
56 | extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value); | ||
57 | extern int et61x251_i2c_read(struct et61x251_device*, u8 address); | ||
58 | extern int et61x251_i2c_try_write(struct et61x251_device*, | ||
59 | struct et61x251_sensor*, u8 address, | ||
60 | u8 value); | ||
61 | extern int et61x251_i2c_try_read(struct et61x251_device*, | ||
62 | struct et61x251_sensor*, u8 address); | ||
63 | extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1, | ||
64 | u8 data2, u8 data3, u8 data4, u8 data5, | ||
65 | u8 data6, u8 data7, u8 data8, u8 address); | ||
66 | |||
67 | /*****************************************************************************/ | ||
68 | |||
69 | enum et61x251_i2c_sysfs_ops { | ||
70 | ET61X251_I2C_READ = 0x01, | ||
71 | ET61X251_I2C_WRITE = 0x02, | ||
72 | }; | ||
73 | |||
74 | enum et61x251_i2c_interface { | ||
75 | ET61X251_I2C_2WIRES, | ||
76 | ET61X251_I2C_3WIRES, | ||
77 | }; | ||
78 | |||
79 | /* Repeat start condition when RSTA is high */ | ||
80 | enum et61x251_i2c_rsta { | ||
81 | ET61X251_I2C_RSTA_STOP = 0x00, /* stop then start */ | ||
82 | ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */ | ||
83 | }; | ||
84 | |||
85 | #define ET61X251_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10 | ||
86 | |||
87 | struct et61x251_sensor { | ||
88 | char name[32]; | ||
89 | |||
90 | enum et61x251_i2c_sysfs_ops sysfs_ops; | ||
91 | |||
92 | enum et61x251_i2c_interface interface; | ||
93 | u8 i2c_slave_id; | ||
94 | enum et61x251_i2c_rsta rsta; | ||
95 | struct v4l2_rect active_pixel; /* left and top define FVSX and FVSY */ | ||
96 | |||
97 | struct v4l2_queryctrl qctrl[ET61X251_MAX_CTRLS]; | ||
98 | struct v4l2_cropcap cropcap; | ||
99 | struct v4l2_pix_format pix_format; | ||
100 | |||
101 | int (*init)(struct et61x251_device* cam); | ||
102 | int (*get_ctrl)(struct et61x251_device* cam, | ||
103 | struct v4l2_control* ctrl); | ||
104 | int (*set_ctrl)(struct et61x251_device* cam, | ||
105 | const struct v4l2_control* ctrl); | ||
106 | int (*set_crop)(struct et61x251_device* cam, | ||
107 | const struct v4l2_rect* rect); | ||
108 | int (*set_pix_format)(struct et61x251_device* cam, | ||
109 | const struct v4l2_pix_format* pix); | ||
110 | |||
111 | /* Private */ | ||
112 | struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS]; | ||
113 | struct v4l2_rect _rect; | ||
114 | }; | ||
115 | |||
116 | #endif /* _ET61X251_SENSOR_H_ */ | ||
diff --git a/drivers/media/video/et61x251/et61x251_tas5130d1b.c b/drivers/media/video/et61x251/et61x251_tas5130d1b.c new file mode 100644 index 000000000000..3998d76a307a --- /dev/null +++ b/drivers/media/video/et61x251/et61x251_tas5130d1b.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51 * | ||
3 | * PC Camera Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include "et61x251_sensor.h" | ||
23 | |||
24 | |||
25 | static int tas5130d1b_init(struct et61x251_device* cam) | ||
26 | { | ||
27 | int err = 0; | ||
28 | |||
29 | err += et61x251_write_reg(cam, 0x14, 0x01); | ||
30 | err += et61x251_write_reg(cam, 0x1b, 0x02); | ||
31 | err += et61x251_write_reg(cam, 0x02, 0x12); | ||
32 | err += et61x251_write_reg(cam, 0x0e, 0x60); | ||
33 | err += et61x251_write_reg(cam, 0x80, 0x61); | ||
34 | err += et61x251_write_reg(cam, 0xf0, 0x62); | ||
35 | err += et61x251_write_reg(cam, 0x03, 0x63); | ||
36 | err += et61x251_write_reg(cam, 0x14, 0x64); | ||
37 | err += et61x251_write_reg(cam, 0xf4, 0x65); | ||
38 | err += et61x251_write_reg(cam, 0x01, 0x66); | ||
39 | err += et61x251_write_reg(cam, 0x05, 0x67); | ||
40 | err += et61x251_write_reg(cam, 0x8f, 0x68); | ||
41 | err += et61x251_write_reg(cam, 0x0f, 0x8d); | ||
42 | err += et61x251_write_reg(cam, 0x08, 0x8e); | ||
43 | |||
44 | return err; | ||
45 | } | ||
46 | |||
47 | |||
48 | static int tas5130d1b_set_ctrl(struct et61x251_device* cam, | ||
49 | const struct v4l2_control* ctrl) | ||
50 | { | ||
51 | int err = 0; | ||
52 | |||
53 | switch (ctrl->id) { | ||
54 | case V4L2_CID_GAIN: | ||
55 | err += et61x251_i2c_raw_write(cam, 2, 0x20, | ||
56 | 0xf6-ctrl->value, 0, 0, 0, | ||
57 | 0, 0, 0, 0); | ||
58 | break; | ||
59 | case V4L2_CID_EXPOSURE: | ||
60 | err += et61x251_i2c_raw_write(cam, 2, 0x40, | ||
61 | 0x47-ctrl->value, 0, 0, 0, | ||
62 | 0, 0, 0, 0); | ||
63 | break; | ||
64 | default: | ||
65 | return -EINVAL; | ||
66 | } | ||
67 | |||
68 | return err ? -EIO : 0; | ||
69 | } | ||
70 | |||
71 | |||
72 | static struct et61x251_sensor tas5130d1b = { | ||
73 | .name = "TAS5130D1B", | ||
74 | .interface = ET61X251_I2C_3WIRES, | ||
75 | .rsta = ET61X251_I2C_RSTA_STOP, | ||
76 | .active_pixel = { | ||
77 | .left = 106, | ||
78 | .top = 13, | ||
79 | }, | ||
80 | .init = &tas5130d1b_init, | ||
81 | .qctrl = { | ||
82 | { | ||
83 | .id = V4L2_CID_GAIN, | ||
84 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
85 | .name = "global gain", | ||
86 | .minimum = 0x00, | ||
87 | .maximum = 0xf6, | ||
88 | .step = 0x02, | ||
89 | .default_value = 0x0d, | ||
90 | .flags = 0, | ||
91 | }, | ||
92 | { | ||
93 | .id = V4L2_CID_EXPOSURE, | ||
94 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
95 | .name = "exposure", | ||
96 | .minimum = 0x00, | ||
97 | .maximum = 0x47, | ||
98 | .step = 0x01, | ||
99 | .default_value = 0x23, | ||
100 | .flags = 0, | ||
101 | }, | ||
102 | }, | ||
103 | .set_ctrl = &tas5130d1b_set_ctrl, | ||
104 | .cropcap = { | ||
105 | .bounds = { | ||
106 | .left = 0, | ||
107 | .top = 0, | ||
108 | .width = 640, | ||
109 | .height = 480, | ||
110 | }, | ||
111 | .defrect = { | ||
112 | .left = 0, | ||
113 | .top = 0, | ||
114 | .width = 640, | ||
115 | .height = 480, | ||
116 | }, | ||
117 | }, | ||
118 | .pix_format = { | ||
119 | .width = 640, | ||
120 | .height = 480, | ||
121 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
122 | .priv = 8, | ||
123 | }, | ||
124 | }; | ||
125 | |||
126 | |||
127 | int et61x251_probe_tas5130d1b(struct et61x251_device* cam) | ||
128 | { | ||
129 | const struct usb_device_id tas5130d1b_id_table[] = { | ||
130 | { USB_DEVICE(0x102c, 0x6251), }, | ||
131 | { } | ||
132 | }; | ||
133 | |||
134 | /* Sensor detection is based on USB pid/vid */ | ||
135 | if (!et61x251_match_id(cam, tas5130d1b_id_table)) | ||
136 | return -ENODEV; | ||
137 | |||
138 | et61x251_attach_sensor(cam, &tas5130d1b); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c new file mode 100644 index 000000000000..da44579d6f29 --- /dev/null +++ b/drivers/media/video/ov511.c | |||
@@ -0,0 +1,5932 @@ | |||
1 | /* | ||
2 | * OmniVision OV511 Camera-to-USB Bridge Driver | ||
3 | * | ||
4 | * Copyright (c) 1999-2003 Mark W. McClelland | ||
5 | * Original decompression code Copyright 1998-2000 OmniVision Technologies | ||
6 | * Many improvements by Bret Wallach <bwallac1@san.rr.com> | ||
7 | * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000) | ||
8 | * Snapshot code by Kevin Moore | ||
9 | * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org> | ||
10 | * Changes by Claudio Matsuoka <claudio@conectiva.com> | ||
11 | * Original SAA7111A code by Dave Perks <dperks@ibm.net> | ||
12 | * URB error messages from pwc driver by Nemosoft | ||
13 | * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox | ||
14 | * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others | ||
15 | * | ||
16 | * Based on the Linux CPiA driver written by Peter Pregler, | ||
17 | * Scott J. Bertin and Johannes Erdfelt. | ||
18 | * | ||
19 | * Please see the file: Documentation/usb/ov511.txt | ||
20 | * and the website at: http://alpha.dyndns.org/ov511 | ||
21 | * for more info. | ||
22 | * | ||
23 | * This program is free software; you can redistribute it and/or modify it | ||
24 | * under the terms of the GNU General Public License as published by the | ||
25 | * Free Software Foundation; either version 2 of the License, or (at your | ||
26 | * option) any later version. | ||
27 | * | ||
28 | * This program is distributed in the hope that it will be useful, but | ||
29 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
30 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
31 | * for more details. | ||
32 | * | ||
33 | * You should have received a copy of the GNU General Public License | ||
34 | * along with this program; if not, write to the Free Software Foundation, | ||
35 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
36 | */ | ||
37 | |||
38 | #include <linux/config.h> | ||
39 | #include <linux/module.h> | ||
40 | #include <linux/init.h> | ||
41 | #include <linux/vmalloc.h> | ||
42 | #include <linux/slab.h> | ||
43 | #include <linux/ctype.h> | ||
44 | #include <linux/pagemap.h> | ||
45 | #include <asm/semaphore.h> | ||
46 | #include <asm/processor.h> | ||
47 | #include <linux/mm.h> | ||
48 | #include <linux/device.h> | ||
49 | |||
50 | #if defined (__i386__) | ||
51 | #include <asm/cpufeature.h> | ||
52 | #endif | ||
53 | |||
54 | #include "ov511.h" | ||
55 | |||
56 | /* | ||
57 | * Version Information | ||
58 | */ | ||
59 | #define DRIVER_VERSION "v1.64 for Linux 2.5" | ||
60 | #define EMAIL "mark@alpha.dyndns.org" | ||
61 | #define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \ | ||
62 | & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \ | ||
63 | <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>" | ||
64 | #define DRIVER_DESC "ov511 USB Camera Driver" | ||
65 | |||
66 | #define OV511_I2C_RETRIES 3 | ||
67 | #define ENABLE_Y_QUANTABLE 1 | ||
68 | #define ENABLE_UV_QUANTABLE 1 | ||
69 | |||
70 | #define OV511_MAX_UNIT_VIDEO 16 | ||
71 | |||
72 | /* Pixel count * bytes per YUV420 pixel (1.5) */ | ||
73 | #define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2) | ||
74 | |||
75 | #define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval)) | ||
76 | |||
77 | /* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */ | ||
78 | #define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024) | ||
79 | |||
80 | #define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM) | ||
81 | |||
82 | /********************************************************************** | ||
83 | * Module Parameters | ||
84 | * (See ov511.txt for detailed descriptions of these) | ||
85 | **********************************************************************/ | ||
86 | |||
87 | /* These variables (and all static globals) default to zero */ | ||
88 | static int autobright = 1; | ||
89 | static int autogain = 1; | ||
90 | static int autoexp = 1; | ||
91 | static int debug; | ||
92 | static int snapshot; | ||
93 | static int cams = 1; | ||
94 | static int compress; | ||
95 | static int testpat; | ||
96 | static int dumppix; | ||
97 | static int led = 1; | ||
98 | static int dump_bridge; | ||
99 | static int dump_sensor; | ||
100 | static int printph; | ||
101 | static int phy = 0x1f; | ||
102 | static int phuv = 0x05; | ||
103 | static int pvy = 0x06; | ||
104 | static int pvuv = 0x06; | ||
105 | static int qhy = 0x14; | ||
106 | static int qhuv = 0x03; | ||
107 | static int qvy = 0x04; | ||
108 | static int qvuv = 0x04; | ||
109 | static int lightfreq; | ||
110 | static int bandingfilter; | ||
111 | static int clockdiv = -1; | ||
112 | static int packetsize = -1; | ||
113 | static int framedrop = -1; | ||
114 | static int fastset; | ||
115 | static int force_palette; | ||
116 | static int backlight; | ||
117 | static int unit_video[OV511_MAX_UNIT_VIDEO]; | ||
118 | static int remove_zeros; | ||
119 | static int mirror; | ||
120 | static int ov518_color; | ||
121 | |||
122 | module_param(autobright, int, 0); | ||
123 | MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness"); | ||
124 | module_param(autogain, int, 0); | ||
125 | MODULE_PARM_DESC(autogain, "Sensor automatically changes gain"); | ||
126 | module_param(autoexp, int, 0); | ||
127 | MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure"); | ||
128 | module_param(debug, int, 0); | ||
129 | MODULE_PARM_DESC(debug, | ||
130 | "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max"); | ||
131 | module_param(snapshot, int, 0); | ||
132 | MODULE_PARM_DESC(snapshot, "Enable snapshot mode"); | ||
133 | module_param(cams, int, 0); | ||
134 | MODULE_PARM_DESC(cams, "Number of simultaneous cameras"); | ||
135 | module_param(compress, int, 0); | ||
136 | MODULE_PARM_DESC(compress, "Turn on compression"); | ||
137 | module_param(testpat, int, 0); | ||
138 | MODULE_PARM_DESC(testpat, | ||
139 | "Replace image with vertical bar testpattern (only partially working)"); | ||
140 | module_param(dumppix, int, 0); | ||
141 | MODULE_PARM_DESC(dumppix, "Dump raw pixel data"); | ||
142 | module_param(led, int, 0); | ||
143 | MODULE_PARM_DESC(led, | ||
144 | "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)"); | ||
145 | module_param(dump_bridge, int, 0); | ||
146 | MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers"); | ||
147 | module_param(dump_sensor, int, 0); | ||
148 | MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers"); | ||
149 | module_param(printph, int, 0); | ||
150 | MODULE_PARM_DESC(printph, "Print frame start/end headers"); | ||
151 | module_param(phy, int, 0); | ||
152 | MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)"); | ||
153 | module_param(phuv, int, 0); | ||
154 | MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)"); | ||
155 | module_param(pvy, int, 0); | ||
156 | MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)"); | ||
157 | module_param(pvuv, int, 0); | ||
158 | MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)"); | ||
159 | module_param(qhy, int, 0); | ||
160 | MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)"); | ||
161 | module_param(qhuv, int, 0); | ||
162 | MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)"); | ||
163 | module_param(qvy, int, 0); | ||
164 | MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)"); | ||
165 | module_param(qvuv, int, 0); | ||
166 | MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)"); | ||
167 | module_param(lightfreq, int, 0); | ||
168 | MODULE_PARM_DESC(lightfreq, | ||
169 | "Light frequency. Set to 50 or 60 Hz, or zero for default settings"); | ||
170 | module_param(bandingfilter, int, 0); | ||
171 | MODULE_PARM_DESC(bandingfilter, | ||
172 | "Enable banding filter (to reduce effects of fluorescent lighting)"); | ||
173 | module_param(clockdiv, int, 0); | ||
174 | MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value"); | ||
175 | module_param(packetsize, int, 0); | ||
176 | MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size"); | ||
177 | module_param(framedrop, int, 0); | ||
178 | MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting"); | ||
179 | module_param(fastset, int, 0); | ||
180 | MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately"); | ||
181 | module_param(force_palette, int, 0); | ||
182 | MODULE_PARM_DESC(force_palette, "Force the palette to a specific value"); | ||
183 | module_param(backlight, int, 0); | ||
184 | MODULE_PARM_DESC(backlight, "For objects that are lit from behind"); | ||
185 | static int num_uv; | ||
186 | module_param_array(unit_video, int, &num_uv, 0); | ||
187 | MODULE_PARM_DESC(unit_video, | ||
188 | "Force use of specific minor number(s). 0 is not allowed."); | ||
189 | module_param(remove_zeros, int, 0); | ||
190 | MODULE_PARM_DESC(remove_zeros, | ||
191 | "Remove zero-padding from uncompressed incoming data"); | ||
192 | module_param(mirror, int, 0); | ||
193 | MODULE_PARM_DESC(mirror, "Reverse image horizontally"); | ||
194 | module_param(ov518_color, int, 0); | ||
195 | MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)"); | ||
196 | |||
197 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
198 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
199 | MODULE_LICENSE("GPL"); | ||
200 | |||
201 | /********************************************************************** | ||
202 | * Miscellaneous Globals | ||
203 | **********************************************************************/ | ||
204 | |||
205 | static struct usb_driver ov511_driver; | ||
206 | |||
207 | /* Number of times to retry a failed I2C transaction. Increase this if you | ||
208 | * are getting "Failed to read sensor ID..." */ | ||
209 | static const int i2c_detect_tries = 5; | ||
210 | |||
211 | static struct usb_device_id device_table [] = { | ||
212 | { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) }, | ||
213 | { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) }, | ||
214 | { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) }, | ||
215 | { USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) }, | ||
216 | { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) }, | ||
217 | { } /* Terminating entry */ | ||
218 | }; | ||
219 | |||
220 | MODULE_DEVICE_TABLE (usb, device_table); | ||
221 | |||
222 | static unsigned char yQuanTable511[] = OV511_YQUANTABLE; | ||
223 | static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE; | ||
224 | static unsigned char yQuanTable518[] = OV518_YQUANTABLE; | ||
225 | static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE; | ||
226 | |||
227 | /********************************************************************** | ||
228 | * Symbolic Names | ||
229 | **********************************************************************/ | ||
230 | |||
231 | /* Known OV511-based cameras */ | ||
232 | static struct symbolic_list camlist[] = { | ||
233 | { 0, "Generic Camera (no ID)" }, | ||
234 | { 1, "Mustek WCam 3X" }, | ||
235 | { 3, "D-Link DSB-C300" }, | ||
236 | { 4, "Generic OV511/OV7610" }, | ||
237 | { 5, "Puretek PT-6007" }, | ||
238 | { 6, "Lifeview USB Life TV (NTSC)" }, | ||
239 | { 21, "Creative Labs WebCam 3" }, | ||
240 | { 22, "Lifeview USB Life TV (PAL D/K+B/G)" }, | ||
241 | { 36, "Koala-Cam" }, | ||
242 | { 38, "Lifeview USB Life TV (PAL)" }, | ||
243 | { 41, "Samsung Anycam MPC-M10" }, | ||
244 | { 43, "Mtekvision Zeca MV402" }, | ||
245 | { 46, "Suma eON" }, | ||
246 | { 70, "Lifeview USB Life TV (PAL/SECAM)" }, | ||
247 | { 100, "Lifeview RoboCam" }, | ||
248 | { 102, "AverMedia InterCam Elite" }, | ||
249 | { 112, "MediaForte MV300" }, /* or OV7110 evaluation kit */ | ||
250 | { 134, "Ezonics EZCam II" }, | ||
251 | { 192, "Webeye 2000B" }, | ||
252 | { 253, "Alpha Vision Tech. AlphaCam SE" }, | ||
253 | { -1, NULL } | ||
254 | }; | ||
255 | |||
256 | /* Video4Linux1 Palettes */ | ||
257 | static struct symbolic_list v4l1_plist[] = { | ||
258 | { VIDEO_PALETTE_GREY, "GREY" }, | ||
259 | { VIDEO_PALETTE_HI240, "HI240" }, | ||
260 | { VIDEO_PALETTE_RGB565, "RGB565" }, | ||
261 | { VIDEO_PALETTE_RGB24, "RGB24" }, | ||
262 | { VIDEO_PALETTE_RGB32, "RGB32" }, | ||
263 | { VIDEO_PALETTE_RGB555, "RGB555" }, | ||
264 | { VIDEO_PALETTE_YUV422, "YUV422" }, | ||
265 | { VIDEO_PALETTE_YUYV, "YUYV" }, | ||
266 | { VIDEO_PALETTE_UYVY, "UYVY" }, | ||
267 | { VIDEO_PALETTE_YUV420, "YUV420" }, | ||
268 | { VIDEO_PALETTE_YUV411, "YUV411" }, | ||
269 | { VIDEO_PALETTE_RAW, "RAW" }, | ||
270 | { VIDEO_PALETTE_YUV422P,"YUV422P" }, | ||
271 | { VIDEO_PALETTE_YUV411P,"YUV411P" }, | ||
272 | { VIDEO_PALETTE_YUV420P,"YUV420P" }, | ||
273 | { VIDEO_PALETTE_YUV410P,"YUV410P" }, | ||
274 | { -1, NULL } | ||
275 | }; | ||
276 | |||
277 | static struct symbolic_list brglist[] = { | ||
278 | { BRG_OV511, "OV511" }, | ||
279 | { BRG_OV511PLUS, "OV511+" }, | ||
280 | { BRG_OV518, "OV518" }, | ||
281 | { BRG_OV518PLUS, "OV518+" }, | ||
282 | { -1, NULL } | ||
283 | }; | ||
284 | |||
285 | static struct symbolic_list senlist[] = { | ||
286 | { SEN_OV76BE, "OV76BE" }, | ||
287 | { SEN_OV7610, "OV7610" }, | ||
288 | { SEN_OV7620, "OV7620" }, | ||
289 | { SEN_OV7620AE, "OV7620AE" }, | ||
290 | { SEN_OV6620, "OV6620" }, | ||
291 | { SEN_OV6630, "OV6630" }, | ||
292 | { SEN_OV6630AE, "OV6630AE" }, | ||
293 | { SEN_OV6630AF, "OV6630AF" }, | ||
294 | { SEN_OV8600, "OV8600" }, | ||
295 | { SEN_KS0127, "KS0127" }, | ||
296 | { SEN_KS0127B, "KS0127B" }, | ||
297 | { SEN_SAA7111A, "SAA7111A" }, | ||
298 | { -1, NULL } | ||
299 | }; | ||
300 | |||
301 | /* URB error codes: */ | ||
302 | static struct symbolic_list urb_errlist[] = { | ||
303 | { -ENOSR, "Buffer error (overrun)" }, | ||
304 | { -EPIPE, "Stalled (device not responding)" }, | ||
305 | { -EOVERFLOW, "Babble (bad cable?)" }, | ||
306 | { -EPROTO, "Bit-stuff error (bad cable?)" }, | ||
307 | { -EILSEQ, "CRC/Timeout" }, | ||
308 | { -ETIMEDOUT, "NAK (device does not respond)" }, | ||
309 | { -1, NULL } | ||
310 | }; | ||
311 | |||
312 | /********************************************************************** | ||
313 | * Memory management | ||
314 | **********************************************************************/ | ||
315 | static void * | ||
316 | rvmalloc(unsigned long size) | ||
317 | { | ||
318 | void *mem; | ||
319 | unsigned long adr; | ||
320 | |||
321 | size = PAGE_ALIGN(size); | ||
322 | mem = vmalloc_32(size); | ||
323 | if (!mem) | ||
324 | return NULL; | ||
325 | |||
326 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
327 | adr = (unsigned long) mem; | ||
328 | while (size > 0) { | ||
329 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
330 | adr += PAGE_SIZE; | ||
331 | size -= PAGE_SIZE; | ||
332 | } | ||
333 | |||
334 | return mem; | ||
335 | } | ||
336 | |||
337 | static void | ||
338 | rvfree(void *mem, unsigned long size) | ||
339 | { | ||
340 | unsigned long adr; | ||
341 | |||
342 | if (!mem) | ||
343 | return; | ||
344 | |||
345 | adr = (unsigned long) mem; | ||
346 | while ((long) size > 0) { | ||
347 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
348 | adr += PAGE_SIZE; | ||
349 | size -= PAGE_SIZE; | ||
350 | } | ||
351 | vfree(mem); | ||
352 | } | ||
353 | |||
354 | /********************************************************************** | ||
355 | * | ||
356 | * Register I/O | ||
357 | * | ||
358 | **********************************************************************/ | ||
359 | |||
360 | /* Write an OV51x register */ | ||
361 | static int | ||
362 | reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) | ||
363 | { | ||
364 | int rc; | ||
365 | |||
366 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
367 | |||
368 | mutex_lock(&ov->cbuf_lock); | ||
369 | ov->cbuf[0] = value; | ||
370 | rc = usb_control_msg(ov->dev, | ||
371 | usb_sndctrlpipe(ov->dev, 0), | ||
372 | (ov->bclass == BCL_OV518)?1:2 /* REG_IO */, | ||
373 | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
374 | 0, (__u16)reg, &ov->cbuf[0], 1, 1000); | ||
375 | mutex_unlock(&ov->cbuf_lock); | ||
376 | |||
377 | if (rc < 0) | ||
378 | err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc)); | ||
379 | |||
380 | return rc; | ||
381 | } | ||
382 | |||
383 | /* Read from an OV51x register */ | ||
384 | /* returns: negative is error, pos or zero is data */ | ||
385 | static int | ||
386 | reg_r(struct usb_ov511 *ov, unsigned char reg) | ||
387 | { | ||
388 | int rc; | ||
389 | |||
390 | mutex_lock(&ov->cbuf_lock); | ||
391 | rc = usb_control_msg(ov->dev, | ||
392 | usb_rcvctrlpipe(ov->dev, 0), | ||
393 | (ov->bclass == BCL_OV518)?1:3 /* REG_IO */, | ||
394 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
395 | 0, (__u16)reg, &ov->cbuf[0], 1, 1000); | ||
396 | |||
397 | if (rc < 0) { | ||
398 | err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc)); | ||
399 | } else { | ||
400 | rc = ov->cbuf[0]; | ||
401 | PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]); | ||
402 | } | ||
403 | |||
404 | mutex_unlock(&ov->cbuf_lock); | ||
405 | |||
406 | return rc; | ||
407 | } | ||
408 | |||
409 | /* | ||
410 | * Writes bits at positions specified by mask to an OV51x reg. Bits that are in | ||
411 | * the same position as 1's in "mask" are cleared and set to "value". Bits | ||
412 | * that are in the same position as 0's in "mask" are preserved, regardless | ||
413 | * of their respective state in "value". | ||
414 | */ | ||
415 | static int | ||
416 | reg_w_mask(struct usb_ov511 *ov, | ||
417 | unsigned char reg, | ||
418 | unsigned char value, | ||
419 | unsigned char mask) | ||
420 | { | ||
421 | int ret; | ||
422 | unsigned char oldval, newval; | ||
423 | |||
424 | ret = reg_r(ov, reg); | ||
425 | if (ret < 0) | ||
426 | return ret; | ||
427 | |||
428 | oldval = (unsigned char) ret; | ||
429 | oldval &= (~mask); /* Clear the masked bits */ | ||
430 | value &= mask; /* Enforce mask on value */ | ||
431 | newval = oldval | value; /* Set the desired bits */ | ||
432 | |||
433 | return (reg_w(ov, reg, newval)); | ||
434 | } | ||
435 | |||
436 | /* | ||
437 | * Writes multiple (n) byte value to a single register. Only valid with certain | ||
438 | * registers (0x30 and 0xc4 - 0xce). | ||
439 | */ | ||
440 | static int | ||
441 | ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n) | ||
442 | { | ||
443 | int rc; | ||
444 | |||
445 | PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n); | ||
446 | |||
447 | mutex_lock(&ov->cbuf_lock); | ||
448 | |||
449 | *((__le32 *)ov->cbuf) = __cpu_to_le32(val); | ||
450 | |||
451 | rc = usb_control_msg(ov->dev, | ||
452 | usb_sndctrlpipe(ov->dev, 0), | ||
453 | 1 /* REG_IO */, | ||
454 | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
455 | 0, (__u16)reg, ov->cbuf, n, 1000); | ||
456 | mutex_unlock(&ov->cbuf_lock); | ||
457 | |||
458 | if (rc < 0) | ||
459 | err("reg write multiple: error %d: %s", rc, | ||
460 | symbolic(urb_errlist, rc)); | ||
461 | |||
462 | return rc; | ||
463 | } | ||
464 | |||
465 | static int | ||
466 | ov511_upload_quan_tables(struct usb_ov511 *ov) | ||
467 | { | ||
468 | unsigned char *pYTable = yQuanTable511; | ||
469 | unsigned char *pUVTable = uvQuanTable511; | ||
470 | unsigned char val0, val1; | ||
471 | int i, rc, reg = R511_COMP_LUT_BEGIN; | ||
472 | |||
473 | PDEBUG(4, "Uploading quantization tables"); | ||
474 | |||
475 | for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) { | ||
476 | if (ENABLE_Y_QUANTABLE) { | ||
477 | val0 = *pYTable++; | ||
478 | val1 = *pYTable++; | ||
479 | val0 &= 0x0f; | ||
480 | val1 &= 0x0f; | ||
481 | val0 |= val1 << 4; | ||
482 | rc = reg_w(ov, reg, val0); | ||
483 | if (rc < 0) | ||
484 | return rc; | ||
485 | } | ||
486 | |||
487 | if (ENABLE_UV_QUANTABLE) { | ||
488 | val0 = *pUVTable++; | ||
489 | val1 = *pUVTable++; | ||
490 | val0 &= 0x0f; | ||
491 | val1 &= 0x0f; | ||
492 | val0 |= val1 << 4; | ||
493 | rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0); | ||
494 | if (rc < 0) | ||
495 | return rc; | ||
496 | } | ||
497 | |||
498 | reg++; | ||
499 | } | ||
500 | |||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | /* OV518 quantization tables are 8x4 (instead of 8x8) */ | ||
505 | static int | ||
506 | ov518_upload_quan_tables(struct usb_ov511 *ov) | ||
507 | { | ||
508 | unsigned char *pYTable = yQuanTable518; | ||
509 | unsigned char *pUVTable = uvQuanTable518; | ||
510 | unsigned char val0, val1; | ||
511 | int i, rc, reg = R511_COMP_LUT_BEGIN; | ||
512 | |||
513 | PDEBUG(4, "Uploading quantization tables"); | ||
514 | |||
515 | for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) { | ||
516 | if (ENABLE_Y_QUANTABLE) { | ||
517 | val0 = *pYTable++; | ||
518 | val1 = *pYTable++; | ||
519 | val0 &= 0x0f; | ||
520 | val1 &= 0x0f; | ||
521 | val0 |= val1 << 4; | ||
522 | rc = reg_w(ov, reg, val0); | ||
523 | if (rc < 0) | ||
524 | return rc; | ||
525 | } | ||
526 | |||
527 | if (ENABLE_UV_QUANTABLE) { | ||
528 | val0 = *pUVTable++; | ||
529 | val1 = *pUVTable++; | ||
530 | val0 &= 0x0f; | ||
531 | val1 &= 0x0f; | ||
532 | val0 |= val1 << 4; | ||
533 | rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0); | ||
534 | if (rc < 0) | ||
535 | return rc; | ||
536 | } | ||
537 | |||
538 | reg++; | ||
539 | } | ||
540 | |||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | static int | ||
545 | ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type) | ||
546 | { | ||
547 | int rc; | ||
548 | |||
549 | /* Setting bit 0 not allowed on 518/518Plus */ | ||
550 | if (ov->bclass == BCL_OV518) | ||
551 | reset_type &= 0xfe; | ||
552 | |||
553 | PDEBUG(4, "Reset: type=0x%02X", reset_type); | ||
554 | |||
555 | rc = reg_w(ov, R51x_SYS_RESET, reset_type); | ||
556 | rc = reg_w(ov, R51x_SYS_RESET, 0); | ||
557 | |||
558 | if (rc < 0) | ||
559 | err("reset: command failed"); | ||
560 | |||
561 | return rc; | ||
562 | } | ||
563 | |||
564 | /********************************************************************** | ||
565 | * | ||
566 | * Low-level I2C I/O functions | ||
567 | * | ||
568 | **********************************************************************/ | ||
569 | |||
570 | /* NOTE: Do not call this function directly! | ||
571 | * The OV518 I2C I/O procedure is different, hence, this function. | ||
572 | * This is normally only called from i2c_w(). Note that this function | ||
573 | * always succeeds regardless of whether the sensor is present and working. | ||
574 | */ | ||
575 | static int | ||
576 | ov518_i2c_write_internal(struct usb_ov511 *ov, | ||
577 | unsigned char reg, | ||
578 | unsigned char value) | ||
579 | { | ||
580 | int rc; | ||
581 | |||
582 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
583 | |||
584 | /* Select camera register */ | ||
585 | rc = reg_w(ov, R51x_I2C_SADDR_3, reg); | ||
586 | if (rc < 0) | ||
587 | return rc; | ||
588 | |||
589 | /* Write "value" to I2C data port of OV511 */ | ||
590 | rc = reg_w(ov, R51x_I2C_DATA, value); | ||
591 | if (rc < 0) | ||
592 | return rc; | ||
593 | |||
594 | /* Initiate 3-byte write cycle */ | ||
595 | rc = reg_w(ov, R518_I2C_CTL, 0x01); | ||
596 | if (rc < 0) | ||
597 | return rc; | ||
598 | |||
599 | return 0; | ||
600 | } | ||
601 | |||
602 | /* NOTE: Do not call this function directly! */ | ||
603 | static int | ||
604 | ov511_i2c_write_internal(struct usb_ov511 *ov, | ||
605 | unsigned char reg, | ||
606 | unsigned char value) | ||
607 | { | ||
608 | int rc, retries; | ||
609 | |||
610 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
611 | |||
612 | /* Three byte write cycle */ | ||
613 | for (retries = OV511_I2C_RETRIES; ; ) { | ||
614 | /* Select camera register */ | ||
615 | rc = reg_w(ov, R51x_I2C_SADDR_3, reg); | ||
616 | if (rc < 0) | ||
617 | break; | ||
618 | |||
619 | /* Write "value" to I2C data port of OV511 */ | ||
620 | rc = reg_w(ov, R51x_I2C_DATA, value); | ||
621 | if (rc < 0) | ||
622 | break; | ||
623 | |||
624 | /* Initiate 3-byte write cycle */ | ||
625 | rc = reg_w(ov, R511_I2C_CTL, 0x01); | ||
626 | if (rc < 0) | ||
627 | break; | ||
628 | |||
629 | /* Retry until idle */ | ||
630 | do | ||
631 | rc = reg_r(ov, R511_I2C_CTL); | ||
632 | while (rc > 0 && ((rc&1) == 0)); | ||
633 | if (rc < 0) | ||
634 | break; | ||
635 | |||
636 | /* Ack? */ | ||
637 | if ((rc&2) == 0) { | ||
638 | rc = 0; | ||
639 | break; | ||
640 | } | ||
641 | #if 0 | ||
642 | /* I2C abort */ | ||
643 | reg_w(ov, R511_I2C_CTL, 0x10); | ||
644 | #endif | ||
645 | if (--retries < 0) { | ||
646 | err("i2c write retries exhausted"); | ||
647 | rc = -1; | ||
648 | break; | ||
649 | } | ||
650 | } | ||
651 | |||
652 | return rc; | ||
653 | } | ||
654 | |||
655 | /* NOTE: Do not call this function directly! | ||
656 | * The OV518 I2C I/O procedure is different, hence, this function. | ||
657 | * This is normally only called from i2c_r(). Note that this function | ||
658 | * always succeeds regardless of whether the sensor is present and working. | ||
659 | */ | ||
660 | static int | ||
661 | ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) | ||
662 | { | ||
663 | int rc, value; | ||
664 | |||
665 | /* Select camera register */ | ||
666 | rc = reg_w(ov, R51x_I2C_SADDR_2, reg); | ||
667 | if (rc < 0) | ||
668 | return rc; | ||
669 | |||
670 | /* Initiate 2-byte write cycle */ | ||
671 | rc = reg_w(ov, R518_I2C_CTL, 0x03); | ||
672 | if (rc < 0) | ||
673 | return rc; | ||
674 | |||
675 | /* Initiate 2-byte read cycle */ | ||
676 | rc = reg_w(ov, R518_I2C_CTL, 0x05); | ||
677 | if (rc < 0) | ||
678 | return rc; | ||
679 | |||
680 | value = reg_r(ov, R51x_I2C_DATA); | ||
681 | |||
682 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
683 | |||
684 | return value; | ||
685 | } | ||
686 | |||
687 | /* NOTE: Do not call this function directly! | ||
688 | * returns: negative is error, pos or zero is data */ | ||
689 | static int | ||
690 | ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) | ||
691 | { | ||
692 | int rc, value, retries; | ||
693 | |||
694 | /* Two byte write cycle */ | ||
695 | for (retries = OV511_I2C_RETRIES; ; ) { | ||
696 | /* Select camera register */ | ||
697 | rc = reg_w(ov, R51x_I2C_SADDR_2, reg); | ||
698 | if (rc < 0) | ||
699 | return rc; | ||
700 | |||
701 | /* Initiate 2-byte write cycle */ | ||
702 | rc = reg_w(ov, R511_I2C_CTL, 0x03); | ||
703 | if (rc < 0) | ||
704 | return rc; | ||
705 | |||
706 | /* Retry until idle */ | ||
707 | do | ||
708 | rc = reg_r(ov, R511_I2C_CTL); | ||
709 | while (rc > 0 && ((rc&1) == 0)); | ||
710 | if (rc < 0) | ||
711 | return rc; | ||
712 | |||
713 | if ((rc&2) == 0) /* Ack? */ | ||
714 | break; | ||
715 | |||
716 | /* I2C abort */ | ||
717 | reg_w(ov, R511_I2C_CTL, 0x10); | ||
718 | |||
719 | if (--retries < 0) { | ||
720 | err("i2c write retries exhausted"); | ||
721 | return -1; | ||
722 | } | ||
723 | } | ||
724 | |||
725 | /* Two byte read cycle */ | ||
726 | for (retries = OV511_I2C_RETRIES; ; ) { | ||
727 | /* Initiate 2-byte read cycle */ | ||
728 | rc = reg_w(ov, R511_I2C_CTL, 0x05); | ||
729 | if (rc < 0) | ||
730 | return rc; | ||
731 | |||
732 | /* Retry until idle */ | ||
733 | do | ||
734 | rc = reg_r(ov, R511_I2C_CTL); | ||
735 | while (rc > 0 && ((rc&1) == 0)); | ||
736 | if (rc < 0) | ||
737 | return rc; | ||
738 | |||
739 | if ((rc&2) == 0) /* Ack? */ | ||
740 | break; | ||
741 | |||
742 | /* I2C abort */ | ||
743 | rc = reg_w(ov, R511_I2C_CTL, 0x10); | ||
744 | if (rc < 0) | ||
745 | return rc; | ||
746 | |||
747 | if (--retries < 0) { | ||
748 | err("i2c read retries exhausted"); | ||
749 | return -1; | ||
750 | } | ||
751 | } | ||
752 | |||
753 | value = reg_r(ov, R51x_I2C_DATA); | ||
754 | |||
755 | PDEBUG(5, "0x%02X:0x%02X", reg, value); | ||
756 | |||
757 | /* This is needed to make i2c_w() work */ | ||
758 | rc = reg_w(ov, R511_I2C_CTL, 0x05); | ||
759 | if (rc < 0) | ||
760 | return rc; | ||
761 | |||
762 | return value; | ||
763 | } | ||
764 | |||
765 | /* returns: negative is error, pos or zero is data */ | ||
766 | static int | ||
767 | i2c_r(struct usb_ov511 *ov, unsigned char reg) | ||
768 | { | ||
769 | int rc; | ||
770 | |||
771 | mutex_lock(&ov->i2c_lock); | ||
772 | |||
773 | if (ov->bclass == BCL_OV518) | ||
774 | rc = ov518_i2c_read_internal(ov, reg); | ||
775 | else | ||
776 | rc = ov511_i2c_read_internal(ov, reg); | ||
777 | |||
778 | mutex_unlock(&ov->i2c_lock); | ||
779 | |||
780 | return rc; | ||
781 | } | ||
782 | |||
783 | static int | ||
784 | i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) | ||
785 | { | ||
786 | int rc; | ||
787 | |||
788 | mutex_lock(&ov->i2c_lock); | ||
789 | |||
790 | if (ov->bclass == BCL_OV518) | ||
791 | rc = ov518_i2c_write_internal(ov, reg, value); | ||
792 | else | ||
793 | rc = ov511_i2c_write_internal(ov, reg, value); | ||
794 | |||
795 | mutex_unlock(&ov->i2c_lock); | ||
796 | |||
797 | return rc; | ||
798 | } | ||
799 | |||
800 | /* Do not call this function directly! */ | ||
801 | static int | ||
802 | ov51x_i2c_write_mask_internal(struct usb_ov511 *ov, | ||
803 | unsigned char reg, | ||
804 | unsigned char value, | ||
805 | unsigned char mask) | ||
806 | { | ||
807 | int rc; | ||
808 | unsigned char oldval, newval; | ||
809 | |||
810 | if (mask == 0xff) { | ||
811 | newval = value; | ||
812 | } else { | ||
813 | if (ov->bclass == BCL_OV518) | ||
814 | rc = ov518_i2c_read_internal(ov, reg); | ||
815 | else | ||
816 | rc = ov511_i2c_read_internal(ov, reg); | ||
817 | if (rc < 0) | ||
818 | return rc; | ||
819 | |||
820 | oldval = (unsigned char) rc; | ||
821 | oldval &= (~mask); /* Clear the masked bits */ | ||
822 | value &= mask; /* Enforce mask on value */ | ||
823 | newval = oldval | value; /* Set the desired bits */ | ||
824 | } | ||
825 | |||
826 | if (ov->bclass == BCL_OV518) | ||
827 | return (ov518_i2c_write_internal(ov, reg, newval)); | ||
828 | else | ||
829 | return (ov511_i2c_write_internal(ov, reg, newval)); | ||
830 | } | ||
831 | |||
832 | /* Writes bits at positions specified by mask to an I2C reg. Bits that are in | ||
833 | * the same position as 1's in "mask" are cleared and set to "value". Bits | ||
834 | * that are in the same position as 0's in "mask" are preserved, regardless | ||
835 | * of their respective state in "value". | ||
836 | */ | ||
837 | static int | ||
838 | i2c_w_mask(struct usb_ov511 *ov, | ||
839 | unsigned char reg, | ||
840 | unsigned char value, | ||
841 | unsigned char mask) | ||
842 | { | ||
843 | int rc; | ||
844 | |||
845 | mutex_lock(&ov->i2c_lock); | ||
846 | rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); | ||
847 | mutex_unlock(&ov->i2c_lock); | ||
848 | |||
849 | return rc; | ||
850 | } | ||
851 | |||
852 | /* Set the read and write slave IDs. The "slave" argument is the write slave, | ||
853 | * and the read slave will be set to (slave + 1). ov->i2c_lock should be held | ||
854 | * when calling this. This should not be called from outside the i2c I/O | ||
855 | * functions. | ||
856 | */ | ||
857 | static int | ||
858 | i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave) | ||
859 | { | ||
860 | int rc; | ||
861 | |||
862 | rc = reg_w(ov, R51x_I2C_W_SID, slave); | ||
863 | if (rc < 0) | ||
864 | return rc; | ||
865 | |||
866 | rc = reg_w(ov, R51x_I2C_R_SID, slave + 1); | ||
867 | if (rc < 0) | ||
868 | return rc; | ||
869 | |||
870 | return 0; | ||
871 | } | ||
872 | |||
873 | /* Write to a specific I2C slave ID and register, using the specified mask */ | ||
874 | static int | ||
875 | i2c_w_slave(struct usb_ov511 *ov, | ||
876 | unsigned char slave, | ||
877 | unsigned char reg, | ||
878 | unsigned char value, | ||
879 | unsigned char mask) | ||
880 | { | ||
881 | int rc = 0; | ||
882 | |||
883 | mutex_lock(&ov->i2c_lock); | ||
884 | |||
885 | /* Set new slave IDs */ | ||
886 | rc = i2c_set_slave_internal(ov, slave); | ||
887 | if (rc < 0) | ||
888 | goto out; | ||
889 | |||
890 | rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); | ||
891 | |||
892 | out: | ||
893 | /* Restore primary IDs */ | ||
894 | if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) | ||
895 | err("Couldn't restore primary I2C slave"); | ||
896 | |||
897 | mutex_unlock(&ov->i2c_lock); | ||
898 | return rc; | ||
899 | } | ||
900 | |||
901 | /* Read from a specific I2C slave ID and register */ | ||
902 | static int | ||
903 | i2c_r_slave(struct usb_ov511 *ov, | ||
904 | unsigned char slave, | ||
905 | unsigned char reg) | ||
906 | { | ||
907 | int rc; | ||
908 | |||
909 | mutex_lock(&ov->i2c_lock); | ||
910 | |||
911 | /* Set new slave IDs */ | ||
912 | rc = i2c_set_slave_internal(ov, slave); | ||
913 | if (rc < 0) | ||
914 | goto out; | ||
915 | |||
916 | if (ov->bclass == BCL_OV518) | ||
917 | rc = ov518_i2c_read_internal(ov, reg); | ||
918 | else | ||
919 | rc = ov511_i2c_read_internal(ov, reg); | ||
920 | |||
921 | out: | ||
922 | /* Restore primary IDs */ | ||
923 | if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) | ||
924 | err("Couldn't restore primary I2C slave"); | ||
925 | |||
926 | mutex_unlock(&ov->i2c_lock); | ||
927 | return rc; | ||
928 | } | ||
929 | |||
930 | /* Sets I2C read and write slave IDs. Returns <0 for error */ | ||
931 | static int | ||
932 | ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid) | ||
933 | { | ||
934 | int rc; | ||
935 | |||
936 | mutex_lock(&ov->i2c_lock); | ||
937 | |||
938 | rc = i2c_set_slave_internal(ov, sid); | ||
939 | if (rc < 0) | ||
940 | goto out; | ||
941 | |||
942 | // FIXME: Is this actually necessary? | ||
943 | rc = ov51x_reset(ov, OV511_RESET_NOREGS); | ||
944 | out: | ||
945 | mutex_unlock(&ov->i2c_lock); | ||
946 | return rc; | ||
947 | } | ||
948 | |||
949 | static int | ||
950 | write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals) | ||
951 | { | ||
952 | int rc; | ||
953 | |||
954 | while (pRegvals->bus != OV511_DONE_BUS) { | ||
955 | if (pRegvals->bus == OV511_REG_BUS) { | ||
956 | if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0) | ||
957 | return rc; | ||
958 | } else if (pRegvals->bus == OV511_I2C_BUS) { | ||
959 | if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0) | ||
960 | return rc; | ||
961 | } else { | ||
962 | err("Bad regval array"); | ||
963 | return -1; | ||
964 | } | ||
965 | pRegvals++; | ||
966 | } | ||
967 | return 0; | ||
968 | } | ||
969 | |||
970 | #ifdef OV511_DEBUG | ||
971 | static void | ||
972 | dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn) | ||
973 | { | ||
974 | int i, rc; | ||
975 | |||
976 | for (i = reg1; i <= regn; i++) { | ||
977 | rc = i2c_r(ov, i); | ||
978 | info("Sensor[0x%02X] = 0x%02X", i, rc); | ||
979 | } | ||
980 | } | ||
981 | |||
982 | static void | ||
983 | dump_i2c_regs(struct usb_ov511 *ov) | ||
984 | { | ||
985 | info("I2C REGS"); | ||
986 | dump_i2c_range(ov, 0x00, 0x7C); | ||
987 | } | ||
988 | |||
989 | static void | ||
990 | dump_reg_range(struct usb_ov511 *ov, int reg1, int regn) | ||
991 | { | ||
992 | int i, rc; | ||
993 | |||
994 | for (i = reg1; i <= regn; i++) { | ||
995 | rc = reg_r(ov, i); | ||
996 | info("OV511[0x%02X] = 0x%02X", i, rc); | ||
997 | } | ||
998 | } | ||
999 | |||
1000 | static void | ||
1001 | ov511_dump_regs(struct usb_ov511 *ov) | ||
1002 | { | ||
1003 | info("CAMERA INTERFACE REGS"); | ||
1004 | dump_reg_range(ov, 0x10, 0x1f); | ||
1005 | info("DRAM INTERFACE REGS"); | ||
1006 | dump_reg_range(ov, 0x20, 0x23); | ||
1007 | info("ISO FIFO REGS"); | ||
1008 | dump_reg_range(ov, 0x30, 0x31); | ||
1009 | info("PIO REGS"); | ||
1010 | dump_reg_range(ov, 0x38, 0x39); | ||
1011 | dump_reg_range(ov, 0x3e, 0x3e); | ||
1012 | info("I2C REGS"); | ||
1013 | dump_reg_range(ov, 0x40, 0x49); | ||
1014 | info("SYSTEM CONTROL REGS"); | ||
1015 | dump_reg_range(ov, 0x50, 0x55); | ||
1016 | dump_reg_range(ov, 0x5e, 0x5f); | ||
1017 | info("OmniCE REGS"); | ||
1018 | dump_reg_range(ov, 0x70, 0x79); | ||
1019 | /* NOTE: Quantization tables are not readable. You will get the value | ||
1020 | * in reg. 0x79 for every table register */ | ||
1021 | dump_reg_range(ov, 0x80, 0x9f); | ||
1022 | dump_reg_range(ov, 0xa0, 0xbf); | ||
1023 | |||
1024 | } | ||
1025 | |||
1026 | static void | ||
1027 | ov518_dump_regs(struct usb_ov511 *ov) | ||
1028 | { | ||
1029 | info("VIDEO MODE REGS"); | ||
1030 | dump_reg_range(ov, 0x20, 0x2f); | ||
1031 | info("DATA PUMP AND SNAPSHOT REGS"); | ||
1032 | dump_reg_range(ov, 0x30, 0x3f); | ||
1033 | info("I2C REGS"); | ||
1034 | dump_reg_range(ov, 0x40, 0x4f); | ||
1035 | info("SYSTEM CONTROL AND VENDOR REGS"); | ||
1036 | dump_reg_range(ov, 0x50, 0x5f); | ||
1037 | info("60 - 6F"); | ||
1038 | dump_reg_range(ov, 0x60, 0x6f); | ||
1039 | info("70 - 7F"); | ||
1040 | dump_reg_range(ov, 0x70, 0x7f); | ||
1041 | info("Y QUANTIZATION TABLE"); | ||
1042 | dump_reg_range(ov, 0x80, 0x8f); | ||
1043 | info("UV QUANTIZATION TABLE"); | ||
1044 | dump_reg_range(ov, 0x90, 0x9f); | ||
1045 | info("A0 - BF"); | ||
1046 | dump_reg_range(ov, 0xa0, 0xbf); | ||
1047 | info("CBR"); | ||
1048 | dump_reg_range(ov, 0xc0, 0xcf); | ||
1049 | } | ||
1050 | #endif | ||
1051 | |||
1052 | /*****************************************************************************/ | ||
1053 | |||
1054 | /* Temporarily stops OV511 from functioning. Must do this before changing | ||
1055 | * registers while the camera is streaming */ | ||
1056 | static inline int | ||
1057 | ov51x_stop(struct usb_ov511 *ov) | ||
1058 | { | ||
1059 | PDEBUG(4, "stopping"); | ||
1060 | ov->stopped = 1; | ||
1061 | if (ov->bclass == BCL_OV518) | ||
1062 | return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a)); | ||
1063 | else | ||
1064 | return (reg_w(ov, R51x_SYS_RESET, 0x3d)); | ||
1065 | } | ||
1066 | |||
1067 | /* Restarts OV511 after ov511_stop() is called. Has no effect if it is not | ||
1068 | * actually stopped (for performance). */ | ||
1069 | static inline int | ||
1070 | ov51x_restart(struct usb_ov511 *ov) | ||
1071 | { | ||
1072 | if (ov->stopped) { | ||
1073 | PDEBUG(4, "restarting"); | ||
1074 | ov->stopped = 0; | ||
1075 | |||
1076 | /* Reinitialize the stream */ | ||
1077 | if (ov->bclass == BCL_OV518) | ||
1078 | reg_w(ov, 0x2f, 0x80); | ||
1079 | |||
1080 | return (reg_w(ov, R51x_SYS_RESET, 0x00)); | ||
1081 | } | ||
1082 | |||
1083 | return 0; | ||
1084 | } | ||
1085 | |||
1086 | /* Sleeps until no frames are active. Returns !0 if got signal */ | ||
1087 | static int | ||
1088 | ov51x_wait_frames_inactive(struct usb_ov511 *ov) | ||
1089 | { | ||
1090 | return wait_event_interruptible(ov->wq, ov->curframe < 0); | ||
1091 | } | ||
1092 | |||
1093 | /* Resets the hardware snapshot button */ | ||
1094 | static void | ||
1095 | ov51x_clear_snapshot(struct usb_ov511 *ov) | ||
1096 | { | ||
1097 | if (ov->bclass == BCL_OV511) { | ||
1098 | reg_w(ov, R51x_SYS_SNAP, 0x00); | ||
1099 | reg_w(ov, R51x_SYS_SNAP, 0x02); | ||
1100 | reg_w(ov, R51x_SYS_SNAP, 0x00); | ||
1101 | } else if (ov->bclass == BCL_OV518) { | ||
1102 | warn("snapshot reset not supported yet on OV518(+)"); | ||
1103 | } else { | ||
1104 | err("clear snap: invalid bridge type"); | ||
1105 | } | ||
1106 | } | ||
1107 | |||
1108 | #if 0 | ||
1109 | /* Checks the status of the snapshot button. Returns 1 if it was pressed since | ||
1110 | * it was last cleared, and zero in all other cases (including errors) */ | ||
1111 | static int | ||
1112 | ov51x_check_snapshot(struct usb_ov511 *ov) | ||
1113 | { | ||
1114 | int ret, status = 0; | ||
1115 | |||
1116 | if (ov->bclass == BCL_OV511) { | ||
1117 | ret = reg_r(ov, R51x_SYS_SNAP); | ||
1118 | if (ret < 0) { | ||
1119 | err("Error checking snspshot status (%d)", ret); | ||
1120 | } else if (ret & 0x08) { | ||
1121 | status = 1; | ||
1122 | } | ||
1123 | } else if (ov->bclass == BCL_OV518) { | ||
1124 | warn("snapshot check not supported yet on OV518(+)"); | ||
1125 | } else { | ||
1126 | err("check snap: invalid bridge type"); | ||
1127 | } | ||
1128 | |||
1129 | return status; | ||
1130 | } | ||
1131 | #endif | ||
1132 | |||
1133 | /* This does an initial reset of an OmniVision sensor and ensures that I2C | ||
1134 | * is synchronized. Returns <0 for failure. | ||
1135 | */ | ||
1136 | static int | ||
1137 | init_ov_sensor(struct usb_ov511 *ov) | ||
1138 | { | ||
1139 | int i, success; | ||
1140 | |||
1141 | /* Reset the sensor */ | ||
1142 | if (i2c_w(ov, 0x12, 0x80) < 0) | ||
1143 | return -EIO; | ||
1144 | |||
1145 | /* Wait for it to initialize */ | ||
1146 | msleep(150); | ||
1147 | |||
1148 | for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { | ||
1149 | if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && | ||
1150 | (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { | ||
1151 | success = 1; | ||
1152 | continue; | ||
1153 | } | ||
1154 | |||
1155 | /* Reset the sensor */ | ||
1156 | if (i2c_w(ov, 0x12, 0x80) < 0) | ||
1157 | return -EIO; | ||
1158 | /* Wait for it to initialize */ | ||
1159 | msleep(150); | ||
1160 | /* Dummy read to sync I2C */ | ||
1161 | if (i2c_r(ov, 0x00) < 0) | ||
1162 | return -EIO; | ||
1163 | } | ||
1164 | |||
1165 | if (!success) | ||
1166 | return -EIO; | ||
1167 | |||
1168 | PDEBUG(1, "I2C synced in %d attempt(s)", i); | ||
1169 | |||
1170 | return 0; | ||
1171 | } | ||
1172 | |||
1173 | static int | ||
1174 | ov511_set_packet_size(struct usb_ov511 *ov, int size) | ||
1175 | { | ||
1176 | int alt, mult; | ||
1177 | |||
1178 | if (ov51x_stop(ov) < 0) | ||
1179 | return -EIO; | ||
1180 | |||
1181 | mult = size >> 5; | ||
1182 | |||
1183 | if (ov->bridge == BRG_OV511) { | ||
1184 | if (size == 0) | ||
1185 | alt = OV511_ALT_SIZE_0; | ||
1186 | else if (size == 257) | ||
1187 | alt = OV511_ALT_SIZE_257; | ||
1188 | else if (size == 513) | ||
1189 | alt = OV511_ALT_SIZE_513; | ||
1190 | else if (size == 769) | ||
1191 | alt = OV511_ALT_SIZE_769; | ||
1192 | else if (size == 993) | ||
1193 | alt = OV511_ALT_SIZE_993; | ||
1194 | else { | ||
1195 | err("Set packet size: invalid size (%d)", size); | ||
1196 | return -EINVAL; | ||
1197 | } | ||
1198 | } else if (ov->bridge == BRG_OV511PLUS) { | ||
1199 | if (size == 0) | ||
1200 | alt = OV511PLUS_ALT_SIZE_0; | ||
1201 | else if (size == 33) | ||
1202 | alt = OV511PLUS_ALT_SIZE_33; | ||
1203 | else if (size == 129) | ||
1204 | alt = OV511PLUS_ALT_SIZE_129; | ||
1205 | else if (size == 257) | ||
1206 | alt = OV511PLUS_ALT_SIZE_257; | ||
1207 | else if (size == 385) | ||
1208 | alt = OV511PLUS_ALT_SIZE_385; | ||
1209 | else if (size == 513) | ||
1210 | alt = OV511PLUS_ALT_SIZE_513; | ||
1211 | else if (size == 769) | ||
1212 | alt = OV511PLUS_ALT_SIZE_769; | ||
1213 | else if (size == 961) | ||
1214 | alt = OV511PLUS_ALT_SIZE_961; | ||
1215 | else { | ||
1216 | err("Set packet size: invalid size (%d)", size); | ||
1217 | return -EINVAL; | ||
1218 | } | ||
1219 | } else { | ||
1220 | err("Set packet size: Invalid bridge type"); | ||
1221 | return -EINVAL; | ||
1222 | } | ||
1223 | |||
1224 | PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt); | ||
1225 | |||
1226 | if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0) | ||
1227 | return -EIO; | ||
1228 | |||
1229 | if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { | ||
1230 | err("Set packet size: set interface error"); | ||
1231 | return -EBUSY; | ||
1232 | } | ||
1233 | |||
1234 | if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) | ||
1235 | return -EIO; | ||
1236 | |||
1237 | ov->packet_size = size; | ||
1238 | |||
1239 | if (ov51x_restart(ov) < 0) | ||
1240 | return -EIO; | ||
1241 | |||
1242 | return 0; | ||
1243 | } | ||
1244 | |||
1245 | /* Note: Unlike the OV511/OV511+, the size argument does NOT include the | ||
1246 | * optional packet number byte. The actual size *is* stored in ov->packet_size, | ||
1247 | * though. */ | ||
1248 | static int | ||
1249 | ov518_set_packet_size(struct usb_ov511 *ov, int size) | ||
1250 | { | ||
1251 | int alt; | ||
1252 | |||
1253 | if (ov51x_stop(ov) < 0) | ||
1254 | return -EIO; | ||
1255 | |||
1256 | if (ov->bclass == BCL_OV518) { | ||
1257 | if (size == 0) | ||
1258 | alt = OV518_ALT_SIZE_0; | ||
1259 | else if (size == 128) | ||
1260 | alt = OV518_ALT_SIZE_128; | ||
1261 | else if (size == 256) | ||
1262 | alt = OV518_ALT_SIZE_256; | ||
1263 | else if (size == 384) | ||
1264 | alt = OV518_ALT_SIZE_384; | ||
1265 | else if (size == 512) | ||
1266 | alt = OV518_ALT_SIZE_512; | ||
1267 | else if (size == 640) | ||
1268 | alt = OV518_ALT_SIZE_640; | ||
1269 | else if (size == 768) | ||
1270 | alt = OV518_ALT_SIZE_768; | ||
1271 | else if (size == 896) | ||
1272 | alt = OV518_ALT_SIZE_896; | ||
1273 | else { | ||
1274 | err("Set packet size: invalid size (%d)", size); | ||
1275 | return -EINVAL; | ||
1276 | } | ||
1277 | } else { | ||
1278 | err("Set packet size: Invalid bridge type"); | ||
1279 | return -EINVAL; | ||
1280 | } | ||
1281 | |||
1282 | PDEBUG(3, "%d, alt=%d", size, alt); | ||
1283 | |||
1284 | ov->packet_size = size; | ||
1285 | if (size > 0) { | ||
1286 | /* Program ISO FIFO size reg (packet number isn't included) */ | ||
1287 | ov518_reg_w32(ov, 0x30, size, 2); | ||
1288 | |||
1289 | if (ov->packet_numbering) | ||
1290 | ++ov->packet_size; | ||
1291 | } | ||
1292 | |||
1293 | if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { | ||
1294 | err("Set packet size: set interface error"); | ||
1295 | return -EBUSY; | ||
1296 | } | ||
1297 | |||
1298 | /* Initialize the stream */ | ||
1299 | if (reg_w(ov, 0x2f, 0x80) < 0) | ||
1300 | return -EIO; | ||
1301 | |||
1302 | if (ov51x_restart(ov) < 0) | ||
1303 | return -EIO; | ||
1304 | |||
1305 | if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) | ||
1306 | return -EIO; | ||
1307 | |||
1308 | return 0; | ||
1309 | } | ||
1310 | |||
1311 | /* Upload compression params and quantization tables. Returns 0 for success. */ | ||
1312 | static int | ||
1313 | ov511_init_compression(struct usb_ov511 *ov) | ||
1314 | { | ||
1315 | int rc = 0; | ||
1316 | |||
1317 | if (!ov->compress_inited) { | ||
1318 | reg_w(ov, 0x70, phy); | ||
1319 | reg_w(ov, 0x71, phuv); | ||
1320 | reg_w(ov, 0x72, pvy); | ||
1321 | reg_w(ov, 0x73, pvuv); | ||
1322 | reg_w(ov, 0x74, qhy); | ||
1323 | reg_w(ov, 0x75, qhuv); | ||
1324 | reg_w(ov, 0x76, qvy); | ||
1325 | reg_w(ov, 0x77, qvuv); | ||
1326 | |||
1327 | if (ov511_upload_quan_tables(ov) < 0) { | ||
1328 | err("Error uploading quantization tables"); | ||
1329 | rc = -EIO; | ||
1330 | goto out; | ||
1331 | } | ||
1332 | } | ||
1333 | |||
1334 | ov->compress_inited = 1; | ||
1335 | out: | ||
1336 | return rc; | ||
1337 | } | ||
1338 | |||
1339 | /* Upload compression params and quantization tables. Returns 0 for success. */ | ||
1340 | static int | ||
1341 | ov518_init_compression(struct usb_ov511 *ov) | ||
1342 | { | ||
1343 | int rc = 0; | ||
1344 | |||
1345 | if (!ov->compress_inited) { | ||
1346 | if (ov518_upload_quan_tables(ov) < 0) { | ||
1347 | err("Error uploading quantization tables"); | ||
1348 | rc = -EIO; | ||
1349 | goto out; | ||
1350 | } | ||
1351 | } | ||
1352 | |||
1353 | ov->compress_inited = 1; | ||
1354 | out: | ||
1355 | return rc; | ||
1356 | } | ||
1357 | |||
1358 | /* -------------------------------------------------------------------------- */ | ||
1359 | |||
1360 | /* Sets sensor's contrast setting to "val" */ | ||
1361 | static int | ||
1362 | sensor_set_contrast(struct usb_ov511 *ov, unsigned short val) | ||
1363 | { | ||
1364 | int rc; | ||
1365 | |||
1366 | PDEBUG(3, "%d", val); | ||
1367 | |||
1368 | if (ov->stop_during_set) | ||
1369 | if (ov51x_stop(ov) < 0) | ||
1370 | return -EIO; | ||
1371 | |||
1372 | switch (ov->sensor) { | ||
1373 | case SEN_OV7610: | ||
1374 | case SEN_OV6620: | ||
1375 | { | ||
1376 | rc = i2c_w(ov, OV7610_REG_CNT, val >> 8); | ||
1377 | if (rc < 0) | ||
1378 | goto out; | ||
1379 | break; | ||
1380 | } | ||
1381 | case SEN_OV6630: | ||
1382 | { | ||
1383 | rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f); | ||
1384 | if (rc < 0) | ||
1385 | goto out; | ||
1386 | break; | ||
1387 | } | ||
1388 | case SEN_OV7620: | ||
1389 | { | ||
1390 | unsigned char ctab[] = { | ||
1391 | 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57, | ||
1392 | 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff | ||
1393 | }; | ||
1394 | |||
1395 | /* Use Y gamma control instead. Bit 0 enables it. */ | ||
1396 | rc = i2c_w(ov, 0x64, ctab[val>>12]); | ||
1397 | if (rc < 0) | ||
1398 | goto out; | ||
1399 | break; | ||
1400 | } | ||
1401 | case SEN_SAA7111A: | ||
1402 | { | ||
1403 | rc = i2c_w(ov, 0x0b, val >> 9); | ||
1404 | if (rc < 0) | ||
1405 | goto out; | ||
1406 | break; | ||
1407 | } | ||
1408 | default: | ||
1409 | { | ||
1410 | PDEBUG(3, "Unsupported with this sensor"); | ||
1411 | rc = -EPERM; | ||
1412 | goto out; | ||
1413 | } | ||
1414 | } | ||
1415 | |||
1416 | rc = 0; /* Success */ | ||
1417 | ov->contrast = val; | ||
1418 | out: | ||
1419 | if (ov51x_restart(ov) < 0) | ||
1420 | return -EIO; | ||
1421 | |||
1422 | return rc; | ||
1423 | } | ||
1424 | |||
1425 | /* Gets sensor's contrast setting */ | ||
1426 | static int | ||
1427 | sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val) | ||
1428 | { | ||
1429 | int rc; | ||
1430 | |||
1431 | switch (ov->sensor) { | ||
1432 | case SEN_OV7610: | ||
1433 | case SEN_OV6620: | ||
1434 | rc = i2c_r(ov, OV7610_REG_CNT); | ||
1435 | if (rc < 0) | ||
1436 | return rc; | ||
1437 | else | ||
1438 | *val = rc << 8; | ||
1439 | break; | ||
1440 | case SEN_OV6630: | ||
1441 | rc = i2c_r(ov, OV7610_REG_CNT); | ||
1442 | if (rc < 0) | ||
1443 | return rc; | ||
1444 | else | ||
1445 | *val = rc << 12; | ||
1446 | break; | ||
1447 | case SEN_OV7620: | ||
1448 | /* Use Y gamma reg instead. Bit 0 is the enable bit. */ | ||
1449 | rc = i2c_r(ov, 0x64); | ||
1450 | if (rc < 0) | ||
1451 | return rc; | ||
1452 | else | ||
1453 | *val = (rc & 0xfe) << 8; | ||
1454 | break; | ||
1455 | case SEN_SAA7111A: | ||
1456 | *val = ov->contrast; | ||
1457 | break; | ||
1458 | default: | ||
1459 | PDEBUG(3, "Unsupported with this sensor"); | ||
1460 | return -EPERM; | ||
1461 | } | ||
1462 | |||
1463 | PDEBUG(3, "%d", *val); | ||
1464 | ov->contrast = *val; | ||
1465 | |||
1466 | return 0; | ||
1467 | } | ||
1468 | |||
1469 | /* -------------------------------------------------------------------------- */ | ||
1470 | |||
1471 | /* Sets sensor's brightness setting to "val" */ | ||
1472 | static int | ||
1473 | sensor_set_brightness(struct usb_ov511 *ov, unsigned short val) | ||
1474 | { | ||
1475 | int rc; | ||
1476 | |||
1477 | PDEBUG(4, "%d", val); | ||
1478 | |||
1479 | if (ov->stop_during_set) | ||
1480 | if (ov51x_stop(ov) < 0) | ||
1481 | return -EIO; | ||
1482 | |||
1483 | switch (ov->sensor) { | ||
1484 | case SEN_OV7610: | ||
1485 | case SEN_OV76BE: | ||
1486 | case SEN_OV6620: | ||
1487 | case SEN_OV6630: | ||
1488 | rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); | ||
1489 | if (rc < 0) | ||
1490 | goto out; | ||
1491 | break; | ||
1492 | case SEN_OV7620: | ||
1493 | /* 7620 doesn't like manual changes when in auto mode */ | ||
1494 | if (!ov->auto_brt) { | ||
1495 | rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); | ||
1496 | if (rc < 0) | ||
1497 | goto out; | ||
1498 | } | ||
1499 | break; | ||
1500 | case SEN_SAA7111A: | ||
1501 | rc = i2c_w(ov, 0x0a, val >> 8); | ||
1502 | if (rc < 0) | ||
1503 | goto out; | ||
1504 | break; | ||
1505 | default: | ||
1506 | PDEBUG(3, "Unsupported with this sensor"); | ||
1507 | rc = -EPERM; | ||
1508 | goto out; | ||
1509 | } | ||
1510 | |||
1511 | rc = 0; /* Success */ | ||
1512 | ov->brightness = val; | ||
1513 | out: | ||
1514 | if (ov51x_restart(ov) < 0) | ||
1515 | return -EIO; | ||
1516 | |||
1517 | return rc; | ||
1518 | } | ||
1519 | |||
1520 | /* Gets sensor's brightness setting */ | ||
1521 | static int | ||
1522 | sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val) | ||
1523 | { | ||
1524 | int rc; | ||
1525 | |||
1526 | switch (ov->sensor) { | ||
1527 | case SEN_OV7610: | ||
1528 | case SEN_OV76BE: | ||
1529 | case SEN_OV7620: | ||
1530 | case SEN_OV6620: | ||
1531 | case SEN_OV6630: | ||
1532 | rc = i2c_r(ov, OV7610_REG_BRT); | ||
1533 | if (rc < 0) | ||
1534 | return rc; | ||
1535 | else | ||
1536 | *val = rc << 8; | ||
1537 | break; | ||
1538 | case SEN_SAA7111A: | ||
1539 | *val = ov->brightness; | ||
1540 | break; | ||
1541 | default: | ||
1542 | PDEBUG(3, "Unsupported with this sensor"); | ||
1543 | return -EPERM; | ||
1544 | } | ||
1545 | |||
1546 | PDEBUG(3, "%d", *val); | ||
1547 | ov->brightness = *val; | ||
1548 | |||
1549 | return 0; | ||
1550 | } | ||
1551 | |||
1552 | /* -------------------------------------------------------------------------- */ | ||
1553 | |||
1554 | /* Sets sensor's saturation (color intensity) setting to "val" */ | ||
1555 | static int | ||
1556 | sensor_set_saturation(struct usb_ov511 *ov, unsigned short val) | ||
1557 | { | ||
1558 | int rc; | ||
1559 | |||
1560 | PDEBUG(3, "%d", val); | ||
1561 | |||
1562 | if (ov->stop_during_set) | ||
1563 | if (ov51x_stop(ov) < 0) | ||
1564 | return -EIO; | ||
1565 | |||
1566 | switch (ov->sensor) { | ||
1567 | case SEN_OV7610: | ||
1568 | case SEN_OV76BE: | ||
1569 | case SEN_OV6620: | ||
1570 | case SEN_OV6630: | ||
1571 | rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); | ||
1572 | if (rc < 0) | ||
1573 | goto out; | ||
1574 | break; | ||
1575 | case SEN_OV7620: | ||
1576 | // /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ | ||
1577 | // rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e); | ||
1578 | // if (rc < 0) | ||
1579 | // goto out; | ||
1580 | rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); | ||
1581 | if (rc < 0) | ||
1582 | goto out; | ||
1583 | break; | ||
1584 | case SEN_SAA7111A: | ||
1585 | rc = i2c_w(ov, 0x0c, val >> 9); | ||
1586 | if (rc < 0) | ||
1587 | goto out; | ||
1588 | break; | ||
1589 | default: | ||
1590 | PDEBUG(3, "Unsupported with this sensor"); | ||
1591 | rc = -EPERM; | ||
1592 | goto out; | ||
1593 | } | ||
1594 | |||
1595 | rc = 0; /* Success */ | ||
1596 | ov->colour = val; | ||
1597 | out: | ||
1598 | if (ov51x_restart(ov) < 0) | ||
1599 | return -EIO; | ||
1600 | |||
1601 | return rc; | ||
1602 | } | ||
1603 | |||
1604 | /* Gets sensor's saturation (color intensity) setting */ | ||
1605 | static int | ||
1606 | sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val) | ||
1607 | { | ||
1608 | int rc; | ||
1609 | |||
1610 | switch (ov->sensor) { | ||
1611 | case SEN_OV7610: | ||
1612 | case SEN_OV76BE: | ||
1613 | case SEN_OV6620: | ||
1614 | case SEN_OV6630: | ||
1615 | rc = i2c_r(ov, OV7610_REG_SAT); | ||
1616 | if (rc < 0) | ||
1617 | return rc; | ||
1618 | else | ||
1619 | *val = rc << 8; | ||
1620 | break; | ||
1621 | case SEN_OV7620: | ||
1622 | // /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */ | ||
1623 | // rc = i2c_r(ov, 0x62); | ||
1624 | // if (rc < 0) | ||
1625 | // return rc; | ||
1626 | // else | ||
1627 | // *val = (rc & 0x7e) << 9; | ||
1628 | rc = i2c_r(ov, OV7610_REG_SAT); | ||
1629 | if (rc < 0) | ||
1630 | return rc; | ||
1631 | else | ||
1632 | *val = rc << 8; | ||
1633 | break; | ||
1634 | case SEN_SAA7111A: | ||
1635 | *val = ov->colour; | ||
1636 | break; | ||
1637 | default: | ||
1638 | PDEBUG(3, "Unsupported with this sensor"); | ||
1639 | return -EPERM; | ||
1640 | } | ||
1641 | |||
1642 | PDEBUG(3, "%d", *val); | ||
1643 | ov->colour = *val; | ||
1644 | |||
1645 | return 0; | ||
1646 | } | ||
1647 | |||
1648 | /* -------------------------------------------------------------------------- */ | ||
1649 | |||
1650 | /* Sets sensor's hue (red/blue balance) setting to "val" */ | ||
1651 | static int | ||
1652 | sensor_set_hue(struct usb_ov511 *ov, unsigned short val) | ||
1653 | { | ||
1654 | int rc; | ||
1655 | |||
1656 | PDEBUG(3, "%d", val); | ||
1657 | |||
1658 | if (ov->stop_during_set) | ||
1659 | if (ov51x_stop(ov) < 0) | ||
1660 | return -EIO; | ||
1661 | |||
1662 | switch (ov->sensor) { | ||
1663 | case SEN_OV7610: | ||
1664 | case SEN_OV6620: | ||
1665 | case SEN_OV6630: | ||
1666 | rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8)); | ||
1667 | if (rc < 0) | ||
1668 | goto out; | ||
1669 | |||
1670 | rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8); | ||
1671 | if (rc < 0) | ||
1672 | goto out; | ||
1673 | break; | ||
1674 | case SEN_OV7620: | ||
1675 | // Hue control is causing problems. I will enable it once it's fixed. | ||
1676 | #if 0 | ||
1677 | rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb); | ||
1678 | if (rc < 0) | ||
1679 | goto out; | ||
1680 | |||
1681 | rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb); | ||
1682 | if (rc < 0) | ||
1683 | goto out; | ||
1684 | #endif | ||
1685 | break; | ||
1686 | case SEN_SAA7111A: | ||
1687 | rc = i2c_w(ov, 0x0d, (val + 32768) >> 8); | ||
1688 | if (rc < 0) | ||
1689 | goto out; | ||
1690 | break; | ||
1691 | default: | ||
1692 | PDEBUG(3, "Unsupported with this sensor"); | ||
1693 | rc = -EPERM; | ||
1694 | goto out; | ||
1695 | } | ||
1696 | |||
1697 | rc = 0; /* Success */ | ||
1698 | ov->hue = val; | ||
1699 | out: | ||
1700 | if (ov51x_restart(ov) < 0) | ||
1701 | return -EIO; | ||
1702 | |||
1703 | return rc; | ||
1704 | } | ||
1705 | |||
1706 | /* Gets sensor's hue (red/blue balance) setting */ | ||
1707 | static int | ||
1708 | sensor_get_hue(struct usb_ov511 *ov, unsigned short *val) | ||
1709 | { | ||
1710 | int rc; | ||
1711 | |||
1712 | switch (ov->sensor) { | ||
1713 | case SEN_OV7610: | ||
1714 | case SEN_OV6620: | ||
1715 | case SEN_OV6630: | ||
1716 | rc = i2c_r(ov, OV7610_REG_BLUE); | ||
1717 | if (rc < 0) | ||
1718 | return rc; | ||
1719 | else | ||
1720 | *val = rc << 8; | ||
1721 | break; | ||
1722 | case SEN_OV7620: | ||
1723 | rc = i2c_r(ov, 0x7a); | ||
1724 | if (rc < 0) | ||
1725 | return rc; | ||
1726 | else | ||
1727 | *val = rc << 8; | ||
1728 | break; | ||
1729 | case SEN_SAA7111A: | ||
1730 | *val = ov->hue; | ||
1731 | break; | ||
1732 | default: | ||
1733 | PDEBUG(3, "Unsupported with this sensor"); | ||
1734 | return -EPERM; | ||
1735 | } | ||
1736 | |||
1737 | PDEBUG(3, "%d", *val); | ||
1738 | ov->hue = *val; | ||
1739 | |||
1740 | return 0; | ||
1741 | } | ||
1742 | |||
1743 | /* -------------------------------------------------------------------------- */ | ||
1744 | |||
1745 | static int | ||
1746 | sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p) | ||
1747 | { | ||
1748 | int rc; | ||
1749 | |||
1750 | PDEBUG(4, "sensor_set_picture"); | ||
1751 | |||
1752 | ov->whiteness = p->whiteness; | ||
1753 | |||
1754 | /* Don't return error if a setting is unsupported, or rest of settings | ||
1755 | * will not be performed */ | ||
1756 | |||
1757 | rc = sensor_set_contrast(ov, p->contrast); | ||
1758 | if (FATAL_ERROR(rc)) | ||
1759 | return rc; | ||
1760 | |||
1761 | rc = sensor_set_brightness(ov, p->brightness); | ||
1762 | if (FATAL_ERROR(rc)) | ||
1763 | return rc; | ||
1764 | |||
1765 | rc = sensor_set_saturation(ov, p->colour); | ||
1766 | if (FATAL_ERROR(rc)) | ||
1767 | return rc; | ||
1768 | |||
1769 | rc = sensor_set_hue(ov, p->hue); | ||
1770 | if (FATAL_ERROR(rc)) | ||
1771 | return rc; | ||
1772 | |||
1773 | return 0; | ||
1774 | } | ||
1775 | |||
1776 | static int | ||
1777 | sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p) | ||
1778 | { | ||
1779 | int rc; | ||
1780 | |||
1781 | PDEBUG(4, "sensor_get_picture"); | ||
1782 | |||
1783 | /* Don't return error if a setting is unsupported, or rest of settings | ||
1784 | * will not be performed */ | ||
1785 | |||
1786 | rc = sensor_get_contrast(ov, &(p->contrast)); | ||
1787 | if (FATAL_ERROR(rc)) | ||
1788 | return rc; | ||
1789 | |||
1790 | rc = sensor_get_brightness(ov, &(p->brightness)); | ||
1791 | if (FATAL_ERROR(rc)) | ||
1792 | return rc; | ||
1793 | |||
1794 | rc = sensor_get_saturation(ov, &(p->colour)); | ||
1795 | if (FATAL_ERROR(rc)) | ||
1796 | return rc; | ||
1797 | |||
1798 | rc = sensor_get_hue(ov, &(p->hue)); | ||
1799 | if (FATAL_ERROR(rc)) | ||
1800 | return rc; | ||
1801 | |||
1802 | p->whiteness = 105 << 8; | ||
1803 | |||
1804 | return 0; | ||
1805 | } | ||
1806 | |||
1807 | #if 0 | ||
1808 | // FIXME: Exposure range is only 0x00-0x7f in interlace mode | ||
1809 | /* Sets current exposure for sensor. This only has an effect if auto-exposure | ||
1810 | * is off */ | ||
1811 | static inline int | ||
1812 | sensor_set_exposure(struct usb_ov511 *ov, unsigned char val) | ||
1813 | { | ||
1814 | int rc; | ||
1815 | |||
1816 | PDEBUG(3, "%d", val); | ||
1817 | |||
1818 | if (ov->stop_during_set) | ||
1819 | if (ov51x_stop(ov) < 0) | ||
1820 | return -EIO; | ||
1821 | |||
1822 | switch (ov->sensor) { | ||
1823 | case SEN_OV6620: | ||
1824 | case SEN_OV6630: | ||
1825 | case SEN_OV7610: | ||
1826 | case SEN_OV7620: | ||
1827 | case SEN_OV76BE: | ||
1828 | case SEN_OV8600: | ||
1829 | rc = i2c_w(ov, 0x10, val); | ||
1830 | if (rc < 0) | ||
1831 | goto out; | ||
1832 | |||
1833 | break; | ||
1834 | case SEN_KS0127: | ||
1835 | case SEN_KS0127B: | ||
1836 | case SEN_SAA7111A: | ||
1837 | PDEBUG(3, "Unsupported with this sensor"); | ||
1838 | return -EPERM; | ||
1839 | default: | ||
1840 | err("Sensor not supported for set_exposure"); | ||
1841 | return -EINVAL; | ||
1842 | } | ||
1843 | |||
1844 | rc = 0; /* Success */ | ||
1845 | ov->exposure = val; | ||
1846 | out: | ||
1847 | if (ov51x_restart(ov) < 0) | ||
1848 | return -EIO; | ||
1849 | |||
1850 | return rc; | ||
1851 | } | ||
1852 | #endif | ||
1853 | |||
1854 | /* Gets current exposure level from sensor, regardless of whether it is under | ||
1855 | * manual control. */ | ||
1856 | static int | ||
1857 | sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val) | ||
1858 | { | ||
1859 | int rc; | ||
1860 | |||
1861 | switch (ov->sensor) { | ||
1862 | case SEN_OV7610: | ||
1863 | case SEN_OV6620: | ||
1864 | case SEN_OV6630: | ||
1865 | case SEN_OV7620: | ||
1866 | case SEN_OV76BE: | ||
1867 | case SEN_OV8600: | ||
1868 | rc = i2c_r(ov, 0x10); | ||
1869 | if (rc < 0) | ||
1870 | return rc; | ||
1871 | else | ||
1872 | *val = rc; | ||
1873 | break; | ||
1874 | case SEN_KS0127: | ||
1875 | case SEN_KS0127B: | ||
1876 | case SEN_SAA7111A: | ||
1877 | val = NULL; | ||
1878 | PDEBUG(3, "Unsupported with this sensor"); | ||
1879 | return -EPERM; | ||
1880 | default: | ||
1881 | err("Sensor not supported for get_exposure"); | ||
1882 | return -EINVAL; | ||
1883 | } | ||
1884 | |||
1885 | PDEBUG(3, "%d", *val); | ||
1886 | ov->exposure = *val; | ||
1887 | |||
1888 | return 0; | ||
1889 | } | ||
1890 | |||
1891 | /* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */ | ||
1892 | static void | ||
1893 | ov51x_led_control(struct usb_ov511 *ov, int enable) | ||
1894 | { | ||
1895 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
1896 | |||
1897 | if (ov->bridge == BRG_OV511PLUS) | ||
1898 | reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0); | ||
1899 | else if (ov->bclass == BCL_OV518) | ||
1900 | reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02); | ||
1901 | |||
1902 | return; | ||
1903 | } | ||
1904 | |||
1905 | /* Matches the sensor's internal frame rate to the lighting frequency. | ||
1906 | * Valid frequencies are: | ||
1907 | * 50 - 50Hz, for European and Asian lighting | ||
1908 | * 60 - 60Hz, for American lighting | ||
1909 | * | ||
1910 | * Tested with: OV7610, OV7620, OV76BE, OV6620 | ||
1911 | * Unsupported: KS0127, KS0127B, SAA7111A | ||
1912 | * Returns: 0 for success | ||
1913 | */ | ||
1914 | static int | ||
1915 | sensor_set_light_freq(struct usb_ov511 *ov, int freq) | ||
1916 | { | ||
1917 | int sixty; | ||
1918 | |||
1919 | PDEBUG(4, "%d Hz", freq); | ||
1920 | |||
1921 | if (freq == 60) | ||
1922 | sixty = 1; | ||
1923 | else if (freq == 50) | ||
1924 | sixty = 0; | ||
1925 | else { | ||
1926 | err("Invalid light freq (%d Hz)", freq); | ||
1927 | return -EINVAL; | ||
1928 | } | ||
1929 | |||
1930 | switch (ov->sensor) { | ||
1931 | case SEN_OV7610: | ||
1932 | i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); | ||
1933 | i2c_w(ov, 0x2b, sixty?0x00:0xac); | ||
1934 | i2c_w_mask(ov, 0x13, 0x10, 0x10); | ||
1935 | i2c_w_mask(ov, 0x13, 0x00, 0x10); | ||
1936 | break; | ||
1937 | case SEN_OV7620: | ||
1938 | case SEN_OV76BE: | ||
1939 | case SEN_OV8600: | ||
1940 | i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); | ||
1941 | i2c_w(ov, 0x2b, sixty?0x00:0xac); | ||
1942 | i2c_w_mask(ov, 0x76, 0x01, 0x01); | ||
1943 | break; | ||
1944 | case SEN_OV6620: | ||
1945 | case SEN_OV6630: | ||
1946 | i2c_w(ov, 0x2b, sixty?0xa8:0x28); | ||
1947 | i2c_w(ov, 0x2a, sixty?0x84:0xa4); | ||
1948 | break; | ||
1949 | case SEN_KS0127: | ||
1950 | case SEN_KS0127B: | ||
1951 | case SEN_SAA7111A: | ||
1952 | PDEBUG(5, "Unsupported with this sensor"); | ||
1953 | return -EPERM; | ||
1954 | default: | ||
1955 | err("Sensor not supported for set_light_freq"); | ||
1956 | return -EINVAL; | ||
1957 | } | ||
1958 | |||
1959 | ov->lightfreq = freq; | ||
1960 | |||
1961 | return 0; | ||
1962 | } | ||
1963 | |||
1964 | /* If enable is true, turn on the sensor's banding filter, otherwise turn it | ||
1965 | * off. This filter tries to reduce the pattern of horizontal light/dark bands | ||
1966 | * caused by some (usually fluorescent) lighting. The light frequency must be | ||
1967 | * set either before or after enabling it with ov51x_set_light_freq(). | ||
1968 | * | ||
1969 | * Tested with: OV7610, OV7620, OV76BE, OV6620. | ||
1970 | * Unsupported: KS0127, KS0127B, SAA7111A | ||
1971 | * Returns: 0 for success | ||
1972 | */ | ||
1973 | static int | ||
1974 | sensor_set_banding_filter(struct usb_ov511 *ov, int enable) | ||
1975 | { | ||
1976 | int rc; | ||
1977 | |||
1978 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
1979 | |||
1980 | if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B | ||
1981 | || ov->sensor == SEN_SAA7111A) { | ||
1982 | PDEBUG(5, "Unsupported with this sensor"); | ||
1983 | return -EPERM; | ||
1984 | } | ||
1985 | |||
1986 | rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04); | ||
1987 | if (rc < 0) | ||
1988 | return rc; | ||
1989 | |||
1990 | ov->bandfilt = enable; | ||
1991 | |||
1992 | return 0; | ||
1993 | } | ||
1994 | |||
1995 | /* If enable is true, turn on the sensor's auto brightness control, otherwise | ||
1996 | * turn it off. | ||
1997 | * | ||
1998 | * Unsupported: KS0127, KS0127B, SAA7111A | ||
1999 | * Returns: 0 for success | ||
2000 | */ | ||
2001 | static int | ||
2002 | sensor_set_auto_brightness(struct usb_ov511 *ov, int enable) | ||
2003 | { | ||
2004 | int rc; | ||
2005 | |||
2006 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
2007 | |||
2008 | if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B | ||
2009 | || ov->sensor == SEN_SAA7111A) { | ||
2010 | PDEBUG(5, "Unsupported with this sensor"); | ||
2011 | return -EPERM; | ||
2012 | } | ||
2013 | |||
2014 | rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10); | ||
2015 | if (rc < 0) | ||
2016 | return rc; | ||
2017 | |||
2018 | ov->auto_brt = enable; | ||
2019 | |||
2020 | return 0; | ||
2021 | } | ||
2022 | |||
2023 | /* If enable is true, turn on the sensor's auto exposure control, otherwise | ||
2024 | * turn it off. | ||
2025 | * | ||
2026 | * Unsupported: KS0127, KS0127B, SAA7111A | ||
2027 | * Returns: 0 for success | ||
2028 | */ | ||
2029 | static int | ||
2030 | sensor_set_auto_exposure(struct usb_ov511 *ov, int enable) | ||
2031 | { | ||
2032 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
2033 | |||
2034 | switch (ov->sensor) { | ||
2035 | case SEN_OV7610: | ||
2036 | i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80); | ||
2037 | break; | ||
2038 | case SEN_OV6620: | ||
2039 | case SEN_OV7620: | ||
2040 | case SEN_OV76BE: | ||
2041 | case SEN_OV8600: | ||
2042 | i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01); | ||
2043 | break; | ||
2044 | case SEN_OV6630: | ||
2045 | i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10); | ||
2046 | break; | ||
2047 | case SEN_KS0127: | ||
2048 | case SEN_KS0127B: | ||
2049 | case SEN_SAA7111A: | ||
2050 | PDEBUG(5, "Unsupported with this sensor"); | ||
2051 | return -EPERM; | ||
2052 | default: | ||
2053 | err("Sensor not supported for set_auto_exposure"); | ||
2054 | return -EINVAL; | ||
2055 | } | ||
2056 | |||
2057 | ov->auto_exp = enable; | ||
2058 | |||
2059 | return 0; | ||
2060 | } | ||
2061 | |||
2062 | /* Modifies the sensor's exposure algorithm to allow proper exposure of objects | ||
2063 | * that are illuminated from behind. | ||
2064 | * | ||
2065 | * Tested with: OV6620, OV7620 | ||
2066 | * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A | ||
2067 | * Returns: 0 for success | ||
2068 | */ | ||
2069 | static int | ||
2070 | sensor_set_backlight(struct usb_ov511 *ov, int enable) | ||
2071 | { | ||
2072 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
2073 | |||
2074 | switch (ov->sensor) { | ||
2075 | case SEN_OV7620: | ||
2076 | case SEN_OV8600: | ||
2077 | i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0); | ||
2078 | i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); | ||
2079 | i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); | ||
2080 | break; | ||
2081 | case SEN_OV6620: | ||
2082 | i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0); | ||
2083 | i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); | ||
2084 | i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80); | ||
2085 | break; | ||
2086 | case SEN_OV6630: | ||
2087 | i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0); | ||
2088 | i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); | ||
2089 | i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); | ||
2090 | break; | ||
2091 | case SEN_OV7610: | ||
2092 | case SEN_OV76BE: | ||
2093 | case SEN_KS0127: | ||
2094 | case SEN_KS0127B: | ||
2095 | case SEN_SAA7111A: | ||
2096 | PDEBUG(5, "Unsupported with this sensor"); | ||
2097 | return -EPERM; | ||
2098 | default: | ||
2099 | err("Sensor not supported for set_backlight"); | ||
2100 | return -EINVAL; | ||
2101 | } | ||
2102 | |||
2103 | ov->backlight = enable; | ||
2104 | |||
2105 | return 0; | ||
2106 | } | ||
2107 | |||
2108 | static int | ||
2109 | sensor_set_mirror(struct usb_ov511 *ov, int enable) | ||
2110 | { | ||
2111 | PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); | ||
2112 | |||
2113 | switch (ov->sensor) { | ||
2114 | case SEN_OV6620: | ||
2115 | case SEN_OV6630: | ||
2116 | case SEN_OV7610: | ||
2117 | case SEN_OV7620: | ||
2118 | case SEN_OV76BE: | ||
2119 | case SEN_OV8600: | ||
2120 | i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40); | ||
2121 | break; | ||
2122 | case SEN_KS0127: | ||
2123 | case SEN_KS0127B: | ||
2124 | case SEN_SAA7111A: | ||
2125 | PDEBUG(5, "Unsupported with this sensor"); | ||
2126 | return -EPERM; | ||
2127 | default: | ||
2128 | err("Sensor not supported for set_mirror"); | ||
2129 | return -EINVAL; | ||
2130 | } | ||
2131 | |||
2132 | ov->mirror = enable; | ||
2133 | |||
2134 | return 0; | ||
2135 | } | ||
2136 | |||
2137 | /* Returns number of bits per pixel (regardless of where they are located; | ||
2138 | * planar or not), or zero for unsupported format. | ||
2139 | */ | ||
2140 | static inline int | ||
2141 | get_depth(int palette) | ||
2142 | { | ||
2143 | switch (palette) { | ||
2144 | case VIDEO_PALETTE_GREY: return 8; | ||
2145 | case VIDEO_PALETTE_YUV420: return 12; | ||
2146 | case VIDEO_PALETTE_YUV420P: return 12; /* Planar */ | ||
2147 | default: return 0; /* Invalid format */ | ||
2148 | } | ||
2149 | } | ||
2150 | |||
2151 | /* Bytes per frame. Used by read(). Return of 0 indicates error */ | ||
2152 | static inline long int | ||
2153 | get_frame_length(struct ov511_frame *frame) | ||
2154 | { | ||
2155 | if (!frame) | ||
2156 | return 0; | ||
2157 | else | ||
2158 | return ((frame->width * frame->height | ||
2159 | * get_depth(frame->format)) >> 3); | ||
2160 | } | ||
2161 | |||
2162 | static int | ||
2163 | mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height, | ||
2164 | int mode, int sub_flag, int qvga) | ||
2165 | { | ||
2166 | int clock; | ||
2167 | |||
2168 | /******** Mode (VGA/QVGA) and sensor specific regs ********/ | ||
2169 | |||
2170 | switch (ov->sensor) { | ||
2171 | case SEN_OV7610: | ||
2172 | i2c_w(ov, 0x14, qvga?0x24:0x04); | ||
2173 | // FIXME: Does this improve the image quality or frame rate? | ||
2174 | #if 0 | ||
2175 | i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); | ||
2176 | i2c_w(ov, 0x24, 0x10); | ||
2177 | i2c_w(ov, 0x25, qvga?0x40:0x8a); | ||
2178 | i2c_w(ov, 0x2f, qvga?0x30:0xb0); | ||
2179 | i2c_w(ov, 0x35, qvga?0x1c:0x9c); | ||
2180 | #endif | ||
2181 | break; | ||
2182 | case SEN_OV7620: | ||
2183 | // i2c_w(ov, 0x2b, 0x00); | ||
2184 | i2c_w(ov, 0x14, qvga?0xa4:0x84); | ||
2185 | i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); | ||
2186 | i2c_w(ov, 0x24, qvga?0x20:0x3a); | ||
2187 | i2c_w(ov, 0x25, qvga?0x30:0x60); | ||
2188 | i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); | ||
2189 | i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0); | ||
2190 | i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); | ||
2191 | break; | ||
2192 | case SEN_OV76BE: | ||
2193 | // i2c_w(ov, 0x2b, 0x00); | ||
2194 | i2c_w(ov, 0x14, qvga?0xa4:0x84); | ||
2195 | // FIXME: Enable this once 7620AE uses 7620 initial settings | ||
2196 | #if 0 | ||
2197 | i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); | ||
2198 | i2c_w(ov, 0x24, qvga?0x20:0x3a); | ||
2199 | i2c_w(ov, 0x25, qvga?0x30:0x60); | ||
2200 | i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); | ||
2201 | i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0); | ||
2202 | i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); | ||
2203 | #endif | ||
2204 | break; | ||
2205 | case SEN_OV6620: | ||
2206 | i2c_w(ov, 0x14, qvga?0x24:0x04); | ||
2207 | break; | ||
2208 | case SEN_OV6630: | ||
2209 | i2c_w(ov, 0x14, qvga?0xa0:0x80); | ||
2210 | break; | ||
2211 | default: | ||
2212 | err("Invalid sensor"); | ||
2213 | return -EINVAL; | ||
2214 | } | ||
2215 | |||
2216 | /******** Palette-specific regs ********/ | ||
2217 | |||
2218 | if (mode == VIDEO_PALETTE_GREY) { | ||
2219 | if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { | ||
2220 | /* these aren't valid on the OV6620/OV7620/6630? */ | ||
2221 | i2c_w_mask(ov, 0x0e, 0x40, 0x40); | ||
2222 | } | ||
2223 | |||
2224 | if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518 | ||
2225 | && ov518_color) { | ||
2226 | i2c_w_mask(ov, 0x12, 0x00, 0x10); | ||
2227 | i2c_w_mask(ov, 0x13, 0x00, 0x20); | ||
2228 | } else { | ||
2229 | i2c_w_mask(ov, 0x13, 0x20, 0x20); | ||
2230 | } | ||
2231 | } else { | ||
2232 | if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { | ||
2233 | /* not valid on the OV6620/OV7620/6630? */ | ||
2234 | i2c_w_mask(ov, 0x0e, 0x00, 0x40); | ||
2235 | } | ||
2236 | |||
2237 | /* The OV518 needs special treatment. Although both the OV518 | ||
2238 | * and the OV6630 support a 16-bit video bus, only the 8 bit Y | ||
2239 | * bus is actually used. The UV bus is tied to ground. | ||
2240 | * Therefore, the OV6630 needs to be in 8-bit multiplexed | ||
2241 | * output mode */ | ||
2242 | |||
2243 | if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518 | ||
2244 | && ov518_color) { | ||
2245 | i2c_w_mask(ov, 0x12, 0x10, 0x10); | ||
2246 | i2c_w_mask(ov, 0x13, 0x20, 0x20); | ||
2247 | } else { | ||
2248 | i2c_w_mask(ov, 0x13, 0x00, 0x20); | ||
2249 | } | ||
2250 | } | ||
2251 | |||
2252 | /******** Clock programming ********/ | ||
2253 | |||
2254 | /* The OV6620 needs special handling. This prevents the | ||
2255 | * severe banding that normally occurs */ | ||
2256 | if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) | ||
2257 | { | ||
2258 | /* Clock down */ | ||
2259 | |||
2260 | i2c_w(ov, 0x2a, 0x04); | ||
2261 | |||
2262 | if (ov->compress) { | ||
2263 | // clock = 0; /* This ensures the highest frame rate */ | ||
2264 | clock = 3; | ||
2265 | } else if (clockdiv == -1) { /* If user didn't override it */ | ||
2266 | clock = 3; /* Gives better exposure time */ | ||
2267 | } else { | ||
2268 | clock = clockdiv; | ||
2269 | } | ||
2270 | |||
2271 | PDEBUG(4, "Setting clock divisor to %d", clock); | ||
2272 | |||
2273 | i2c_w(ov, 0x11, clock); | ||
2274 | |||
2275 | i2c_w(ov, 0x2a, 0x84); | ||
2276 | /* This next setting is critical. It seems to improve | ||
2277 | * the gain or the contrast. The "reserved" bits seem | ||
2278 | * to have some effect in this case. */ | ||
2279 | i2c_w(ov, 0x2d, 0x85); | ||
2280 | } | ||
2281 | else | ||
2282 | { | ||
2283 | if (ov->compress) { | ||
2284 | clock = 1; /* This ensures the highest frame rate */ | ||
2285 | } else if (clockdiv == -1) { /* If user didn't override it */ | ||
2286 | /* Calculate and set the clock divisor */ | ||
2287 | clock = ((sub_flag ? ov->subw * ov->subh | ||
2288 | : width * height) | ||
2289 | * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2) | ||
2290 | / 66000; | ||
2291 | } else { | ||
2292 | clock = clockdiv; | ||
2293 | } | ||
2294 | |||
2295 | PDEBUG(4, "Setting clock divisor to %d", clock); | ||
2296 | |||
2297 | i2c_w(ov, 0x11, clock); | ||
2298 | } | ||
2299 | |||
2300 | /******** Special Features ********/ | ||
2301 | |||
2302 | if (framedrop >= 0) | ||
2303 | i2c_w(ov, 0x16, framedrop); | ||
2304 | |||
2305 | /* Test Pattern */ | ||
2306 | i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02); | ||
2307 | |||
2308 | /* Enable auto white balance */ | ||
2309 | i2c_w_mask(ov, 0x12, 0x04, 0x04); | ||
2310 | |||
2311 | // This will go away as soon as ov51x_mode_init_sensor_regs() | ||
2312 | // is fully tested. | ||
2313 | /* 7620/6620/6630? don't have register 0x35, so play it safe */ | ||
2314 | if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { | ||
2315 | if (width == 640 && height == 480) | ||
2316 | i2c_w(ov, 0x35, 0x9e); | ||
2317 | else | ||
2318 | i2c_w(ov, 0x35, 0x1e); | ||
2319 | } | ||
2320 | |||
2321 | return 0; | ||
2322 | } | ||
2323 | |||
2324 | static int | ||
2325 | set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode, | ||
2326 | int sub_flag) | ||
2327 | { | ||
2328 | int ret; | ||
2329 | int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize; | ||
2330 | int hoffset, voffset, hwscale = 0, vwscale = 0; | ||
2331 | |||
2332 | /* The different sensor ICs handle setting up of window differently. | ||
2333 | * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */ | ||
2334 | switch (ov->sensor) { | ||
2335 | case SEN_OV7610: | ||
2336 | case SEN_OV76BE: | ||
2337 | hwsbase = 0x38; | ||
2338 | hwebase = 0x3a; | ||
2339 | vwsbase = vwebase = 0x05; | ||
2340 | break; | ||
2341 | case SEN_OV6620: | ||
2342 | case SEN_OV6630: | ||
2343 | hwsbase = 0x38; | ||
2344 | hwebase = 0x3a; | ||
2345 | vwsbase = 0x05; | ||
2346 | vwebase = 0x06; | ||
2347 | break; | ||
2348 | case SEN_OV7620: | ||
2349 | hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */ | ||
2350 | hwebase = 0x2f; | ||
2351 | vwsbase = vwebase = 0x05; | ||
2352 | break; | ||
2353 | default: | ||
2354 | err("Invalid sensor"); | ||
2355 | return -EINVAL; | ||
2356 | } | ||
2357 | |||
2358 | if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) { | ||
2359 | /* Note: OV518(+) does downsample on its own) */ | ||
2360 | if ((width > 176 && height > 144) | ||
2361 | || ov->bclass == BCL_OV518) { /* CIF */ | ||
2362 | ret = mode_init_ov_sensor_regs(ov, width, height, | ||
2363 | mode, sub_flag, 0); | ||
2364 | if (ret < 0) | ||
2365 | return ret; | ||
2366 | hwscale = 1; | ||
2367 | vwscale = 1; /* The datasheet says 0; it's wrong */ | ||
2368 | hwsize = 352; | ||
2369 | vwsize = 288; | ||
2370 | } else if (width > 176 || height > 144) { | ||
2371 | err("Illegal dimensions"); | ||
2372 | return -EINVAL; | ||
2373 | } else { /* QCIF */ | ||
2374 | ret = mode_init_ov_sensor_regs(ov, width, height, | ||
2375 | mode, sub_flag, 1); | ||
2376 | if (ret < 0) | ||
2377 | return ret; | ||
2378 | hwsize = 176; | ||
2379 | vwsize = 144; | ||
2380 | } | ||
2381 | } else { | ||
2382 | if (width > 320 && height > 240) { /* VGA */ | ||
2383 | ret = mode_init_ov_sensor_regs(ov, width, height, | ||
2384 | mode, sub_flag, 0); | ||
2385 | if (ret < 0) | ||
2386 | return ret; | ||
2387 | hwscale = 2; | ||
2388 | vwscale = 1; | ||
2389 | hwsize = 640; | ||
2390 | vwsize = 480; | ||
2391 | } else if (width > 320 || height > 240) { | ||
2392 | err("Illegal dimensions"); | ||
2393 | return -EINVAL; | ||
2394 | } else { /* QVGA */ | ||
2395 | ret = mode_init_ov_sensor_regs(ov, width, height, | ||
2396 | mode, sub_flag, 1); | ||
2397 | if (ret < 0) | ||
2398 | return ret; | ||
2399 | hwscale = 1; | ||
2400 | hwsize = 320; | ||
2401 | vwsize = 240; | ||
2402 | } | ||
2403 | } | ||
2404 | |||
2405 | /* Center the window */ | ||
2406 | hoffset = ((hwsize - width) / 2) >> hwscale; | ||
2407 | voffset = ((vwsize - height) / 2) >> vwscale; | ||
2408 | |||
2409 | /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */ | ||
2410 | if (sub_flag) { | ||
2411 | i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale)); | ||
2412 | i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale)); | ||
2413 | i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale)); | ||
2414 | i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale)); | ||
2415 | } else { | ||
2416 | i2c_w(ov, 0x17, hwsbase + hoffset); | ||
2417 | i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale)); | ||
2418 | i2c_w(ov, 0x19, vwsbase + voffset); | ||
2419 | i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale)); | ||
2420 | } | ||
2421 | |||
2422 | #ifdef OV511_DEBUG | ||
2423 | if (dump_sensor) | ||
2424 | dump_i2c_regs(ov); | ||
2425 | #endif | ||
2426 | |||
2427 | return 0; | ||
2428 | } | ||
2429 | |||
2430 | /* Set up the OV511/OV511+ with the given image parameters. | ||
2431 | * | ||
2432 | * Do not put any sensor-specific code in here (including I2C I/O functions) | ||
2433 | */ | ||
2434 | static int | ||
2435 | ov511_mode_init_regs(struct usb_ov511 *ov, | ||
2436 | int width, int height, int mode, int sub_flag) | ||
2437 | { | ||
2438 | int hsegs, vsegs; | ||
2439 | |||
2440 | if (sub_flag) { | ||
2441 | width = ov->subw; | ||
2442 | height = ov->subh; | ||
2443 | } | ||
2444 | |||
2445 | PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", | ||
2446 | width, height, mode, sub_flag); | ||
2447 | |||
2448 | // FIXME: This should be moved to a 7111a-specific function once | ||
2449 | // subcapture is dealt with properly | ||
2450 | if (ov->sensor == SEN_SAA7111A) { | ||
2451 | if (width == 320 && height == 240) { | ||
2452 | /* No need to do anything special */ | ||
2453 | } else if (width == 640 && height == 480) { | ||
2454 | /* Set the OV511 up as 320x480, but keep the | ||
2455 | * V4L resolution as 640x480 */ | ||
2456 | width = 320; | ||
2457 | } else { | ||
2458 | err("SAA7111A only allows 320x240 or 640x480"); | ||
2459 | return -EINVAL; | ||
2460 | } | ||
2461 | } | ||
2462 | |||
2463 | /* Make sure width and height are a multiple of 8 */ | ||
2464 | if (width % 8 || height % 8) { | ||
2465 | err("Invalid size (%d, %d) (mode = %d)", width, height, mode); | ||
2466 | return -EINVAL; | ||
2467 | } | ||
2468 | |||
2469 | if (width < ov->minwidth || height < ov->minheight) { | ||
2470 | err("Requested dimensions are too small"); | ||
2471 | return -EINVAL; | ||
2472 | } | ||
2473 | |||
2474 | if (ov51x_stop(ov) < 0) | ||
2475 | return -EIO; | ||
2476 | |||
2477 | if (mode == VIDEO_PALETTE_GREY) { | ||
2478 | reg_w(ov, R511_CAM_UV_EN, 0x00); | ||
2479 | reg_w(ov, R511_SNAP_UV_EN, 0x00); | ||
2480 | reg_w(ov, R511_SNAP_OPTS, 0x01); | ||
2481 | } else { | ||
2482 | reg_w(ov, R511_CAM_UV_EN, 0x01); | ||
2483 | reg_w(ov, R511_SNAP_UV_EN, 0x01); | ||
2484 | reg_w(ov, R511_SNAP_OPTS, 0x03); | ||
2485 | } | ||
2486 | |||
2487 | /* Here I'm assuming that snapshot size == image size. | ||
2488 | * I hope that's always true. --claudio | ||
2489 | */ | ||
2490 | hsegs = (width >> 3) - 1; | ||
2491 | vsegs = (height >> 3) - 1; | ||
2492 | |||
2493 | reg_w(ov, R511_CAM_PXCNT, hsegs); | ||
2494 | reg_w(ov, R511_CAM_LNCNT, vsegs); | ||
2495 | reg_w(ov, R511_CAM_PXDIV, 0x00); | ||
2496 | reg_w(ov, R511_CAM_LNDIV, 0x00); | ||
2497 | |||
2498 | /* YUV420, low pass filter on */ | ||
2499 | reg_w(ov, R511_CAM_OPTS, 0x03); | ||
2500 | |||
2501 | /* Snapshot additions */ | ||
2502 | reg_w(ov, R511_SNAP_PXCNT, hsegs); | ||
2503 | reg_w(ov, R511_SNAP_LNCNT, vsegs); | ||
2504 | reg_w(ov, R511_SNAP_PXDIV, 0x00); | ||
2505 | reg_w(ov, R511_SNAP_LNDIV, 0x00); | ||
2506 | |||
2507 | if (ov->compress) { | ||
2508 | /* Enable Y and UV quantization and compression */ | ||
2509 | reg_w(ov, R511_COMP_EN, 0x07); | ||
2510 | reg_w(ov, R511_COMP_LUT_EN, 0x03); | ||
2511 | ov51x_reset(ov, OV511_RESET_OMNICE); | ||
2512 | } | ||
2513 | |||
2514 | if (ov51x_restart(ov) < 0) | ||
2515 | return -EIO; | ||
2516 | |||
2517 | return 0; | ||
2518 | } | ||
2519 | |||
2520 | /* Sets up the OV518/OV518+ with the given image parameters | ||
2521 | * | ||
2522 | * OV518 needs a completely different approach, until we can figure out what | ||
2523 | * the individual registers do. Also, only 15 FPS is supported now. | ||
2524 | * | ||
2525 | * Do not put any sensor-specific code in here (including I2C I/O functions) | ||
2526 | */ | ||
2527 | static int | ||
2528 | ov518_mode_init_regs(struct usb_ov511 *ov, | ||
2529 | int width, int height, int mode, int sub_flag) | ||
2530 | { | ||
2531 | int hsegs, vsegs, hi_res; | ||
2532 | |||
2533 | if (sub_flag) { | ||
2534 | width = ov->subw; | ||
2535 | height = ov->subh; | ||
2536 | } | ||
2537 | |||
2538 | PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", | ||
2539 | width, height, mode, sub_flag); | ||
2540 | |||
2541 | if (width % 16 || height % 8) { | ||
2542 | err("Invalid size (%d, %d)", width, height); | ||
2543 | return -EINVAL; | ||
2544 | } | ||
2545 | |||
2546 | if (width < ov->minwidth || height < ov->minheight) { | ||
2547 | err("Requested dimensions are too small"); | ||
2548 | return -EINVAL; | ||
2549 | } | ||
2550 | |||
2551 | if (width >= 320 && height >= 240) { | ||
2552 | hi_res = 1; | ||
2553 | } else if (width >= 320 || height >= 240) { | ||
2554 | err("Invalid width/height combination (%d, %d)", width, height); | ||
2555 | return -EINVAL; | ||
2556 | } else { | ||
2557 | hi_res = 0; | ||
2558 | } | ||
2559 | |||
2560 | if (ov51x_stop(ov) < 0) | ||
2561 | return -EIO; | ||
2562 | |||
2563 | /******** Set the mode ********/ | ||
2564 | |||
2565 | reg_w(ov, 0x2b, 0); | ||
2566 | reg_w(ov, 0x2c, 0); | ||
2567 | reg_w(ov, 0x2d, 0); | ||
2568 | reg_w(ov, 0x2e, 0); | ||
2569 | reg_w(ov, 0x3b, 0); | ||
2570 | reg_w(ov, 0x3c, 0); | ||
2571 | reg_w(ov, 0x3d, 0); | ||
2572 | reg_w(ov, 0x3e, 0); | ||
2573 | |||
2574 | if (ov->bridge == BRG_OV518 && ov518_color) { | ||
2575 | /* OV518 needs U and V swapped */ | ||
2576 | i2c_w_mask(ov, 0x15, 0x00, 0x01); | ||
2577 | |||
2578 | if (mode == VIDEO_PALETTE_GREY) { | ||
2579 | /* Set 16-bit input format (UV data are ignored) */ | ||
2580 | reg_w_mask(ov, 0x20, 0x00, 0x08); | ||
2581 | |||
2582 | /* Set 8-bit (4:0:0) output format */ | ||
2583 | reg_w_mask(ov, 0x28, 0x00, 0xf0); | ||
2584 | reg_w_mask(ov, 0x38, 0x00, 0xf0); | ||
2585 | } else { | ||
2586 | /* Set 8-bit (YVYU) input format */ | ||
2587 | reg_w_mask(ov, 0x20, 0x08, 0x08); | ||
2588 | |||
2589 | /* Set 12-bit (4:2:0) output format */ | ||
2590 | reg_w_mask(ov, 0x28, 0x80, 0xf0); | ||
2591 | reg_w_mask(ov, 0x38, 0x80, 0xf0); | ||
2592 | } | ||
2593 | } else { | ||
2594 | reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); | ||
2595 | reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); | ||
2596 | } | ||
2597 | |||
2598 | hsegs = width / 16; | ||
2599 | vsegs = height / 4; | ||
2600 | |||
2601 | reg_w(ov, 0x29, hsegs); | ||
2602 | reg_w(ov, 0x2a, vsegs); | ||
2603 | |||
2604 | reg_w(ov, 0x39, hsegs); | ||
2605 | reg_w(ov, 0x3a, vsegs); | ||
2606 | |||
2607 | /* Windows driver does this here; who knows why */ | ||
2608 | reg_w(ov, 0x2f, 0x80); | ||
2609 | |||
2610 | /******** Set the framerate (to 15 FPS) ********/ | ||
2611 | |||
2612 | /* Mode independent, but framerate dependent, regs */ | ||
2613 | reg_w(ov, 0x51, 0x02); /* Clock divider; lower==faster */ | ||
2614 | reg_w(ov, 0x22, 0x18); | ||
2615 | reg_w(ov, 0x23, 0xff); | ||
2616 | |||
2617 | if (ov->bridge == BRG_OV518PLUS) | ||
2618 | reg_w(ov, 0x21, 0x19); | ||
2619 | else | ||
2620 | reg_w(ov, 0x71, 0x19); /* Compression-related? */ | ||
2621 | |||
2622 | // FIXME: Sensor-specific | ||
2623 | /* Bit 5 is what matters here. Of course, it is "reserved" */ | ||
2624 | i2c_w(ov, 0x54, 0x23); | ||
2625 | |||
2626 | reg_w(ov, 0x2f, 0x80); | ||
2627 | |||
2628 | if (ov->bridge == BRG_OV518PLUS) { | ||
2629 | reg_w(ov, 0x24, 0x94); | ||
2630 | reg_w(ov, 0x25, 0x90); | ||
2631 | ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ | ||
2632 | ov518_reg_w32(ov, 0xc6, 540, 2); /* 21ch */ | ||
2633 | ov518_reg_w32(ov, 0xc7, 540, 2); /* 21ch */ | ||
2634 | ov518_reg_w32(ov, 0xc8, 108, 2); /* 6ch */ | ||
2635 | ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */ | ||
2636 | ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */ | ||
2637 | ov518_reg_w32(ov, 0xcc, 2400, 2); /* 960h */ | ||
2638 | ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */ | ||
2639 | ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */ | ||
2640 | } else { | ||
2641 | reg_w(ov, 0x24, 0x9f); | ||
2642 | reg_w(ov, 0x25, 0x90); | ||
2643 | ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ | ||
2644 | ov518_reg_w32(ov, 0xc6, 500, 2); /* 1f4h */ | ||
2645 | ov518_reg_w32(ov, 0xc7, 500, 2); /* 1f4h */ | ||
2646 | ov518_reg_w32(ov, 0xc8, 142, 2); /* 8eh */ | ||
2647 | ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */ | ||
2648 | ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */ | ||
2649 | ov518_reg_w32(ov, 0xcc, 2000, 2); /* 7d0h */ | ||
2650 | ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */ | ||
2651 | ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */ | ||
2652 | } | ||
2653 | |||
2654 | reg_w(ov, 0x2f, 0x80); | ||
2655 | |||
2656 | if (ov51x_restart(ov) < 0) | ||
2657 | return -EIO; | ||
2658 | |||
2659 | /* Reset it just for good measure */ | ||
2660 | if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) | ||
2661 | return -EIO; | ||
2662 | |||
2663 | return 0; | ||
2664 | } | ||
2665 | |||
2666 | /* This is a wrapper around the OV511, OV518, and sensor specific functions */ | ||
2667 | static int | ||
2668 | mode_init_regs(struct usb_ov511 *ov, | ||
2669 | int width, int height, int mode, int sub_flag) | ||
2670 | { | ||
2671 | int rc = 0; | ||
2672 | |||
2673 | if (!ov || !ov->dev) | ||
2674 | return -EFAULT; | ||
2675 | |||
2676 | if (ov->bclass == BCL_OV518) { | ||
2677 | rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag); | ||
2678 | } else { | ||
2679 | rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag); | ||
2680 | } | ||
2681 | |||
2682 | if (FATAL_ERROR(rc)) | ||
2683 | return rc; | ||
2684 | |||
2685 | switch (ov->sensor) { | ||
2686 | case SEN_OV7610: | ||
2687 | case SEN_OV7620: | ||
2688 | case SEN_OV76BE: | ||
2689 | case SEN_OV8600: | ||
2690 | case SEN_OV6620: | ||
2691 | case SEN_OV6630: | ||
2692 | rc = set_ov_sensor_window(ov, width, height, mode, sub_flag); | ||
2693 | break; | ||
2694 | case SEN_KS0127: | ||
2695 | case SEN_KS0127B: | ||
2696 | err("KS0127-series decoders not supported yet"); | ||
2697 | rc = -EINVAL; | ||
2698 | break; | ||
2699 | case SEN_SAA7111A: | ||
2700 | // rc = mode_init_saa_sensor_regs(ov, width, height, mode, | ||
2701 | // sub_flag); | ||
2702 | |||
2703 | PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f)); | ||
2704 | break; | ||
2705 | default: | ||
2706 | err("Unknown sensor"); | ||
2707 | rc = -EINVAL; | ||
2708 | } | ||
2709 | |||
2710 | if (FATAL_ERROR(rc)) | ||
2711 | return rc; | ||
2712 | |||
2713 | /* Sensor-independent settings */ | ||
2714 | rc = sensor_set_auto_brightness(ov, ov->auto_brt); | ||
2715 | if (FATAL_ERROR(rc)) | ||
2716 | return rc; | ||
2717 | |||
2718 | rc = sensor_set_auto_exposure(ov, ov->auto_exp); | ||
2719 | if (FATAL_ERROR(rc)) | ||
2720 | return rc; | ||
2721 | |||
2722 | rc = sensor_set_banding_filter(ov, bandingfilter); | ||
2723 | if (FATAL_ERROR(rc)) | ||
2724 | return rc; | ||
2725 | |||
2726 | if (ov->lightfreq) { | ||
2727 | rc = sensor_set_light_freq(ov, lightfreq); | ||
2728 | if (FATAL_ERROR(rc)) | ||
2729 | return rc; | ||
2730 | } | ||
2731 | |||
2732 | rc = sensor_set_backlight(ov, ov->backlight); | ||
2733 | if (FATAL_ERROR(rc)) | ||
2734 | return rc; | ||
2735 | |||
2736 | rc = sensor_set_mirror(ov, ov->mirror); | ||
2737 | if (FATAL_ERROR(rc)) | ||
2738 | return rc; | ||
2739 | |||
2740 | return 0; | ||
2741 | } | ||
2742 | |||
2743 | /* This sets the default image parameters. This is useful for apps that use | ||
2744 | * read() and do not set these. | ||
2745 | */ | ||
2746 | static int | ||
2747 | ov51x_set_default_params(struct usb_ov511 *ov) | ||
2748 | { | ||
2749 | int i; | ||
2750 | |||
2751 | /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used | ||
2752 | * (using read() instead). */ | ||
2753 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
2754 | ov->frame[i].width = ov->maxwidth; | ||
2755 | ov->frame[i].height = ov->maxheight; | ||
2756 | ov->frame[i].bytes_read = 0; | ||
2757 | if (force_palette) | ||
2758 | ov->frame[i].format = force_palette; | ||
2759 | else | ||
2760 | ov->frame[i].format = VIDEO_PALETTE_YUV420; | ||
2761 | |||
2762 | ov->frame[i].depth = get_depth(ov->frame[i].format); | ||
2763 | } | ||
2764 | |||
2765 | PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight, | ||
2766 | symbolic(v4l1_plist, ov->frame[0].format)); | ||
2767 | |||
2768 | /* Initialize to max width/height, YUV420 or RGB24 (if supported) */ | ||
2769 | if (mode_init_regs(ov, ov->maxwidth, ov->maxheight, | ||
2770 | ov->frame[0].format, 0) < 0) | ||
2771 | return -EINVAL; | ||
2772 | |||
2773 | return 0; | ||
2774 | } | ||
2775 | |||
2776 | /********************************************************************** | ||
2777 | * | ||
2778 | * Video decoder stuff | ||
2779 | * | ||
2780 | **********************************************************************/ | ||
2781 | |||
2782 | /* Set analog input port of decoder */ | ||
2783 | static int | ||
2784 | decoder_set_input(struct usb_ov511 *ov, int input) | ||
2785 | { | ||
2786 | PDEBUG(4, "port %d", input); | ||
2787 | |||
2788 | switch (ov->sensor) { | ||
2789 | case SEN_SAA7111A: | ||
2790 | { | ||
2791 | /* Select mode */ | ||
2792 | i2c_w_mask(ov, 0x02, input, 0x07); | ||
2793 | /* Bypass chrominance trap for modes 4..7 */ | ||
2794 | i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80); | ||
2795 | break; | ||
2796 | } | ||
2797 | default: | ||
2798 | return -EINVAL; | ||
2799 | } | ||
2800 | |||
2801 | return 0; | ||
2802 | } | ||
2803 | |||
2804 | /* Get ASCII name of video input */ | ||
2805 | static int | ||
2806 | decoder_get_input_name(struct usb_ov511 *ov, int input, char *name) | ||
2807 | { | ||
2808 | switch (ov->sensor) { | ||
2809 | case SEN_SAA7111A: | ||
2810 | { | ||
2811 | if (input < 0 || input > 7) | ||
2812 | return -EINVAL; | ||
2813 | else if (input < 4) | ||
2814 | sprintf(name, "CVBS-%d", input); | ||
2815 | else // if (input < 8) | ||
2816 | sprintf(name, "S-Video-%d", input - 4); | ||
2817 | break; | ||
2818 | } | ||
2819 | default: | ||
2820 | sprintf(name, "%s", "Camera"); | ||
2821 | } | ||
2822 | |||
2823 | return 0; | ||
2824 | } | ||
2825 | |||
2826 | /* Set norm (NTSC, PAL, SECAM, AUTO) */ | ||
2827 | static int | ||
2828 | decoder_set_norm(struct usb_ov511 *ov, int norm) | ||
2829 | { | ||
2830 | PDEBUG(4, "%d", norm); | ||
2831 | |||
2832 | switch (ov->sensor) { | ||
2833 | case SEN_SAA7111A: | ||
2834 | { | ||
2835 | int reg_8, reg_e; | ||
2836 | |||
2837 | if (norm == VIDEO_MODE_NTSC) { | ||
2838 | reg_8 = 0x40; /* 60 Hz */ | ||
2839 | reg_e = 0x00; /* NTSC M / PAL BGHI */ | ||
2840 | } else if (norm == VIDEO_MODE_PAL) { | ||
2841 | reg_8 = 0x00; /* 50 Hz */ | ||
2842 | reg_e = 0x00; /* NTSC M / PAL BGHI */ | ||
2843 | } else if (norm == VIDEO_MODE_AUTO) { | ||
2844 | reg_8 = 0x80; /* Auto field detect */ | ||
2845 | reg_e = 0x00; /* NTSC M / PAL BGHI */ | ||
2846 | } else if (norm == VIDEO_MODE_SECAM) { | ||
2847 | reg_8 = 0x00; /* 50 Hz */ | ||
2848 | reg_e = 0x50; /* SECAM / PAL 4.43 */ | ||
2849 | } else { | ||
2850 | return -EINVAL; | ||
2851 | } | ||
2852 | |||
2853 | i2c_w_mask(ov, 0x08, reg_8, 0xc0); | ||
2854 | i2c_w_mask(ov, 0x0e, reg_e, 0x70); | ||
2855 | break; | ||
2856 | } | ||
2857 | default: | ||
2858 | return -EINVAL; | ||
2859 | } | ||
2860 | |||
2861 | return 0; | ||
2862 | } | ||
2863 | |||
2864 | /********************************************************************** | ||
2865 | * | ||
2866 | * Raw data parsing | ||
2867 | * | ||
2868 | **********************************************************************/ | ||
2869 | |||
2870 | /* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the | ||
2871 | * image at pOut is specified by w. | ||
2872 | */ | ||
2873 | static inline void | ||
2874 | make_8x8(unsigned char *pIn, unsigned char *pOut, int w) | ||
2875 | { | ||
2876 | unsigned char *pOut1 = pOut; | ||
2877 | int x, y; | ||
2878 | |||
2879 | for (y = 0; y < 8; y++) { | ||
2880 | pOut1 = pOut; | ||
2881 | for (x = 0; x < 8; x++) { | ||
2882 | *pOut1++ = *pIn++; | ||
2883 | } | ||
2884 | pOut += w; | ||
2885 | } | ||
2886 | } | ||
2887 | |||
2888 | /* | ||
2889 | * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments. | ||
2890 | * The segments represent 4 squares of 8x8 pixels as follows: | ||
2891 | * | ||
2892 | * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 | ||
2893 | * 8 9 ... 15 72 73 ... 79 200 201 ... 207 | ||
2894 | * ... ... ... | ||
2895 | * 56 57 ... 63 120 121 ... 127 248 249 ... 255 | ||
2896 | * | ||
2897 | */ | ||
2898 | static void | ||
2899 | yuv400raw_to_yuv400p(struct ov511_frame *frame, | ||
2900 | unsigned char *pIn0, unsigned char *pOut0) | ||
2901 | { | ||
2902 | int x, y; | ||
2903 | unsigned char *pIn, *pOut, *pOutLine; | ||
2904 | |||
2905 | /* Copy Y */ | ||
2906 | pIn = pIn0; | ||
2907 | pOutLine = pOut0; | ||
2908 | for (y = 0; y < frame->rawheight - 1; y += 8) { | ||
2909 | pOut = pOutLine; | ||
2910 | for (x = 0; x < frame->rawwidth - 1; x += 8) { | ||
2911 | make_8x8(pIn, pOut, frame->rawwidth); | ||
2912 | pIn += 64; | ||
2913 | pOut += 8; | ||
2914 | } | ||
2915 | pOutLine += 8 * frame->rawwidth; | ||
2916 | } | ||
2917 | } | ||
2918 | |||
2919 | /* | ||
2920 | * For YUV 4:2:0 images, the data show up in 384 byte segments. | ||
2921 | * The first 64 bytes of each segment are U, the next 64 are V. The U and | ||
2922 | * V are arranged as follows: | ||
2923 | * | ||
2924 | * 0 1 ... 7 | ||
2925 | * 8 9 ... 15 | ||
2926 | * ... | ||
2927 | * 56 57 ... 63 | ||
2928 | * | ||
2929 | * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block). | ||
2930 | * | ||
2931 | * The next 256 bytes are full resolution Y data and represent 4 squares | ||
2932 | * of 8x8 pixels as follows: | ||
2933 | * | ||
2934 | * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 | ||
2935 | * 8 9 ... 15 72 73 ... 79 200 201 ... 207 | ||
2936 | * ... ... ... | ||
2937 | * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255 | ||
2938 | * | ||
2939 | * Note that the U and V data in one segment represent a 16 x 16 pixel | ||
2940 | * area, but the Y data represent a 32 x 8 pixel area. If the width is not an | ||
2941 | * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the | ||
2942 | * next horizontal stripe. | ||
2943 | * | ||
2944 | * If dumppix module param is set, _parse_data just dumps the incoming segments, | ||
2945 | * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480 | ||
2946 | * this puts the data on the standard output and can be analyzed with the | ||
2947 | * parseppm.c utility I wrote. That's a much faster way for figuring out how | ||
2948 | * these data are scrambled. | ||
2949 | */ | ||
2950 | |||
2951 | /* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0. | ||
2952 | * | ||
2953 | * FIXME: Currently only handles width and height that are multiples of 16 | ||
2954 | */ | ||
2955 | static void | ||
2956 | yuv420raw_to_yuv420p(struct ov511_frame *frame, | ||
2957 | unsigned char *pIn0, unsigned char *pOut0) | ||
2958 | { | ||
2959 | int k, x, y; | ||
2960 | unsigned char *pIn, *pOut, *pOutLine; | ||
2961 | const unsigned int a = frame->rawwidth * frame->rawheight; | ||
2962 | const unsigned int w = frame->rawwidth / 2; | ||
2963 | |||
2964 | /* Copy U and V */ | ||
2965 | pIn = pIn0; | ||
2966 | pOutLine = pOut0 + a; | ||
2967 | for (y = 0; y < frame->rawheight - 1; y += 16) { | ||
2968 | pOut = pOutLine; | ||
2969 | for (x = 0; x < frame->rawwidth - 1; x += 16) { | ||
2970 | make_8x8(pIn, pOut, w); | ||
2971 | make_8x8(pIn + 64, pOut + a/4, w); | ||
2972 | pIn += 384; | ||
2973 | pOut += 8; | ||
2974 | } | ||
2975 | pOutLine += 8 * w; | ||
2976 | } | ||
2977 | |||
2978 | /* Copy Y */ | ||
2979 | pIn = pIn0 + 128; | ||
2980 | pOutLine = pOut0; | ||
2981 | k = 0; | ||
2982 | for (y = 0; y < frame->rawheight - 1; y += 8) { | ||
2983 | pOut = pOutLine; | ||
2984 | for (x = 0; x < frame->rawwidth - 1; x += 8) { | ||
2985 | make_8x8(pIn, pOut, frame->rawwidth); | ||
2986 | pIn += 64; | ||
2987 | pOut += 8; | ||
2988 | if ((++k) > 3) { | ||
2989 | k = 0; | ||
2990 | pIn += 128; | ||
2991 | } | ||
2992 | } | ||
2993 | pOutLine += 8 * frame->rawwidth; | ||
2994 | } | ||
2995 | } | ||
2996 | |||
2997 | /********************************************************************** | ||
2998 | * | ||
2999 | * Decompression | ||
3000 | * | ||
3001 | **********************************************************************/ | ||
3002 | |||
3003 | static int | ||
3004 | request_decompressor(struct usb_ov511 *ov) | ||
3005 | { | ||
3006 | if (ov->bclass == BCL_OV511 || ov->bclass == BCL_OV518) { | ||
3007 | err("No decompressor available"); | ||
3008 | } else { | ||
3009 | err("Unknown bridge"); | ||
3010 | } | ||
3011 | |||
3012 | return -ENOSYS; | ||
3013 | } | ||
3014 | |||
3015 | static void | ||
3016 | decompress(struct usb_ov511 *ov, struct ov511_frame *frame, | ||
3017 | unsigned char *pIn0, unsigned char *pOut0) | ||
3018 | { | ||
3019 | if (!ov->decomp_ops) | ||
3020 | if (request_decompressor(ov)) | ||
3021 | return; | ||
3022 | |||
3023 | } | ||
3024 | |||
3025 | /********************************************************************** | ||
3026 | * | ||
3027 | * Format conversion | ||
3028 | * | ||
3029 | **********************************************************************/ | ||
3030 | |||
3031 | /* Fuses even and odd fields together, and doubles width. | ||
3032 | * INPUT: an odd field followed by an even field at pIn0, in YUV planar format | ||
3033 | * OUTPUT: a normal YUV planar image, with correct aspect ratio | ||
3034 | */ | ||
3035 | static void | ||
3036 | deinterlace(struct ov511_frame *frame, int rawformat, | ||
3037 | unsigned char *pIn0, unsigned char *pOut0) | ||
3038 | { | ||
3039 | const int fieldheight = frame->rawheight / 2; | ||
3040 | const int fieldpix = fieldheight * frame->rawwidth; | ||
3041 | const int w = frame->width; | ||
3042 | int x, y; | ||
3043 | unsigned char *pInEven, *pInOdd, *pOut; | ||
3044 | |||
3045 | PDEBUG(5, "fieldheight=%d", fieldheight); | ||
3046 | |||
3047 | if (frame->rawheight != frame->height) { | ||
3048 | err("invalid height"); | ||
3049 | return; | ||
3050 | } | ||
3051 | |||
3052 | if ((frame->rawwidth * 2) != frame->width) { | ||
3053 | err("invalid width"); | ||
3054 | return; | ||
3055 | } | ||
3056 | |||
3057 | /* Y */ | ||
3058 | pInOdd = pIn0; | ||
3059 | pInEven = pInOdd + fieldpix; | ||
3060 | pOut = pOut0; | ||
3061 | for (y = 0; y < fieldheight; y++) { | ||
3062 | for (x = 0; x < frame->rawwidth; x++) { | ||
3063 | *pOut = *pInEven; | ||
3064 | *(pOut+1) = *pInEven++; | ||
3065 | *(pOut+w) = *pInOdd; | ||
3066 | *(pOut+w+1) = *pInOdd++; | ||
3067 | pOut += 2; | ||
3068 | } | ||
3069 | pOut += w; | ||
3070 | } | ||
3071 | |||
3072 | if (rawformat == RAWFMT_YUV420) { | ||
3073 | /* U */ | ||
3074 | pInOdd = pIn0 + fieldpix * 2; | ||
3075 | pInEven = pInOdd + fieldpix / 4; | ||
3076 | for (y = 0; y < fieldheight / 2; y++) { | ||
3077 | for (x = 0; x < frame->rawwidth / 2; x++) { | ||
3078 | *pOut = *pInEven; | ||
3079 | *(pOut+1) = *pInEven++; | ||
3080 | *(pOut+w/2) = *pInOdd; | ||
3081 | *(pOut+w/2+1) = *pInOdd++; | ||
3082 | pOut += 2; | ||
3083 | } | ||
3084 | pOut += w/2; | ||
3085 | } | ||
3086 | /* V */ | ||
3087 | pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2; | ||
3088 | pInEven = pInOdd + fieldpix / 4; | ||
3089 | for (y = 0; y < fieldheight / 2; y++) { | ||
3090 | for (x = 0; x < frame->rawwidth / 2; x++) { | ||
3091 | *pOut = *pInEven; | ||
3092 | *(pOut+1) = *pInEven++; | ||
3093 | *(pOut+w/2) = *pInOdd; | ||
3094 | *(pOut+w/2+1) = *pInOdd++; | ||
3095 | pOut += 2; | ||
3096 | } | ||
3097 | pOut += w/2; | ||
3098 | } | ||
3099 | } | ||
3100 | } | ||
3101 | |||
3102 | static void | ||
3103 | ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame) | ||
3104 | { | ||
3105 | /* Deinterlace frame, if necessary */ | ||
3106 | if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) { | ||
3107 | if (frame->compressed) | ||
3108 | decompress(ov, frame, frame->rawdata, | ||
3109 | frame->tempdata); | ||
3110 | else | ||
3111 | yuv400raw_to_yuv400p(frame, frame->rawdata, | ||
3112 | frame->tempdata); | ||
3113 | |||
3114 | deinterlace(frame, RAWFMT_YUV400, frame->tempdata, | ||
3115 | frame->data); | ||
3116 | } else { | ||
3117 | if (frame->compressed) | ||
3118 | decompress(ov, frame, frame->rawdata, | ||
3119 | frame->data); | ||
3120 | else | ||
3121 | yuv400raw_to_yuv400p(frame, frame->rawdata, | ||
3122 | frame->data); | ||
3123 | } | ||
3124 | } | ||
3125 | |||
3126 | /* Process raw YUV420 data into standard YUV420P */ | ||
3127 | static void | ||
3128 | ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame) | ||
3129 | { | ||
3130 | /* Deinterlace frame, if necessary */ | ||
3131 | if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) { | ||
3132 | if (frame->compressed) | ||
3133 | decompress(ov, frame, frame->rawdata, frame->tempdata); | ||
3134 | else | ||
3135 | yuv420raw_to_yuv420p(frame, frame->rawdata, | ||
3136 | frame->tempdata); | ||
3137 | |||
3138 | deinterlace(frame, RAWFMT_YUV420, frame->tempdata, | ||
3139 | frame->data); | ||
3140 | } else { | ||
3141 | if (frame->compressed) | ||
3142 | decompress(ov, frame, frame->rawdata, frame->data); | ||
3143 | else | ||
3144 | yuv420raw_to_yuv420p(frame, frame->rawdata, | ||
3145 | frame->data); | ||
3146 | } | ||
3147 | } | ||
3148 | |||
3149 | /* Post-processes the specified frame. This consists of: | ||
3150 | * 1. Decompress frame, if necessary | ||
3151 | * 2. Deinterlace frame and scale to proper size, if necessary | ||
3152 | * 3. Convert from YUV planar to destination format, if necessary | ||
3153 | * 4. Fix the RGB offset, if necessary | ||
3154 | */ | ||
3155 | static void | ||
3156 | ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame) | ||
3157 | { | ||
3158 | if (dumppix) { | ||
3159 | memset(frame->data, 0, | ||
3160 | MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); | ||
3161 | PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd); | ||
3162 | memcpy(frame->data, frame->rawdata, frame->bytes_recvd); | ||
3163 | } else { | ||
3164 | switch (frame->format) { | ||
3165 | case VIDEO_PALETTE_GREY: | ||
3166 | ov51x_postprocess_grey(ov, frame); | ||
3167 | break; | ||
3168 | case VIDEO_PALETTE_YUV420: | ||
3169 | case VIDEO_PALETTE_YUV420P: | ||
3170 | ov51x_postprocess_yuv420(ov, frame); | ||
3171 | break; | ||
3172 | default: | ||
3173 | err("Cannot convert data to %s", | ||
3174 | symbolic(v4l1_plist, frame->format)); | ||
3175 | } | ||
3176 | } | ||
3177 | } | ||
3178 | |||
3179 | /********************************************************************** | ||
3180 | * | ||
3181 | * OV51x data transfer, IRQ handler | ||
3182 | * | ||
3183 | **********************************************************************/ | ||
3184 | |||
3185 | static inline void | ||
3186 | ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n) | ||
3187 | { | ||
3188 | int num, offset; | ||
3189 | int pnum = in[ov->packet_size - 1]; /* Get packet number */ | ||
3190 | int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight); | ||
3191 | struct ov511_frame *frame = &ov->frame[ov->curframe]; | ||
3192 | struct timeval *ts; | ||
3193 | |||
3194 | /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th | ||
3195 | * byte non-zero. The EOF packet has image width/height in the | ||
3196 | * 10th and 11th bytes. The 9th byte is given as follows: | ||
3197 | * | ||
3198 | * bit 7: EOF | ||
3199 | * 6: compression enabled | ||
3200 | * 5: 422/420/400 modes | ||
3201 | * 4: 422/420/400 modes | ||
3202 | * 3: 1 | ||
3203 | * 2: snapshot button on | ||
3204 | * 1: snapshot frame | ||
3205 | * 0: even/odd field | ||
3206 | */ | ||
3207 | |||
3208 | if (printph) { | ||
3209 | info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", | ||
3210 | pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6], | ||
3211 | in[7], in[8], in[9], in[10], in[11]); | ||
3212 | } | ||
3213 | |||
3214 | /* Check for SOF/EOF packet */ | ||
3215 | if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) || | ||
3216 | (~in[8] & 0x08)) | ||
3217 | goto check_middle; | ||
3218 | |||
3219 | /* Frame end */ | ||
3220 | if (in[8] & 0x80) { | ||
3221 | ts = (struct timeval *)(frame->data | ||
3222 | + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); | ||
3223 | do_gettimeofday(ts); | ||
3224 | |||
3225 | /* Get the actual frame size from the EOF header */ | ||
3226 | frame->rawwidth = ((int)(in[9]) + 1) * 8; | ||
3227 | frame->rawheight = ((int)(in[10]) + 1) * 8; | ||
3228 | |||
3229 | PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d", | ||
3230 | ov->curframe, pnum, frame->rawwidth, frame->rawheight, | ||
3231 | frame->bytes_recvd); | ||
3232 | |||
3233 | /* Validate the header data */ | ||
3234 | RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); | ||
3235 | RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, | ||
3236 | ov->maxheight); | ||
3237 | |||
3238 | /* Don't allow byte count to exceed buffer size */ | ||
3239 | RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw); | ||
3240 | |||
3241 | if (frame->scanstate == STATE_LINES) { | ||
3242 | int nextf; | ||
3243 | |||
3244 | frame->grabstate = FRAME_DONE; | ||
3245 | wake_up_interruptible(&frame->wq); | ||
3246 | |||
3247 | /* If next frame is ready or grabbing, | ||
3248 | * point to it */ | ||
3249 | nextf = (ov->curframe + 1) % OV511_NUMFRAMES; | ||
3250 | if (ov->frame[nextf].grabstate == FRAME_READY | ||
3251 | || ov->frame[nextf].grabstate == FRAME_GRABBING) { | ||
3252 | ov->curframe = nextf; | ||
3253 | ov->frame[nextf].scanstate = STATE_SCANNING; | ||
3254 | } else { | ||
3255 | if (frame->grabstate == FRAME_DONE) { | ||
3256 | PDEBUG(4, "** Frame done **"); | ||
3257 | } else { | ||
3258 | PDEBUG(4, "Frame not ready? state = %d", | ||
3259 | ov->frame[nextf].grabstate); | ||
3260 | } | ||
3261 | |||
3262 | ov->curframe = -1; | ||
3263 | } | ||
3264 | } else { | ||
3265 | PDEBUG(5, "Frame done, but not scanning"); | ||
3266 | } | ||
3267 | /* Image corruption caused by misplaced frame->segment = 0 | ||
3268 | * fixed by carlosf@conectiva.com.br | ||
3269 | */ | ||
3270 | } else { | ||
3271 | /* Frame start */ | ||
3272 | PDEBUG(4, "Frame start, framenum = %d", ov->curframe); | ||
3273 | |||
3274 | /* Check to see if it's a snapshot frame */ | ||
3275 | /* FIXME?? Should the snapshot reset go here? Performance? */ | ||
3276 | if (in[8] & 0x02) { | ||
3277 | frame->snapshot = 1; | ||
3278 | PDEBUG(3, "snapshot detected"); | ||
3279 | } | ||
3280 | |||
3281 | frame->scanstate = STATE_LINES; | ||
3282 | frame->bytes_recvd = 0; | ||
3283 | frame->compressed = in[8] & 0x40; | ||
3284 | } | ||
3285 | |||
3286 | check_middle: | ||
3287 | /* Are we in a frame? */ | ||
3288 | if (frame->scanstate != STATE_LINES) { | ||
3289 | PDEBUG(5, "Not in a frame; packet skipped"); | ||
3290 | return; | ||
3291 | } | ||
3292 | |||
3293 | /* If frame start, skip header */ | ||
3294 | if (frame->bytes_recvd == 0) | ||
3295 | offset = 9; | ||
3296 | else | ||
3297 | offset = 0; | ||
3298 | |||
3299 | num = n - offset - 1; | ||
3300 | |||
3301 | /* Dump all data exactly as received */ | ||
3302 | if (dumppix == 2) { | ||
3303 | frame->bytes_recvd += n - 1; | ||
3304 | if (frame->bytes_recvd <= max_raw) | ||
3305 | memcpy(frame->rawdata + frame->bytes_recvd - (n - 1), | ||
3306 | in, n - 1); | ||
3307 | else | ||
3308 | PDEBUG(3, "Raw data buffer overrun!! (%d)", | ||
3309 | frame->bytes_recvd - max_raw); | ||
3310 | } else if (!frame->compressed && !remove_zeros) { | ||
3311 | frame->bytes_recvd += num; | ||
3312 | if (frame->bytes_recvd <= max_raw) | ||
3313 | memcpy(frame->rawdata + frame->bytes_recvd - num, | ||
3314 | in + offset, num); | ||
3315 | else | ||
3316 | PDEBUG(3, "Raw data buffer overrun!! (%d)", | ||
3317 | frame->bytes_recvd - max_raw); | ||
3318 | } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */ | ||
3319 | int b, read = 0, allzero, copied = 0; | ||
3320 | if (offset) { | ||
3321 | frame->bytes_recvd += 32 - offset; // Bytes out | ||
3322 | memcpy(frame->rawdata, in + offset, 32 - offset); | ||
3323 | read += 32; | ||
3324 | } | ||
3325 | |||
3326 | while (read < n - 1) { | ||
3327 | allzero = 1; | ||
3328 | for (b = 0; b < 32; b++) { | ||
3329 | if (in[read + b]) { | ||
3330 | allzero = 0; | ||
3331 | break; | ||
3332 | } | ||
3333 | } | ||
3334 | |||
3335 | if (allzero) { | ||
3336 | /* Don't copy it */ | ||
3337 | } else { | ||
3338 | if (frame->bytes_recvd + copied + 32 <= max_raw) | ||
3339 | { | ||
3340 | memcpy(frame->rawdata | ||
3341 | + frame->bytes_recvd + copied, | ||
3342 | in + read, 32); | ||
3343 | copied += 32; | ||
3344 | } else { | ||
3345 | PDEBUG(3, "Raw data buffer overrun!!"); | ||
3346 | } | ||
3347 | } | ||
3348 | read += 32; | ||
3349 | } | ||
3350 | |||
3351 | frame->bytes_recvd += copied; | ||
3352 | } | ||
3353 | } | ||
3354 | |||
3355 | static inline void | ||
3356 | ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n) | ||
3357 | { | ||
3358 | int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight); | ||
3359 | struct ov511_frame *frame = &ov->frame[ov->curframe]; | ||
3360 | struct timeval *ts; | ||
3361 | |||
3362 | /* Don't copy the packet number byte */ | ||
3363 | if (ov->packet_numbering) | ||
3364 | --n; | ||
3365 | |||
3366 | /* A false positive here is likely, until OVT gives me | ||
3367 | * the definitive SOF/EOF format */ | ||
3368 | if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) { | ||
3369 | if (printph) { | ||
3370 | info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0], | ||
3371 | in[1], in[2], in[3], in[4], in[5], in[6], in[7]); | ||
3372 | } | ||
3373 | |||
3374 | if (frame->scanstate == STATE_LINES) { | ||
3375 | PDEBUG(4, "Detected frame end/start"); | ||
3376 | goto eof; | ||
3377 | } else { //scanstate == STATE_SCANNING | ||
3378 | /* Frame start */ | ||
3379 | PDEBUG(4, "Frame start, framenum = %d", ov->curframe); | ||
3380 | goto sof; | ||
3381 | } | ||
3382 | } else { | ||
3383 | goto check_middle; | ||
3384 | } | ||
3385 | |||
3386 | eof: | ||
3387 | ts = (struct timeval *)(frame->data | ||
3388 | + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); | ||
3389 | do_gettimeofday(ts); | ||
3390 | |||
3391 | PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d", | ||
3392 | ov->curframe, | ||
3393 | (int)(in[9]), (int)(in[10]), frame->bytes_recvd); | ||
3394 | |||
3395 | // FIXME: Since we don't know the header formats yet, | ||
3396 | // there is no way to know what the actual image size is | ||
3397 | frame->rawwidth = frame->width; | ||
3398 | frame->rawheight = frame->height; | ||
3399 | |||
3400 | /* Validate the header data */ | ||
3401 | RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); | ||
3402 | RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight); | ||
3403 | |||
3404 | /* Don't allow byte count to exceed buffer size */ | ||
3405 | RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw); | ||
3406 | |||
3407 | if (frame->scanstate == STATE_LINES) { | ||
3408 | int nextf; | ||
3409 | |||
3410 | frame->grabstate = FRAME_DONE; | ||
3411 | wake_up_interruptible(&frame->wq); | ||
3412 | |||
3413 | /* If next frame is ready or grabbing, | ||
3414 | * point to it */ | ||
3415 | nextf = (ov->curframe + 1) % OV511_NUMFRAMES; | ||
3416 | if (ov->frame[nextf].grabstate == FRAME_READY | ||
3417 | || ov->frame[nextf].grabstate == FRAME_GRABBING) { | ||
3418 | ov->curframe = nextf; | ||
3419 | ov->frame[nextf].scanstate = STATE_SCANNING; | ||
3420 | frame = &ov->frame[nextf]; | ||
3421 | } else { | ||
3422 | if (frame->grabstate == FRAME_DONE) { | ||
3423 | PDEBUG(4, "** Frame done **"); | ||
3424 | } else { | ||
3425 | PDEBUG(4, "Frame not ready? state = %d", | ||
3426 | ov->frame[nextf].grabstate); | ||
3427 | } | ||
3428 | |||
3429 | ov->curframe = -1; | ||
3430 | PDEBUG(4, "SOF dropped (no active frame)"); | ||
3431 | return; /* Nowhere to store this frame */ | ||
3432 | } | ||
3433 | } | ||
3434 | sof: | ||
3435 | PDEBUG(4, "Starting capture on frame %d", frame->framenum); | ||
3436 | |||
3437 | // Snapshot not reverse-engineered yet. | ||
3438 | #if 0 | ||
3439 | /* Check to see if it's a snapshot frame */ | ||
3440 | /* FIXME?? Should the snapshot reset go here? Performance? */ | ||
3441 | if (in[8] & 0x02) { | ||
3442 | frame->snapshot = 1; | ||
3443 | PDEBUG(3, "snapshot detected"); | ||
3444 | } | ||
3445 | #endif | ||
3446 | frame->scanstate = STATE_LINES; | ||
3447 | frame->bytes_recvd = 0; | ||
3448 | frame->compressed = 1; | ||
3449 | |||
3450 | check_middle: | ||
3451 | /* Are we in a frame? */ | ||
3452 | if (frame->scanstate != STATE_LINES) { | ||
3453 | PDEBUG(4, "scanstate: no SOF yet"); | ||
3454 | return; | ||
3455 | } | ||
3456 | |||
3457 | /* Dump all data exactly as received */ | ||
3458 | if (dumppix == 2) { | ||
3459 | frame->bytes_recvd += n; | ||
3460 | if (frame->bytes_recvd <= max_raw) | ||
3461 | memcpy(frame->rawdata + frame->bytes_recvd - n, in, n); | ||
3462 | else | ||
3463 | PDEBUG(3, "Raw data buffer overrun!! (%d)", | ||
3464 | frame->bytes_recvd - max_raw); | ||
3465 | } else { | ||
3466 | /* All incoming data are divided into 8-byte segments. If the | ||
3467 | * segment contains all zero bytes, it must be skipped. These | ||
3468 | * zero-segments allow the OV518 to mainain a constant data rate | ||
3469 | * regardless of the effectiveness of the compression. Segments | ||
3470 | * are aligned relative to the beginning of each isochronous | ||
3471 | * packet. The first segment in each image is a header (the | ||
3472 | * decompressor skips it later). | ||
3473 | */ | ||
3474 | |||
3475 | int b, read = 0, allzero, copied = 0; | ||
3476 | |||
3477 | while (read < n) { | ||
3478 | allzero = 1; | ||
3479 | for (b = 0; b < 8; b++) { | ||
3480 | if (in[read + b]) { | ||
3481 | allzero = 0; | ||
3482 | break; | ||
3483 | } | ||
3484 | } | ||
3485 | |||
3486 | if (allzero) { | ||
3487 | /* Don't copy it */ | ||
3488 | } else { | ||
3489 | if (frame->bytes_recvd + copied + 8 <= max_raw) | ||
3490 | { | ||
3491 | memcpy(frame->rawdata | ||
3492 | + frame->bytes_recvd + copied, | ||
3493 | in + read, 8); | ||
3494 | copied += 8; | ||
3495 | } else { | ||
3496 | PDEBUG(3, "Raw data buffer overrun!!"); | ||
3497 | } | ||
3498 | } | ||
3499 | read += 8; | ||
3500 | } | ||
3501 | frame->bytes_recvd += copied; | ||
3502 | } | ||
3503 | } | ||
3504 | |||
3505 | static void | ||
3506 | ov51x_isoc_irq(struct urb *urb, struct pt_regs *regs) | ||
3507 | { | ||
3508 | int i; | ||
3509 | struct usb_ov511 *ov; | ||
3510 | struct ov511_sbuf *sbuf; | ||
3511 | |||
3512 | if (!urb->context) { | ||
3513 | PDEBUG(4, "no context"); | ||
3514 | return; | ||
3515 | } | ||
3516 | |||
3517 | sbuf = urb->context; | ||
3518 | ov = sbuf->ov; | ||
3519 | |||
3520 | if (!ov || !ov->dev || !ov->user) { | ||
3521 | PDEBUG(4, "no device, or not open"); | ||
3522 | return; | ||
3523 | } | ||
3524 | |||
3525 | if (!ov->streaming) { | ||
3526 | PDEBUG(4, "hmmm... not streaming, but got interrupt"); | ||
3527 | return; | ||
3528 | } | ||
3529 | |||
3530 | if (urb->status == -ENOENT || urb->status == -ECONNRESET) { | ||
3531 | PDEBUG(4, "URB unlinked"); | ||
3532 | return; | ||
3533 | } | ||
3534 | |||
3535 | if (urb->status != -EINPROGRESS && urb->status != 0) { | ||
3536 | err("ERROR: urb->status=%d: %s", urb->status, | ||
3537 | symbolic(urb_errlist, urb->status)); | ||
3538 | } | ||
3539 | |||
3540 | /* Copy the data received into our frame buffer */ | ||
3541 | PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n, | ||
3542 | urb->number_of_packets); | ||
3543 | for (i = 0; i < urb->number_of_packets; i++) { | ||
3544 | /* Warning: Don't call *_move_data() if no frame active! */ | ||
3545 | if (ov->curframe >= 0) { | ||
3546 | int n = urb->iso_frame_desc[i].actual_length; | ||
3547 | int st = urb->iso_frame_desc[i].status; | ||
3548 | unsigned char *cdata; | ||
3549 | |||
3550 | urb->iso_frame_desc[i].actual_length = 0; | ||
3551 | urb->iso_frame_desc[i].status = 0; | ||
3552 | |||
3553 | cdata = urb->transfer_buffer | ||
3554 | + urb->iso_frame_desc[i].offset; | ||
3555 | |||
3556 | if (!n) { | ||
3557 | PDEBUG(4, "Zero-length packet"); | ||
3558 | continue; | ||
3559 | } | ||
3560 | |||
3561 | if (st) | ||
3562 | PDEBUG(2, "data error: [%d] len=%d, status=%d", | ||
3563 | i, n, st); | ||
3564 | |||
3565 | if (ov->bclass == BCL_OV511) | ||
3566 | ov511_move_data(ov, cdata, n); | ||
3567 | else if (ov->bclass == BCL_OV518) | ||
3568 | ov518_move_data(ov, cdata, n); | ||
3569 | else | ||
3570 | err("Unknown bridge device (%d)", ov->bridge); | ||
3571 | |||
3572 | } else if (waitqueue_active(&ov->wq)) { | ||
3573 | wake_up_interruptible(&ov->wq); | ||
3574 | } | ||
3575 | } | ||
3576 | |||
3577 | /* Resubmit this URB */ | ||
3578 | urb->dev = ov->dev; | ||
3579 | if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0) | ||
3580 | err("usb_submit_urb() ret %d", i); | ||
3581 | |||
3582 | return; | ||
3583 | } | ||
3584 | |||
3585 | /**************************************************************************** | ||
3586 | * | ||
3587 | * Stream initialization and termination | ||
3588 | * | ||
3589 | ***************************************************************************/ | ||
3590 | |||
3591 | static int | ||
3592 | ov51x_init_isoc(struct usb_ov511 *ov) | ||
3593 | { | ||
3594 | struct urb *urb; | ||
3595 | int fx, err, n, size; | ||
3596 | |||
3597 | PDEBUG(3, "*** Initializing capture ***"); | ||
3598 | |||
3599 | ov->curframe = -1; | ||
3600 | |||
3601 | if (ov->bridge == BRG_OV511) { | ||
3602 | if (cams == 1) | ||
3603 | size = 993; | ||
3604 | else if (cams == 2) | ||
3605 | size = 513; | ||
3606 | else if (cams == 3 || cams == 4) | ||
3607 | size = 257; | ||
3608 | else { | ||
3609 | err("\"cams\" parameter too high!"); | ||
3610 | return -1; | ||
3611 | } | ||
3612 | } else if (ov->bridge == BRG_OV511PLUS) { | ||
3613 | if (cams == 1) | ||
3614 | size = 961; | ||
3615 | else if (cams == 2) | ||
3616 | size = 513; | ||
3617 | else if (cams == 3 || cams == 4) | ||
3618 | size = 257; | ||
3619 | else if (cams >= 5 && cams <= 8) | ||
3620 | size = 129; | ||
3621 | else if (cams >= 9 && cams <= 31) | ||
3622 | size = 33; | ||
3623 | else { | ||
3624 | err("\"cams\" parameter too high!"); | ||
3625 | return -1; | ||
3626 | } | ||
3627 | } else if (ov->bclass == BCL_OV518) { | ||
3628 | if (cams == 1) | ||
3629 | size = 896; | ||
3630 | else if (cams == 2) | ||
3631 | size = 512; | ||
3632 | else if (cams == 3 || cams == 4) | ||
3633 | size = 256; | ||
3634 | else if (cams >= 5 && cams <= 8) | ||
3635 | size = 128; | ||
3636 | else { | ||
3637 | err("\"cams\" parameter too high!"); | ||
3638 | return -1; | ||
3639 | } | ||
3640 | } else { | ||
3641 | err("invalid bridge type"); | ||
3642 | return -1; | ||
3643 | } | ||
3644 | |||
3645 | // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now | ||
3646 | if (ov->bclass == BCL_OV518) { | ||
3647 | if (packetsize == -1) { | ||
3648 | ov518_set_packet_size(ov, 640); | ||
3649 | } else { | ||
3650 | info("Forcing packet size to %d", packetsize); | ||
3651 | ov518_set_packet_size(ov, packetsize); | ||
3652 | } | ||
3653 | } else { | ||
3654 | if (packetsize == -1) { | ||
3655 | ov511_set_packet_size(ov, size); | ||
3656 | } else { | ||
3657 | info("Forcing packet size to %d", packetsize); | ||
3658 | ov511_set_packet_size(ov, packetsize); | ||
3659 | } | ||
3660 | } | ||
3661 | |||
3662 | for (n = 0; n < OV511_NUMSBUF; n++) { | ||
3663 | urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); | ||
3664 | if (!urb) { | ||
3665 | err("init isoc: usb_alloc_urb ret. NULL"); | ||
3666 | return -ENOMEM; | ||
3667 | } | ||
3668 | ov->sbuf[n].urb = urb; | ||
3669 | urb->dev = ov->dev; | ||
3670 | urb->context = &ov->sbuf[n]; | ||
3671 | urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS); | ||
3672 | urb->transfer_flags = URB_ISO_ASAP; | ||
3673 | urb->transfer_buffer = ov->sbuf[n].data; | ||
3674 | urb->complete = ov51x_isoc_irq; | ||
3675 | urb->number_of_packets = FRAMES_PER_DESC; | ||
3676 | urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC; | ||
3677 | urb->interval = 1; | ||
3678 | for (fx = 0; fx < FRAMES_PER_DESC; fx++) { | ||
3679 | urb->iso_frame_desc[fx].offset = ov->packet_size * fx; | ||
3680 | urb->iso_frame_desc[fx].length = ov->packet_size; | ||
3681 | } | ||
3682 | } | ||
3683 | |||
3684 | ov->streaming = 1; | ||
3685 | |||
3686 | for (n = 0; n < OV511_NUMSBUF; n++) { | ||
3687 | ov->sbuf[n].urb->dev = ov->dev; | ||
3688 | err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL); | ||
3689 | if (err) { | ||
3690 | err("init isoc: usb_submit_urb(%d) ret %d", n, err); | ||
3691 | return err; | ||
3692 | } | ||
3693 | } | ||
3694 | |||
3695 | return 0; | ||
3696 | } | ||
3697 | |||
3698 | static void | ||
3699 | ov51x_unlink_isoc(struct usb_ov511 *ov) | ||
3700 | { | ||
3701 | int n; | ||
3702 | |||
3703 | /* Unschedule all of the iso td's */ | ||
3704 | for (n = OV511_NUMSBUF - 1; n >= 0; n--) { | ||
3705 | if (ov->sbuf[n].urb) { | ||
3706 | usb_kill_urb(ov->sbuf[n].urb); | ||
3707 | usb_free_urb(ov->sbuf[n].urb); | ||
3708 | ov->sbuf[n].urb = NULL; | ||
3709 | } | ||
3710 | } | ||
3711 | } | ||
3712 | |||
3713 | static void | ||
3714 | ov51x_stop_isoc(struct usb_ov511 *ov) | ||
3715 | { | ||
3716 | if (!ov->streaming || !ov->dev) | ||
3717 | return; | ||
3718 | |||
3719 | PDEBUG(3, "*** Stopping capture ***"); | ||
3720 | |||
3721 | if (ov->bclass == BCL_OV518) | ||
3722 | ov518_set_packet_size(ov, 0); | ||
3723 | else | ||
3724 | ov511_set_packet_size(ov, 0); | ||
3725 | |||
3726 | ov->streaming = 0; | ||
3727 | |||
3728 | ov51x_unlink_isoc(ov); | ||
3729 | } | ||
3730 | |||
3731 | static int | ||
3732 | ov51x_new_frame(struct usb_ov511 *ov, int framenum) | ||
3733 | { | ||
3734 | struct ov511_frame *frame; | ||
3735 | int newnum; | ||
3736 | |||
3737 | PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum); | ||
3738 | |||
3739 | if (!ov->dev) | ||
3740 | return -1; | ||
3741 | |||
3742 | /* If we're not grabbing a frame right now and the other frame is */ | ||
3743 | /* ready to be grabbed into, then use it instead */ | ||
3744 | if (ov->curframe == -1) { | ||
3745 | newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES; | ||
3746 | if (ov->frame[newnum].grabstate == FRAME_READY) | ||
3747 | framenum = newnum; | ||
3748 | } else | ||
3749 | return 0; | ||
3750 | |||
3751 | frame = &ov->frame[framenum]; | ||
3752 | |||
3753 | PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum, | ||
3754 | frame->width, frame->height); | ||
3755 | |||
3756 | frame->grabstate = FRAME_GRABBING; | ||
3757 | frame->scanstate = STATE_SCANNING; | ||
3758 | frame->snapshot = 0; | ||
3759 | |||
3760 | ov->curframe = framenum; | ||
3761 | |||
3762 | /* Make sure it's not too big */ | ||
3763 | if (frame->width > ov->maxwidth) | ||
3764 | frame->width = ov->maxwidth; | ||
3765 | |||
3766 | frame->width &= ~7L; /* Multiple of 8 */ | ||
3767 | |||
3768 | if (frame->height > ov->maxheight) | ||
3769 | frame->height = ov->maxheight; | ||
3770 | |||
3771 | frame->height &= ~3L; /* Multiple of 4 */ | ||
3772 | |||
3773 | return 0; | ||
3774 | } | ||
3775 | |||
3776 | /**************************************************************************** | ||
3777 | * | ||
3778 | * Buffer management | ||
3779 | * | ||
3780 | ***************************************************************************/ | ||
3781 | |||
3782 | /* | ||
3783 | * - You must acquire buf_lock before entering this function. | ||
3784 | * - Because this code will free any non-null pointer, you must be sure to null | ||
3785 | * them if you explicitly free them somewhere else! | ||
3786 | */ | ||
3787 | static void | ||
3788 | ov51x_do_dealloc(struct usb_ov511 *ov) | ||
3789 | { | ||
3790 | int i; | ||
3791 | PDEBUG(4, "entered"); | ||
3792 | |||
3793 | if (ov->fbuf) { | ||
3794 | rvfree(ov->fbuf, OV511_NUMFRAMES | ||
3795 | * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); | ||
3796 | ov->fbuf = NULL; | ||
3797 | } | ||
3798 | |||
3799 | vfree(ov->rawfbuf); | ||
3800 | ov->rawfbuf = NULL; | ||
3801 | |||
3802 | vfree(ov->tempfbuf); | ||
3803 | ov->tempfbuf = NULL; | ||
3804 | |||
3805 | for (i = 0; i < OV511_NUMSBUF; i++) { | ||
3806 | kfree(ov->sbuf[i].data); | ||
3807 | ov->sbuf[i].data = NULL; | ||
3808 | } | ||
3809 | |||
3810 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
3811 | ov->frame[i].data = NULL; | ||
3812 | ov->frame[i].rawdata = NULL; | ||
3813 | ov->frame[i].tempdata = NULL; | ||
3814 | if (ov->frame[i].compbuf) { | ||
3815 | free_page((unsigned long) ov->frame[i].compbuf); | ||
3816 | ov->frame[i].compbuf = NULL; | ||
3817 | } | ||
3818 | } | ||
3819 | |||
3820 | PDEBUG(4, "buffer memory deallocated"); | ||
3821 | ov->buf_state = BUF_NOT_ALLOCATED; | ||
3822 | PDEBUG(4, "leaving"); | ||
3823 | } | ||
3824 | |||
3825 | static int | ||
3826 | ov51x_alloc(struct usb_ov511 *ov) | ||
3827 | { | ||
3828 | int i; | ||
3829 | const int w = ov->maxwidth; | ||
3830 | const int h = ov->maxheight; | ||
3831 | const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h); | ||
3832 | const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h); | ||
3833 | |||
3834 | PDEBUG(4, "entered"); | ||
3835 | mutex_lock(&ov->buf_lock); | ||
3836 | |||
3837 | if (ov->buf_state == BUF_ALLOCATED) | ||
3838 | goto out; | ||
3839 | |||
3840 | ov->fbuf = rvmalloc(data_bufsize); | ||
3841 | if (!ov->fbuf) | ||
3842 | goto error; | ||
3843 | |||
3844 | ov->rawfbuf = vmalloc(raw_bufsize); | ||
3845 | if (!ov->rawfbuf) | ||
3846 | goto error; | ||
3847 | |||
3848 | memset(ov->rawfbuf, 0, raw_bufsize); | ||
3849 | |||
3850 | ov->tempfbuf = vmalloc(raw_bufsize); | ||
3851 | if (!ov->tempfbuf) | ||
3852 | goto error; | ||
3853 | |||
3854 | memset(ov->tempfbuf, 0, raw_bufsize); | ||
3855 | |||
3856 | for (i = 0; i < OV511_NUMSBUF; i++) { | ||
3857 | ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC * | ||
3858 | MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL); | ||
3859 | if (!ov->sbuf[i].data) | ||
3860 | goto error; | ||
3861 | |||
3862 | PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data); | ||
3863 | } | ||
3864 | |||
3865 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
3866 | ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h); | ||
3867 | ov->frame[i].rawdata = ov->rawfbuf | ||
3868 | + i * MAX_RAW_DATA_SIZE(w, h); | ||
3869 | ov->frame[i].tempdata = ov->tempfbuf | ||
3870 | + i * MAX_RAW_DATA_SIZE(w, h); | ||
3871 | |||
3872 | ov->frame[i].compbuf = | ||
3873 | (unsigned char *) __get_free_page(GFP_KERNEL); | ||
3874 | if (!ov->frame[i].compbuf) | ||
3875 | goto error; | ||
3876 | |||
3877 | PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data); | ||
3878 | } | ||
3879 | |||
3880 | ov->buf_state = BUF_ALLOCATED; | ||
3881 | out: | ||
3882 | mutex_unlock(&ov->buf_lock); | ||
3883 | PDEBUG(4, "leaving"); | ||
3884 | return 0; | ||
3885 | error: | ||
3886 | ov51x_do_dealloc(ov); | ||
3887 | mutex_unlock(&ov->buf_lock); | ||
3888 | PDEBUG(4, "errored"); | ||
3889 | return -ENOMEM; | ||
3890 | } | ||
3891 | |||
3892 | static void | ||
3893 | ov51x_dealloc(struct usb_ov511 *ov) | ||
3894 | { | ||
3895 | PDEBUG(4, "entered"); | ||
3896 | mutex_lock(&ov->buf_lock); | ||
3897 | ov51x_do_dealloc(ov); | ||
3898 | mutex_unlock(&ov->buf_lock); | ||
3899 | PDEBUG(4, "leaving"); | ||
3900 | } | ||
3901 | |||
3902 | /**************************************************************************** | ||
3903 | * | ||
3904 | * V4L 1 API | ||
3905 | * | ||
3906 | ***************************************************************************/ | ||
3907 | |||
3908 | static int | ||
3909 | ov51x_v4l1_open(struct inode *inode, struct file *file) | ||
3910 | { | ||
3911 | struct video_device *vdev = video_devdata(file); | ||
3912 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
3913 | int err, i; | ||
3914 | |||
3915 | PDEBUG(4, "opening"); | ||
3916 | |||
3917 | mutex_lock(&ov->lock); | ||
3918 | |||
3919 | err = -EBUSY; | ||
3920 | if (ov->user) | ||
3921 | goto out; | ||
3922 | |||
3923 | ov->sub_flag = 0; | ||
3924 | |||
3925 | /* In case app doesn't set them... */ | ||
3926 | err = ov51x_set_default_params(ov); | ||
3927 | if (err < 0) | ||
3928 | goto out; | ||
3929 | |||
3930 | /* Make sure frames are reset */ | ||
3931 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
3932 | ov->frame[i].grabstate = FRAME_UNUSED; | ||
3933 | ov->frame[i].bytes_read = 0; | ||
3934 | } | ||
3935 | |||
3936 | /* If compression is on, make sure now that a | ||
3937 | * decompressor can be loaded */ | ||
3938 | if (ov->compress && !ov->decomp_ops) { | ||
3939 | err = request_decompressor(ov); | ||
3940 | if (err && !dumppix) | ||
3941 | goto out; | ||
3942 | } | ||
3943 | |||
3944 | err = ov51x_alloc(ov); | ||
3945 | if (err < 0) | ||
3946 | goto out; | ||
3947 | |||
3948 | err = ov51x_init_isoc(ov); | ||
3949 | if (err) { | ||
3950 | ov51x_dealloc(ov); | ||
3951 | goto out; | ||
3952 | } | ||
3953 | |||
3954 | ov->user++; | ||
3955 | file->private_data = vdev; | ||
3956 | |||
3957 | if (ov->led_policy == LED_AUTO) | ||
3958 | ov51x_led_control(ov, 1); | ||
3959 | |||
3960 | out: | ||
3961 | mutex_unlock(&ov->lock); | ||
3962 | return err; | ||
3963 | } | ||
3964 | |||
3965 | static int | ||
3966 | ov51x_v4l1_close(struct inode *inode, struct file *file) | ||
3967 | { | ||
3968 | struct video_device *vdev = file->private_data; | ||
3969 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
3970 | |||
3971 | PDEBUG(4, "ov511_close"); | ||
3972 | |||
3973 | mutex_lock(&ov->lock); | ||
3974 | |||
3975 | ov->user--; | ||
3976 | ov51x_stop_isoc(ov); | ||
3977 | |||
3978 | if (ov->led_policy == LED_AUTO) | ||
3979 | ov51x_led_control(ov, 0); | ||
3980 | |||
3981 | if (ov->dev) | ||
3982 | ov51x_dealloc(ov); | ||
3983 | |||
3984 | mutex_unlock(&ov->lock); | ||
3985 | |||
3986 | /* Device unplugged while open. Only a minimum of unregistration is done | ||
3987 | * here; the disconnect callback already did the rest. */ | ||
3988 | if (!ov->dev) { | ||
3989 | mutex_lock(&ov->cbuf_lock); | ||
3990 | kfree(ov->cbuf); | ||
3991 | ov->cbuf = NULL; | ||
3992 | mutex_unlock(&ov->cbuf_lock); | ||
3993 | |||
3994 | ov51x_dealloc(ov); | ||
3995 | kfree(ov); | ||
3996 | ov = NULL; | ||
3997 | } | ||
3998 | |||
3999 | file->private_data = NULL; | ||
4000 | return 0; | ||
4001 | } | ||
4002 | |||
4003 | /* Do not call this function directly! */ | ||
4004 | static int | ||
4005 | ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, | ||
4006 | unsigned int cmd, void *arg) | ||
4007 | { | ||
4008 | struct video_device *vdev = file->private_data; | ||
4009 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
4010 | PDEBUG(5, "IOCtl: 0x%X", cmd); | ||
4011 | |||
4012 | if (!ov->dev) | ||
4013 | return -EIO; | ||
4014 | |||
4015 | switch (cmd) { | ||
4016 | case VIDIOCGCAP: | ||
4017 | { | ||
4018 | struct video_capability *b = arg; | ||
4019 | |||
4020 | PDEBUG(4, "VIDIOCGCAP"); | ||
4021 | |||
4022 | memset(b, 0, sizeof(struct video_capability)); | ||
4023 | sprintf(b->name, "%s USB Camera", | ||
4024 | symbolic(brglist, ov->bridge)); | ||
4025 | b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; | ||
4026 | b->channels = ov->num_inputs; | ||
4027 | b->audios = 0; | ||
4028 | b->maxwidth = ov->maxwidth; | ||
4029 | b->maxheight = ov->maxheight; | ||
4030 | b->minwidth = ov->minwidth; | ||
4031 | b->minheight = ov->minheight; | ||
4032 | |||
4033 | return 0; | ||
4034 | } | ||
4035 | case VIDIOCGCHAN: | ||
4036 | { | ||
4037 | struct video_channel *v = arg; | ||
4038 | |||
4039 | PDEBUG(4, "VIDIOCGCHAN"); | ||
4040 | |||
4041 | if ((unsigned)(v->channel) >= ov->num_inputs) { | ||
4042 | err("Invalid channel (%d)", v->channel); | ||
4043 | return -EINVAL; | ||
4044 | } | ||
4045 | |||
4046 | v->norm = ov->norm; | ||
4047 | v->type = VIDEO_TYPE_CAMERA; | ||
4048 | v->flags = 0; | ||
4049 | // v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0; | ||
4050 | v->tuners = 0; | ||
4051 | decoder_get_input_name(ov, v->channel, v->name); | ||
4052 | |||
4053 | return 0; | ||
4054 | } | ||
4055 | case VIDIOCSCHAN: | ||
4056 | { | ||
4057 | struct video_channel *v = arg; | ||
4058 | int err; | ||
4059 | |||
4060 | PDEBUG(4, "VIDIOCSCHAN"); | ||
4061 | |||
4062 | /* Make sure it's not a camera */ | ||
4063 | if (!ov->has_decoder) { | ||
4064 | if (v->channel == 0) | ||
4065 | return 0; | ||
4066 | else | ||
4067 | return -EINVAL; | ||
4068 | } | ||
4069 | |||
4070 | if (v->norm != VIDEO_MODE_PAL && | ||
4071 | v->norm != VIDEO_MODE_NTSC && | ||
4072 | v->norm != VIDEO_MODE_SECAM && | ||
4073 | v->norm != VIDEO_MODE_AUTO) { | ||
4074 | err("Invalid norm (%d)", v->norm); | ||
4075 | return -EINVAL; | ||
4076 | } | ||
4077 | |||
4078 | if ((unsigned)(v->channel) >= ov->num_inputs) { | ||
4079 | err("Invalid channel (%d)", v->channel); | ||
4080 | return -EINVAL; | ||
4081 | } | ||
4082 | |||
4083 | err = decoder_set_input(ov, v->channel); | ||
4084 | if (err) | ||
4085 | return err; | ||
4086 | |||
4087 | err = decoder_set_norm(ov, v->norm); | ||
4088 | if (err) | ||
4089 | return err; | ||
4090 | |||
4091 | return 0; | ||
4092 | } | ||
4093 | case VIDIOCGPICT: | ||
4094 | { | ||
4095 | struct video_picture *p = arg; | ||
4096 | |||
4097 | PDEBUG(4, "VIDIOCGPICT"); | ||
4098 | |||
4099 | memset(p, 0, sizeof(struct video_picture)); | ||
4100 | if (sensor_get_picture(ov, p)) | ||
4101 | return -EIO; | ||
4102 | |||
4103 | /* Can we get these from frame[0]? -claudio? */ | ||
4104 | p->depth = ov->frame[0].depth; | ||
4105 | p->palette = ov->frame[0].format; | ||
4106 | |||
4107 | return 0; | ||
4108 | } | ||
4109 | case VIDIOCSPICT: | ||
4110 | { | ||
4111 | struct video_picture *p = arg; | ||
4112 | int i, rc; | ||
4113 | |||
4114 | PDEBUG(4, "VIDIOCSPICT"); | ||
4115 | |||
4116 | if (!get_depth(p->palette)) | ||
4117 | return -EINVAL; | ||
4118 | |||
4119 | if (sensor_set_picture(ov, p)) | ||
4120 | return -EIO; | ||
4121 | |||
4122 | if (force_palette && p->palette != force_palette) { | ||
4123 | info("Palette rejected (%s)", | ||
4124 | symbolic(v4l1_plist, p->palette)); | ||
4125 | return -EINVAL; | ||
4126 | } | ||
4127 | |||
4128 | // FIXME: Format should be independent of frames | ||
4129 | if (p->palette != ov->frame[0].format) { | ||
4130 | PDEBUG(4, "Detected format change"); | ||
4131 | |||
4132 | rc = ov51x_wait_frames_inactive(ov); | ||
4133 | if (rc) | ||
4134 | return rc; | ||
4135 | |||
4136 | mode_init_regs(ov, ov->frame[0].width, | ||
4137 | ov->frame[0].height, p->palette, ov->sub_flag); | ||
4138 | } | ||
4139 | |||
4140 | PDEBUG(4, "Setting depth=%d, palette=%s", | ||
4141 | p->depth, symbolic(v4l1_plist, p->palette)); | ||
4142 | |||
4143 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
4144 | ov->frame[i].depth = p->depth; | ||
4145 | ov->frame[i].format = p->palette; | ||
4146 | } | ||
4147 | |||
4148 | return 0; | ||
4149 | } | ||
4150 | case VIDIOCGCAPTURE: | ||
4151 | { | ||
4152 | int *vf = arg; | ||
4153 | |||
4154 | PDEBUG(4, "VIDIOCGCAPTURE"); | ||
4155 | |||
4156 | ov->sub_flag = *vf; | ||
4157 | return 0; | ||
4158 | } | ||
4159 | case VIDIOCSCAPTURE: | ||
4160 | { | ||
4161 | struct video_capture *vc = arg; | ||
4162 | |||
4163 | PDEBUG(4, "VIDIOCSCAPTURE"); | ||
4164 | |||
4165 | if (vc->flags) | ||
4166 | return -EINVAL; | ||
4167 | if (vc->decimation) | ||
4168 | return -EINVAL; | ||
4169 | |||
4170 | vc->x &= ~3L; | ||
4171 | vc->y &= ~1L; | ||
4172 | vc->y &= ~31L; | ||
4173 | |||
4174 | if (vc->width == 0) | ||
4175 | vc->width = 32; | ||
4176 | |||
4177 | vc->height /= 16; | ||
4178 | vc->height *= 16; | ||
4179 | if (vc->height == 0) | ||
4180 | vc->height = 16; | ||
4181 | |||
4182 | ov->subx = vc->x; | ||
4183 | ov->suby = vc->y; | ||
4184 | ov->subw = vc->width; | ||
4185 | ov->subh = vc->height; | ||
4186 | |||
4187 | return 0; | ||
4188 | } | ||
4189 | case VIDIOCSWIN: | ||
4190 | { | ||
4191 | struct video_window *vw = arg; | ||
4192 | int i, rc; | ||
4193 | |||
4194 | PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height); | ||
4195 | |||
4196 | #if 0 | ||
4197 | if (vw->flags) | ||
4198 | return -EINVAL; | ||
4199 | if (vw->clipcount) | ||
4200 | return -EINVAL; | ||
4201 | if (vw->height != ov->maxheight) | ||
4202 | return -EINVAL; | ||
4203 | if (vw->width != ov->maxwidth) | ||
4204 | return -EINVAL; | ||
4205 | #endif | ||
4206 | |||
4207 | rc = ov51x_wait_frames_inactive(ov); | ||
4208 | if (rc) | ||
4209 | return rc; | ||
4210 | |||
4211 | rc = mode_init_regs(ov, vw->width, vw->height, | ||
4212 | ov->frame[0].format, ov->sub_flag); | ||
4213 | if (rc < 0) | ||
4214 | return rc; | ||
4215 | |||
4216 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
4217 | ov->frame[i].width = vw->width; | ||
4218 | ov->frame[i].height = vw->height; | ||
4219 | } | ||
4220 | |||
4221 | return 0; | ||
4222 | } | ||
4223 | case VIDIOCGWIN: | ||
4224 | { | ||
4225 | struct video_window *vw = arg; | ||
4226 | |||
4227 | memset(vw, 0, sizeof(struct video_window)); | ||
4228 | vw->x = 0; /* FIXME */ | ||
4229 | vw->y = 0; | ||
4230 | vw->width = ov->frame[0].width; | ||
4231 | vw->height = ov->frame[0].height; | ||
4232 | vw->flags = 30; | ||
4233 | |||
4234 | PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height); | ||
4235 | |||
4236 | return 0; | ||
4237 | } | ||
4238 | case VIDIOCGMBUF: | ||
4239 | { | ||
4240 | struct video_mbuf *vm = arg; | ||
4241 | int i; | ||
4242 | |||
4243 | PDEBUG(4, "VIDIOCGMBUF"); | ||
4244 | |||
4245 | memset(vm, 0, sizeof(struct video_mbuf)); | ||
4246 | vm->size = OV511_NUMFRAMES | ||
4247 | * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); | ||
4248 | vm->frames = OV511_NUMFRAMES; | ||
4249 | |||
4250 | vm->offsets[0] = 0; | ||
4251 | for (i = 1; i < OV511_NUMFRAMES; i++) { | ||
4252 | vm->offsets[i] = vm->offsets[i-1] | ||
4253 | + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); | ||
4254 | } | ||
4255 | |||
4256 | return 0; | ||
4257 | } | ||
4258 | case VIDIOCMCAPTURE: | ||
4259 | { | ||
4260 | struct video_mmap *vm = arg; | ||
4261 | int rc, depth; | ||
4262 | unsigned int f = vm->frame; | ||
4263 | |||
4264 | PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width, | ||
4265 | vm->height, symbolic(v4l1_plist, vm->format)); | ||
4266 | |||
4267 | depth = get_depth(vm->format); | ||
4268 | if (!depth) { | ||
4269 | PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)", | ||
4270 | symbolic(v4l1_plist, vm->format)); | ||
4271 | return -EINVAL; | ||
4272 | } | ||
4273 | |||
4274 | if (f >= OV511_NUMFRAMES) { | ||
4275 | err("VIDIOCMCAPTURE: invalid frame (%d)", f); | ||
4276 | return -EINVAL; | ||
4277 | } | ||
4278 | |||
4279 | if (vm->width > ov->maxwidth | ||
4280 | || vm->height > ov->maxheight) { | ||
4281 | err("VIDIOCMCAPTURE: requested dimensions too big"); | ||
4282 | return -EINVAL; | ||
4283 | } | ||
4284 | |||
4285 | if (ov->frame[f].grabstate == FRAME_GRABBING) { | ||
4286 | PDEBUG(4, "VIDIOCMCAPTURE: already grabbing"); | ||
4287 | return -EBUSY; | ||
4288 | } | ||
4289 | |||
4290 | if (force_palette && (vm->format != force_palette)) { | ||
4291 | PDEBUG(2, "palette rejected (%s)", | ||
4292 | symbolic(v4l1_plist, vm->format)); | ||
4293 | return -EINVAL; | ||
4294 | } | ||
4295 | |||
4296 | if ((ov->frame[f].width != vm->width) || | ||
4297 | (ov->frame[f].height != vm->height) || | ||
4298 | (ov->frame[f].format != vm->format) || | ||
4299 | (ov->frame[f].sub_flag != ov->sub_flag) || | ||
4300 | (ov->frame[f].depth != depth)) { | ||
4301 | PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters"); | ||
4302 | |||
4303 | rc = ov51x_wait_frames_inactive(ov); | ||
4304 | if (rc) | ||
4305 | return rc; | ||
4306 | |||
4307 | rc = mode_init_regs(ov, vm->width, vm->height, | ||
4308 | vm->format, ov->sub_flag); | ||
4309 | #if 0 | ||
4310 | if (rc < 0) { | ||
4311 | PDEBUG(1, "Got error while initializing regs "); | ||
4312 | return ret; | ||
4313 | } | ||
4314 | #endif | ||
4315 | ov->frame[f].width = vm->width; | ||
4316 | ov->frame[f].height = vm->height; | ||
4317 | ov->frame[f].format = vm->format; | ||
4318 | ov->frame[f].sub_flag = ov->sub_flag; | ||
4319 | ov->frame[f].depth = depth; | ||
4320 | } | ||
4321 | |||
4322 | /* Mark it as ready */ | ||
4323 | ov->frame[f].grabstate = FRAME_READY; | ||
4324 | |||
4325 | PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f); | ||
4326 | |||
4327 | return ov51x_new_frame(ov, f); | ||
4328 | } | ||
4329 | case VIDIOCSYNC: | ||
4330 | { | ||
4331 | unsigned int fnum = *((unsigned int *) arg); | ||
4332 | struct ov511_frame *frame; | ||
4333 | int rc; | ||
4334 | |||
4335 | if (fnum >= OV511_NUMFRAMES) { | ||
4336 | err("VIDIOCSYNC: invalid frame (%d)", fnum); | ||
4337 | return -EINVAL; | ||
4338 | } | ||
4339 | |||
4340 | frame = &ov->frame[fnum]; | ||
4341 | |||
4342 | PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum, | ||
4343 | frame->grabstate); | ||
4344 | |||
4345 | switch (frame->grabstate) { | ||
4346 | case FRAME_UNUSED: | ||
4347 | return -EINVAL; | ||
4348 | case FRAME_READY: | ||
4349 | case FRAME_GRABBING: | ||
4350 | case FRAME_ERROR: | ||
4351 | redo: | ||
4352 | if (!ov->dev) | ||
4353 | return -EIO; | ||
4354 | |||
4355 | rc = wait_event_interruptible(frame->wq, | ||
4356 | (frame->grabstate == FRAME_DONE) | ||
4357 | || (frame->grabstate == FRAME_ERROR)); | ||
4358 | |||
4359 | if (rc) | ||
4360 | return rc; | ||
4361 | |||
4362 | if (frame->grabstate == FRAME_ERROR) { | ||
4363 | if ((rc = ov51x_new_frame(ov, fnum)) < 0) | ||
4364 | return rc; | ||
4365 | goto redo; | ||
4366 | } | ||
4367 | /* Fall through */ | ||
4368 | case FRAME_DONE: | ||
4369 | if (ov->snap_enabled && !frame->snapshot) { | ||
4370 | if ((rc = ov51x_new_frame(ov, fnum)) < 0) | ||
4371 | return rc; | ||
4372 | goto redo; | ||
4373 | } | ||
4374 | |||
4375 | frame->grabstate = FRAME_UNUSED; | ||
4376 | |||
4377 | /* Reset the hardware snapshot button */ | ||
4378 | /* FIXME - Is this the best place for this? */ | ||
4379 | if ((ov->snap_enabled) && (frame->snapshot)) { | ||
4380 | frame->snapshot = 0; | ||
4381 | ov51x_clear_snapshot(ov); | ||
4382 | } | ||
4383 | |||
4384 | /* Decompression, format conversion, etc... */ | ||
4385 | ov51x_postprocess(ov, frame); | ||
4386 | |||
4387 | break; | ||
4388 | } /* end switch */ | ||
4389 | |||
4390 | return 0; | ||
4391 | } | ||
4392 | case VIDIOCGFBUF: | ||
4393 | { | ||
4394 | struct video_buffer *vb = arg; | ||
4395 | |||
4396 | PDEBUG(4, "VIDIOCGFBUF"); | ||
4397 | |||
4398 | memset(vb, 0, sizeof(struct video_buffer)); | ||
4399 | |||
4400 | return 0; | ||
4401 | } | ||
4402 | case VIDIOCGUNIT: | ||
4403 | { | ||
4404 | struct video_unit *vu = arg; | ||
4405 | |||
4406 | PDEBUG(4, "VIDIOCGUNIT"); | ||
4407 | |||
4408 | memset(vu, 0, sizeof(struct video_unit)); | ||
4409 | |||
4410 | vu->video = ov->vdev->minor; | ||
4411 | vu->vbi = VIDEO_NO_UNIT; | ||
4412 | vu->radio = VIDEO_NO_UNIT; | ||
4413 | vu->audio = VIDEO_NO_UNIT; | ||
4414 | vu->teletext = VIDEO_NO_UNIT; | ||
4415 | |||
4416 | return 0; | ||
4417 | } | ||
4418 | case OV511IOC_WI2C: | ||
4419 | { | ||
4420 | struct ov511_i2c_struct *w = arg; | ||
4421 | |||
4422 | return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask); | ||
4423 | } | ||
4424 | case OV511IOC_RI2C: | ||
4425 | { | ||
4426 | struct ov511_i2c_struct *r = arg; | ||
4427 | int rc; | ||
4428 | |||
4429 | rc = i2c_r_slave(ov, r->slave, r->reg); | ||
4430 | if (rc < 0) | ||
4431 | return rc; | ||
4432 | |||
4433 | r->value = rc; | ||
4434 | return 0; | ||
4435 | } | ||
4436 | default: | ||
4437 | PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd); | ||
4438 | return -ENOIOCTLCMD; | ||
4439 | } /* end switch */ | ||
4440 | |||
4441 | return 0; | ||
4442 | } | ||
4443 | |||
4444 | static int | ||
4445 | ov51x_v4l1_ioctl(struct inode *inode, struct file *file, | ||
4446 | unsigned int cmd, unsigned long arg) | ||
4447 | { | ||
4448 | struct video_device *vdev = file->private_data; | ||
4449 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
4450 | int rc; | ||
4451 | |||
4452 | if (mutex_lock_interruptible(&ov->lock)) | ||
4453 | return -EINTR; | ||
4454 | |||
4455 | rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal); | ||
4456 | |||
4457 | mutex_unlock(&ov->lock); | ||
4458 | return rc; | ||
4459 | } | ||
4460 | |||
4461 | static ssize_t | ||
4462 | ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos) | ||
4463 | { | ||
4464 | struct video_device *vdev = file->private_data; | ||
4465 | int noblock = file->f_flags&O_NONBLOCK; | ||
4466 | unsigned long count = cnt; | ||
4467 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
4468 | int i, rc = 0, frmx = -1; | ||
4469 | struct ov511_frame *frame; | ||
4470 | |||
4471 | if (mutex_lock_interruptible(&ov->lock)) | ||
4472 | return -EINTR; | ||
4473 | |||
4474 | PDEBUG(4, "%ld bytes, noblock=%d", count, noblock); | ||
4475 | |||
4476 | if (!vdev || !buf) { | ||
4477 | rc = -EFAULT; | ||
4478 | goto error; | ||
4479 | } | ||
4480 | |||
4481 | if (!ov->dev) { | ||
4482 | rc = -EIO; | ||
4483 | goto error; | ||
4484 | } | ||
4485 | |||
4486 | // FIXME: Only supports two frames | ||
4487 | /* See if a frame is completed, then use it. */ | ||
4488 | if (ov->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ | ||
4489 | frmx = 0; | ||
4490 | else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ | ||
4491 | frmx = 1; | ||
4492 | |||
4493 | /* If nonblocking we return immediately */ | ||
4494 | if (noblock && (frmx == -1)) { | ||
4495 | rc = -EAGAIN; | ||
4496 | goto error; | ||
4497 | } | ||
4498 | |||
4499 | /* If no FRAME_DONE, look for a FRAME_GRABBING state. */ | ||
4500 | /* See if a frame is in process (grabbing), then use it. */ | ||
4501 | if (frmx == -1) { | ||
4502 | if (ov->frame[0].grabstate == FRAME_GRABBING) | ||
4503 | frmx = 0; | ||
4504 | else if (ov->frame[1].grabstate == FRAME_GRABBING) | ||
4505 | frmx = 1; | ||
4506 | } | ||
4507 | |||
4508 | /* If no frame is active, start one. */ | ||
4509 | if (frmx == -1) { | ||
4510 | if ((rc = ov51x_new_frame(ov, frmx = 0))) { | ||
4511 | err("read: ov51x_new_frame error"); | ||
4512 | goto error; | ||
4513 | } | ||
4514 | } | ||
4515 | |||
4516 | frame = &ov->frame[frmx]; | ||
4517 | |||
4518 | restart: | ||
4519 | if (!ov->dev) { | ||
4520 | rc = -EIO; | ||
4521 | goto error; | ||
4522 | } | ||
4523 | |||
4524 | /* Wait while we're grabbing the image */ | ||
4525 | PDEBUG(4, "Waiting image grabbing"); | ||
4526 | rc = wait_event_interruptible(frame->wq, | ||
4527 | (frame->grabstate == FRAME_DONE) | ||
4528 | || (frame->grabstate == FRAME_ERROR)); | ||
4529 | |||
4530 | if (rc) | ||
4531 | goto error; | ||
4532 | |||
4533 | PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate); | ||
4534 | PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd); | ||
4535 | |||
4536 | if (frame->grabstate == FRAME_ERROR) { | ||
4537 | frame->bytes_read = 0; | ||
4538 | err("** ick! ** Errored frame %d", ov->curframe); | ||
4539 | if (ov51x_new_frame(ov, frmx)) { | ||
4540 | err("read: ov51x_new_frame error"); | ||
4541 | goto error; | ||
4542 | } | ||
4543 | goto restart; | ||
4544 | } | ||
4545 | |||
4546 | |||
4547 | /* Repeat until we get a snapshot frame */ | ||
4548 | if (ov->snap_enabled) | ||
4549 | PDEBUG(4, "Waiting snapshot frame"); | ||
4550 | if (ov->snap_enabled && !frame->snapshot) { | ||
4551 | frame->bytes_read = 0; | ||
4552 | if ((rc = ov51x_new_frame(ov, frmx))) { | ||
4553 | err("read: ov51x_new_frame error"); | ||
4554 | goto error; | ||
4555 | } | ||
4556 | goto restart; | ||
4557 | } | ||
4558 | |||
4559 | /* Clear the snapshot */ | ||
4560 | if (ov->snap_enabled && frame->snapshot) { | ||
4561 | frame->snapshot = 0; | ||
4562 | ov51x_clear_snapshot(ov); | ||
4563 | } | ||
4564 | |||
4565 | /* Decompression, format conversion, etc... */ | ||
4566 | ov51x_postprocess(ov, frame); | ||
4567 | |||
4568 | PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx, | ||
4569 | frame->bytes_read, | ||
4570 | get_frame_length(frame)); | ||
4571 | |||
4572 | /* copy bytes to user space; we allow for partials reads */ | ||
4573 | // if ((count + frame->bytes_read) | ||
4574 | // > get_frame_length((struct ov511_frame *)frame)) | ||
4575 | // count = frame->scanlength - frame->bytes_read; | ||
4576 | |||
4577 | /* FIXME - count hardwired to be one frame... */ | ||
4578 | count = get_frame_length(frame); | ||
4579 | |||
4580 | PDEBUG(4, "Copy to user space: %ld bytes", count); | ||
4581 | if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) { | ||
4582 | PDEBUG(4, "Copy failed! %d bytes not copied", i); | ||
4583 | rc = -EFAULT; | ||
4584 | goto error; | ||
4585 | } | ||
4586 | |||
4587 | frame->bytes_read += count; | ||
4588 | PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld", | ||
4589 | count, frame->bytes_read); | ||
4590 | |||
4591 | /* If all data have been read... */ | ||
4592 | if (frame->bytes_read | ||
4593 | >= get_frame_length(frame)) { | ||
4594 | frame->bytes_read = 0; | ||
4595 | |||
4596 | // FIXME: Only supports two frames | ||
4597 | /* Mark it as available to be used again. */ | ||
4598 | ov->frame[frmx].grabstate = FRAME_UNUSED; | ||
4599 | if ((rc = ov51x_new_frame(ov, !frmx))) { | ||
4600 | err("ov51x_new_frame returned error"); | ||
4601 | goto error; | ||
4602 | } | ||
4603 | } | ||
4604 | |||
4605 | PDEBUG(4, "read finished, returning %ld (sweet)", count); | ||
4606 | |||
4607 | mutex_unlock(&ov->lock); | ||
4608 | return count; | ||
4609 | |||
4610 | error: | ||
4611 | mutex_unlock(&ov->lock); | ||
4612 | return rc; | ||
4613 | } | ||
4614 | |||
4615 | static int | ||
4616 | ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma) | ||
4617 | { | ||
4618 | struct video_device *vdev = file->private_data; | ||
4619 | unsigned long start = vma->vm_start; | ||
4620 | unsigned long size = vma->vm_end - vma->vm_start; | ||
4621 | struct usb_ov511 *ov = video_get_drvdata(vdev); | ||
4622 | unsigned long page, pos; | ||
4623 | |||
4624 | if (ov->dev == NULL) | ||
4625 | return -EIO; | ||
4626 | |||
4627 | PDEBUG(4, "mmap: %ld (%lX) bytes", size, size); | ||
4628 | |||
4629 | if (size > (((OV511_NUMFRAMES | ||
4630 | * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight) | ||
4631 | + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))) | ||
4632 | return -EINVAL; | ||
4633 | |||
4634 | if (mutex_lock_interruptible(&ov->lock)) | ||
4635 | return -EINTR; | ||
4636 | |||
4637 | pos = (unsigned long)ov->fbuf; | ||
4638 | while (size > 0) { | ||
4639 | page = vmalloc_to_pfn((void *)pos); | ||
4640 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { | ||
4641 | mutex_unlock(&ov->lock); | ||
4642 | return -EAGAIN; | ||
4643 | } | ||
4644 | start += PAGE_SIZE; | ||
4645 | pos += PAGE_SIZE; | ||
4646 | if (size > PAGE_SIZE) | ||
4647 | size -= PAGE_SIZE; | ||
4648 | else | ||
4649 | size = 0; | ||
4650 | } | ||
4651 | |||
4652 | mutex_unlock(&ov->lock); | ||
4653 | return 0; | ||
4654 | } | ||
4655 | |||
4656 | static struct file_operations ov511_fops = { | ||
4657 | .owner = THIS_MODULE, | ||
4658 | .open = ov51x_v4l1_open, | ||
4659 | .release = ov51x_v4l1_close, | ||
4660 | .read = ov51x_v4l1_read, | ||
4661 | .mmap = ov51x_v4l1_mmap, | ||
4662 | .ioctl = ov51x_v4l1_ioctl, | ||
4663 | .compat_ioctl = v4l_compat_ioctl32, | ||
4664 | .llseek = no_llseek, | ||
4665 | }; | ||
4666 | |||
4667 | static struct video_device vdev_template = { | ||
4668 | .owner = THIS_MODULE, | ||
4669 | .name = "OV511 USB Camera", | ||
4670 | .type = VID_TYPE_CAPTURE, | ||
4671 | .hardware = VID_HARDWARE_OV511, | ||
4672 | .fops = &ov511_fops, | ||
4673 | .release = video_device_release, | ||
4674 | .minor = -1, | ||
4675 | }; | ||
4676 | |||
4677 | /**************************************************************************** | ||
4678 | * | ||
4679 | * OV511 and sensor configuration | ||
4680 | * | ||
4681 | ***************************************************************************/ | ||
4682 | |||
4683 | /* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses | ||
4684 | * the same register settings as the OV7610, since they are very similar. | ||
4685 | */ | ||
4686 | static int | ||
4687 | ov7xx0_configure(struct usb_ov511 *ov) | ||
4688 | { | ||
4689 | int i, success; | ||
4690 | int rc; | ||
4691 | |||
4692 | /* Lawrence Glaister <lg@jfm.bc.ca> reports: | ||
4693 | * | ||
4694 | * Register 0x0f in the 7610 has the following effects: | ||
4695 | * | ||
4696 | * 0x85 (AEC method 1): Best overall, good contrast range | ||
4697 | * 0x45 (AEC method 2): Very overexposed | ||
4698 | * 0xa5 (spec sheet default): Ok, but the black level is | ||
4699 | * shifted resulting in loss of contrast | ||
4700 | * 0x05 (old driver setting): very overexposed, too much | ||
4701 | * contrast | ||
4702 | */ | ||
4703 | static struct ov511_regvals aRegvalsNorm7610[] = { | ||
4704 | { OV511_I2C_BUS, 0x10, 0xff }, | ||
4705 | { OV511_I2C_BUS, 0x16, 0x06 }, | ||
4706 | { OV511_I2C_BUS, 0x28, 0x24 }, | ||
4707 | { OV511_I2C_BUS, 0x2b, 0xac }, | ||
4708 | { OV511_I2C_BUS, 0x12, 0x00 }, | ||
4709 | { OV511_I2C_BUS, 0x38, 0x81 }, | ||
4710 | { OV511_I2C_BUS, 0x28, 0x24 }, /* 0c */ | ||
4711 | { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */ | ||
4712 | { OV511_I2C_BUS, 0x15, 0x01 }, | ||
4713 | { OV511_I2C_BUS, 0x20, 0x1c }, | ||
4714 | { OV511_I2C_BUS, 0x23, 0x2a }, | ||
4715 | { OV511_I2C_BUS, 0x24, 0x10 }, | ||
4716 | { OV511_I2C_BUS, 0x25, 0x8a }, | ||
4717 | { OV511_I2C_BUS, 0x26, 0xa2 }, | ||
4718 | { OV511_I2C_BUS, 0x27, 0xc2 }, | ||
4719 | { OV511_I2C_BUS, 0x2a, 0x04 }, | ||
4720 | { OV511_I2C_BUS, 0x2c, 0xfe }, | ||
4721 | { OV511_I2C_BUS, 0x2d, 0x93 }, | ||
4722 | { OV511_I2C_BUS, 0x30, 0x71 }, | ||
4723 | { OV511_I2C_BUS, 0x31, 0x60 }, | ||
4724 | { OV511_I2C_BUS, 0x32, 0x26 }, | ||
4725 | { OV511_I2C_BUS, 0x33, 0x20 }, | ||
4726 | { OV511_I2C_BUS, 0x34, 0x48 }, | ||
4727 | { OV511_I2C_BUS, 0x12, 0x24 }, | ||
4728 | { OV511_I2C_BUS, 0x11, 0x01 }, | ||
4729 | { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
4730 | { OV511_I2C_BUS, 0x0d, 0x24 }, | ||
4731 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
4732 | }; | ||
4733 | |||
4734 | static struct ov511_regvals aRegvalsNorm7620[] = { | ||
4735 | { OV511_I2C_BUS, 0x00, 0x00 }, | ||
4736 | { OV511_I2C_BUS, 0x01, 0x80 }, | ||
4737 | { OV511_I2C_BUS, 0x02, 0x80 }, | ||
4738 | { OV511_I2C_BUS, 0x03, 0xc0 }, | ||
4739 | { OV511_I2C_BUS, 0x06, 0x60 }, | ||
4740 | { OV511_I2C_BUS, 0x07, 0x00 }, | ||
4741 | { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
4742 | { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
4743 | { OV511_I2C_BUS, 0x0d, 0x24 }, | ||
4744 | { OV511_I2C_BUS, 0x11, 0x01 }, | ||
4745 | { OV511_I2C_BUS, 0x12, 0x24 }, | ||
4746 | { OV511_I2C_BUS, 0x13, 0x01 }, | ||
4747 | { OV511_I2C_BUS, 0x14, 0x84 }, | ||
4748 | { OV511_I2C_BUS, 0x15, 0x01 }, | ||
4749 | { OV511_I2C_BUS, 0x16, 0x03 }, | ||
4750 | { OV511_I2C_BUS, 0x17, 0x2f }, | ||
4751 | { OV511_I2C_BUS, 0x18, 0xcf }, | ||
4752 | { OV511_I2C_BUS, 0x19, 0x06 }, | ||
4753 | { OV511_I2C_BUS, 0x1a, 0xf5 }, | ||
4754 | { OV511_I2C_BUS, 0x1b, 0x00 }, | ||
4755 | { OV511_I2C_BUS, 0x20, 0x18 }, | ||
4756 | { OV511_I2C_BUS, 0x21, 0x80 }, | ||
4757 | { OV511_I2C_BUS, 0x22, 0x80 }, | ||
4758 | { OV511_I2C_BUS, 0x23, 0x00 }, | ||
4759 | { OV511_I2C_BUS, 0x26, 0xa2 }, | ||
4760 | { OV511_I2C_BUS, 0x27, 0xea }, | ||
4761 | { OV511_I2C_BUS, 0x28, 0x20 }, | ||
4762 | { OV511_I2C_BUS, 0x29, 0x00 }, | ||
4763 | { OV511_I2C_BUS, 0x2a, 0x10 }, | ||
4764 | { OV511_I2C_BUS, 0x2b, 0x00 }, | ||
4765 | { OV511_I2C_BUS, 0x2c, 0x88 }, | ||
4766 | { OV511_I2C_BUS, 0x2d, 0x91 }, | ||
4767 | { OV511_I2C_BUS, 0x2e, 0x80 }, | ||
4768 | { OV511_I2C_BUS, 0x2f, 0x44 }, | ||
4769 | { OV511_I2C_BUS, 0x60, 0x27 }, | ||
4770 | { OV511_I2C_BUS, 0x61, 0x02 }, | ||
4771 | { OV511_I2C_BUS, 0x62, 0x5f }, | ||
4772 | { OV511_I2C_BUS, 0x63, 0xd5 }, | ||
4773 | { OV511_I2C_BUS, 0x64, 0x57 }, | ||
4774 | { OV511_I2C_BUS, 0x65, 0x83 }, | ||
4775 | { OV511_I2C_BUS, 0x66, 0x55 }, | ||
4776 | { OV511_I2C_BUS, 0x67, 0x92 }, | ||
4777 | { OV511_I2C_BUS, 0x68, 0xcf }, | ||
4778 | { OV511_I2C_BUS, 0x69, 0x76 }, | ||
4779 | { OV511_I2C_BUS, 0x6a, 0x22 }, | ||
4780 | { OV511_I2C_BUS, 0x6b, 0x00 }, | ||
4781 | { OV511_I2C_BUS, 0x6c, 0x02 }, | ||
4782 | { OV511_I2C_BUS, 0x6d, 0x44 }, | ||
4783 | { OV511_I2C_BUS, 0x6e, 0x80 }, | ||
4784 | { OV511_I2C_BUS, 0x6f, 0x1d }, | ||
4785 | { OV511_I2C_BUS, 0x70, 0x8b }, | ||
4786 | { OV511_I2C_BUS, 0x71, 0x00 }, | ||
4787 | { OV511_I2C_BUS, 0x72, 0x14 }, | ||
4788 | { OV511_I2C_BUS, 0x73, 0x54 }, | ||
4789 | { OV511_I2C_BUS, 0x74, 0x00 }, | ||
4790 | { OV511_I2C_BUS, 0x75, 0x8e }, | ||
4791 | { OV511_I2C_BUS, 0x76, 0x00 }, | ||
4792 | { OV511_I2C_BUS, 0x77, 0xff }, | ||
4793 | { OV511_I2C_BUS, 0x78, 0x80 }, | ||
4794 | { OV511_I2C_BUS, 0x79, 0x80 }, | ||
4795 | { OV511_I2C_BUS, 0x7a, 0x80 }, | ||
4796 | { OV511_I2C_BUS, 0x7b, 0xe2 }, | ||
4797 | { OV511_I2C_BUS, 0x7c, 0x00 }, | ||
4798 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
4799 | }; | ||
4800 | |||
4801 | PDEBUG(4, "starting configuration"); | ||
4802 | |||
4803 | /* This looks redundant, but is necessary for WebCam 3 */ | ||
4804 | ov->primary_i2c_slave = OV7xx0_SID; | ||
4805 | if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) | ||
4806 | return -1; | ||
4807 | |||
4808 | if (init_ov_sensor(ov) >= 0) { | ||
4809 | PDEBUG(1, "OV7xx0 sensor initalized (method 1)"); | ||
4810 | } else { | ||
4811 | /* Reset the 76xx */ | ||
4812 | if (i2c_w(ov, 0x12, 0x80) < 0) | ||
4813 | return -1; | ||
4814 | |||
4815 | /* Wait for it to initialize */ | ||
4816 | msleep(150); | ||
4817 | |||
4818 | i = 0; | ||
4819 | success = 0; | ||
4820 | while (i <= i2c_detect_tries) { | ||
4821 | if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && | ||
4822 | (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { | ||
4823 | success = 1; | ||
4824 | break; | ||
4825 | } else { | ||
4826 | i++; | ||
4827 | } | ||
4828 | } | ||
4829 | |||
4830 | // Was (i == i2c_detect_tries) previously. This obviously used to always report | ||
4831 | // success. Whether anyone actually depended on that bug is unknown | ||
4832 | if ((i >= i2c_detect_tries) && (success == 0)) { | ||
4833 | err("Failed to read sensor ID. You might not have an"); | ||
4834 | err("OV7610/20, or it may be not responding. Report"); | ||
4835 | err("this to " EMAIL); | ||
4836 | err("This is only a warning. You can attempt to use"); | ||
4837 | err("your camera anyway"); | ||
4838 | // Only issue a warning for now | ||
4839 | // return -1; | ||
4840 | } else { | ||
4841 | PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1); | ||
4842 | } | ||
4843 | } | ||
4844 | |||
4845 | /* Detect sensor (sub)type */ | ||
4846 | rc = i2c_r(ov, OV7610_REG_COM_I); | ||
4847 | |||
4848 | if (rc < 0) { | ||
4849 | err("Error detecting sensor type"); | ||
4850 | return -1; | ||
4851 | } else if ((rc & 3) == 3) { | ||
4852 | info("Sensor is an OV7610"); | ||
4853 | ov->sensor = SEN_OV7610; | ||
4854 | } else if ((rc & 3) == 1) { | ||
4855 | /* I don't know what's different about the 76BE yet. */ | ||
4856 | if (i2c_r(ov, 0x15) & 1) | ||
4857 | info("Sensor is an OV7620AE"); | ||
4858 | else | ||
4859 | info("Sensor is an OV76BE"); | ||
4860 | |||
4861 | /* OV511+ will return all zero isoc data unless we | ||
4862 | * configure the sensor as a 7620. Someone needs to | ||
4863 | * find the exact reg. setting that causes this. */ | ||
4864 | if (ov->bridge == BRG_OV511PLUS) { | ||
4865 | info("Enabling 511+/7620AE workaround"); | ||
4866 | ov->sensor = SEN_OV7620; | ||
4867 | } else { | ||
4868 | ov->sensor = SEN_OV76BE; | ||
4869 | } | ||
4870 | } else if ((rc & 3) == 0) { | ||
4871 | info("Sensor is an OV7620"); | ||
4872 | ov->sensor = SEN_OV7620; | ||
4873 | } else { | ||
4874 | err("Unknown image sensor version: %d", rc & 3); | ||
4875 | return -1; | ||
4876 | } | ||
4877 | |||
4878 | if (ov->sensor == SEN_OV7620) { | ||
4879 | PDEBUG(4, "Writing 7620 registers"); | ||
4880 | if (write_regvals(ov, aRegvalsNorm7620)) | ||
4881 | return -1; | ||
4882 | } else { | ||
4883 | PDEBUG(4, "Writing 7610 registers"); | ||
4884 | if (write_regvals(ov, aRegvalsNorm7610)) | ||
4885 | return -1; | ||
4886 | } | ||
4887 | |||
4888 | /* Set sensor-specific vars */ | ||
4889 | ov->maxwidth = 640; | ||
4890 | ov->maxheight = 480; | ||
4891 | ov->minwidth = 64; | ||
4892 | ov->minheight = 48; | ||
4893 | |||
4894 | // FIXME: These do not match the actual settings yet | ||
4895 | ov->brightness = 0x80 << 8; | ||
4896 | ov->contrast = 0x80 << 8; | ||
4897 | ov->colour = 0x80 << 8; | ||
4898 | ov->hue = 0x80 << 8; | ||
4899 | |||
4900 | return 0; | ||
4901 | } | ||
4902 | |||
4903 | /* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */ | ||
4904 | static int | ||
4905 | ov6xx0_configure(struct usb_ov511 *ov) | ||
4906 | { | ||
4907 | int rc; | ||
4908 | |||
4909 | static struct ov511_regvals aRegvalsNorm6x20[] = { | ||
4910 | { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ | ||
4911 | { OV511_I2C_BUS, 0x11, 0x01 }, | ||
4912 | { OV511_I2C_BUS, 0x03, 0x60 }, | ||
4913 | { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ | ||
4914 | { OV511_I2C_BUS, 0x07, 0xa8 }, | ||
4915 | /* The ratio of 0x0c and 0x0d controls the white point */ | ||
4916 | { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
4917 | { OV511_I2C_BUS, 0x0d, 0x24 }, | ||
4918 | { OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */ | ||
4919 | { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */ | ||
4920 | { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */ | ||
4921 | { OV511_I2C_BUS, 0x14, 0x04 }, | ||
4922 | /* 0x16: 0x06 helps frame stability with moving objects */ | ||
4923 | { OV511_I2C_BUS, 0x16, 0x06 }, | ||
4924 | // { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ | ||
4925 | { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ | ||
4926 | /* 0x28: 0x05 Selects RGB format if RGB on */ | ||
4927 | { OV511_I2C_BUS, 0x28, 0x05 }, | ||
4928 | { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ | ||
4929 | // { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ | ||
4930 | { OV511_I2C_BUS, 0x2d, 0x99 }, | ||
4931 | { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Processing Parameter */ | ||
4932 | { OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */ | ||
4933 | { OV511_I2C_BUS, 0x38, 0x8b }, | ||
4934 | { OV511_I2C_BUS, 0x39, 0x40 }, | ||
4935 | |||
4936 | { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ | ||
4937 | { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ | ||
4938 | { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ | ||
4939 | |||
4940 | { OV511_I2C_BUS, 0x3d, 0x80 }, | ||
4941 | /* These next two registers (0x4a, 0x4b) are undocumented. They | ||
4942 | * control the color balance */ | ||
4943 | { OV511_I2C_BUS, 0x4a, 0x80 }, | ||
4944 | { OV511_I2C_BUS, 0x4b, 0x80 }, | ||
4945 | { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */ | ||
4946 | { OV511_I2C_BUS, 0x4e, 0xc1 }, | ||
4947 | { OV511_I2C_BUS, 0x4f, 0x04 }, | ||
4948 | // Do 50-53 have any effect? | ||
4949 | // Toggle 0x12[2] off and on here? | ||
4950 | { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ | ||
4951 | }; | ||
4952 | |||
4953 | static struct ov511_regvals aRegvalsNorm6x30[] = { | ||
4954 | /*OK*/ { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ | ||
4955 | { OV511_I2C_BUS, 0x11, 0x00 }, | ||
4956 | /*OK*/ { OV511_I2C_BUS, 0x03, 0x60 }, | ||
4957 | /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ | ||
4958 | { OV511_I2C_BUS, 0x07, 0xa8 }, | ||
4959 | /* The ratio of 0x0c and 0x0d controls the white point */ | ||
4960 | /*OK*/ { OV511_I2C_BUS, 0x0c, 0x24 }, | ||
4961 | /*OK*/ { OV511_I2C_BUS, 0x0d, 0x24 }, | ||
4962 | /*A*/ { OV511_I2C_BUS, 0x0e, 0x20 }, | ||
4963 | // /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 }, | ||
4964 | { OV511_I2C_BUS, 0x16, 0x03 }, | ||
4965 | // /*OK*/ { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ | ||
4966 | // 21 & 22? The suggested values look wrong. Go with default | ||
4967 | /*A*/ { OV511_I2C_BUS, 0x23, 0xc0 }, | ||
4968 | /*A*/ { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default | ||
4969 | // /*OK*/ { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ | ||
4970 | |||
4971 | /* 0x28: 0x05 Selects RGB format if RGB on */ | ||
4972 | // /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 }, | ||
4973 | // /*04?*/ { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus | ||
4974 | |||
4975 | /*OK*/ { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ | ||
4976 | // /*OK*/ { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ | ||
4977 | { OV511_I2C_BUS, 0x2d, 0x99 }, | ||
4978 | // /*A*/ { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620 | ||
4979 | // /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */ | ||
4980 | // /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 }, | ||
4981 | // /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7 | ||
4982 | // { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ | ||
4983 | // { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ | ||
4984 | // { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ | ||
4985 | { OV511_I2C_BUS, 0x3d, 0x80 }, | ||
4986 | // /*A*/ { OV511_I2C_BUS, 0x3f, 0x0e }, | ||
4987 | |||
4988 | /* These next two registers (0x4a, 0x4b) are undocumented. They | ||
4989 | * control the color balance */ | ||
4990 | // /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these | ||
4991 | // /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 }, | ||
4992 | { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ | ||
4993 | /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 }, | ||
4994 | |||
4995 | /* UV average mode, color killer: strongest */ | ||
4996 | { OV511_I2C_BUS, 0x4f, 0x07 }, | ||
4997 | |||
4998 | { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */ | ||
4999 | { OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */ | ||
5000 | { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */ | ||
5001 | { OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */ | ||
5002 | { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */ | ||
5003 | // { OV511_I2C_BUS, 0x5c, 0x10 }, | ||
5004 | { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ | ||
5005 | }; | ||
5006 | |||
5007 | PDEBUG(4, "starting sensor configuration"); | ||
5008 | |||
5009 | if (init_ov_sensor(ov) < 0) { | ||
5010 | err("Failed to read sensor ID. You might not have an OV6xx0,"); | ||
5011 | err("or it may be not responding. Report this to " EMAIL); | ||
5012 | return -1; | ||
5013 | } else { | ||
5014 | PDEBUG(1, "OV6xx0 sensor detected"); | ||
5015 | } | ||
5016 | |||
5017 | /* Detect sensor (sub)type */ | ||
5018 | rc = i2c_r(ov, OV7610_REG_COM_I); | ||
5019 | |||
5020 | if (rc < 0) { | ||
5021 | err("Error detecting sensor type"); | ||
5022 | return -1; | ||
5023 | } | ||
5024 | |||
5025 | if ((rc & 3) == 0) { | ||
5026 | ov->sensor = SEN_OV6630; | ||
5027 | info("Sensor is an OV6630"); | ||
5028 | } else if ((rc & 3) == 1) { | ||
5029 | ov->sensor = SEN_OV6620; | ||
5030 | info("Sensor is an OV6620"); | ||
5031 | } else if ((rc & 3) == 2) { | ||
5032 | ov->sensor = SEN_OV6630; | ||
5033 | info("Sensor is an OV6630AE"); | ||
5034 | } else if ((rc & 3) == 3) { | ||
5035 | ov->sensor = SEN_OV6630; | ||
5036 | info("Sensor is an OV6630AF"); | ||
5037 | } | ||
5038 | |||
5039 | /* Set sensor-specific vars */ | ||
5040 | ov->maxwidth = 352; | ||
5041 | ov->maxheight = 288; | ||
5042 | ov->minwidth = 64; | ||
5043 | ov->minheight = 48; | ||
5044 | |||
5045 | // FIXME: These do not match the actual settings yet | ||
5046 | ov->brightness = 0x80 << 8; | ||
5047 | ov->contrast = 0x80 << 8; | ||
5048 | ov->colour = 0x80 << 8; | ||
5049 | ov->hue = 0x80 << 8; | ||
5050 | |||
5051 | if (ov->sensor == SEN_OV6620) { | ||
5052 | PDEBUG(4, "Writing 6x20 registers"); | ||
5053 | if (write_regvals(ov, aRegvalsNorm6x20)) | ||
5054 | return -1; | ||
5055 | } else { | ||
5056 | PDEBUG(4, "Writing 6x30 registers"); | ||
5057 | if (write_regvals(ov, aRegvalsNorm6x30)) | ||
5058 | return -1; | ||
5059 | } | ||
5060 | |||
5061 | return 0; | ||
5062 | } | ||
5063 | |||
5064 | /* This initializes the KS0127 and KS0127B video decoders. */ | ||
5065 | static int | ||
5066 | ks0127_configure(struct usb_ov511 *ov) | ||
5067 | { | ||
5068 | int rc; | ||
5069 | |||
5070 | // FIXME: I don't know how to sync or reset it yet | ||
5071 | #if 0 | ||
5072 | if (ov51x_init_ks_sensor(ov) < 0) { | ||
5073 | err("Failed to initialize the KS0127"); | ||
5074 | return -1; | ||
5075 | } else { | ||
5076 | PDEBUG(1, "KS012x(B) sensor detected"); | ||
5077 | } | ||
5078 | #endif | ||
5079 | |||
5080 | /* Detect decoder subtype */ | ||
5081 | rc = i2c_r(ov, 0x00); | ||
5082 | if (rc < 0) { | ||
5083 | err("Error detecting sensor type"); | ||
5084 | return -1; | ||
5085 | } else if (rc & 0x08) { | ||
5086 | rc = i2c_r(ov, 0x3d); | ||
5087 | if (rc < 0) { | ||
5088 | err("Error detecting sensor type"); | ||
5089 | return -1; | ||
5090 | } else if ((rc & 0x0f) == 0) { | ||
5091 | info("Sensor is a KS0127"); | ||
5092 | ov->sensor = SEN_KS0127; | ||
5093 | } else if ((rc & 0x0f) == 9) { | ||
5094 | info("Sensor is a KS0127B Rev. A"); | ||
5095 | ov->sensor = SEN_KS0127B; | ||
5096 | } | ||
5097 | } else { | ||
5098 | err("Error: Sensor is an unsupported KS0122"); | ||
5099 | return -1; | ||
5100 | } | ||
5101 | |||
5102 | /* Set sensor-specific vars */ | ||
5103 | ov->maxwidth = 640; | ||
5104 | ov->maxheight = 480; | ||
5105 | ov->minwidth = 64; | ||
5106 | ov->minheight = 48; | ||
5107 | |||
5108 | // FIXME: These do not match the actual settings yet | ||
5109 | ov->brightness = 0x80 << 8; | ||
5110 | ov->contrast = 0x80 << 8; | ||
5111 | ov->colour = 0x80 << 8; | ||
5112 | ov->hue = 0x80 << 8; | ||
5113 | |||
5114 | /* This device is not supported yet. Bail out now... */ | ||
5115 | err("This sensor is not supported yet."); | ||
5116 | return -1; | ||
5117 | |||
5118 | return 0; | ||
5119 | } | ||
5120 | |||
5121 | /* This initializes the SAA7111A video decoder. */ | ||
5122 | static int | ||
5123 | saa7111a_configure(struct usb_ov511 *ov) | ||
5124 | { | ||
5125 | int rc; | ||
5126 | |||
5127 | /* Since there is no register reset command, all registers must be | ||
5128 | * written, otherwise gives erratic results */ | ||
5129 | static struct ov511_regvals aRegvalsNormSAA7111A[] = { | ||
5130 | { OV511_I2C_BUS, 0x06, 0xce }, | ||
5131 | { OV511_I2C_BUS, 0x07, 0x00 }, | ||
5132 | { OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */ | ||
5133 | { OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */ | ||
5134 | { OV511_I2C_BUS, 0x00, 0x00 }, | ||
5135 | { OV511_I2C_BUS, 0x01, 0x00 }, | ||
5136 | { OV511_I2C_BUS, 0x03, 0x23 }, | ||
5137 | { OV511_I2C_BUS, 0x04, 0x00 }, | ||
5138 | { OV511_I2C_BUS, 0x05, 0x00 }, | ||
5139 | { OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */ | ||
5140 | { OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */ | ||
5141 | { OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */ | ||
5142 | { OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */ | ||
5143 | { OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */ | ||
5144 | { OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */ | ||
5145 | { OV511_I2C_BUS, 0x0f, 0x00 }, | ||
5146 | { OV511_I2C_BUS, 0x11, 0x0c }, | ||
5147 | { OV511_I2C_BUS, 0x12, 0x00 }, | ||
5148 | { OV511_I2C_BUS, 0x13, 0x00 }, | ||
5149 | { OV511_I2C_BUS, 0x14, 0x00 }, | ||
5150 | { OV511_I2C_BUS, 0x15, 0x00 }, | ||
5151 | { OV511_I2C_BUS, 0x16, 0x00 }, | ||
5152 | { OV511_I2C_BUS, 0x17, 0x00 }, | ||
5153 | { OV511_I2C_BUS, 0x02, 0xc0 }, /* Composite input 0 */ | ||
5154 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
5155 | }; | ||
5156 | |||
5157 | // FIXME: I don't know how to sync or reset it yet | ||
5158 | #if 0 | ||
5159 | if (ov51x_init_saa_sensor(ov) < 0) { | ||
5160 | err("Failed to initialize the SAA7111A"); | ||
5161 | return -1; | ||
5162 | } else { | ||
5163 | PDEBUG(1, "SAA7111A sensor detected"); | ||
5164 | } | ||
5165 | #endif | ||
5166 | |||
5167 | /* 640x480 not supported with PAL */ | ||
5168 | if (ov->pal) { | ||
5169 | ov->maxwidth = 320; | ||
5170 | ov->maxheight = 240; /* Even field only */ | ||
5171 | } else { | ||
5172 | ov->maxwidth = 640; | ||
5173 | ov->maxheight = 480; /* Even/Odd fields */ | ||
5174 | } | ||
5175 | |||
5176 | ov->minwidth = 320; | ||
5177 | ov->minheight = 240; /* Even field only */ | ||
5178 | |||
5179 | ov->has_decoder = 1; | ||
5180 | ov->num_inputs = 8; | ||
5181 | ov->norm = VIDEO_MODE_AUTO; | ||
5182 | ov->stop_during_set = 0; /* Decoder guarantees stable image */ | ||
5183 | |||
5184 | /* Decoder doesn't change these values, so we use these instead of | ||
5185 | * acutally reading the registers (which doesn't work) */ | ||
5186 | ov->brightness = 0x80 << 8; | ||
5187 | ov->contrast = 0x40 << 9; | ||
5188 | ov->colour = 0x40 << 9; | ||
5189 | ov->hue = 32768; | ||
5190 | |||
5191 | PDEBUG(4, "Writing SAA7111A registers"); | ||
5192 | if (write_regvals(ov, aRegvalsNormSAA7111A)) | ||
5193 | return -1; | ||
5194 | |||
5195 | /* Detect version of decoder. This must be done after writing the | ||
5196 | * initial regs or the decoder will lock up. */ | ||
5197 | rc = i2c_r(ov, 0x00); | ||
5198 | |||
5199 | if (rc < 0) { | ||
5200 | err("Error detecting sensor version"); | ||
5201 | return -1; | ||
5202 | } else { | ||
5203 | info("Sensor is an SAA7111A (version 0x%x)", rc); | ||
5204 | ov->sensor = SEN_SAA7111A; | ||
5205 | } | ||
5206 | |||
5207 | // FIXME: Fix this for OV518(+) | ||
5208 | /* Latch to negative edge of clock. Otherwise, we get incorrect | ||
5209 | * colors and jitter in the digital signal. */ | ||
5210 | if (ov->bclass == BCL_OV511) | ||
5211 | reg_w(ov, 0x11, 0x00); | ||
5212 | else | ||
5213 | warn("SAA7111A not yet supported with OV518/OV518+"); | ||
5214 | |||
5215 | return 0; | ||
5216 | } | ||
5217 | |||
5218 | /* This initializes the OV511/OV511+ and the sensor */ | ||
5219 | static int | ||
5220 | ov511_configure(struct usb_ov511 *ov) | ||
5221 | { | ||
5222 | static struct ov511_regvals aRegvalsInit511[] = { | ||
5223 | { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, | ||
5224 | { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, | ||
5225 | { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, | ||
5226 | { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, | ||
5227 | { OV511_REG_BUS, R51x_SYS_RESET, 0x3f }, | ||
5228 | { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, | ||
5229 | { OV511_REG_BUS, R51x_SYS_RESET, 0x3d }, | ||
5230 | { OV511_DONE_BUS, 0x0, 0x00}, | ||
5231 | }; | ||
5232 | |||
5233 | static struct ov511_regvals aRegvalsNorm511[] = { | ||
5234 | { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0x01 }, | ||
5235 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, | ||
5236 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, | ||
5237 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, | ||
5238 | { OV511_REG_BUS, R511_FIFO_OPTS, 0x1f }, | ||
5239 | { OV511_REG_BUS, R511_COMP_EN, 0x00 }, | ||
5240 | { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, | ||
5241 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
5242 | }; | ||
5243 | |||
5244 | static struct ov511_regvals aRegvalsNorm511Plus[] = { | ||
5245 | { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0xff }, | ||
5246 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, | ||
5247 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, | ||
5248 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, | ||
5249 | { OV511_REG_BUS, R511_FIFO_OPTS, 0xff }, | ||
5250 | { OV511_REG_BUS, R511_COMP_EN, 0x00 }, | ||
5251 | { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, | ||
5252 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
5253 | }; | ||
5254 | |||
5255 | PDEBUG(4, ""); | ||
5256 | |||
5257 | ov->customid = reg_r(ov, R511_SYS_CUST_ID); | ||
5258 | if (ov->customid < 0) { | ||
5259 | err("Unable to read camera bridge registers"); | ||
5260 | goto error; | ||
5261 | } | ||
5262 | |||
5263 | PDEBUG (1, "CustomID = %d", ov->customid); | ||
5264 | ov->desc = symbolic(camlist, ov->customid); | ||
5265 | info("model: %s", ov->desc); | ||
5266 | |||
5267 | if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) { | ||
5268 | err("Camera type (%d) not recognized", ov->customid); | ||
5269 | err("Please notify " EMAIL " of the name,"); | ||
5270 | err("manufacturer, model, and this number of your camera."); | ||
5271 | err("Also include the output of the detection process."); | ||
5272 | } | ||
5273 | |||
5274 | if (ov->customid == 70) /* USB Life TV (PAL/SECAM) */ | ||
5275 | ov->pal = 1; | ||
5276 | |||
5277 | if (write_regvals(ov, aRegvalsInit511)) | ||
5278 | goto error; | ||
5279 | |||
5280 | if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) | ||
5281 | ov51x_led_control(ov, 0); | ||
5282 | |||
5283 | /* The OV511+ has undocumented bits in the flow control register. | ||
5284 | * Setting it to 0xff fixes the corruption with moving objects. */ | ||
5285 | if (ov->bridge == BRG_OV511) { | ||
5286 | if (write_regvals(ov, aRegvalsNorm511)) | ||
5287 | goto error; | ||
5288 | } else if (ov->bridge == BRG_OV511PLUS) { | ||
5289 | if (write_regvals(ov, aRegvalsNorm511Plus)) | ||
5290 | goto error; | ||
5291 | } else { | ||
5292 | err("Invalid bridge"); | ||
5293 | } | ||
5294 | |||
5295 | if (ov511_init_compression(ov)) | ||
5296 | goto error; | ||
5297 | |||
5298 | ov->packet_numbering = 1; | ||
5299 | ov511_set_packet_size(ov, 0); | ||
5300 | |||
5301 | ov->snap_enabled = snapshot; | ||
5302 | |||
5303 | /* Test for 7xx0 */ | ||
5304 | PDEBUG(3, "Testing for 0V7xx0"); | ||
5305 | ov->primary_i2c_slave = OV7xx0_SID; | ||
5306 | if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) | ||
5307 | goto error; | ||
5308 | |||
5309 | if (i2c_w(ov, 0x12, 0x80) < 0) { | ||
5310 | /* Test for 6xx0 */ | ||
5311 | PDEBUG(3, "Testing for 0V6xx0"); | ||
5312 | ov->primary_i2c_slave = OV6xx0_SID; | ||
5313 | if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) | ||
5314 | goto error; | ||
5315 | |||
5316 | if (i2c_w(ov, 0x12, 0x80) < 0) { | ||
5317 | /* Test for 8xx0 */ | ||
5318 | PDEBUG(3, "Testing for 0V8xx0"); | ||
5319 | ov->primary_i2c_slave = OV8xx0_SID; | ||
5320 | if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) | ||
5321 | goto error; | ||
5322 | |||
5323 | if (i2c_w(ov, 0x12, 0x80) < 0) { | ||
5324 | /* Test for SAA7111A */ | ||
5325 | PDEBUG(3, "Testing for SAA7111A"); | ||
5326 | ov->primary_i2c_slave = SAA7111A_SID; | ||
5327 | if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0) | ||
5328 | goto error; | ||
5329 | |||
5330 | if (i2c_w(ov, 0x0d, 0x00) < 0) { | ||
5331 | /* Test for KS0127 */ | ||
5332 | PDEBUG(3, "Testing for KS0127"); | ||
5333 | ov->primary_i2c_slave = KS0127_SID; | ||
5334 | if (ov51x_set_slave_ids(ov, KS0127_SID) < 0) | ||
5335 | goto error; | ||
5336 | |||
5337 | if (i2c_w(ov, 0x10, 0x00) < 0) { | ||
5338 | err("Can't determine sensor slave IDs"); | ||
5339 | goto error; | ||
5340 | } else { | ||
5341 | if (ks0127_configure(ov) < 0) { | ||
5342 | err("Failed to configure KS0127"); | ||
5343 | goto error; | ||
5344 | } | ||
5345 | } | ||
5346 | } else { | ||
5347 | if (saa7111a_configure(ov) < 0) { | ||
5348 | err("Failed to configure SAA7111A"); | ||
5349 | goto error; | ||
5350 | } | ||
5351 | } | ||
5352 | } else { | ||
5353 | err("Detected unsupported OV8xx0 sensor"); | ||
5354 | goto error; | ||
5355 | } | ||
5356 | } else { | ||
5357 | if (ov6xx0_configure(ov) < 0) { | ||
5358 | err("Failed to configure OV6xx0"); | ||
5359 | goto error; | ||
5360 | } | ||
5361 | } | ||
5362 | } else { | ||
5363 | if (ov7xx0_configure(ov) < 0) { | ||
5364 | err("Failed to configure OV7xx0"); | ||
5365 | goto error; | ||
5366 | } | ||
5367 | } | ||
5368 | |||
5369 | return 0; | ||
5370 | |||
5371 | error: | ||
5372 | err("OV511 Config failed"); | ||
5373 | |||
5374 | return -EBUSY; | ||
5375 | } | ||
5376 | |||
5377 | /* This initializes the OV518/OV518+ and the sensor */ | ||
5378 | static int | ||
5379 | ov518_configure(struct usb_ov511 *ov) | ||
5380 | { | ||
5381 | /* For 518 and 518+ */ | ||
5382 | static struct ov511_regvals aRegvalsInit518[] = { | ||
5383 | { OV511_REG_BUS, R51x_SYS_RESET, 0x40 }, | ||
5384 | { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, | ||
5385 | { OV511_REG_BUS, R51x_SYS_RESET, 0x3e }, | ||
5386 | { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, | ||
5387 | { OV511_REG_BUS, R51x_SYS_RESET, 0x00 }, | ||
5388 | { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, | ||
5389 | { OV511_REG_BUS, 0x46, 0x00 }, | ||
5390 | { OV511_REG_BUS, 0x5d, 0x03 }, | ||
5391 | { OV511_DONE_BUS, 0x0, 0x00}, | ||
5392 | }; | ||
5393 | |||
5394 | static struct ov511_regvals aRegvalsNorm518[] = { | ||
5395 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ | ||
5396 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ | ||
5397 | { OV511_REG_BUS, 0x31, 0x0f }, | ||
5398 | { OV511_REG_BUS, 0x5d, 0x03 }, | ||
5399 | { OV511_REG_BUS, 0x24, 0x9f }, | ||
5400 | { OV511_REG_BUS, 0x25, 0x90 }, | ||
5401 | { OV511_REG_BUS, 0x20, 0x00 }, | ||
5402 | { OV511_REG_BUS, 0x51, 0x04 }, | ||
5403 | { OV511_REG_BUS, 0x71, 0x19 }, | ||
5404 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
5405 | }; | ||
5406 | |||
5407 | static struct ov511_regvals aRegvalsNorm518Plus[] = { | ||
5408 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ | ||
5409 | { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ | ||
5410 | { OV511_REG_BUS, 0x31, 0x0f }, | ||
5411 | { OV511_REG_BUS, 0x5d, 0x03 }, | ||
5412 | { OV511_REG_BUS, 0x24, 0x9f }, | ||
5413 | { OV511_REG_BUS, 0x25, 0x90 }, | ||
5414 | { OV511_REG_BUS, 0x20, 0x60 }, | ||
5415 | { OV511_REG_BUS, 0x51, 0x02 }, | ||
5416 | { OV511_REG_BUS, 0x71, 0x19 }, | ||
5417 | { OV511_REG_BUS, 0x40, 0xff }, | ||
5418 | { OV511_REG_BUS, 0x41, 0x42 }, | ||
5419 | { OV511_REG_BUS, 0x46, 0x00 }, | ||
5420 | { OV511_REG_BUS, 0x33, 0x04 }, | ||
5421 | { OV511_REG_BUS, 0x21, 0x19 }, | ||
5422 | { OV511_REG_BUS, 0x3f, 0x10 }, | ||
5423 | { OV511_DONE_BUS, 0x0, 0x00 }, | ||
5424 | }; | ||
5425 | |||
5426 | PDEBUG(4, ""); | ||
5427 | |||
5428 | /* First 5 bits of custom ID reg are a revision ID on OV518 */ | ||
5429 | info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID)); | ||
5430 | |||
5431 | /* Give it the default description */ | ||
5432 | ov->desc = symbolic(camlist, 0); | ||
5433 | |||
5434 | if (write_regvals(ov, aRegvalsInit518)) | ||
5435 | goto error; | ||
5436 | |||
5437 | /* Set LED GPIO pin to output mode */ | ||
5438 | if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0) | ||
5439 | goto error; | ||
5440 | |||
5441 | /* LED is off by default with OV518; have to explicitly turn it on */ | ||
5442 | if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) | ||
5443 | ov51x_led_control(ov, 0); | ||
5444 | else | ||
5445 | ov51x_led_control(ov, 1); | ||
5446 | |||
5447 | /* Don't require compression if dumppix is enabled; otherwise it's | ||
5448 | * required. OV518 has no uncompressed mode, to save RAM. */ | ||
5449 | if (!dumppix && !ov->compress) { | ||
5450 | ov->compress = 1; | ||
5451 | warn("Compression required with OV518...enabling"); | ||
5452 | } | ||
5453 | |||
5454 | if (ov->bridge == BRG_OV518) { | ||
5455 | if (write_regvals(ov, aRegvalsNorm518)) | ||
5456 | goto error; | ||
5457 | } else if (ov->bridge == BRG_OV518PLUS) { | ||
5458 | if (write_regvals(ov, aRegvalsNorm518Plus)) | ||
5459 | goto error; | ||
5460 | } else { | ||
5461 | err("Invalid bridge"); | ||
5462 | } | ||
5463 | |||
5464 | if (reg_w(ov, 0x2f, 0x80) < 0) | ||
5465 | goto error; | ||
5466 | |||
5467 | if (ov518_init_compression(ov)) | ||
5468 | goto error; | ||
5469 | |||
5470 | if (ov->bridge == BRG_OV518) | ||
5471 | { | ||
5472 | struct usb_interface *ifp; | ||
5473 | struct usb_host_interface *alt; | ||
5474 | __u16 mxps = 0; | ||
5475 | |||
5476 | ifp = usb_ifnum_to_if(ov->dev, 0); | ||
5477 | if (ifp) { | ||
5478 | alt = usb_altnum_to_altsetting(ifp, 7); | ||
5479 | if (alt) | ||
5480 | mxps = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); | ||
5481 | } | ||
5482 | |||
5483 | /* Some OV518s have packet numbering by default, some don't */ | ||
5484 | if (mxps == 897) | ||
5485 | ov->packet_numbering = 1; | ||
5486 | else | ||
5487 | ov->packet_numbering = 0; | ||
5488 | } else { | ||
5489 | /* OV518+ has packet numbering turned on by default */ | ||
5490 | ov->packet_numbering = 1; | ||
5491 | } | ||
5492 | |||
5493 | ov518_set_packet_size(ov, 0); | ||
5494 | |||
5495 | ov->snap_enabled = snapshot; | ||
5496 | |||
5497 | /* Test for 76xx */ | ||
5498 | ov->primary_i2c_slave = OV7xx0_SID; | ||
5499 | if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) | ||
5500 | goto error; | ||
5501 | |||
5502 | /* The OV518 must be more aggressive about sensor detection since | ||
5503 | * I2C write will never fail if the sensor is not present. We have | ||
5504 | * to try to initialize the sensor to detect its presence */ | ||
5505 | |||
5506 | if (init_ov_sensor(ov) < 0) { | ||
5507 | /* Test for 6xx0 */ | ||
5508 | ov->primary_i2c_slave = OV6xx0_SID; | ||
5509 | if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) | ||
5510 | goto error; | ||
5511 | |||
5512 | if (init_ov_sensor(ov) < 0) { | ||
5513 | /* Test for 8xx0 */ | ||
5514 | ov->primary_i2c_slave = OV8xx0_SID; | ||
5515 | if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) | ||
5516 | goto error; | ||
5517 | |||
5518 | if (init_ov_sensor(ov) < 0) { | ||
5519 | err("Can't determine sensor slave IDs"); | ||
5520 | goto error; | ||
5521 | } else { | ||
5522 | err("Detected unsupported OV8xx0 sensor"); | ||
5523 | goto error; | ||
5524 | } | ||
5525 | } else { | ||
5526 | if (ov6xx0_configure(ov) < 0) { | ||
5527 | err("Failed to configure OV6xx0"); | ||
5528 | goto error; | ||
5529 | } | ||
5530 | } | ||
5531 | } else { | ||
5532 | if (ov7xx0_configure(ov) < 0) { | ||
5533 | err("Failed to configure OV7xx0"); | ||
5534 | goto error; | ||
5535 | } | ||
5536 | } | ||
5537 | |||
5538 | ov->maxwidth = 352; | ||
5539 | ov->maxheight = 288; | ||
5540 | |||
5541 | // The OV518 cannot go as low as the sensor can | ||
5542 | ov->minwidth = 160; | ||
5543 | ov->minheight = 120; | ||
5544 | |||
5545 | return 0; | ||
5546 | |||
5547 | error: | ||
5548 | err("OV518 Config failed"); | ||
5549 | |||
5550 | return -EBUSY; | ||
5551 | } | ||
5552 | |||
5553 | /**************************************************************************** | ||
5554 | * sysfs | ||
5555 | ***************************************************************************/ | ||
5556 | |||
5557 | static inline struct usb_ov511 *cd_to_ov(struct class_device *cd) | ||
5558 | { | ||
5559 | struct video_device *vdev = to_video_device(cd); | ||
5560 | return video_get_drvdata(vdev); | ||
5561 | } | ||
5562 | |||
5563 | static ssize_t show_custom_id(struct class_device *cd, char *buf) | ||
5564 | { | ||
5565 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5566 | return sprintf(buf, "%d\n", ov->customid); | ||
5567 | } | ||
5568 | static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL); | ||
5569 | |||
5570 | static ssize_t show_model(struct class_device *cd, char *buf) | ||
5571 | { | ||
5572 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5573 | return sprintf(buf, "%s\n", ov->desc); | ||
5574 | } | ||
5575 | static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); | ||
5576 | |||
5577 | static ssize_t show_bridge(struct class_device *cd, char *buf) | ||
5578 | { | ||
5579 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5580 | return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge)); | ||
5581 | } | ||
5582 | static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL); | ||
5583 | |||
5584 | static ssize_t show_sensor(struct class_device *cd, char *buf) | ||
5585 | { | ||
5586 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5587 | return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor)); | ||
5588 | } | ||
5589 | static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL); | ||
5590 | |||
5591 | static ssize_t show_brightness(struct class_device *cd, char *buf) | ||
5592 | { | ||
5593 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5594 | unsigned short x; | ||
5595 | |||
5596 | if (!ov->dev) | ||
5597 | return -ENODEV; | ||
5598 | sensor_get_brightness(ov, &x); | ||
5599 | return sprintf(buf, "%d\n", x >> 8); | ||
5600 | } | ||
5601 | static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); | ||
5602 | |||
5603 | static ssize_t show_saturation(struct class_device *cd, char *buf) | ||
5604 | { | ||
5605 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5606 | unsigned short x; | ||
5607 | |||
5608 | if (!ov->dev) | ||
5609 | return -ENODEV; | ||
5610 | sensor_get_saturation(ov, &x); | ||
5611 | return sprintf(buf, "%d\n", x >> 8); | ||
5612 | } | ||
5613 | static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); | ||
5614 | |||
5615 | static ssize_t show_contrast(struct class_device *cd, char *buf) | ||
5616 | { | ||
5617 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5618 | unsigned short x; | ||
5619 | |||
5620 | if (!ov->dev) | ||
5621 | return -ENODEV; | ||
5622 | sensor_get_contrast(ov, &x); | ||
5623 | return sprintf(buf, "%d\n", x >> 8); | ||
5624 | } | ||
5625 | static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); | ||
5626 | |||
5627 | static ssize_t show_hue(struct class_device *cd, char *buf) | ||
5628 | { | ||
5629 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5630 | unsigned short x; | ||
5631 | |||
5632 | if (!ov->dev) | ||
5633 | return -ENODEV; | ||
5634 | sensor_get_hue(ov, &x); | ||
5635 | return sprintf(buf, "%d\n", x >> 8); | ||
5636 | } | ||
5637 | static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); | ||
5638 | |||
5639 | static ssize_t show_exposure(struct class_device *cd, char *buf) | ||
5640 | { | ||
5641 | struct usb_ov511 *ov = cd_to_ov(cd); | ||
5642 | unsigned char exp = 0; | ||
5643 | |||
5644 | if (!ov->dev) | ||
5645 | return -ENODEV; | ||
5646 | sensor_get_exposure(ov, &exp); | ||
5647 | return sprintf(buf, "%d\n", exp >> 8); | ||
5648 | } | ||
5649 | static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); | ||
5650 | |||
5651 | static void ov_create_sysfs(struct video_device *vdev) | ||
5652 | { | ||
5653 | video_device_create_file(vdev, &class_device_attr_custom_id); | ||
5654 | video_device_create_file(vdev, &class_device_attr_model); | ||
5655 | video_device_create_file(vdev, &class_device_attr_bridge); | ||
5656 | video_device_create_file(vdev, &class_device_attr_sensor); | ||
5657 | video_device_create_file(vdev, &class_device_attr_brightness); | ||
5658 | video_device_create_file(vdev, &class_device_attr_saturation); | ||
5659 | video_device_create_file(vdev, &class_device_attr_contrast); | ||
5660 | video_device_create_file(vdev, &class_device_attr_hue); | ||
5661 | video_device_create_file(vdev, &class_device_attr_exposure); | ||
5662 | } | ||
5663 | |||
5664 | /**************************************************************************** | ||
5665 | * USB routines | ||
5666 | ***************************************************************************/ | ||
5667 | |||
5668 | static int | ||
5669 | ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
5670 | { | ||
5671 | struct usb_device *dev = interface_to_usbdev(intf); | ||
5672 | struct usb_interface_descriptor *idesc; | ||
5673 | struct usb_ov511 *ov; | ||
5674 | int i; | ||
5675 | |||
5676 | PDEBUG(1, "probing for device..."); | ||
5677 | |||
5678 | /* We don't handle multi-config cameras */ | ||
5679 | if (dev->descriptor.bNumConfigurations != 1) | ||
5680 | return -ENODEV; | ||
5681 | |||
5682 | idesc = &intf->cur_altsetting->desc; | ||
5683 | |||
5684 | if (idesc->bInterfaceClass != 0xFF) | ||
5685 | return -ENODEV; | ||
5686 | if (idesc->bInterfaceSubClass != 0x00) | ||
5687 | return -ENODEV; | ||
5688 | |||
5689 | if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) { | ||
5690 | err("couldn't kmalloc ov struct"); | ||
5691 | goto error_out; | ||
5692 | } | ||
5693 | |||
5694 | ov->dev = dev; | ||
5695 | ov->iface = idesc->bInterfaceNumber; | ||
5696 | ov->led_policy = led; | ||
5697 | ov->compress = compress; | ||
5698 | ov->lightfreq = lightfreq; | ||
5699 | ov->num_inputs = 1; /* Video decoder init functs. change this */ | ||
5700 | ov->stop_during_set = !fastset; | ||
5701 | ov->backlight = backlight; | ||
5702 | ov->mirror = mirror; | ||
5703 | ov->auto_brt = autobright; | ||
5704 | ov->auto_gain = autogain; | ||
5705 | ov->auto_exp = autoexp; | ||
5706 | |||
5707 | switch (le16_to_cpu(dev->descriptor.idProduct)) { | ||
5708 | case PROD_OV511: | ||
5709 | ov->bridge = BRG_OV511; | ||
5710 | ov->bclass = BCL_OV511; | ||
5711 | break; | ||
5712 | case PROD_OV511PLUS: | ||
5713 | ov->bridge = BRG_OV511PLUS; | ||
5714 | ov->bclass = BCL_OV511; | ||
5715 | break; | ||
5716 | case PROD_OV518: | ||
5717 | ov->bridge = BRG_OV518; | ||
5718 | ov->bclass = BCL_OV518; | ||
5719 | break; | ||
5720 | case PROD_OV518PLUS: | ||
5721 | ov->bridge = BRG_OV518PLUS; | ||
5722 | ov->bclass = BCL_OV518; | ||
5723 | break; | ||
5724 | case PROD_ME2CAM: | ||
5725 | if (le16_to_cpu(dev->descriptor.idVendor) != VEND_MATTEL) | ||
5726 | goto error; | ||
5727 | ov->bridge = BRG_OV511PLUS; | ||
5728 | ov->bclass = BCL_OV511; | ||
5729 | break; | ||
5730 | default: | ||
5731 | err("Unknown product ID 0x%04x", le16_to_cpu(dev->descriptor.idProduct)); | ||
5732 | goto error; | ||
5733 | } | ||
5734 | |||
5735 | info("USB %s video device found", symbolic(brglist, ov->bridge)); | ||
5736 | |||
5737 | init_waitqueue_head(&ov->wq); | ||
5738 | |||
5739 | mutex_init(&ov->lock); /* to 1 == available */ | ||
5740 | mutex_init(&ov->buf_lock); | ||
5741 | mutex_init(&ov->i2c_lock); | ||
5742 | mutex_init(&ov->cbuf_lock); | ||
5743 | |||
5744 | ov->buf_state = BUF_NOT_ALLOCATED; | ||
5745 | |||
5746 | if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) { | ||
5747 | err("usb_make_path error"); | ||
5748 | goto error; | ||
5749 | } | ||
5750 | |||
5751 | /* Allocate control transfer buffer. */ | ||
5752 | /* Must be kmalloc()'ed, for DMA compatibility */ | ||
5753 | ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL); | ||
5754 | if (!ov->cbuf) | ||
5755 | goto error; | ||
5756 | |||
5757 | if (ov->bclass == BCL_OV518) { | ||
5758 | if (ov518_configure(ov) < 0) | ||
5759 | goto error; | ||
5760 | } else { | ||
5761 | if (ov511_configure(ov) < 0) | ||
5762 | goto error; | ||
5763 | } | ||
5764 | |||
5765 | for (i = 0; i < OV511_NUMFRAMES; i++) { | ||
5766 | ov->frame[i].framenum = i; | ||
5767 | init_waitqueue_head(&ov->frame[i].wq); | ||
5768 | } | ||
5769 | |||
5770 | for (i = 0; i < OV511_NUMSBUF; i++) { | ||
5771 | ov->sbuf[i].ov = ov; | ||
5772 | spin_lock_init(&ov->sbuf[i].lock); | ||
5773 | ov->sbuf[i].n = i; | ||
5774 | } | ||
5775 | |||
5776 | /* Unnecessary? (This is done on open(). Need to make sure variables | ||
5777 | * are properly initialized without this before removing it, though). */ | ||
5778 | if (ov51x_set_default_params(ov) < 0) | ||
5779 | goto error; | ||
5780 | |||
5781 | #ifdef OV511_DEBUG | ||
5782 | if (dump_bridge) { | ||
5783 | if (ov->bclass == BCL_OV511) | ||
5784 | ov511_dump_regs(ov); | ||
5785 | else | ||
5786 | ov518_dump_regs(ov); | ||
5787 | } | ||
5788 | #endif | ||
5789 | |||
5790 | ov->vdev = video_device_alloc(); | ||
5791 | if (!ov->vdev) | ||
5792 | goto error; | ||
5793 | |||
5794 | memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev)); | ||
5795 | ov->vdev->dev = &dev->dev; | ||
5796 | video_set_drvdata(ov->vdev, ov); | ||
5797 | |||
5798 | for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) { | ||
5799 | /* Minor 0 cannot be specified; assume user wants autodetect */ | ||
5800 | if (unit_video[i] == 0) | ||
5801 | break; | ||
5802 | |||
5803 | if (video_register_device(ov->vdev, VFL_TYPE_GRABBER, | ||
5804 | unit_video[i]) >= 0) { | ||
5805 | break; | ||
5806 | } | ||
5807 | } | ||
5808 | |||
5809 | /* Use the next available one */ | ||
5810 | if ((ov->vdev->minor == -1) && | ||
5811 | video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1) < 0) { | ||
5812 | err("video_register_device failed"); | ||
5813 | goto error; | ||
5814 | } | ||
5815 | |||
5816 | info("Device at %s registered to minor %d", ov->usb_path, | ||
5817 | ov->vdev->minor); | ||
5818 | |||
5819 | usb_set_intfdata(intf, ov); | ||
5820 | ov_create_sysfs(ov->vdev); | ||
5821 | return 0; | ||
5822 | |||
5823 | error: | ||
5824 | if (ov->vdev) { | ||
5825 | if (-1 == ov->vdev->minor) | ||
5826 | video_device_release(ov->vdev); | ||
5827 | else | ||
5828 | video_unregister_device(ov->vdev); | ||
5829 | ov->vdev = NULL; | ||
5830 | } | ||
5831 | |||
5832 | if (ov->cbuf) { | ||
5833 | mutex_lock(&ov->cbuf_lock); | ||
5834 | kfree(ov->cbuf); | ||
5835 | ov->cbuf = NULL; | ||
5836 | mutex_unlock(&ov->cbuf_lock); | ||
5837 | } | ||
5838 | |||
5839 | kfree(ov); | ||
5840 | ov = NULL; | ||
5841 | |||
5842 | error_out: | ||
5843 | err("Camera initialization failed"); | ||
5844 | return -EIO; | ||
5845 | } | ||
5846 | |||
5847 | static void | ||
5848 | ov51x_disconnect(struct usb_interface *intf) | ||
5849 | { | ||
5850 | struct usb_ov511 *ov = usb_get_intfdata(intf); | ||
5851 | int n; | ||
5852 | |||
5853 | PDEBUG(3, ""); | ||
5854 | |||
5855 | usb_set_intfdata (intf, NULL); | ||
5856 | |||
5857 | if (!ov) | ||
5858 | return; | ||
5859 | |||
5860 | if (ov->vdev) | ||
5861 | video_unregister_device(ov->vdev); | ||
5862 | |||
5863 | for (n = 0; n < OV511_NUMFRAMES; n++) | ||
5864 | ov->frame[n].grabstate = FRAME_ERROR; | ||
5865 | |||
5866 | ov->curframe = -1; | ||
5867 | |||
5868 | /* This will cause the process to request another frame */ | ||
5869 | for (n = 0; n < OV511_NUMFRAMES; n++) | ||
5870 | wake_up_interruptible(&ov->frame[n].wq); | ||
5871 | |||
5872 | wake_up_interruptible(&ov->wq); | ||
5873 | |||
5874 | ov->streaming = 0; | ||
5875 | ov51x_unlink_isoc(ov); | ||
5876 | |||
5877 | ov->dev = NULL; | ||
5878 | |||
5879 | /* Free the memory */ | ||
5880 | if (ov && !ov->user) { | ||
5881 | mutex_lock(&ov->cbuf_lock); | ||
5882 | kfree(ov->cbuf); | ||
5883 | ov->cbuf = NULL; | ||
5884 | mutex_unlock(&ov->cbuf_lock); | ||
5885 | |||
5886 | ov51x_dealloc(ov); | ||
5887 | kfree(ov); | ||
5888 | ov = NULL; | ||
5889 | } | ||
5890 | |||
5891 | PDEBUG(3, "Disconnect complete"); | ||
5892 | } | ||
5893 | |||
5894 | static struct usb_driver ov511_driver = { | ||
5895 | .name = "ov511", | ||
5896 | .id_table = device_table, | ||
5897 | .probe = ov51x_probe, | ||
5898 | .disconnect = ov51x_disconnect | ||
5899 | }; | ||
5900 | |||
5901 | /**************************************************************************** | ||
5902 | * | ||
5903 | * Module routines | ||
5904 | * | ||
5905 | ***************************************************************************/ | ||
5906 | |||
5907 | static int __init | ||
5908 | usb_ov511_init(void) | ||
5909 | { | ||
5910 | int retval; | ||
5911 | |||
5912 | retval = usb_register(&ov511_driver); | ||
5913 | if (retval) | ||
5914 | goto out; | ||
5915 | |||
5916 | info(DRIVER_VERSION " : " DRIVER_DESC); | ||
5917 | |||
5918 | out: | ||
5919 | return retval; | ||
5920 | } | ||
5921 | |||
5922 | static void __exit | ||
5923 | usb_ov511_exit(void) | ||
5924 | { | ||
5925 | usb_deregister(&ov511_driver); | ||
5926 | info("driver deregistered"); | ||
5927 | |||
5928 | } | ||
5929 | |||
5930 | module_init(usb_ov511_init); | ||
5931 | module_exit(usb_ov511_exit); | ||
5932 | |||
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h new file mode 100644 index 000000000000..bce9b3633889 --- /dev/null +++ b/drivers/media/video/ov511.h | |||
@@ -0,0 +1,568 @@ | |||
1 | #ifndef __LINUX_OV511_H | ||
2 | #define __LINUX_OV511_H | ||
3 | |||
4 | #include <asm/uaccess.h> | ||
5 | #include <linux/videodev.h> | ||
6 | #include <linux/smp_lock.h> | ||
7 | #include <linux/usb.h> | ||
8 | #include <linux/mutex.h> | ||
9 | |||
10 | #define OV511_DEBUG /* Turn on debug messages */ | ||
11 | |||
12 | #ifdef OV511_DEBUG | ||
13 | #define PDEBUG(level, fmt, args...) \ | ||
14 | if (debug >= (level)) info("[%s:%d] " fmt, \ | ||
15 | __FUNCTION__, __LINE__ , ## args) | ||
16 | #else | ||
17 | #define PDEBUG(level, fmt, args...) do {} while(0) | ||
18 | #endif | ||
19 | |||
20 | /* This macro restricts an int variable to an inclusive range */ | ||
21 | #define RESTRICT_TO_RANGE(v,mi,ma) { \ | ||
22 | if ((v) < (mi)) (v) = (mi); \ | ||
23 | else if ((v) > (ma)) (v) = (ma); \ | ||
24 | } | ||
25 | |||
26 | /* --------------------------------- */ | ||
27 | /* DEFINES FOR OV511 AND OTHER CHIPS */ | ||
28 | /* --------------------------------- */ | ||
29 | |||
30 | /* USB IDs */ | ||
31 | #define VEND_OMNIVISION 0x05A9 | ||
32 | #define PROD_OV511 0x0511 | ||
33 | #define PROD_OV511PLUS 0xA511 | ||
34 | #define PROD_OV518 0x0518 | ||
35 | #define PROD_OV518PLUS 0xA518 | ||
36 | |||
37 | #define VEND_MATTEL 0x0813 | ||
38 | #define PROD_ME2CAM 0x0002 | ||
39 | |||
40 | /* --------------------------------- */ | ||
41 | /* OV51x REGISTER MNEMONICS */ | ||
42 | /* --------------------------------- */ | ||
43 | |||
44 | /* Camera interface register numbers */ | ||
45 | #define R511_CAM_DELAY 0x10 | ||
46 | #define R511_CAM_EDGE 0x11 | ||
47 | #define R511_CAM_PXCNT 0x12 | ||
48 | #define R511_CAM_LNCNT 0x13 | ||
49 | #define R511_CAM_PXDIV 0x14 | ||
50 | #define R511_CAM_LNDIV 0x15 | ||
51 | #define R511_CAM_UV_EN 0x16 | ||
52 | #define R511_CAM_LINE_MODE 0x17 | ||
53 | #define R511_CAM_OPTS 0x18 | ||
54 | |||
55 | /* Snapshot mode camera interface register numbers */ | ||
56 | #define R511_SNAP_FRAME 0x19 | ||
57 | #define R511_SNAP_PXCNT 0x1A | ||
58 | #define R511_SNAP_LNCNT 0x1B | ||
59 | #define R511_SNAP_PXDIV 0x1C | ||
60 | #define R511_SNAP_LNDIV 0x1D | ||
61 | #define R511_SNAP_UV_EN 0x1E | ||
62 | #define R511_SNAP_OPTS 0x1F | ||
63 | |||
64 | /* DRAM register numbers */ | ||
65 | #define R511_DRAM_FLOW_CTL 0x20 | ||
66 | #define R511_DRAM_ARCP 0x21 | ||
67 | #define R511_DRAM_MRC 0x22 | ||
68 | #define R511_DRAM_RFC 0x23 | ||
69 | |||
70 | /* ISO FIFO register numbers */ | ||
71 | #define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */ | ||
72 | #define R511_FIFO_OPTS 0x31 | ||
73 | |||
74 | /* Parallel IO register numbers */ | ||
75 | #define R511_PIO_OPTS 0x38 | ||
76 | #define R511_PIO_DATA 0x39 | ||
77 | #define R511_PIO_BIST 0x3E | ||
78 | #define R518_GPIO_IN 0x55 /* OV518(+) only */ | ||
79 | #define R518_GPIO_OUT 0x56 /* OV518(+) only */ | ||
80 | #define R518_GPIO_CTL 0x57 /* OV518(+) only */ | ||
81 | #define R518_GPIO_PULSE_IN 0x58 /* OV518(+) only */ | ||
82 | #define R518_GPIO_PULSE_CLEAR 0x59 /* OV518(+) only */ | ||
83 | #define R518_GPIO_PULSE_POL 0x5a /* OV518(+) only */ | ||
84 | #define R518_GPIO_PULSE_EN 0x5b /* OV518(+) only */ | ||
85 | #define R518_GPIO_RESET 0x5c /* OV518(+) only */ | ||
86 | |||
87 | /* I2C registers */ | ||
88 | #define R511_I2C_CTL 0x40 | ||
89 | #define R518_I2C_CTL 0x47 /* OV518(+) only */ | ||
90 | #define R51x_I2C_W_SID 0x41 | ||
91 | #define R51x_I2C_SADDR_3 0x42 | ||
92 | #define R51x_I2C_SADDR_2 0x43 | ||
93 | #define R51x_I2C_R_SID 0x44 | ||
94 | #define R51x_I2C_DATA 0x45 | ||
95 | #define R51x_I2C_CLOCK 0x46 | ||
96 | #define R51x_I2C_TIMEOUT 0x47 | ||
97 | |||
98 | /* I2C snapshot registers */ | ||
99 | #define R511_SI2C_SADDR_3 0x48 | ||
100 | #define R511_SI2C_DATA 0x49 | ||
101 | |||
102 | /* System control registers */ | ||
103 | #define R51x_SYS_RESET 0x50 | ||
104 | /* Reset type definitions */ | ||
105 | #define OV511_RESET_UDC 0x01 | ||
106 | #define OV511_RESET_I2C 0x02 | ||
107 | #define OV511_RESET_FIFO 0x04 | ||
108 | #define OV511_RESET_OMNICE 0x08 | ||
109 | #define OV511_RESET_DRAM 0x10 | ||
110 | #define OV511_RESET_CAM_INT 0x20 | ||
111 | #define OV511_RESET_OV511 0x40 | ||
112 | #define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */ | ||
113 | #define OV511_RESET_ALL 0x7F | ||
114 | |||
115 | #define R511_SYS_CLOCK_DIV 0x51 | ||
116 | #define R51x_SYS_SNAP 0x52 | ||
117 | #define R51x_SYS_INIT 0x53 | ||
118 | #define R511_SYS_PWR_CLK 0x54 /* OV511+/OV518(+) only */ | ||
119 | #define R511_SYS_LED_CTL 0x55 /* OV511+ only */ | ||
120 | #define R511_SYS_USER 0x5E | ||
121 | #define R511_SYS_CUST_ID 0x5F | ||
122 | |||
123 | /* OmniCE (compression) registers */ | ||
124 | #define R511_COMP_PHY 0x70 | ||
125 | #define R511_COMP_PHUV 0x71 | ||
126 | #define R511_COMP_PVY 0x72 | ||
127 | #define R511_COMP_PVUV 0x73 | ||
128 | #define R511_COMP_QHY 0x74 | ||
129 | #define R511_COMP_QHUV 0x75 | ||
130 | #define R511_COMP_QVY 0x76 | ||
131 | #define R511_COMP_QVUV 0x77 | ||
132 | #define R511_COMP_EN 0x78 | ||
133 | #define R511_COMP_LUT_EN 0x79 | ||
134 | #define R511_COMP_LUT_BEGIN 0x80 | ||
135 | |||
136 | /* --------------------------------- */ | ||
137 | /* ALTERNATE NUMBERS */ | ||
138 | /* --------------------------------- */ | ||
139 | |||
140 | /* Alternate numbers for various max packet sizes (OV511 only) */ | ||
141 | #define OV511_ALT_SIZE_992 0 | ||
142 | #define OV511_ALT_SIZE_993 1 | ||
143 | #define OV511_ALT_SIZE_768 2 | ||
144 | #define OV511_ALT_SIZE_769 3 | ||
145 | #define OV511_ALT_SIZE_512 4 | ||
146 | #define OV511_ALT_SIZE_513 5 | ||
147 | #define OV511_ALT_SIZE_257 6 | ||
148 | #define OV511_ALT_SIZE_0 7 | ||
149 | |||
150 | /* Alternate numbers for various max packet sizes (OV511+ only) */ | ||
151 | #define OV511PLUS_ALT_SIZE_0 0 | ||
152 | #define OV511PLUS_ALT_SIZE_33 1 | ||
153 | #define OV511PLUS_ALT_SIZE_129 2 | ||
154 | #define OV511PLUS_ALT_SIZE_257 3 | ||
155 | #define OV511PLUS_ALT_SIZE_385 4 | ||
156 | #define OV511PLUS_ALT_SIZE_513 5 | ||
157 | #define OV511PLUS_ALT_SIZE_769 6 | ||
158 | #define OV511PLUS_ALT_SIZE_961 7 | ||
159 | |||
160 | /* Alternate numbers for various max packet sizes (OV518(+) only) */ | ||
161 | #define OV518_ALT_SIZE_0 0 | ||
162 | #define OV518_ALT_SIZE_128 1 | ||
163 | #define OV518_ALT_SIZE_256 2 | ||
164 | #define OV518_ALT_SIZE_384 3 | ||
165 | #define OV518_ALT_SIZE_512 4 | ||
166 | #define OV518_ALT_SIZE_640 5 | ||
167 | #define OV518_ALT_SIZE_768 6 | ||
168 | #define OV518_ALT_SIZE_896 7 | ||
169 | |||
170 | /* --------------------------------- */ | ||
171 | /* OV7610 REGISTER MNEMONICS */ | ||
172 | /* --------------------------------- */ | ||
173 | |||
174 | /* OV7610 registers */ | ||
175 | #define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */ | ||
176 | #define OV7610_REG_BLUE 0x01 /* blue channel balance */ | ||
177 | #define OV7610_REG_RED 0x02 /* red channel balance */ | ||
178 | #define OV7610_REG_SAT 0x03 /* saturation */ | ||
179 | /* 04 reserved */ | ||
180 | #define OV7610_REG_CNT 0x05 /* Y contrast */ | ||
181 | #define OV7610_REG_BRT 0x06 /* Y brightness */ | ||
182 | /* 08-0b reserved */ | ||
183 | #define OV7610_REG_BLUE_BIAS 0x0C /* blue channel bias (5:0) */ | ||
184 | #define OV7610_REG_RED_BIAS 0x0D /* read channel bias (5:0) */ | ||
185 | #define OV7610_REG_GAMMA_COEFF 0x0E /* gamma settings */ | ||
186 | #define OV7610_REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */ | ||
187 | #define OV7610_REG_EXP 0x10 /* manual exposure setting */ | ||
188 | #define OV7610_REG_CLOCK 0x11 /* polarity/clock prescaler */ | ||
189 | #define OV7610_REG_COM_A 0x12 /* misc common regs */ | ||
190 | #define OV7610_REG_COM_B 0x13 /* misc common regs */ | ||
191 | #define OV7610_REG_COM_C 0x14 /* misc common regs */ | ||
192 | #define OV7610_REG_COM_D 0x15 /* misc common regs */ | ||
193 | #define OV7610_REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */ | ||
194 | #define OV7610_REG_HWIN_START 0x17 /* horizontal window start */ | ||
195 | #define OV7610_REG_HWIN_END 0x18 /* horizontal window end */ | ||
196 | #define OV7610_REG_VWIN_START 0x19 /* vertical window start */ | ||
197 | #define OV7610_REG_VWIN_END 0x1A /* vertical window end */ | ||
198 | #define OV7610_REG_PIXEL_SHIFT 0x1B /* pixel shift */ | ||
199 | #define OV7610_REG_ID_HIGH 0x1C /* manufacturer ID MSB */ | ||
200 | #define OV7610_REG_ID_LOW 0x1D /* manufacturer ID LSB */ | ||
201 | /* 0e-0f reserved */ | ||
202 | #define OV7610_REG_COM_E 0x20 /* misc common regs */ | ||
203 | #define OV7610_REG_YOFFSET 0x21 /* Y channel offset */ | ||
204 | #define OV7610_REG_UOFFSET 0x22 /* U channel offset */ | ||
205 | /* 23 reserved */ | ||
206 | #define OV7610_REG_ECW 0x24 /* Exposure white level for AEC */ | ||
207 | #define OV7610_REG_ECB 0x25 /* Exposure black level for AEC */ | ||
208 | #define OV7610_REG_COM_F 0x26 /* misc settings */ | ||
209 | #define OV7610_REG_COM_G 0x27 /* misc settings */ | ||
210 | #define OV7610_REG_COM_H 0x28 /* misc settings */ | ||
211 | #define OV7610_REG_COM_I 0x29 /* misc settings */ | ||
212 | #define OV7610_REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */ | ||
213 | #define OV7610_REG_FRAMERATE_L 0x2B /* frame rate LSB */ | ||
214 | #define OV7610_REG_ALC 0x2C /* Auto Level Control settings */ | ||
215 | #define OV7610_REG_COM_J 0x2D /* misc settings */ | ||
216 | #define OV7610_REG_VOFFSET 0x2E /* V channel offset adjustment */ | ||
217 | #define OV7610_REG_ARRAY_BIAS 0x2F /* Array bias -- don't change */ | ||
218 | /* 30-32 reserved */ | ||
219 | #define OV7610_REG_YGAMMA 0x33 /* misc gamma settings (7:6) */ | ||
220 | #define OV7610_REG_BIAS_ADJUST 0x34 /* misc bias settings */ | ||
221 | #define OV7610_REG_COM_L 0x35 /* misc settings */ | ||
222 | /* 36-37 reserved */ | ||
223 | #define OV7610_REG_COM_K 0x38 /* misc registers */ | ||
224 | |||
225 | /* --------------------------------- */ | ||
226 | /* I2C ADDRESSES */ | ||
227 | /* --------------------------------- */ | ||
228 | |||
229 | #define OV7xx0_SID 0x42 | ||
230 | #define OV6xx0_SID 0xC0 | ||
231 | #define OV8xx0_SID 0xA0 | ||
232 | #define KS0127_SID 0xD8 | ||
233 | #define SAA7111A_SID 0x48 | ||
234 | |||
235 | /* --------------------------------- */ | ||
236 | /* MISCELLANEOUS DEFINES */ | ||
237 | /* --------------------------------- */ | ||
238 | |||
239 | #define I2C_CLOCK_PRESCALER 0x03 | ||
240 | |||
241 | #define FRAMES_PER_DESC 10 /* FIXME - What should this be? */ | ||
242 | #define MAX_FRAME_SIZE_PER_DESC 993 /* For statically allocated stuff */ | ||
243 | #define PIXELS_PER_SEG 256 /* Pixels per segment */ | ||
244 | |||
245 | #define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ | ||
246 | |||
247 | #define OV511_NUMFRAMES 2 | ||
248 | #if OV511_NUMFRAMES > VIDEO_MAX_FRAME | ||
249 | #error "OV511_NUMFRAMES is too high" | ||
250 | #endif | ||
251 | |||
252 | #define OV511_NUMSBUF 2 | ||
253 | |||
254 | /* Control transfers use up to 4 bytes */ | ||
255 | #define OV511_CBUF_SIZE 4 | ||
256 | |||
257 | /* Size of usb_make_path() buffer */ | ||
258 | #define OV511_USB_PATH_LEN 64 | ||
259 | |||
260 | /* Bridge types */ | ||
261 | enum { | ||
262 | BRG_UNKNOWN, | ||
263 | BRG_OV511, | ||
264 | BRG_OV511PLUS, | ||
265 | BRG_OV518, | ||
266 | BRG_OV518PLUS, | ||
267 | }; | ||
268 | |||
269 | /* Bridge classes */ | ||
270 | enum { | ||
271 | BCL_UNKNOWN, | ||
272 | BCL_OV511, | ||
273 | BCL_OV518, | ||
274 | }; | ||
275 | |||
276 | /* Sensor types */ | ||
277 | enum { | ||
278 | SEN_UNKNOWN, | ||
279 | SEN_OV76BE, | ||
280 | SEN_OV7610, | ||
281 | SEN_OV7620, | ||
282 | SEN_OV7620AE, | ||
283 | SEN_OV6620, | ||
284 | SEN_OV6630, | ||
285 | SEN_OV6630AE, | ||
286 | SEN_OV6630AF, | ||
287 | SEN_OV8600, | ||
288 | SEN_KS0127, | ||
289 | SEN_KS0127B, | ||
290 | SEN_SAA7111A, | ||
291 | }; | ||
292 | |||
293 | enum { | ||
294 | STATE_SCANNING, /* Scanning for start */ | ||
295 | STATE_HEADER, /* Parsing header */ | ||
296 | STATE_LINES, /* Parsing lines */ | ||
297 | }; | ||
298 | |||
299 | /* Buffer states */ | ||
300 | enum { | ||
301 | BUF_NOT_ALLOCATED, | ||
302 | BUF_ALLOCATED, | ||
303 | }; | ||
304 | |||
305 | /* --------- Definition of ioctl interface --------- */ | ||
306 | |||
307 | #define OV511_INTERFACE_VER 101 | ||
308 | |||
309 | /* LED options */ | ||
310 | enum { | ||
311 | LED_OFF, | ||
312 | LED_ON, | ||
313 | LED_AUTO, | ||
314 | }; | ||
315 | |||
316 | /* Raw frame formats */ | ||
317 | enum { | ||
318 | RAWFMT_INVALID, | ||
319 | RAWFMT_YUV400, | ||
320 | RAWFMT_YUV420, | ||
321 | RAWFMT_YUV422, | ||
322 | RAWFMT_GBR422, | ||
323 | }; | ||
324 | |||
325 | struct ov511_i2c_struct { | ||
326 | unsigned char slave; /* Write slave ID (read ID - 1) */ | ||
327 | unsigned char reg; /* Index of register */ | ||
328 | unsigned char value; /* User sets this w/ write, driver does w/ read */ | ||
329 | unsigned char mask; /* Bits to be changed. Not used with read ops */ | ||
330 | }; | ||
331 | |||
332 | /* ioctls */ | ||
333 | #define OV511IOC_WI2C _IOW('v', BASE_VIDIOCPRIVATE + 5, \ | ||
334 | struct ov511_i2c_struct) | ||
335 | #define OV511IOC_RI2C _IOWR('v', BASE_VIDIOCPRIVATE + 6, \ | ||
336 | struct ov511_i2c_struct) | ||
337 | /* ------------- End IOCTL interface -------------- */ | ||
338 | |||
339 | struct usb_ov511; /* Forward declaration */ | ||
340 | |||
341 | struct ov511_sbuf { | ||
342 | struct usb_ov511 *ov; | ||
343 | unsigned char *data; | ||
344 | struct urb *urb; | ||
345 | spinlock_t lock; | ||
346 | int n; | ||
347 | }; | ||
348 | |||
349 | enum { | ||
350 | FRAME_UNUSED, /* Unused (no MCAPTURE) */ | ||
351 | FRAME_READY, /* Ready to start grabbing */ | ||
352 | FRAME_GRABBING, /* In the process of being grabbed into */ | ||
353 | FRAME_DONE, /* Finished grabbing, but not been synced yet */ | ||
354 | FRAME_ERROR, /* Something bad happened while processing */ | ||
355 | }; | ||
356 | |||
357 | struct ov511_regvals { | ||
358 | enum { | ||
359 | OV511_DONE_BUS, | ||
360 | OV511_REG_BUS, | ||
361 | OV511_I2C_BUS, | ||
362 | } bus; | ||
363 | unsigned char reg; | ||
364 | unsigned char val; | ||
365 | }; | ||
366 | |||
367 | struct ov511_frame { | ||
368 | int framenum; /* Index of this frame */ | ||
369 | unsigned char *data; /* Frame buffer */ | ||
370 | unsigned char *tempdata; /* Temp buffer for multi-stage conversions */ | ||
371 | unsigned char *rawdata; /* Raw camera data buffer */ | ||
372 | unsigned char *compbuf; /* Temp buffer for decompressor */ | ||
373 | |||
374 | int depth; /* Bytes per pixel */ | ||
375 | int width; /* Width application is expecting */ | ||
376 | int height; /* Height application is expecting */ | ||
377 | |||
378 | int rawwidth; /* Actual width of frame sent from camera */ | ||
379 | int rawheight; /* Actual height of frame sent from camera */ | ||
380 | |||
381 | int sub_flag; /* Sub-capture mode for this frame? */ | ||
382 | unsigned int format; /* Format for this frame */ | ||
383 | int compressed; /* Is frame compressed? */ | ||
384 | |||
385 | volatile int grabstate; /* State of grabbing */ | ||
386 | int scanstate; /* State of scanning */ | ||
387 | |||
388 | int bytes_recvd; /* Number of image bytes received from camera */ | ||
389 | |||
390 | long bytes_read; /* Amount that has been read() */ | ||
391 | |||
392 | wait_queue_head_t wq; /* Processes waiting */ | ||
393 | |||
394 | int snapshot; /* True if frame was a snapshot */ | ||
395 | }; | ||
396 | |||
397 | #define DECOMP_INTERFACE_VER 4 | ||
398 | |||
399 | /* Compression module operations */ | ||
400 | struct ov51x_decomp_ops { | ||
401 | int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *, | ||
402 | int, int, int); | ||
403 | int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *, | ||
404 | int, int, int); | ||
405 | int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *, | ||
406 | int, int, int); | ||
407 | struct module *owner; | ||
408 | }; | ||
409 | |||
410 | struct usb_ov511 { | ||
411 | struct video_device *vdev; | ||
412 | struct usb_device *dev; | ||
413 | |||
414 | int customid; | ||
415 | char *desc; | ||
416 | unsigned char iface; | ||
417 | char usb_path[OV511_USB_PATH_LEN]; | ||
418 | |||
419 | /* Determined by sensor type */ | ||
420 | int maxwidth; | ||
421 | int maxheight; | ||
422 | int minwidth; | ||
423 | int minheight; | ||
424 | |||
425 | int brightness; | ||
426 | int colour; | ||
427 | int contrast; | ||
428 | int hue; | ||
429 | int whiteness; | ||
430 | int exposure; | ||
431 | int auto_brt; /* Auto brightness enabled flag */ | ||
432 | int auto_gain; /* Auto gain control enabled flag */ | ||
433 | int auto_exp; /* Auto exposure enabled flag */ | ||
434 | int backlight; /* Backlight exposure algorithm flag */ | ||
435 | int mirror; /* Image is reversed horizontally */ | ||
436 | |||
437 | int led_policy; /* LED: off|on|auto; OV511+ only */ | ||
438 | |||
439 | struct mutex lock; /* Serializes user-accessible operations */ | ||
440 | int user; /* user count for exclusive use */ | ||
441 | |||
442 | int streaming; /* Are we streaming Isochronous? */ | ||
443 | int grabbing; /* Are we grabbing? */ | ||
444 | |||
445 | int compress; /* Should the next frame be compressed? */ | ||
446 | int compress_inited; /* Are compression params uploaded? */ | ||
447 | |||
448 | int lightfreq; /* Power (lighting) frequency */ | ||
449 | int bandfilt; /* Banding filter enabled flag */ | ||
450 | |||
451 | unsigned char *fbuf; /* Videodev buffer area */ | ||
452 | unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */ | ||
453 | unsigned char *rawfbuf; /* Raw camera data buffer area */ | ||
454 | |||
455 | int sub_flag; /* Pix Array subcapture on flag */ | ||
456 | int subx; /* Pix Array subcapture x offset */ | ||
457 | int suby; /* Pix Array subcapture y offset */ | ||
458 | int subw; /* Pix Array subcapture width */ | ||
459 | int subh; /* Pix Array subcapture height */ | ||
460 | |||
461 | int curframe; /* Current receiving sbuf */ | ||
462 | struct ov511_frame frame[OV511_NUMFRAMES]; | ||
463 | |||
464 | struct ov511_sbuf sbuf[OV511_NUMSBUF]; | ||
465 | |||
466 | wait_queue_head_t wq; /* Processes waiting */ | ||
467 | |||
468 | int snap_enabled; /* Snapshot mode enabled */ | ||
469 | |||
470 | int bridge; /* Type of bridge (BRG_*) */ | ||
471 | int bclass; /* Class of bridge (BCL_*) */ | ||
472 | int sensor; /* Type of image sensor chip (SEN_*) */ | ||
473 | |||
474 | int packet_size; /* Frame size per isoc desc */ | ||
475 | int packet_numbering; /* Is ISO frame numbering enabled? */ | ||
476 | |||
477 | /* Framebuffer/sbuf management */ | ||
478 | int buf_state; | ||
479 | struct mutex buf_lock; | ||
480 | |||
481 | struct ov51x_decomp_ops *decomp_ops; | ||
482 | |||
483 | /* Stop streaming while changing picture settings */ | ||
484 | int stop_during_set; | ||
485 | |||
486 | int stopped; /* Streaming is temporarily paused */ | ||
487 | |||
488 | /* Video decoder stuff */ | ||
489 | int input; /* Composite, S-VIDEO, etc... */ | ||
490 | int num_inputs; /* Number of inputs */ | ||
491 | int norm; /* NTSC / PAL / SECAM */ | ||
492 | int has_decoder; /* Device has a video decoder */ | ||
493 | int pal; /* Device is designed for PAL resolution */ | ||
494 | |||
495 | /* I2C interface */ | ||
496 | struct mutex i2c_lock; /* Protect I2C controller regs */ | ||
497 | unsigned char primary_i2c_slave; /* I2C write id of sensor */ | ||
498 | |||
499 | /* Control transaction stuff */ | ||
500 | unsigned char *cbuf; /* Buffer for payload */ | ||
501 | struct mutex cbuf_lock; | ||
502 | }; | ||
503 | |||
504 | /* Used to represent a list of values and their respective symbolic names */ | ||
505 | struct symbolic_list { | ||
506 | int num; | ||
507 | char *name; | ||
508 | }; | ||
509 | |||
510 | #define NOT_DEFINED_STR "Unknown" | ||
511 | |||
512 | /* Returns the name of the matching element in the symbolic_list array. The | ||
513 | * end of the list must be marked with an element that has a NULL name. | ||
514 | */ | ||
515 | static inline char * | ||
516 | symbolic(struct symbolic_list list[], int num) | ||
517 | { | ||
518 | int i; | ||
519 | |||
520 | for (i = 0; list[i].name != NULL; i++) | ||
521 | if (list[i].num == num) | ||
522 | return (list[i].name); | ||
523 | |||
524 | return (NOT_DEFINED_STR); | ||
525 | } | ||
526 | |||
527 | /* Compression stuff */ | ||
528 | |||
529 | #define OV511_QUANTABLESIZE 64 | ||
530 | #define OV518_QUANTABLESIZE 32 | ||
531 | |||
532 | #define OV511_YQUANTABLE { \ | ||
533 | 0, 1, 1, 2, 2, 3, 3, 4, \ | ||
534 | 1, 1, 1, 2, 2, 3, 4, 4, \ | ||
535 | 1, 1, 2, 2, 3, 4, 4, 4, \ | ||
536 | 2, 2, 2, 3, 4, 4, 4, 4, \ | ||
537 | 2, 2, 3, 4, 4, 5, 5, 5, \ | ||
538 | 3, 3, 4, 4, 5, 5, 5, 5, \ | ||
539 | 3, 4, 4, 4, 5, 5, 5, 5, \ | ||
540 | 4, 4, 4, 4, 5, 5, 5, 5 \ | ||
541 | } | ||
542 | |||
543 | #define OV511_UVQUANTABLE { \ | ||
544 | 0, 2, 2, 3, 4, 4, 4, 4, \ | ||
545 | 2, 2, 2, 4, 4, 4, 4, 4, \ | ||
546 | 2, 2, 3, 4, 4, 4, 4, 4, \ | ||
547 | 3, 4, 4, 4, 4, 4, 4, 4, \ | ||
548 | 4, 4, 4, 4, 4, 4, 4, 4, \ | ||
549 | 4, 4, 4, 4, 4, 4, 4, 4, \ | ||
550 | 4, 4, 4, 4, 4, 4, 4, 4, \ | ||
551 | 4, 4, 4, 4, 4, 4, 4, 4 \ | ||
552 | } | ||
553 | |||
554 | #define OV518_YQUANTABLE { \ | ||
555 | 5, 4, 5, 6, 6, 7, 7, 7, \ | ||
556 | 5, 5, 5, 5, 6, 7, 7, 7, \ | ||
557 | 6, 6, 6, 6, 7, 7, 7, 8, \ | ||
558 | 7, 7, 6, 7, 7, 7, 8, 8 \ | ||
559 | } | ||
560 | |||
561 | #define OV518_UVQUANTABLE { \ | ||
562 | 6, 6, 6, 7, 7, 7, 7, 7, \ | ||
563 | 6, 6, 6, 7, 7, 7, 7, 7, \ | ||
564 | 6, 6, 6, 7, 7, 7, 7, 8, \ | ||
565 | 7, 7, 7, 7, 7, 7, 8, 8 \ | ||
566 | } | ||
567 | |||
568 | #endif | ||
diff --git a/drivers/media/video/pwc/Makefile b/drivers/media/video/pwc/Makefile new file mode 100644 index 000000000000..2d93a775011a --- /dev/null +++ b/drivers/media/video/pwc/Makefile | |||
@@ -0,0 +1,20 @@ | |||
1 | ifneq ($(KERNELRELEASE),) | ||
2 | |||
3 | pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o | ||
4 | |||
5 | obj-$(CONFIG_USB_PWC) += pwc.o | ||
6 | |||
7 | else | ||
8 | |||
9 | KDIR := /lib/modules/$(shell uname -r)/build | ||
10 | PWD := $(shell pwd) | ||
11 | |||
12 | default: | ||
13 | $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules | ||
14 | |||
15 | endif | ||
16 | |||
17 | clean: | ||
18 | rm -f *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c | ||
19 | rm -rf .tmp_versions | ||
20 | |||
diff --git a/drivers/media/video/pwc/philips.txt b/drivers/media/video/pwc/philips.txt new file mode 100644 index 000000000000..04a640d723ed --- /dev/null +++ b/drivers/media/video/pwc/philips.txt | |||
@@ -0,0 +1,236 @@ | |||
1 | This file contains some additional information for the Philips and OEM webcams. | ||
2 | E-mail: webcam@smcc.demon.nl Last updated: 2004-01-19 | ||
3 | Site: http://www.smcc.demon.nl/webcam/ | ||
4 | |||
5 | As of this moment, the following cameras are supported: | ||
6 | * Philips PCA645 | ||
7 | * Philips PCA646 | ||
8 | * Philips PCVC675 | ||
9 | * Philips PCVC680 | ||
10 | * Philips PCVC690 | ||
11 | * Philips PCVC720/40 | ||
12 | * Philips PCVC730 | ||
13 | * Philips PCVC740 | ||
14 | * Philips PCVC750 | ||
15 | * Askey VC010 | ||
16 | * Creative Labs Webcam 5 | ||
17 | * Creative Labs Webcam Pro Ex | ||
18 | * Logitech QuickCam 3000 Pro | ||
19 | * Logitech QuickCam 4000 Pro | ||
20 | * Logitech QuickCam Notebook Pro | ||
21 | * Logitech QuickCam Zoom | ||
22 | * Logitech QuickCam Orbit | ||
23 | * Logitech QuickCam Sphere | ||
24 | * Samsung MPC-C10 | ||
25 | * Samsung MPC-C30 | ||
26 | * Sotec Afina Eye | ||
27 | * AME CU-001 | ||
28 | * Visionite VCS-UM100 | ||
29 | * Visionite VCS-UC300 | ||
30 | |||
31 | The main webpage for the Philips driver is at the address above. It contains | ||
32 | a lot of extra information, a FAQ, and the binary plugin 'PWCX'. This plugin | ||
33 | contains decompression routines that allow you to use higher image sizes and | ||
34 | framerates; in addition the webcam uses less bandwidth on the USB bus (handy | ||
35 | if you want to run more than 1 camera simultaneously). These routines fall | ||
36 | under a NDA, and may therefor not be distributed as source; however, its use | ||
37 | is completely optional. | ||
38 | |||
39 | You can build this code either into your kernel, or as a module. I recommend | ||
40 | the latter, since it makes troubleshooting a lot easier. The built-in | ||
41 | microphone is supported through the USB Audio class. | ||
42 | |||
43 | When you load the module you can set some default settings for the | ||
44 | camera; some programs depend on a particular image-size or -format and | ||
45 | don't know how to set it properly in the driver. The options are: | ||
46 | |||
47 | size | ||
48 | Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or | ||
49 | 'vga', for an image size of resp. 128x96, 160x120, 176x144, | ||
50 | 320x240, 352x288 and 640x480 (of course, only for those cameras that | ||
51 | support these resolutions). | ||
52 | |||
53 | fps | ||
54 | Specifies the desired framerate. Is an integer in the range of 4-30. | ||
55 | |||
56 | fbufs | ||
57 | This paramter specifies the number of internal buffers to use for storing | ||
58 | frames from the cam. This will help if the process that reads images from | ||
59 | the cam is a bit slow or momentarely busy. However, on slow machines it | ||
60 | only introduces lag, so choose carefully. The default is 3, which is | ||
61 | reasonable. You can set it between 2 and 5. | ||
62 | |||
63 | mbufs | ||
64 | This is an integer between 1 and 10. It will tell the module the number of | ||
65 | buffers to reserve for mmap(), VIDIOCCGMBUF, VIDIOCMCAPTURE and friends. | ||
66 | The default is 2, which is adequate for most applications (double | ||
67 | buffering). | ||
68 | |||
69 | Should you experience a lot of 'Dumping frame...' messages during | ||
70 | grabbing with a tool that uses mmap(), you might want to increase if. | ||
71 | However, it doesn't really buffer images, it just gives you a bit more | ||
72 | slack when your program is behind. But you need a multi-threaded or | ||
73 | forked program to really take advantage of these buffers. | ||
74 | |||
75 | The absolute maximum is 10, but don't set it too high! Every buffer takes | ||
76 | up 460 KB of RAM, so unless you have a lot of memory setting this to | ||
77 | something more than 4 is an absolute waste. This memory is only | ||
78 | allocated during open(), so nothing is wasted when the camera is not in | ||
79 | use. | ||
80 | |||
81 | power_save | ||
82 | When power_save is enabled (set to 1), the module will try to shut down | ||
83 | the cam on close() and re-activate on open(). This will save power and | ||
84 | turn off the LED. Not all cameras support this though (the 645 and 646 | ||
85 | don't have power saving at all), and some models don't work either (they | ||
86 | will shut down, but never wake up). Consider this experimental. By | ||
87 | default this option is disabled. | ||
88 | |||
89 | compression (only useful with the plugin) | ||
90 | With this option you can control the compression factor that the camera | ||
91 | uses to squeeze the image through the USB bus. You can set the | ||
92 | parameter between 0 and 3: | ||
93 | 0 = prefer uncompressed images; if the requested mode is not available | ||
94 | in an uncompressed format, the driver will silently switch to low | ||
95 | compression. | ||
96 | 1 = low compression. | ||
97 | 2 = medium compression. | ||
98 | 3 = high compression. | ||
99 | |||
100 | High compression takes less bandwidth of course, but it could also | ||
101 | introduce some unwanted artefacts. The default is 2, medium compression. | ||
102 | See the FAQ on the website for an overview of which modes require | ||
103 | compression. | ||
104 | |||
105 | The compression parameter does not apply to the 645 and 646 cameras | ||
106 | and OEM models derived from those (only a few). Most cams honour this | ||
107 | parameter. | ||
108 | |||
109 | leds | ||
110 | This settings takes 2 integers, that define the on/off time for the LED | ||
111 | (in milliseconds). One of the interesting things that you can do with | ||
112 | this is let the LED blink while the camera is in use. This: | ||
113 | |||
114 | leds=500,500 | ||
115 | |||
116 | will blink the LED once every second. But with: | ||
117 | |||
118 | leds=0,0 | ||
119 | |||
120 | the LED never goes on, making it suitable for silent surveillance. | ||
121 | |||
122 | By default the camera's LED is on solid while in use, and turned off | ||
123 | when the camera is not used anymore. | ||
124 | |||
125 | This parameter works only with the ToUCam range of cameras (720, 730, 740, | ||
126 | 750) and OEMs. For other cameras this command is silently ignored, and | ||
127 | the LED cannot be controlled. | ||
128 | |||
129 | Finally: this parameters does not take effect UNTIL the first time you | ||
130 | open the camera device. Until then, the LED remains on. | ||
131 | |||
132 | dev_hint | ||
133 | A long standing problem with USB devices is their dynamic nature: you | ||
134 | never know what device a camera gets assigned; it depends on module load | ||
135 | order, the hub configuration, the order in which devices are plugged in, | ||
136 | and the phase of the moon (i.e. it can be random). With this option you | ||
137 | can give the driver a hint as to what video device node (/dev/videoX) it | ||
138 | should use with a specific camera. This is also handy if you have two | ||
139 | cameras of the same model. | ||
140 | |||
141 | A camera is specified by its type (the number from the camera model, | ||
142 | like PCA645, PCVC750VC, etc) and optionally the serial number (visible | ||
143 | in /proc/bus/usb/devices). A hint consists of a string with the following | ||
144 | format: | ||
145 | |||
146 | [type[.serialnumber]:]node | ||
147 | |||
148 | The square brackets mean that both the type and the serialnumber are | ||
149 | optional, but a serialnumber cannot be specified without a type (which | ||
150 | would be rather pointless). The serialnumber is separated from the type | ||
151 | by a '.'; the node number by a ':'. | ||
152 | |||
153 | This somewhat cryptic syntax is best explained by a few examples: | ||
154 | |||
155 | dev_hint=3,5 The first detected cam gets assigned | ||
156 | /dev/video3, the second /dev/video5. Any | ||
157 | other cameras will get the first free | ||
158 | available slot (see below). | ||
159 | |||
160 | dev_hint=645:1,680:2 The PCA645 camera will get /dev/video1, | ||
161 | and a PCVC680 /dev/video2. | ||
162 | |||
163 | dev_hint=645.0123:3,645.4567:0 The PCA645 camera with serialnumber | ||
164 | 0123 goes to /dev/video3, the same | ||
165 | camera model with the 4567 serial | ||
166 | gets /dev/video0. | ||
167 | |||
168 | dev_hint=750:1,4,5,6 The PCVC750 camera will get /dev/video1, the | ||
169 | next 3 Philips cams will use /dev/video4 | ||
170 | through /dev/video6. | ||
171 | |||
172 | Some points worth knowing: | ||
173 | - Serialnumbers are case sensitive and must be written full, including | ||
174 | leading zeroes (it's treated as a string). | ||
175 | - If a device node is already occupied, registration will fail and | ||
176 | the webcam is not available. | ||
177 | - You can have up to 64 video devices; be sure to make enough device | ||
178 | nodes in /dev if you want to spread the numbers (this does not apply | ||
179 | to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA). | ||
180 | - If a camera does not match any dev_hint, it will simply get assigned | ||
181 | the first available device node, just as it used to be. | ||
182 | |||
183 | trace | ||
184 | In order to better detect problems, it is now possible to turn on a | ||
185 | 'trace' of some of the calls the module makes; it logs all items in your | ||
186 | kernel log at debug level. | ||
187 | |||
188 | The trace variable is a bitmask; each bit represents a certain feature. | ||
189 | If you want to trace something, look up the bit value(s) in the table | ||
190 | below, add the values together and supply that to the trace variable. | ||
191 | |||
192 | Value Value Description Default | ||
193 | (dec) (hex) | ||
194 | 1 0x1 Module initialization; this will log messages On | ||
195 | while loading and unloading the module | ||
196 | |||
197 | 2 0x2 probe() and disconnect() traces On | ||
198 | |||
199 | 4 0x4 Trace open() and close() calls Off | ||
200 | |||
201 | 8 0x8 read(), mmap() and associated ioctl() calls Off | ||
202 | |||
203 | 16 0x10 Memory allocation of buffers, etc. Off | ||
204 | |||
205 | 32 0x20 Showing underflow, overflow and Dumping frame On | ||
206 | messages | ||
207 | |||
208 | 64 0x40 Show viewport and image sizes Off | ||
209 | |||
210 | 128 0x80 PWCX debugging Off | ||
211 | |||
212 | For example, to trace the open() & read() fuctions, sum 8 + 4 = 12, | ||
213 | so you would supply trace=12 during insmod or modprobe. If | ||
214 | you want to turn the initialization and probing tracing off, set trace=0. | ||
215 | The default value for trace is 35 (0x23). | ||
216 | |||
217 | |||
218 | |||
219 | Example: | ||
220 | |||
221 | # modprobe pwc size=cif fps=15 power_save=1 | ||
222 | |||
223 | The fbufs, mbufs and trace parameters are global and apply to all connected | ||
224 | cameras. Each camera has its own set of buffers. | ||
225 | |||
226 | size and fps only specify defaults when you open() the device; this is to | ||
227 | accommodate some tools that don't set the size. You can change these | ||
228 | settings after open() with the Video4Linux ioctl() calls. The default of | ||
229 | defaults is QCIF size at 10 fps. | ||
230 | |||
231 | The compression parameter is semiglobal; it sets the initial compression | ||
232 | preference for all camera's, but this parameter can be set per camera with | ||
233 | the VIDIOCPWCSCQUAL ioctl() call. | ||
234 | |||
235 | All parameters are optional. | ||
236 | |||
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c new file mode 100644 index 000000000000..0398b812e0ce --- /dev/null +++ b/drivers/media/video/pwc/pwc-ctrl.c | |||
@@ -0,0 +1,1541 @@ | |||
1 | /* Driver for Philips webcam | ||
2 | Functions that send various control messages to the webcam, including | ||
3 | video modes. | ||
4 | (C) 1999-2003 Nemosoft Unv. | ||
5 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
6 | |||
7 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
8 | driver and thus may have bugs that are not present in the original version. | ||
9 | Please send bug reports and support requests to <luc@saillard.org>. | ||
10 | |||
11 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
12 | driver and thus may have bugs that are not present in the original version. | ||
13 | Please send bug reports and support requests to <luc@saillard.org>. | ||
14 | The decompression routines have been implemented by reverse-engineering the | ||
15 | Nemosoft binary pwcx module. Caveat emptor. | ||
16 | |||
17 | This program is free software; you can redistribute it and/or modify | ||
18 | it under the terms of the GNU General Public License as published by | ||
19 | the Free Software Foundation; either version 2 of the License, or | ||
20 | (at your option) any later version. | ||
21 | |||
22 | This program is distributed in the hope that it will be useful, | ||
23 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
25 | GNU General Public License for more details. | ||
26 | |||
27 | You should have received a copy of the GNU General Public License | ||
28 | along with this program; if not, write to the Free Software | ||
29 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
30 | */ | ||
31 | |||
32 | /* | ||
33 | Changes | ||
34 | 2001/08/03 Alvarado Added methods for changing white balance and | ||
35 | red/green gains | ||
36 | */ | ||
37 | |||
38 | /* Control functions for the cam; brightness, contrast, video mode, etc. */ | ||
39 | |||
40 | #ifdef __KERNEL__ | ||
41 | #include <asm/uaccess.h> | ||
42 | #endif | ||
43 | #include <asm/errno.h> | ||
44 | |||
45 | #include "pwc.h" | ||
46 | #include "pwc-ioctl.h" | ||
47 | #include "pwc-uncompress.h" | ||
48 | #include "pwc-kiara.h" | ||
49 | #include "pwc-timon.h" | ||
50 | |||
51 | /* Request types: video */ | ||
52 | #define SET_LUM_CTL 0x01 | ||
53 | #define GET_LUM_CTL 0x02 | ||
54 | #define SET_CHROM_CTL 0x03 | ||
55 | #define GET_CHROM_CTL 0x04 | ||
56 | #define SET_STATUS_CTL 0x05 | ||
57 | #define GET_STATUS_CTL 0x06 | ||
58 | #define SET_EP_STREAM_CTL 0x07 | ||
59 | #define GET_EP_STREAM_CTL 0x08 | ||
60 | #define SET_MPT_CTL 0x0D | ||
61 | #define GET_MPT_CTL 0x0E | ||
62 | |||
63 | /* Selectors for the Luminance controls [GS]ET_LUM_CTL */ | ||
64 | #define AGC_MODE_FORMATTER 0x2000 | ||
65 | #define PRESET_AGC_FORMATTER 0x2100 | ||
66 | #define SHUTTER_MODE_FORMATTER 0x2200 | ||
67 | #define PRESET_SHUTTER_FORMATTER 0x2300 | ||
68 | #define PRESET_CONTOUR_FORMATTER 0x2400 | ||
69 | #define AUTO_CONTOUR_FORMATTER 0x2500 | ||
70 | #define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600 | ||
71 | #define CONTRAST_FORMATTER 0x2700 | ||
72 | #define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800 | ||
73 | #define FLICKERLESS_MODE_FORMATTER 0x2900 | ||
74 | #define AE_CONTROL_SPEED 0x2A00 | ||
75 | #define BRIGHTNESS_FORMATTER 0x2B00 | ||
76 | #define GAMMA_FORMATTER 0x2C00 | ||
77 | |||
78 | /* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ | ||
79 | #define WB_MODE_FORMATTER 0x1000 | ||
80 | #define AWB_CONTROL_SPEED_FORMATTER 0x1100 | ||
81 | #define AWB_CONTROL_DELAY_FORMATTER 0x1200 | ||
82 | #define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300 | ||
83 | #define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400 | ||
84 | #define COLOUR_MODE_FORMATTER 0x1500 | ||
85 | #define SATURATION_MODE_FORMATTER1 0x1600 | ||
86 | #define SATURATION_MODE_FORMATTER2 0x1700 | ||
87 | |||
88 | /* Selectors for the Status controls [GS]ET_STATUS_CTL */ | ||
89 | #define SAVE_USER_DEFAULTS_FORMATTER 0x0200 | ||
90 | #define RESTORE_USER_DEFAULTS_FORMATTER 0x0300 | ||
91 | #define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400 | ||
92 | #define READ_AGC_FORMATTER 0x0500 | ||
93 | #define READ_SHUTTER_FORMATTER 0x0600 | ||
94 | #define READ_RED_GAIN_FORMATTER 0x0700 | ||
95 | #define READ_BLUE_GAIN_FORMATTER 0x0800 | ||
96 | #define SENSOR_TYPE_FORMATTER1 0x0C00 | ||
97 | #define READ_RAW_Y_MEAN_FORMATTER 0x3100 | ||
98 | #define SET_POWER_SAVE_MODE_FORMATTER 0x3200 | ||
99 | #define MIRROR_IMAGE_FORMATTER 0x3300 | ||
100 | #define LED_FORMATTER 0x3400 | ||
101 | #define SENSOR_TYPE_FORMATTER2 0x3700 | ||
102 | |||
103 | /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ | ||
104 | #define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 | ||
105 | |||
106 | /* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */ | ||
107 | #define PT_RELATIVE_CONTROL_FORMATTER 0x01 | ||
108 | #define PT_RESET_CONTROL_FORMATTER 0x02 | ||
109 | #define PT_STATUS_FORMATTER 0x03 | ||
110 | |||
111 | static const char *size2name[PSZ_MAX] = | ||
112 | { | ||
113 | "subQCIF", | ||
114 | "QSIF", | ||
115 | "QCIF", | ||
116 | "SIF", | ||
117 | "CIF", | ||
118 | "VGA", | ||
119 | }; | ||
120 | |||
121 | /********/ | ||
122 | |||
123 | /* Entries for the Nala (645/646) camera; the Nala doesn't have compression | ||
124 | preferences, so you either get compressed or non-compressed streams. | ||
125 | |||
126 | An alternate value of 0 means this mode is not available at all. | ||
127 | */ | ||
128 | |||
129 | struct Nala_table_entry { | ||
130 | char alternate; /* USB alternate setting */ | ||
131 | int compressed; /* Compressed yes/no */ | ||
132 | |||
133 | unsigned char mode[3]; /* precomputed mode table */ | ||
134 | }; | ||
135 | |||
136 | static struct Nala_table_entry Nala_table[PSZ_MAX][8] = | ||
137 | { | ||
138 | #include "pwc-nala.h" | ||
139 | }; | ||
140 | |||
141 | |||
142 | /****************************************************************************/ | ||
143 | |||
144 | |||
145 | #define SendControlMsg(request, value, buflen) \ | ||
146 | usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \ | ||
147 | request, \ | ||
148 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ | ||
149 | value, \ | ||
150 | pdev->vcinterface, \ | ||
151 | &buf, buflen, 500) | ||
152 | |||
153 | #define RecvControlMsg(request, value, buflen) \ | ||
154 | usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \ | ||
155 | request, \ | ||
156 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ | ||
157 | value, \ | ||
158 | pdev->vcinterface, \ | ||
159 | &buf, buflen, 500) | ||
160 | |||
161 | |||
162 | #if PWC_DEBUG | ||
163 | void pwc_hexdump(void *p, int len) | ||
164 | { | ||
165 | int i; | ||
166 | unsigned char *s; | ||
167 | char buf[100], *d; | ||
168 | |||
169 | s = (unsigned char *)p; | ||
170 | d = buf; | ||
171 | *d = '\0'; | ||
172 | Debug("Doing hexdump @ %p, %d bytes.\n", p, len); | ||
173 | for (i = 0; i < len; i++) { | ||
174 | d += sprintf(d, "%02X ", *s++); | ||
175 | if ((i & 0xF) == 0xF) { | ||
176 | Debug("%s\n", buf); | ||
177 | d = buf; | ||
178 | *d = '\0'; | ||
179 | } | ||
180 | } | ||
181 | if ((i & 0xF) != 0) | ||
182 | Debug("%s\n", buf); | ||
183 | } | ||
184 | #endif | ||
185 | |||
186 | static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen) | ||
187 | { | ||
188 | return usb_control_msg(udev, | ||
189 | usb_sndctrlpipe(udev, 0), | ||
190 | SET_EP_STREAM_CTL, | ||
191 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
192 | VIDEO_OUTPUT_CONTROL_FORMATTER, | ||
193 | index, | ||
194 | buf, buflen, 1000); | ||
195 | } | ||
196 | |||
197 | |||
198 | |||
199 | static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) | ||
200 | { | ||
201 | unsigned char buf[3]; | ||
202 | int ret, fps; | ||
203 | struct Nala_table_entry *pEntry; | ||
204 | int frames2frames[31] = | ||
205 | { /* closest match of framerate */ | ||
206 | 0, 0, 0, 0, 4, /* 0-4 */ | ||
207 | 5, 5, 7, 7, 10, /* 5-9 */ | ||
208 | 10, 10, 12, 12, 15, /* 10-14 */ | ||
209 | 15, 15, 15, 20, 20, /* 15-19 */ | ||
210 | 20, 20, 20, 24, 24, /* 20-24 */ | ||
211 | 24, 24, 24, 24, 24, /* 25-29 */ | ||
212 | 24 /* 30 */ | ||
213 | }; | ||
214 | int frames2table[31] = | ||
215 | { 0, 0, 0, 0, 0, /* 0-4 */ | ||
216 | 1, 1, 1, 2, 2, /* 5-9 */ | ||
217 | 3, 3, 4, 4, 4, /* 10-14 */ | ||
218 | 5, 5, 5, 5, 5, /* 15-19 */ | ||
219 | 6, 6, 6, 6, 7, /* 20-24 */ | ||
220 | 7, 7, 7, 7, 7, /* 25-29 */ | ||
221 | 7 /* 30 */ | ||
222 | }; | ||
223 | |||
224 | if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25) | ||
225 | return -EINVAL; | ||
226 | frames = frames2frames[frames]; | ||
227 | fps = frames2table[frames]; | ||
228 | pEntry = &Nala_table[size][fps]; | ||
229 | if (pEntry->alternate == 0) | ||
230 | return -EINVAL; | ||
231 | |||
232 | if (pEntry->compressed) | ||
233 | return -ENOENT; /* Not supported. */ | ||
234 | |||
235 | memcpy(buf, pEntry->mode, 3); | ||
236 | ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); | ||
237 | if (ret < 0) { | ||
238 | Debug("Failed to send video command... %d\n", ret); | ||
239 | return ret; | ||
240 | } | ||
241 | if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW) | ||
242 | { | ||
243 | switch(pdev->type) { | ||
244 | case 645: | ||
245 | case 646: | ||
246 | /* pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); */ | ||
247 | break; | ||
248 | |||
249 | case 675: | ||
250 | case 680: | ||
251 | case 690: | ||
252 | case 720: | ||
253 | case 730: | ||
254 | case 740: | ||
255 | case 750: | ||
256 | /* pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */ | ||
257 | break; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | pdev->cmd_len = 3; | ||
262 | memcpy(pdev->cmd_buf, buf, 3); | ||
263 | |||
264 | /* Set various parameters */ | ||
265 | pdev->vframes = frames; | ||
266 | pdev->vsize = size; | ||
267 | pdev->valternate = pEntry->alternate; | ||
268 | pdev->image = pwc_image_sizes[size]; | ||
269 | pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; | ||
270 | if (pEntry->compressed) { | ||
271 | if (pdev->release < 5) { /* 4 fold compression */ | ||
272 | pdev->vbandlength = 528; | ||
273 | pdev->frame_size /= 4; | ||
274 | } | ||
275 | else { | ||
276 | pdev->vbandlength = 704; | ||
277 | pdev->frame_size /= 3; | ||
278 | } | ||
279 | } | ||
280 | else | ||
281 | pdev->vbandlength = 0; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | |||
286 | static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) | ||
287 | { | ||
288 | unsigned char buf[13]; | ||
289 | const struct Timon_table_entry *pChoose; | ||
290 | int ret, fps; | ||
291 | |||
292 | if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) | ||
293 | return -EINVAL; | ||
294 | if (size == PSZ_VGA && frames > 15) | ||
295 | return -EINVAL; | ||
296 | fps = (frames / 5) - 1; | ||
297 | |||
298 | /* Find a supported framerate with progressively higher compression ratios | ||
299 | if the preferred ratio is not available. | ||
300 | */ | ||
301 | pChoose = NULL; | ||
302 | while (compression <= 3) { | ||
303 | pChoose = &Timon_table[size][fps][compression]; | ||
304 | if (pChoose->alternate != 0) | ||
305 | break; | ||
306 | compression++; | ||
307 | } | ||
308 | if (pChoose == NULL || pChoose->alternate == 0) | ||
309 | return -ENOENT; /* Not supported. */ | ||
310 | |||
311 | memcpy(buf, pChoose->mode, 13); | ||
312 | if (snapshot) | ||
313 | buf[0] |= 0x80; | ||
314 | ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13); | ||
315 | if (ret < 0) | ||
316 | return ret; | ||
317 | |||
318 | /* if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) | ||
319 | pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */ | ||
320 | |||
321 | pdev->cmd_len = 13; | ||
322 | memcpy(pdev->cmd_buf, buf, 13); | ||
323 | |||
324 | /* Set various parameters */ | ||
325 | pdev->vframes = frames; | ||
326 | pdev->vsize = size; | ||
327 | pdev->vsnapshot = snapshot; | ||
328 | pdev->valternate = pChoose->alternate; | ||
329 | pdev->image = pwc_image_sizes[size]; | ||
330 | pdev->vbandlength = pChoose->bandlength; | ||
331 | if (pChoose->bandlength > 0) | ||
332 | pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; | ||
333 | else | ||
334 | pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | |||
339 | static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) | ||
340 | { | ||
341 | const struct Kiara_table_entry *pChoose = NULL; | ||
342 | int fps, ret; | ||
343 | unsigned char buf[12]; | ||
344 | struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; | ||
345 | |||
346 | if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) | ||
347 | return -EINVAL; | ||
348 | if (size == PSZ_VGA && frames > 15) | ||
349 | return -EINVAL; | ||
350 | fps = (frames / 5) - 1; | ||
351 | |||
352 | /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ | ||
353 | if (size == PSZ_VGA && frames == 5 && snapshot) | ||
354 | { | ||
355 | /* Only available in case the raw palette is selected or | ||
356 | we have the decompressor available. This mode is | ||
357 | only available in compressed form | ||
358 | */ | ||
359 | if (pdev->vpalette == VIDEO_PALETTE_RAW) | ||
360 | { | ||
361 | Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette); | ||
362 | pChoose = &RawEntry; | ||
363 | } | ||
364 | else | ||
365 | { | ||
366 | Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n"); | ||
367 | } | ||
368 | } | ||
369 | else | ||
370 | { | ||
371 | /* Find a supported framerate with progressively higher compression ratios | ||
372 | if the preferred ratio is not available. | ||
373 | Skip this step when using RAW modes. | ||
374 | */ | ||
375 | while (compression <= 3) { | ||
376 | pChoose = &Kiara_table[size][fps][compression]; | ||
377 | if (pChoose->alternate != 0) | ||
378 | break; | ||
379 | compression++; | ||
380 | } | ||
381 | } | ||
382 | if (pChoose == NULL || pChoose->alternate == 0) | ||
383 | return -ENOENT; /* Not supported. */ | ||
384 | |||
385 | Debug("Using alternate setting %d.\n", pChoose->alternate); | ||
386 | |||
387 | /* usb_control_msg won't take staticly allocated arrays as argument?? */ | ||
388 | memcpy(buf, pChoose->mode, 12); | ||
389 | if (snapshot) | ||
390 | buf[0] |= 0x80; | ||
391 | |||
392 | /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ | ||
393 | ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12); | ||
394 | if (ret < 0) | ||
395 | return ret; | ||
396 | |||
397 | /* if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) | ||
398 | pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */ | ||
399 | |||
400 | pdev->cmd_len = 12; | ||
401 | memcpy(pdev->cmd_buf, buf, 12); | ||
402 | /* All set and go */ | ||
403 | pdev->vframes = frames; | ||
404 | pdev->vsize = size; | ||
405 | pdev->vsnapshot = snapshot; | ||
406 | pdev->valternate = pChoose->alternate; | ||
407 | pdev->image = pwc_image_sizes[size]; | ||
408 | pdev->vbandlength = pChoose->bandlength; | ||
409 | if (pdev->vbandlength > 0) | ||
410 | pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; | ||
411 | else | ||
412 | pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | |||
417 | |||
418 | static void pwc_set_image_buffer_size(struct pwc_device *pdev) | ||
419 | { | ||
420 | int i, factor = 0, filler = 0; | ||
421 | |||
422 | /* for PALETTE_YUV420P */ | ||
423 | switch(pdev->vpalette) | ||
424 | { | ||
425 | case VIDEO_PALETTE_YUV420P: | ||
426 | factor = 6; | ||
427 | filler = 128; | ||
428 | break; | ||
429 | case VIDEO_PALETTE_RAW: | ||
430 | factor = 6; /* can be uncompressed YUV420P */ | ||
431 | filler = 0; | ||
432 | break; | ||
433 | } | ||
434 | |||
435 | /* Set sizes in bytes */ | ||
436 | pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; | ||
437 | pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; | ||
438 | |||
439 | /* Align offset, or you'll get some very weird results in | ||
440 | YUV420 mode... x must be multiple of 4 (to get the Y's in | ||
441 | place), and y even (or you'll mixup U & V). This is less of a | ||
442 | problem for YUV420P. | ||
443 | */ | ||
444 | pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; | ||
445 | pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; | ||
446 | |||
447 | /* Fill buffers with gray or black */ | ||
448 | for (i = 0; i < MAX_IMAGES; i++) { | ||
449 | if (pdev->image_ptr[i] != NULL) | ||
450 | memset(pdev->image_ptr[i], filler, pdev->view.size); | ||
451 | } | ||
452 | } | ||
453 | |||
454 | |||
455 | |||
456 | /** | ||
457 | @pdev: device structure | ||
458 | @width: viewport width | ||
459 | @height: viewport height | ||
460 | @frame: framerate, in fps | ||
461 | @compression: preferred compression ratio | ||
462 | @snapshot: snapshot mode or streaming | ||
463 | */ | ||
464 | int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) | ||
465 | { | ||
466 | int ret, size; | ||
467 | |||
468 | Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette); | ||
469 | size = pwc_decode_size(pdev, width, height); | ||
470 | if (size < 0) { | ||
471 | Debug("Could not find suitable size.\n"); | ||
472 | return -ERANGE; | ||
473 | } | ||
474 | Debug("decode_size = %d.\n", size); | ||
475 | |||
476 | ret = -EINVAL; | ||
477 | switch(pdev->type) { | ||
478 | case 645: | ||
479 | case 646: | ||
480 | ret = set_video_mode_Nala(pdev, size, frames); | ||
481 | break; | ||
482 | |||
483 | case 675: | ||
484 | case 680: | ||
485 | case 690: | ||
486 | ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); | ||
487 | break; | ||
488 | |||
489 | case 720: | ||
490 | case 730: | ||
491 | case 740: | ||
492 | case 750: | ||
493 | ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); | ||
494 | break; | ||
495 | } | ||
496 | if (ret < 0) { | ||
497 | if (ret == -ENOENT) | ||
498 | Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames); | ||
499 | else { | ||
500 | Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); | ||
501 | } | ||
502 | return ret; | ||
503 | } | ||
504 | pdev->view.x = width; | ||
505 | pdev->view.y = height; | ||
506 | pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; | ||
507 | pwc_set_image_buffer_size(pdev); | ||
508 | Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); | ||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | |||
513 | /* BRIGHTNESS */ | ||
514 | |||
515 | int pwc_get_brightness(struct pwc_device *pdev) | ||
516 | { | ||
517 | char buf; | ||
518 | int ret; | ||
519 | |||
520 | ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); | ||
521 | if (ret < 0) | ||
522 | return ret; | ||
523 | return buf << 9; | ||
524 | } | ||
525 | |||
526 | int pwc_set_brightness(struct pwc_device *pdev, int value) | ||
527 | { | ||
528 | char buf; | ||
529 | |||
530 | if (value < 0) | ||
531 | value = 0; | ||
532 | if (value > 0xffff) | ||
533 | value = 0xffff; | ||
534 | buf = (value >> 9) & 0x7f; | ||
535 | return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); | ||
536 | } | ||
537 | |||
538 | /* CONTRAST */ | ||
539 | |||
540 | int pwc_get_contrast(struct pwc_device *pdev) | ||
541 | { | ||
542 | char buf; | ||
543 | int ret; | ||
544 | |||
545 | ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1); | ||
546 | if (ret < 0) | ||
547 | return ret; | ||
548 | return buf << 10; | ||
549 | } | ||
550 | |||
551 | int pwc_set_contrast(struct pwc_device *pdev, int value) | ||
552 | { | ||
553 | char buf; | ||
554 | |||
555 | if (value < 0) | ||
556 | value = 0; | ||
557 | if (value > 0xffff) | ||
558 | value = 0xffff; | ||
559 | buf = (value >> 10) & 0x3f; | ||
560 | return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1); | ||
561 | } | ||
562 | |||
563 | /* GAMMA */ | ||
564 | |||
565 | int pwc_get_gamma(struct pwc_device *pdev) | ||
566 | { | ||
567 | char buf; | ||
568 | int ret; | ||
569 | |||
570 | ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1); | ||
571 | if (ret < 0) | ||
572 | return ret; | ||
573 | return buf << 11; | ||
574 | } | ||
575 | |||
576 | int pwc_set_gamma(struct pwc_device *pdev, int value) | ||
577 | { | ||
578 | char buf; | ||
579 | |||
580 | if (value < 0) | ||
581 | value = 0; | ||
582 | if (value > 0xffff) | ||
583 | value = 0xffff; | ||
584 | buf = (value >> 11) & 0x1f; | ||
585 | return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1); | ||
586 | } | ||
587 | |||
588 | |||
589 | /* SATURATION */ | ||
590 | |||
591 | int pwc_get_saturation(struct pwc_device *pdev) | ||
592 | { | ||
593 | char buf; | ||
594 | int ret; | ||
595 | |||
596 | if (pdev->type < 675) | ||
597 | return -1; | ||
598 | ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); | ||
599 | if (ret < 0) | ||
600 | return ret; | ||
601 | return 32768 + buf * 327; | ||
602 | } | ||
603 | |||
604 | int pwc_set_saturation(struct pwc_device *pdev, int value) | ||
605 | { | ||
606 | char buf; | ||
607 | |||
608 | if (pdev->type < 675) | ||
609 | return -EINVAL; | ||
610 | if (value < 0) | ||
611 | value = 0; | ||
612 | if (value > 0xffff) | ||
613 | value = 0xffff; | ||
614 | /* saturation ranges from -100 to +100 */ | ||
615 | buf = (value - 32768) / 327; | ||
616 | return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); | ||
617 | } | ||
618 | |||
619 | /* AGC */ | ||
620 | |||
621 | static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value) | ||
622 | { | ||
623 | char buf; | ||
624 | int ret; | ||
625 | |||
626 | if (mode) | ||
627 | buf = 0x0; /* auto */ | ||
628 | else | ||
629 | buf = 0xff; /* fixed */ | ||
630 | |||
631 | ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1); | ||
632 | |||
633 | if (!mode && ret >= 0) { | ||
634 | if (value < 0) | ||
635 | value = 0; | ||
636 | if (value > 0xffff) | ||
637 | value = 0xffff; | ||
638 | buf = (value >> 10) & 0x3F; | ||
639 | ret = SendControlMsg(SET_LUM_CTL, PRESET_AGC_FORMATTER, 1); | ||
640 | } | ||
641 | if (ret < 0) | ||
642 | return ret; | ||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | static inline int pwc_get_agc(struct pwc_device *pdev, int *value) | ||
647 | { | ||
648 | unsigned char buf; | ||
649 | int ret; | ||
650 | |||
651 | ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1); | ||
652 | if (ret < 0) | ||
653 | return ret; | ||
654 | |||
655 | if (buf != 0) { /* fixed */ | ||
656 | ret = RecvControlMsg(GET_LUM_CTL, PRESET_AGC_FORMATTER, 1); | ||
657 | if (ret < 0) | ||
658 | return ret; | ||
659 | if (buf > 0x3F) | ||
660 | buf = 0x3F; | ||
661 | *value = (buf << 10); | ||
662 | } | ||
663 | else { /* auto */ | ||
664 | ret = RecvControlMsg(GET_STATUS_CTL, READ_AGC_FORMATTER, 1); | ||
665 | if (ret < 0) | ||
666 | return ret; | ||
667 | /* Gah... this value ranges from 0x00 ... 0x9F */ | ||
668 | if (buf > 0x9F) | ||
669 | buf = 0x9F; | ||
670 | *value = -(48 + buf * 409); | ||
671 | } | ||
672 | |||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value) | ||
677 | { | ||
678 | char buf[2]; | ||
679 | int speed, ret; | ||
680 | |||
681 | |||
682 | if (mode) | ||
683 | buf[0] = 0x0; /* auto */ | ||
684 | else | ||
685 | buf[0] = 0xff; /* fixed */ | ||
686 | |||
687 | ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1); | ||
688 | |||
689 | if (!mode && ret >= 0) { | ||
690 | if (value < 0) | ||
691 | value = 0; | ||
692 | if (value > 0xffff) | ||
693 | value = 0xffff; | ||
694 | switch(pdev->type) { | ||
695 | case 675: | ||
696 | case 680: | ||
697 | case 690: | ||
698 | /* speed ranges from 0x0 to 0x290 (656) */ | ||
699 | speed = (value / 100); | ||
700 | buf[1] = speed >> 8; | ||
701 | buf[0] = speed & 0xff; | ||
702 | break; | ||
703 | case 720: | ||
704 | case 730: | ||
705 | case 740: | ||
706 | case 750: | ||
707 | /* speed seems to range from 0x0 to 0xff */ | ||
708 | buf[1] = 0; | ||
709 | buf[0] = value >> 8; | ||
710 | break; | ||
711 | } | ||
712 | |||
713 | ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2); | ||
714 | } | ||
715 | return ret; | ||
716 | } | ||
717 | |||
718 | |||
719 | /* POWER */ | ||
720 | |||
721 | int pwc_camera_power(struct pwc_device *pdev, int power) | ||
722 | { | ||
723 | char buf; | ||
724 | |||
725 | if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) | ||
726 | return 0; /* Not supported by Nala or Timon < release 6 */ | ||
727 | |||
728 | if (power) | ||
729 | buf = 0x00; /* active */ | ||
730 | else | ||
731 | buf = 0xFF; /* power save */ | ||
732 | return SendControlMsg(SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, 1); | ||
733 | } | ||
734 | |||
735 | |||
736 | |||
737 | /* private calls */ | ||
738 | |||
739 | static inline int pwc_restore_user(struct pwc_device *pdev) | ||
740 | { | ||
741 | char buf; /* dummy */ | ||
742 | return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0); | ||
743 | } | ||
744 | |||
745 | static inline int pwc_save_user(struct pwc_device *pdev) | ||
746 | { | ||
747 | char buf; /* dummy */ | ||
748 | return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0); | ||
749 | } | ||
750 | |||
751 | static inline int pwc_restore_factory(struct pwc_device *pdev) | ||
752 | { | ||
753 | char buf; /* dummy */ | ||
754 | return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0); | ||
755 | } | ||
756 | |||
757 | /* ************************************************* */ | ||
758 | /* Patch by Alvarado: (not in the original version */ | ||
759 | |||
760 | /* | ||
761 | * the camera recognizes modes from 0 to 4: | ||
762 | * | ||
763 | * 00: indoor (incandescant lighting) | ||
764 | * 01: outdoor (sunlight) | ||
765 | * 02: fluorescent lighting | ||
766 | * 03: manual | ||
767 | * 04: auto | ||
768 | */ | ||
769 | static inline int pwc_set_awb(struct pwc_device *pdev, int mode) | ||
770 | { | ||
771 | char buf; | ||
772 | int ret; | ||
773 | |||
774 | if (mode < 0) | ||
775 | mode = 0; | ||
776 | |||
777 | if (mode > 4) | ||
778 | mode = 4; | ||
779 | |||
780 | buf = mode & 0x07; /* just the lowest three bits */ | ||
781 | |||
782 | ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1); | ||
783 | |||
784 | if (ret < 0) | ||
785 | return ret; | ||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | static inline int pwc_get_awb(struct pwc_device *pdev) | ||
790 | { | ||
791 | unsigned char buf; | ||
792 | int ret; | ||
793 | |||
794 | ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1); | ||
795 | |||
796 | if (ret < 0) | ||
797 | return ret; | ||
798 | return buf; | ||
799 | } | ||
800 | |||
801 | static inline int pwc_set_red_gain(struct pwc_device *pdev, int value) | ||
802 | { | ||
803 | unsigned char buf; | ||
804 | |||
805 | if (value < 0) | ||
806 | value = 0; | ||
807 | if (value > 0xffff) | ||
808 | value = 0xffff; | ||
809 | /* only the msb is considered */ | ||
810 | buf = value >> 8; | ||
811 | return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); | ||
812 | } | ||
813 | |||
814 | static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value) | ||
815 | { | ||
816 | unsigned char buf; | ||
817 | int ret; | ||
818 | |||
819 | ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); | ||
820 | if (ret < 0) | ||
821 | return ret; | ||
822 | *value = buf << 8; | ||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | |||
827 | static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value) | ||
828 | { | ||
829 | unsigned char buf; | ||
830 | |||
831 | if (value < 0) | ||
832 | value = 0; | ||
833 | if (value > 0xffff) | ||
834 | value = 0xffff; | ||
835 | /* only the msb is considered */ | ||
836 | buf = value >> 8; | ||
837 | return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); | ||
838 | } | ||
839 | |||
840 | static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value) | ||
841 | { | ||
842 | unsigned char buf; | ||
843 | int ret; | ||
844 | |||
845 | ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); | ||
846 | if (ret < 0) | ||
847 | return ret; | ||
848 | *value = buf << 8; | ||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | |||
853 | /* The following two functions are different, since they only read the | ||
854 | internal red/blue gains, which may be different from the manual | ||
855 | gains set or read above. | ||
856 | */ | ||
857 | static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value) | ||
858 | { | ||
859 | unsigned char buf; | ||
860 | int ret; | ||
861 | |||
862 | ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1); | ||
863 | if (ret < 0) | ||
864 | return ret; | ||
865 | *value = buf << 8; | ||
866 | return 0; | ||
867 | } | ||
868 | |||
869 | static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value) | ||
870 | { | ||
871 | unsigned char buf; | ||
872 | int ret; | ||
873 | |||
874 | ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1); | ||
875 | if (ret < 0) | ||
876 | return ret; | ||
877 | *value = buf << 8; | ||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | |||
882 | static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed) | ||
883 | { | ||
884 | unsigned char buf; | ||
885 | |||
886 | /* useful range is 0x01..0x20 */ | ||
887 | buf = speed / 0x7f0; | ||
888 | return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); | ||
889 | } | ||
890 | |||
891 | static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value) | ||
892 | { | ||
893 | unsigned char buf; | ||
894 | int ret; | ||
895 | |||
896 | ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); | ||
897 | if (ret < 0) | ||
898 | return ret; | ||
899 | *value = buf * 0x7f0; | ||
900 | return 0; | ||
901 | } | ||
902 | |||
903 | |||
904 | static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay) | ||
905 | { | ||
906 | unsigned char buf; | ||
907 | |||
908 | /* useful range is 0x01..0x3F */ | ||
909 | buf = (delay >> 10); | ||
910 | return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); | ||
911 | } | ||
912 | |||
913 | static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value) | ||
914 | { | ||
915 | unsigned char buf; | ||
916 | int ret; | ||
917 | |||
918 | ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); | ||
919 | if (ret < 0) | ||
920 | return ret; | ||
921 | *value = buf << 10; | ||
922 | return 0; | ||
923 | } | ||
924 | |||
925 | |||
926 | int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) | ||
927 | { | ||
928 | unsigned char buf[2]; | ||
929 | |||
930 | if (pdev->type < 730) | ||
931 | return 0; | ||
932 | on_value /= 100; | ||
933 | off_value /= 100; | ||
934 | if (on_value < 0) | ||
935 | on_value = 0; | ||
936 | if (on_value > 0xff) | ||
937 | on_value = 0xff; | ||
938 | if (off_value < 0) | ||
939 | off_value = 0; | ||
940 | if (off_value > 0xff) | ||
941 | off_value = 0xff; | ||
942 | |||
943 | buf[0] = on_value; | ||
944 | buf[1] = off_value; | ||
945 | |||
946 | return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2); | ||
947 | } | ||
948 | |||
949 | static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) | ||
950 | { | ||
951 | unsigned char buf[2]; | ||
952 | int ret; | ||
953 | |||
954 | if (pdev->type < 730) { | ||
955 | *on_value = -1; | ||
956 | *off_value = -1; | ||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2); | ||
961 | if (ret < 0) | ||
962 | return ret; | ||
963 | *on_value = buf[0] * 100; | ||
964 | *off_value = buf[1] * 100; | ||
965 | return 0; | ||
966 | } | ||
967 | |||
968 | static inline int pwc_set_contour(struct pwc_device *pdev, int contour) | ||
969 | { | ||
970 | unsigned char buf; | ||
971 | int ret; | ||
972 | |||
973 | if (contour < 0) | ||
974 | buf = 0xff; /* auto contour on */ | ||
975 | else | ||
976 | buf = 0x0; /* auto contour off */ | ||
977 | ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); | ||
978 | if (ret < 0) | ||
979 | return ret; | ||
980 | |||
981 | if (contour < 0) | ||
982 | return 0; | ||
983 | if (contour > 0xffff) | ||
984 | contour = 0xffff; | ||
985 | |||
986 | buf = (contour >> 10); /* contour preset is [0..3f] */ | ||
987 | ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); | ||
988 | if (ret < 0) | ||
989 | return ret; | ||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | static inline int pwc_get_contour(struct pwc_device *pdev, int *contour) | ||
994 | { | ||
995 | unsigned char buf; | ||
996 | int ret; | ||
997 | |||
998 | ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); | ||
999 | if (ret < 0) | ||
1000 | return ret; | ||
1001 | |||
1002 | if (buf == 0) { | ||
1003 | /* auto mode off, query current preset value */ | ||
1004 | ret = RecvControlMsg(GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); | ||
1005 | if (ret < 0) | ||
1006 | return ret; | ||
1007 | *contour = buf << 10; | ||
1008 | } | ||
1009 | else | ||
1010 | *contour = -1; | ||
1011 | return 0; | ||
1012 | } | ||
1013 | |||
1014 | |||
1015 | static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight) | ||
1016 | { | ||
1017 | unsigned char buf; | ||
1018 | |||
1019 | if (backlight) | ||
1020 | buf = 0xff; | ||
1021 | else | ||
1022 | buf = 0x0; | ||
1023 | return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); | ||
1024 | } | ||
1025 | |||
1026 | static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight) | ||
1027 | { | ||
1028 | int ret; | ||
1029 | unsigned char buf; | ||
1030 | |||
1031 | ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); | ||
1032 | if (ret < 0) | ||
1033 | return ret; | ||
1034 | *backlight = buf; | ||
1035 | return 0; | ||
1036 | } | ||
1037 | |||
1038 | |||
1039 | static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker) | ||
1040 | { | ||
1041 | unsigned char buf; | ||
1042 | |||
1043 | if (flicker) | ||
1044 | buf = 0xff; | ||
1045 | else | ||
1046 | buf = 0x0; | ||
1047 | return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); | ||
1048 | } | ||
1049 | |||
1050 | static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker) | ||
1051 | { | ||
1052 | int ret; | ||
1053 | unsigned char buf; | ||
1054 | |||
1055 | ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); | ||
1056 | if (ret < 0) | ||
1057 | return ret; | ||
1058 | *flicker = buf; | ||
1059 | return 0; | ||
1060 | } | ||
1061 | |||
1062 | |||
1063 | static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise) | ||
1064 | { | ||
1065 | unsigned char buf; | ||
1066 | |||
1067 | if (noise < 0) | ||
1068 | noise = 0; | ||
1069 | if (noise > 3) | ||
1070 | noise = 3; | ||
1071 | buf = noise; | ||
1072 | return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); | ||
1073 | } | ||
1074 | |||
1075 | static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise) | ||
1076 | { | ||
1077 | int ret; | ||
1078 | unsigned char buf; | ||
1079 | |||
1080 | ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); | ||
1081 | if (ret < 0) | ||
1082 | return ret; | ||
1083 | *noise = buf; | ||
1084 | return 0; | ||
1085 | } | ||
1086 | |||
1087 | static int pwc_mpt_reset(struct pwc_device *pdev, int flags) | ||
1088 | { | ||
1089 | unsigned char buf; | ||
1090 | |||
1091 | buf = flags & 0x03; // only lower two bits are currently used | ||
1092 | return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1); | ||
1093 | } | ||
1094 | |||
1095 | static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) | ||
1096 | { | ||
1097 | unsigned char buf[4]; | ||
1098 | |||
1099 | /* set new relative angle; angles are expressed in degrees * 100, | ||
1100 | but cam as .5 degree resolution, hence divide by 200. Also | ||
1101 | the angle must be multiplied by 64 before it's send to | ||
1102 | the cam (??) | ||
1103 | */ | ||
1104 | pan = 64 * pan / 100; | ||
1105 | tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */ | ||
1106 | buf[0] = pan & 0xFF; | ||
1107 | buf[1] = (pan >> 8) & 0xFF; | ||
1108 | buf[2] = tilt & 0xFF; | ||
1109 | buf[3] = (tilt >> 8) & 0xFF; | ||
1110 | return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4); | ||
1111 | } | ||
1112 | |||
1113 | static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status) | ||
1114 | { | ||
1115 | int ret; | ||
1116 | unsigned char buf[5]; | ||
1117 | |||
1118 | ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5); | ||
1119 | if (ret < 0) | ||
1120 | return ret; | ||
1121 | status->status = buf[0] & 0x7; // 3 bits are used for reporting | ||
1122 | status->time_pan = (buf[1] << 8) + buf[2]; | ||
1123 | status->time_tilt = (buf[3] << 8) + buf[4]; | ||
1124 | return 0; | ||
1125 | } | ||
1126 | |||
1127 | |||
1128 | int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) | ||
1129 | { | ||
1130 | unsigned char buf; | ||
1131 | int ret = -1, request; | ||
1132 | |||
1133 | if (pdev->type < 675) | ||
1134 | request = SENSOR_TYPE_FORMATTER1; | ||
1135 | else if (pdev->type < 730) | ||
1136 | return -1; /* The Vesta series doesn't have this call */ | ||
1137 | else | ||
1138 | request = SENSOR_TYPE_FORMATTER2; | ||
1139 | |||
1140 | ret = RecvControlMsg(GET_STATUS_CTL, request, 1); | ||
1141 | if (ret < 0) | ||
1142 | return ret; | ||
1143 | if (pdev->type < 675) | ||
1144 | *sensor = buf | 0x100; | ||
1145 | else | ||
1146 | *sensor = buf; | ||
1147 | return 0; | ||
1148 | } | ||
1149 | |||
1150 | |||
1151 | /* End of Add-Ons */ | ||
1152 | /* ************************************************* */ | ||
1153 | |||
1154 | |||
1155 | int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | ||
1156 | { | ||
1157 | int ret = 0; | ||
1158 | |||
1159 | switch(cmd) { | ||
1160 | case VIDIOCPWCRUSER: | ||
1161 | { | ||
1162 | if (pwc_restore_user(pdev)) | ||
1163 | ret = -EINVAL; | ||
1164 | break; | ||
1165 | } | ||
1166 | |||
1167 | case VIDIOCPWCSUSER: | ||
1168 | { | ||
1169 | if (pwc_save_user(pdev)) | ||
1170 | ret = -EINVAL; | ||
1171 | break; | ||
1172 | } | ||
1173 | |||
1174 | case VIDIOCPWCFACTORY: | ||
1175 | { | ||
1176 | if (pwc_restore_factory(pdev)) | ||
1177 | ret = -EINVAL; | ||
1178 | break; | ||
1179 | } | ||
1180 | |||
1181 | case VIDIOCPWCSCQUAL: | ||
1182 | { | ||
1183 | int *qual = arg; | ||
1184 | |||
1185 | if (*qual < 0 || *qual > 3) | ||
1186 | ret = -EINVAL; | ||
1187 | else | ||
1188 | ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot); | ||
1189 | if (ret >= 0) | ||
1190 | pdev->vcompression = *qual; | ||
1191 | break; | ||
1192 | } | ||
1193 | |||
1194 | case VIDIOCPWCGCQUAL: | ||
1195 | { | ||
1196 | int *qual = arg; | ||
1197 | *qual = pdev->vcompression; | ||
1198 | break; | ||
1199 | } | ||
1200 | |||
1201 | case VIDIOCPWCPROBE: | ||
1202 | { | ||
1203 | struct pwc_probe *probe = arg; | ||
1204 | strcpy(probe->name, pdev->vdev->name); | ||
1205 | probe->type = pdev->type; | ||
1206 | break; | ||
1207 | } | ||
1208 | |||
1209 | case VIDIOCPWCGSERIAL: | ||
1210 | { | ||
1211 | struct pwc_serial *serial = arg; | ||
1212 | strcpy(serial->serial, pdev->serial); | ||
1213 | break; | ||
1214 | } | ||
1215 | |||
1216 | case VIDIOCPWCSAGC: | ||
1217 | { | ||
1218 | int *agc = arg; | ||
1219 | if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc)) | ||
1220 | ret = -EINVAL; | ||
1221 | break; | ||
1222 | } | ||
1223 | |||
1224 | case VIDIOCPWCGAGC: | ||
1225 | { | ||
1226 | int *agc = arg; | ||
1227 | |||
1228 | if (pwc_get_agc(pdev, agc)) | ||
1229 | ret = -EINVAL; | ||
1230 | break; | ||
1231 | } | ||
1232 | |||
1233 | case VIDIOCPWCSSHUTTER: | ||
1234 | { | ||
1235 | int *shutter_speed = arg; | ||
1236 | ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed); | ||
1237 | break; | ||
1238 | } | ||
1239 | |||
1240 | case VIDIOCPWCSAWB: | ||
1241 | { | ||
1242 | struct pwc_whitebalance *wb = arg; | ||
1243 | |||
1244 | ret = pwc_set_awb(pdev, wb->mode); | ||
1245 | if (ret >= 0 && wb->mode == PWC_WB_MANUAL) { | ||
1246 | pwc_set_red_gain(pdev, wb->manual_red); | ||
1247 | pwc_set_blue_gain(pdev, wb->manual_blue); | ||
1248 | } | ||
1249 | break; | ||
1250 | } | ||
1251 | |||
1252 | case VIDIOCPWCGAWB: | ||
1253 | { | ||
1254 | struct pwc_whitebalance *wb = arg; | ||
1255 | |||
1256 | memset(wb, 0, sizeof(struct pwc_whitebalance)); | ||
1257 | wb->mode = pwc_get_awb(pdev); | ||
1258 | if (wb->mode < 0) | ||
1259 | ret = -EINVAL; | ||
1260 | else { | ||
1261 | if (wb->mode == PWC_WB_MANUAL) { | ||
1262 | ret = pwc_get_red_gain(pdev, &wb->manual_red); | ||
1263 | if (ret < 0) | ||
1264 | break; | ||
1265 | ret = pwc_get_blue_gain(pdev, &wb->manual_blue); | ||
1266 | if (ret < 0) | ||
1267 | break; | ||
1268 | } | ||
1269 | if (wb->mode == PWC_WB_AUTO) { | ||
1270 | ret = pwc_read_red_gain(pdev, &wb->read_red); | ||
1271 | if (ret < 0) | ||
1272 | break; | ||
1273 | ret = pwc_read_blue_gain(pdev, &wb->read_blue); | ||
1274 | if (ret < 0) | ||
1275 | break; | ||
1276 | } | ||
1277 | } | ||
1278 | break; | ||
1279 | } | ||
1280 | |||
1281 | case VIDIOCPWCSAWBSPEED: | ||
1282 | { | ||
1283 | struct pwc_wb_speed *wbs = arg; | ||
1284 | |||
1285 | if (wbs->control_speed > 0) { | ||
1286 | ret = pwc_set_wb_speed(pdev, wbs->control_speed); | ||
1287 | } | ||
1288 | if (wbs->control_delay > 0) { | ||
1289 | ret = pwc_set_wb_delay(pdev, wbs->control_delay); | ||
1290 | } | ||
1291 | break; | ||
1292 | } | ||
1293 | |||
1294 | case VIDIOCPWCGAWBSPEED: | ||
1295 | { | ||
1296 | struct pwc_wb_speed *wbs = arg; | ||
1297 | |||
1298 | ret = pwc_get_wb_speed(pdev, &wbs->control_speed); | ||
1299 | if (ret < 0) | ||
1300 | break; | ||
1301 | ret = pwc_get_wb_delay(pdev, &wbs->control_delay); | ||
1302 | if (ret < 0) | ||
1303 | break; | ||
1304 | break; | ||
1305 | } | ||
1306 | |||
1307 | case VIDIOCPWCSLED: | ||
1308 | { | ||
1309 | struct pwc_leds *leds = arg; | ||
1310 | ret = pwc_set_leds(pdev, leds->led_on, leds->led_off); | ||
1311 | break; | ||
1312 | } | ||
1313 | |||
1314 | |||
1315 | case VIDIOCPWCGLED: | ||
1316 | { | ||
1317 | struct pwc_leds *leds = arg; | ||
1318 | ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off); | ||
1319 | break; | ||
1320 | } | ||
1321 | |||
1322 | case VIDIOCPWCSCONTOUR: | ||
1323 | { | ||
1324 | int *contour = arg; | ||
1325 | ret = pwc_set_contour(pdev, *contour); | ||
1326 | break; | ||
1327 | } | ||
1328 | |||
1329 | case VIDIOCPWCGCONTOUR: | ||
1330 | { | ||
1331 | int *contour = arg; | ||
1332 | ret = pwc_get_contour(pdev, contour); | ||
1333 | break; | ||
1334 | } | ||
1335 | |||
1336 | case VIDIOCPWCSBACKLIGHT: | ||
1337 | { | ||
1338 | int *backlight = arg; | ||
1339 | ret = pwc_set_backlight(pdev, *backlight); | ||
1340 | break; | ||
1341 | } | ||
1342 | |||
1343 | case VIDIOCPWCGBACKLIGHT: | ||
1344 | { | ||
1345 | int *backlight = arg; | ||
1346 | ret = pwc_get_backlight(pdev, backlight); | ||
1347 | break; | ||
1348 | } | ||
1349 | |||
1350 | case VIDIOCPWCSFLICKER: | ||
1351 | { | ||
1352 | int *flicker = arg; | ||
1353 | ret = pwc_set_flicker(pdev, *flicker); | ||
1354 | break; | ||
1355 | } | ||
1356 | |||
1357 | case VIDIOCPWCGFLICKER: | ||
1358 | { | ||
1359 | int *flicker = arg; | ||
1360 | ret = pwc_get_flicker(pdev, flicker); | ||
1361 | break; | ||
1362 | } | ||
1363 | |||
1364 | case VIDIOCPWCSDYNNOISE: | ||
1365 | { | ||
1366 | int *dynnoise = arg; | ||
1367 | ret = pwc_set_dynamic_noise(pdev, *dynnoise); | ||
1368 | break; | ||
1369 | } | ||
1370 | |||
1371 | case VIDIOCPWCGDYNNOISE: | ||
1372 | { | ||
1373 | int *dynnoise = arg; | ||
1374 | ret = pwc_get_dynamic_noise(pdev, dynnoise); | ||
1375 | break; | ||
1376 | } | ||
1377 | |||
1378 | case VIDIOCPWCGREALSIZE: | ||
1379 | { | ||
1380 | struct pwc_imagesize *size = arg; | ||
1381 | size->width = pdev->image.x; | ||
1382 | size->height = pdev->image.y; | ||
1383 | break; | ||
1384 | } | ||
1385 | |||
1386 | case VIDIOCPWCMPTRESET: | ||
1387 | { | ||
1388 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1389 | { | ||
1390 | int *flags = arg; | ||
1391 | |||
1392 | ret = pwc_mpt_reset(pdev, *flags); | ||
1393 | if (ret >= 0) | ||
1394 | { | ||
1395 | pdev->pan_angle = 0; | ||
1396 | pdev->tilt_angle = 0; | ||
1397 | } | ||
1398 | } | ||
1399 | else | ||
1400 | { | ||
1401 | ret = -ENXIO; | ||
1402 | } | ||
1403 | break; | ||
1404 | } | ||
1405 | |||
1406 | case VIDIOCPWCMPTGRANGE: | ||
1407 | { | ||
1408 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1409 | { | ||
1410 | struct pwc_mpt_range *range = arg; | ||
1411 | *range = pdev->angle_range; | ||
1412 | } | ||
1413 | else | ||
1414 | { | ||
1415 | ret = -ENXIO; | ||
1416 | } | ||
1417 | break; | ||
1418 | } | ||
1419 | |||
1420 | case VIDIOCPWCMPTSANGLE: | ||
1421 | { | ||
1422 | int new_pan, new_tilt; | ||
1423 | |||
1424 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1425 | { | ||
1426 | struct pwc_mpt_angles *angles = arg; | ||
1427 | /* The camera can only set relative angles, so | ||
1428 | do some calculations when getting an absolute angle . | ||
1429 | */ | ||
1430 | if (angles->absolute) | ||
1431 | { | ||
1432 | new_pan = angles->pan; | ||
1433 | new_tilt = angles->tilt; | ||
1434 | } | ||
1435 | else | ||
1436 | { | ||
1437 | new_pan = pdev->pan_angle + angles->pan; | ||
1438 | new_tilt = pdev->tilt_angle + angles->tilt; | ||
1439 | } | ||
1440 | /* check absolute ranges */ | ||
1441 | if (new_pan < pdev->angle_range.pan_min || | ||
1442 | new_pan > pdev->angle_range.pan_max || | ||
1443 | new_tilt < pdev->angle_range.tilt_min || | ||
1444 | new_tilt > pdev->angle_range.tilt_max) | ||
1445 | { | ||
1446 | ret = -ERANGE; | ||
1447 | } | ||
1448 | else | ||
1449 | { | ||
1450 | /* go to relative range, check again */ | ||
1451 | new_pan -= pdev->pan_angle; | ||
1452 | new_tilt -= pdev->tilt_angle; | ||
1453 | /* angles are specified in degrees * 100, thus the limit = 36000 */ | ||
1454 | if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000) | ||
1455 | ret = -ERANGE; | ||
1456 | } | ||
1457 | if (ret == 0) /* no errors so far */ | ||
1458 | { | ||
1459 | ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt); | ||
1460 | if (ret >= 0) | ||
1461 | { | ||
1462 | pdev->pan_angle += new_pan; | ||
1463 | pdev->tilt_angle += new_tilt; | ||
1464 | } | ||
1465 | if (ret == -EPIPE) /* stall -> out of range */ | ||
1466 | ret = -ERANGE; | ||
1467 | } | ||
1468 | } | ||
1469 | else | ||
1470 | { | ||
1471 | ret = -ENXIO; | ||
1472 | } | ||
1473 | break; | ||
1474 | } | ||
1475 | |||
1476 | case VIDIOCPWCMPTGANGLE: | ||
1477 | { | ||
1478 | |||
1479 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1480 | { | ||
1481 | struct pwc_mpt_angles *angles = arg; | ||
1482 | |||
1483 | angles->absolute = 1; | ||
1484 | angles->pan = pdev->pan_angle; | ||
1485 | angles->tilt = pdev->tilt_angle; | ||
1486 | } | ||
1487 | else | ||
1488 | { | ||
1489 | ret = -ENXIO; | ||
1490 | } | ||
1491 | break; | ||
1492 | } | ||
1493 | |||
1494 | case VIDIOCPWCMPTSTATUS: | ||
1495 | { | ||
1496 | if (pdev->features & FEATURE_MOTOR_PANTILT) | ||
1497 | { | ||
1498 | struct pwc_mpt_status *status = arg; | ||
1499 | ret = pwc_mpt_get_status(pdev, status); | ||
1500 | } | ||
1501 | else | ||
1502 | { | ||
1503 | ret = -ENXIO; | ||
1504 | } | ||
1505 | break; | ||
1506 | } | ||
1507 | |||
1508 | case VIDIOCPWCGVIDCMD: | ||
1509 | { | ||
1510 | struct pwc_video_command *cmd = arg; | ||
1511 | |||
1512 | cmd->type = pdev->type; | ||
1513 | cmd->release = pdev->release; | ||
1514 | cmd->command_len = pdev->cmd_len; | ||
1515 | memcpy(&cmd->command_buf, pdev->cmd_buf, pdev->cmd_len); | ||
1516 | cmd->bandlength = pdev->vbandlength; | ||
1517 | cmd->frame_size = pdev->frame_size; | ||
1518 | break; | ||
1519 | } | ||
1520 | /* | ||
1521 | case VIDIOCPWCGVIDTABLE: | ||
1522 | { | ||
1523 | struct pwc_table_init_buffer *table = arg; | ||
1524 | table->len = pdev->cmd_len; | ||
1525 | memcpy(&table->buffer, pdev->decompress_data, pdev->decompressor->table_size); | ||
1526 | break; | ||
1527 | } | ||
1528 | */ | ||
1529 | |||
1530 | default: | ||
1531 | ret = -ENOIOCTLCMD; | ||
1532 | break; | ||
1533 | } | ||
1534 | |||
1535 | if (ret > 0) | ||
1536 | return 0; | ||
1537 | return ret; | ||
1538 | } | ||
1539 | |||
1540 | |||
1541 | |||
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c new file mode 100644 index 000000000000..90eb26042817 --- /dev/null +++ b/drivers/media/video/pwc/pwc-if.c | |||
@@ -0,0 +1,2205 @@ | |||
1 | /* Linux driver for Philips webcam | ||
2 | USB and Video4Linux interface part. | ||
3 | (C) 1999-2004 Nemosoft Unv. | ||
4 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
5 | |||
6 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
7 | driver and thus may have bugs that are not present in the original version. | ||
8 | Please send bug reports and support requests to <luc@saillard.org>. | ||
9 | The decompression routines have been implemented by reverse-engineering the | ||
10 | Nemosoft binary pwcx module. Caveat emptor. | ||
11 | |||
12 | This program is free software; you can redistribute it and/or modify | ||
13 | it under the terms of the GNU General Public License as published by | ||
14 | the Free Software Foundation; either version 2 of the License, or | ||
15 | (at your option) any later version. | ||
16 | |||
17 | This program is distributed in the hope that it will be useful, | ||
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | GNU General Public License for more details. | ||
21 | |||
22 | You should have received a copy of the GNU General Public License | ||
23 | along with this program; if not, write to the Free Software | ||
24 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | |||
26 | */ | ||
27 | |||
28 | /* | ||
29 | This code forms the interface between the USB layers and the Philips | ||
30 | specific stuff. Some adanved stuff of the driver falls under an | ||
31 | NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and | ||
32 | is thus not distributed in source form. The binary pwcx.o module | ||
33 | contains the code that falls under the NDA. | ||
34 | |||
35 | In case you're wondering: 'pwc' stands for "Philips WebCam", but | ||
36 | I really didn't want to type 'philips_web_cam' every time (I'm lazy as | ||
37 | any Linux kernel hacker, but I don't like uncomprehensible abbreviations | ||
38 | without explanation). | ||
39 | |||
40 | Oh yes, convention: to disctinguish between all the various pointers to | ||
41 | device-structures, I use these names for the pointer variables: | ||
42 | udev: struct usb_device * | ||
43 | vdev: struct video_device * | ||
44 | pdev: struct pwc_devive * | ||
45 | */ | ||
46 | |||
47 | /* Contributors: | ||
48 | - Alvarado: adding whitebalance code | ||
49 | - Alistar Moire: QuickCam 3000 Pro device/product ID | ||
50 | - Tony Hoyle: Creative Labs Webcam 5 device/product ID | ||
51 | - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged | ||
52 | - Jk Fang: Sotec Afina Eye ID | ||
53 | - Xavier Roche: QuickCam Pro 4000 ID | ||
54 | - Jens Knudsen: QuickCam Zoom ID | ||
55 | - J. Debert: QuickCam for Notebooks ID | ||
56 | */ | ||
57 | |||
58 | #include <linux/errno.h> | ||
59 | #include <linux/init.h> | ||
60 | #include <linux/mm.h> | ||
61 | #include <linux/module.h> | ||
62 | #include <linux/poll.h> | ||
63 | #include <linux/slab.h> | ||
64 | #include <linux/vmalloc.h> | ||
65 | #include <asm/io.h> | ||
66 | |||
67 | #include "pwc.h" | ||
68 | #include "pwc-ioctl.h" | ||
69 | #include "pwc-kiara.h" | ||
70 | #include "pwc-timon.h" | ||
71 | #include "pwc-uncompress.h" | ||
72 | |||
73 | /* Function prototypes and driver templates */ | ||
74 | |||
75 | /* hotplug device table support */ | ||
76 | static struct usb_device_id pwc_device_table [] = { | ||
77 | { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ | ||
78 | { USB_DEVICE(0x0471, 0x0303) }, | ||
79 | { USB_DEVICE(0x0471, 0x0304) }, | ||
80 | { USB_DEVICE(0x0471, 0x0307) }, | ||
81 | { USB_DEVICE(0x0471, 0x0308) }, | ||
82 | { USB_DEVICE(0x0471, 0x030C) }, | ||
83 | { USB_DEVICE(0x0471, 0x0310) }, | ||
84 | { USB_DEVICE(0x0471, 0x0311) }, | ||
85 | { USB_DEVICE(0x0471, 0x0312) }, | ||
86 | { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */ | ||
87 | { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ | ||
88 | { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */ | ||
89 | { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */ | ||
90 | { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */ | ||
91 | { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */ | ||
92 | { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */ | ||
93 | { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */ | ||
94 | { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */ | ||
95 | { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */ | ||
96 | { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ | ||
97 | { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */ | ||
98 | { USB_DEVICE(0x055D, 0x9001) }, | ||
99 | { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */ | ||
100 | { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */ | ||
101 | { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ | ||
102 | { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */ | ||
103 | { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ | ||
104 | { USB_DEVICE(0x0d81, 0x1900) }, | ||
105 | { } | ||
106 | }; | ||
107 | MODULE_DEVICE_TABLE(usb, pwc_device_table); | ||
108 | |||
109 | static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id); | ||
110 | static void usb_pwc_disconnect(struct usb_interface *intf); | ||
111 | |||
112 | static struct usb_driver pwc_driver = { | ||
113 | .name = "Philips webcam", /* name */ | ||
114 | .id_table = pwc_device_table, | ||
115 | .probe = usb_pwc_probe, /* probe() */ | ||
116 | .disconnect = usb_pwc_disconnect, /* disconnect() */ | ||
117 | }; | ||
118 | |||
119 | #define MAX_DEV_HINTS 20 | ||
120 | #define MAX_ISOC_ERRORS 20 | ||
121 | |||
122 | static int default_size = PSZ_QCIF; | ||
123 | static int default_fps = 10; | ||
124 | static int default_fbufs = 3; /* Default number of frame buffers */ | ||
125 | static int default_mbufs = 2; /* Default number of mmap() buffers */ | ||
126 | int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; | ||
127 | static int power_save = 0; | ||
128 | static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ | ||
129 | static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ | ||
130 | static struct { | ||
131 | int type; | ||
132 | char serial_number[30]; | ||
133 | int device_node; | ||
134 | struct pwc_device *pdev; | ||
135 | } device_hint[MAX_DEV_HINTS]; | ||
136 | |||
137 | /***/ | ||
138 | |||
139 | static int pwc_video_open(struct inode *inode, struct file *file); | ||
140 | static int pwc_video_close(struct inode *inode, struct file *file); | ||
141 | static ssize_t pwc_video_read(struct file *file, char __user * buf, | ||
142 | size_t count, loff_t *ppos); | ||
143 | static unsigned int pwc_video_poll(struct file *file, poll_table *wait); | ||
144 | static int pwc_video_ioctl(struct inode *inode, struct file *file, | ||
145 | unsigned int ioctlnr, unsigned long arg); | ||
146 | static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); | ||
147 | |||
148 | static struct file_operations pwc_fops = { | ||
149 | .owner = THIS_MODULE, | ||
150 | .open = pwc_video_open, | ||
151 | .release = pwc_video_close, | ||
152 | .read = pwc_video_read, | ||
153 | .poll = pwc_video_poll, | ||
154 | .mmap = pwc_video_mmap, | ||
155 | .ioctl = pwc_video_ioctl, | ||
156 | .compat_ioctl = v4l_compat_ioctl32, | ||
157 | .llseek = no_llseek, | ||
158 | }; | ||
159 | static struct video_device pwc_template = { | ||
160 | .owner = THIS_MODULE, | ||
161 | .name = "Philips Webcam", /* Filled in later */ | ||
162 | .type = VID_TYPE_CAPTURE, | ||
163 | .hardware = VID_HARDWARE_PWC, | ||
164 | .release = video_device_release, | ||
165 | .fops = &pwc_fops, | ||
166 | .minor = -1, | ||
167 | }; | ||
168 | |||
169 | /***************************************************************************/ | ||
170 | |||
171 | /* Okay, this is some magic that I worked out and the reasoning behind it... | ||
172 | |||
173 | The biggest problem with any USB device is of course: "what to do | ||
174 | when the user unplugs the device while it is in use by an application?" | ||
175 | We have several options: | ||
176 | 1) Curse them with the 7 plagues when they do (requires divine intervention) | ||
177 | 2) Tell them not to (won't work: they'll do it anyway) | ||
178 | 3) Oops the kernel (this will have a negative effect on a user's uptime) | ||
179 | 4) Do something sensible. | ||
180 | |||
181 | Of course, we go for option 4. | ||
182 | |||
183 | It happens that this device will be linked to two times, once from | ||
184 | usb_device and once from the video_device in their respective 'private' | ||
185 | pointers. This is done when the device is probed() and all initialization | ||
186 | succeeded. The pwc_device struct links back to both structures. | ||
187 | |||
188 | When a device is unplugged while in use it will be removed from the | ||
189 | list of known USB devices; I also de-register it as a V4L device, but | ||
190 | unfortunately I can't free the memory since the struct is still in use | ||
191 | by the file descriptor. This free-ing is then deferend until the first | ||
192 | opportunity. Crude, but it works. | ||
193 | |||
194 | A small 'advantage' is that if a user unplugs the cam and plugs it back | ||
195 | in, it should get assigned the same video device minor, but unfortunately | ||
196 | it's non-trivial to re-link the cam back to the video device... (that | ||
197 | would surely be magic! :)) | ||
198 | */ | ||
199 | |||
200 | /***************************************************************************/ | ||
201 | /* Private functions */ | ||
202 | |||
203 | /* Here we want the physical address of the memory. | ||
204 | * This is used when initializing the contents of the area. | ||
205 | */ | ||
206 | static inline unsigned long kvirt_to_pa(unsigned long adr) | ||
207 | { | ||
208 | unsigned long kva, ret; | ||
209 | |||
210 | kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); | ||
211 | kva |= adr & (PAGE_SIZE-1); /* restore the offset */ | ||
212 | ret = __pa(kva); | ||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | static void * rvmalloc(unsigned long size) | ||
217 | { | ||
218 | void * mem; | ||
219 | unsigned long adr; | ||
220 | |||
221 | size=PAGE_ALIGN(size); | ||
222 | mem=vmalloc_32(size); | ||
223 | if (mem) | ||
224 | { | ||
225 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
226 | adr=(unsigned long) mem; | ||
227 | while (size > 0) | ||
228 | { | ||
229 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
230 | adr+=PAGE_SIZE; | ||
231 | size-=PAGE_SIZE; | ||
232 | } | ||
233 | } | ||
234 | return mem; | ||
235 | } | ||
236 | |||
237 | static void rvfree(void * mem, unsigned long size) | ||
238 | { | ||
239 | unsigned long adr; | ||
240 | |||
241 | if (mem) | ||
242 | { | ||
243 | adr=(unsigned long) mem; | ||
244 | while ((long) size > 0) | ||
245 | { | ||
246 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
247 | adr+=PAGE_SIZE; | ||
248 | size-=PAGE_SIZE; | ||
249 | } | ||
250 | vfree(mem); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | |||
255 | |||
256 | |||
257 | static int pwc_allocate_buffers(struct pwc_device *pdev) | ||
258 | { | ||
259 | int i; | ||
260 | void *kbuf; | ||
261 | |||
262 | Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev); | ||
263 | |||
264 | if (pdev == NULL) | ||
265 | return -ENXIO; | ||
266 | |||
267 | #ifdef PWC_MAGIC | ||
268 | if (pdev->magic != PWC_MAGIC) { | ||
269 | Err("allocate_buffers(): magic failed.\n"); | ||
270 | return -ENXIO; | ||
271 | } | ||
272 | #endif | ||
273 | /* Allocate Isochronous pipe buffers */ | ||
274 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
275 | if (pdev->sbuf[i].data == NULL) { | ||
276 | kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL); | ||
277 | if (kbuf == NULL) { | ||
278 | Err("Failed to allocate iso buffer %d.\n", i); | ||
279 | return -ENOMEM; | ||
280 | } | ||
281 | Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf); | ||
282 | pdev->sbuf[i].data = kbuf; | ||
283 | memset(kbuf, 0, ISO_BUFFER_SIZE); | ||
284 | } | ||
285 | } | ||
286 | |||
287 | /* Allocate frame buffer structure */ | ||
288 | if (pdev->fbuf == NULL) { | ||
289 | kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL); | ||
290 | if (kbuf == NULL) { | ||
291 | Err("Failed to allocate frame buffer structure.\n"); | ||
292 | return -ENOMEM; | ||
293 | } | ||
294 | Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf); | ||
295 | pdev->fbuf = kbuf; | ||
296 | memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf)); | ||
297 | } | ||
298 | /* create frame buffers, and make circular ring */ | ||
299 | for (i = 0; i < default_fbufs; i++) { | ||
300 | if (pdev->fbuf[i].data == NULL) { | ||
301 | kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */ | ||
302 | if (kbuf == NULL) { | ||
303 | Err("Failed to allocate frame buffer %d.\n", i); | ||
304 | return -ENOMEM; | ||
305 | } | ||
306 | Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf); | ||
307 | pdev->fbuf[i].data = kbuf; | ||
308 | memset(kbuf, 128, PWC_FRAME_SIZE); | ||
309 | } | ||
310 | } | ||
311 | |||
312 | /* Allocate decompressor table space */ | ||
313 | kbuf = NULL; | ||
314 | switch (pdev->type) | ||
315 | { | ||
316 | case 675: | ||
317 | case 680: | ||
318 | case 690: | ||
319 | case 720: | ||
320 | case 730: | ||
321 | case 740: | ||
322 | case 750: | ||
323 | #if 0 | ||
324 | Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private)); | ||
325 | kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); /* Timon & Kiara */ | ||
326 | break; | ||
327 | case 645: | ||
328 | case 646: | ||
329 | /* TODO & FIXME */ | ||
330 | kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); | ||
331 | break; | ||
332 | #endif | ||
333 | ; | ||
334 | } | ||
335 | pdev->decompress_data = kbuf; | ||
336 | |||
337 | /* Allocate image buffer; double buffer for mmap() */ | ||
338 | kbuf = rvmalloc(default_mbufs * pdev->len_per_image); | ||
339 | if (kbuf == NULL) { | ||
340 | Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image); | ||
341 | return -ENOMEM; | ||
342 | } | ||
343 | Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf); | ||
344 | pdev->image_data = kbuf; | ||
345 | for (i = 0; i < default_mbufs; i++) | ||
346 | pdev->image_ptr[i] = kbuf + i * pdev->len_per_image; | ||
347 | for (; i < MAX_IMAGES; i++) | ||
348 | pdev->image_ptr[i] = NULL; | ||
349 | |||
350 | kbuf = NULL; | ||
351 | |||
352 | Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n"); | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static void pwc_free_buffers(struct pwc_device *pdev) | ||
357 | { | ||
358 | int i; | ||
359 | |||
360 | Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev); | ||
361 | |||
362 | if (pdev == NULL) | ||
363 | return; | ||
364 | #ifdef PWC_MAGIC | ||
365 | if (pdev->magic != PWC_MAGIC) { | ||
366 | Err("free_buffers(): magic failed.\n"); | ||
367 | return; | ||
368 | } | ||
369 | #endif | ||
370 | |||
371 | /* Release Iso-pipe buffers */ | ||
372 | for (i = 0; i < MAX_ISO_BUFS; i++) | ||
373 | if (pdev->sbuf[i].data != NULL) { | ||
374 | Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data); | ||
375 | kfree(pdev->sbuf[i].data); | ||
376 | pdev->sbuf[i].data = NULL; | ||
377 | } | ||
378 | |||
379 | /* The same for frame buffers */ | ||
380 | if (pdev->fbuf != NULL) { | ||
381 | for (i = 0; i < default_fbufs; i++) { | ||
382 | if (pdev->fbuf[i].data != NULL) { | ||
383 | Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data); | ||
384 | vfree(pdev->fbuf[i].data); | ||
385 | pdev->fbuf[i].data = NULL; | ||
386 | } | ||
387 | } | ||
388 | kfree(pdev->fbuf); | ||
389 | pdev->fbuf = NULL; | ||
390 | } | ||
391 | |||
392 | /* Intermediate decompression buffer & tables */ | ||
393 | if (pdev->decompress_data != NULL) { | ||
394 | Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data); | ||
395 | kfree(pdev->decompress_data); | ||
396 | pdev->decompress_data = NULL; | ||
397 | } | ||
398 | pdev->decompressor = NULL; | ||
399 | |||
400 | /* Release image buffers */ | ||
401 | if (pdev->image_data != NULL) { | ||
402 | Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data); | ||
403 | rvfree(pdev->image_data, default_mbufs * pdev->len_per_image); | ||
404 | } | ||
405 | pdev->image_data = NULL; | ||
406 | |||
407 | Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); | ||
408 | } | ||
409 | |||
410 | /* The frame & image buffer mess. | ||
411 | |||
412 | Yes, this is a mess. Well, it used to be simple, but alas... In this | ||
413 | module, 3 buffers schemes are used to get the data from the USB bus to | ||
414 | the user program. The first scheme involves the ISO buffers (called thus | ||
415 | since they transport ISO data from the USB controller), and not really | ||
416 | interesting. Suffices to say the data from this buffer is quickly | ||
417 | gathered in an interrupt handler (pwc_isoc_handler) and placed into the | ||
418 | frame buffer. | ||
419 | |||
420 | The frame buffer is the second scheme, and is the central element here. | ||
421 | It collects the data from a single frame from the camera (hence, the | ||
422 | name). Frames are delimited by the USB camera with a short USB packet, | ||
423 | so that's easy to detect. The frame buffers form a list that is filled | ||
424 | by the camera+USB controller and drained by the user process through | ||
425 | either read() or mmap(). | ||
426 | |||
427 | The image buffer is the third scheme, in which frames are decompressed | ||
428 | and converted into planar format. For mmap() there is more than | ||
429 | one image buffer available. | ||
430 | |||
431 | The frame buffers provide the image buffering. In case the user process | ||
432 | is a bit slow, this introduces lag and some undesired side-effects. | ||
433 | The problem arises when the frame buffer is full. I used to drop the last | ||
434 | frame, which makes the data in the queue stale very quickly. But dropping | ||
435 | the frame at the head of the queue proved to be a litte bit more difficult. | ||
436 | I tried a circular linked scheme, but this introduced more problems than | ||
437 | it solved. | ||
438 | |||
439 | Because filling and draining are completely asynchronous processes, this | ||
440 | requires some fiddling with pointers and mutexes. | ||
441 | |||
442 | Eventually, I came up with a system with 2 lists: an 'empty' frame list | ||
443 | and a 'full' frame list: | ||
444 | * Initially, all frame buffers but one are on the 'empty' list; the one | ||
445 | remaining buffer is our initial fill frame. | ||
446 | * If a frame is needed for filling, we try to take it from the 'empty' | ||
447 | list, unless that list is empty, in which case we take the buffer at | ||
448 | the head of the 'full' list. | ||
449 | * When our fill buffer has been filled, it is appended to the 'full' | ||
450 | list. | ||
451 | * If a frame is needed by read() or mmap(), it is taken from the head of | ||
452 | the 'full' list, handled, and then appended to the 'empty' list. If no | ||
453 | buffer is present on the 'full' list, we wait. | ||
454 | The advantage is that the buffer that is currently being decompressed/ | ||
455 | converted, is on neither list, and thus not in our way (any other scheme | ||
456 | I tried had the problem of old data lingering in the queue). | ||
457 | |||
458 | Whatever strategy you choose, it always remains a tradeoff: with more | ||
459 | frame buffers the chances of a missed frame are reduced. On the other | ||
460 | hand, on slower machines it introduces lag because the queue will | ||
461 | always be full. | ||
462 | */ | ||
463 | |||
464 | /** | ||
465 | \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first. | ||
466 | */ | ||
467 | static inline int pwc_next_fill_frame(struct pwc_device *pdev) | ||
468 | { | ||
469 | int ret; | ||
470 | unsigned long flags; | ||
471 | |||
472 | ret = 0; | ||
473 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
474 | if (pdev->fill_frame != NULL) { | ||
475 | /* append to 'full' list */ | ||
476 | if (pdev->full_frames == NULL) { | ||
477 | pdev->full_frames = pdev->fill_frame; | ||
478 | pdev->full_frames_tail = pdev->full_frames; | ||
479 | } | ||
480 | else { | ||
481 | pdev->full_frames_tail->next = pdev->fill_frame; | ||
482 | pdev->full_frames_tail = pdev->fill_frame; | ||
483 | } | ||
484 | } | ||
485 | if (pdev->empty_frames != NULL) { | ||
486 | /* We have empty frames available. That's easy */ | ||
487 | pdev->fill_frame = pdev->empty_frames; | ||
488 | pdev->empty_frames = pdev->empty_frames->next; | ||
489 | } | ||
490 | else { | ||
491 | /* Hmm. Take it from the full list */ | ||
492 | #if PWC_DEBUG | ||
493 | /* sanity check */ | ||
494 | if (pdev->full_frames == NULL) { | ||
495 | Err("Neither empty or full frames available!\n"); | ||
496 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
497 | return -EINVAL; | ||
498 | } | ||
499 | #endif | ||
500 | pdev->fill_frame = pdev->full_frames; | ||
501 | pdev->full_frames = pdev->full_frames->next; | ||
502 | ret = 1; | ||
503 | } | ||
504 | pdev->fill_frame->next = NULL; | ||
505 | #if PWC_DEBUG | ||
506 | Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence); | ||
507 | pdev->fill_frame->sequence = pdev->sequence++; | ||
508 | #endif | ||
509 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
510 | return ret; | ||
511 | } | ||
512 | |||
513 | |||
514 | /** | ||
515 | \brief Reset all buffers, pointers and lists, except for the image_used[] buffer. | ||
516 | |||
517 | If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble. | ||
518 | */ | ||
519 | static void pwc_reset_buffers(struct pwc_device *pdev) | ||
520 | { | ||
521 | int i; | ||
522 | unsigned long flags; | ||
523 | |||
524 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
525 | pdev->full_frames = NULL; | ||
526 | pdev->full_frames_tail = NULL; | ||
527 | for (i = 0; i < default_fbufs; i++) { | ||
528 | pdev->fbuf[i].filled = 0; | ||
529 | if (i > 0) | ||
530 | pdev->fbuf[i].next = &pdev->fbuf[i - 1]; | ||
531 | else | ||
532 | pdev->fbuf->next = NULL; | ||
533 | } | ||
534 | pdev->empty_frames = &pdev->fbuf[default_fbufs - 1]; | ||
535 | pdev->empty_frames_tail = pdev->fbuf; | ||
536 | pdev->read_frame = NULL; | ||
537 | pdev->fill_frame = pdev->empty_frames; | ||
538 | pdev->empty_frames = pdev->empty_frames->next; | ||
539 | |||
540 | pdev->image_read_pos = 0; | ||
541 | pdev->fill_image = 0; | ||
542 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
543 | } | ||
544 | |||
545 | |||
546 | /** | ||
547 | \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers. | ||
548 | */ | ||
549 | static int pwc_handle_frame(struct pwc_device *pdev) | ||
550 | { | ||
551 | int ret = 0; | ||
552 | unsigned long flags; | ||
553 | |||
554 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
555 | /* First grab our read_frame; this is removed from all lists, so | ||
556 | we can release the lock after this without problems */ | ||
557 | if (pdev->read_frame != NULL) { | ||
558 | /* This can't theoretically happen */ | ||
559 | Err("Huh? Read frame still in use?\n"); | ||
560 | } | ||
561 | else { | ||
562 | if (pdev->full_frames == NULL) { | ||
563 | Err("Woops. No frames ready.\n"); | ||
564 | } | ||
565 | else { | ||
566 | pdev->read_frame = pdev->full_frames; | ||
567 | pdev->full_frames = pdev->full_frames->next; | ||
568 | pdev->read_frame->next = NULL; | ||
569 | } | ||
570 | |||
571 | if (pdev->read_frame != NULL) { | ||
572 | #if PWC_DEBUG | ||
573 | Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence); | ||
574 | #endif | ||
575 | /* Decompression is a lenghty process, so it's outside of the lock. | ||
576 | This gives the isoc_handler the opportunity to fill more frames | ||
577 | in the mean time. | ||
578 | */ | ||
579 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
580 | ret = pwc_decompress(pdev); | ||
581 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
582 | |||
583 | /* We're done with read_buffer, tack it to the end of the empty buffer list */ | ||
584 | if (pdev->empty_frames == NULL) { | ||
585 | pdev->empty_frames = pdev->read_frame; | ||
586 | pdev->empty_frames_tail = pdev->empty_frames; | ||
587 | } | ||
588 | else { | ||
589 | pdev->empty_frames_tail->next = pdev->read_frame; | ||
590 | pdev->empty_frames_tail = pdev->read_frame; | ||
591 | } | ||
592 | pdev->read_frame = NULL; | ||
593 | } | ||
594 | } | ||
595 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
596 | return ret; | ||
597 | } | ||
598 | |||
599 | /** | ||
600 | \brief Advance pointers of image buffer (after each user request) | ||
601 | */ | ||
602 | static inline void pwc_next_image(struct pwc_device *pdev) | ||
603 | { | ||
604 | pdev->image_used[pdev->fill_image] = 0; | ||
605 | pdev->fill_image = (pdev->fill_image + 1) % default_mbufs; | ||
606 | } | ||
607 | |||
608 | |||
609 | /* This gets called for the Isochronous pipe (video). This is done in | ||
610 | * interrupt time, so it has to be fast, not crash, and not stall. Neat. | ||
611 | */ | ||
612 | static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) | ||
613 | { | ||
614 | struct pwc_device *pdev; | ||
615 | int i, fst, flen; | ||
616 | int awake; | ||
617 | struct pwc_frame_buf *fbuf; | ||
618 | unsigned char *fillptr = NULL, *iso_buf = NULL; | ||
619 | |||
620 | awake = 0; | ||
621 | pdev = (struct pwc_device *)urb->context; | ||
622 | if (pdev == NULL) { | ||
623 | Err("isoc_handler() called with NULL device?!\n"); | ||
624 | return; | ||
625 | } | ||
626 | #ifdef PWC_MAGIC | ||
627 | if (pdev->magic != PWC_MAGIC) { | ||
628 | Err("isoc_handler() called with bad magic!\n"); | ||
629 | return; | ||
630 | } | ||
631 | #endif | ||
632 | if (urb->status == -ENOENT || urb->status == -ECONNRESET) { | ||
633 | Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); | ||
634 | return; | ||
635 | } | ||
636 | if (urb->status != -EINPROGRESS && urb->status != 0) { | ||
637 | const char *errmsg; | ||
638 | |||
639 | errmsg = "Unknown"; | ||
640 | switch(urb->status) { | ||
641 | case -ENOSR: errmsg = "Buffer error (overrun)"; break; | ||
642 | case -EPIPE: errmsg = "Stalled (device not responding)"; break; | ||
643 | case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break; | ||
644 | case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break; | ||
645 | case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break; | ||
646 | case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break; | ||
647 | } | ||
648 | Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg); | ||
649 | /* Give up after a number of contiguous errors on the USB bus. | ||
650 | Appearantly something is wrong so we simulate an unplug event. | ||
651 | */ | ||
652 | if (++pdev->visoc_errors > MAX_ISOC_ERRORS) | ||
653 | { | ||
654 | Info("Too many ISOC errors, bailing out.\n"); | ||
655 | pdev->error_status = EIO; | ||
656 | awake = 1; | ||
657 | wake_up_interruptible(&pdev->frameq); | ||
658 | } | ||
659 | goto handler_end; // ugly, but practical | ||
660 | } | ||
661 | |||
662 | fbuf = pdev->fill_frame; | ||
663 | if (fbuf == NULL) { | ||
664 | Err("pwc_isoc_handler without valid fill frame.\n"); | ||
665 | awake = 1; | ||
666 | goto handler_end; | ||
667 | } | ||
668 | else { | ||
669 | fillptr = fbuf->data + fbuf->filled; | ||
670 | } | ||
671 | |||
672 | /* Reset ISOC error counter. We did get here, after all. */ | ||
673 | pdev->visoc_errors = 0; | ||
674 | |||
675 | /* vsync: 0 = don't copy data | ||
676 | 1 = sync-hunt | ||
677 | 2 = synched | ||
678 | */ | ||
679 | /* Compact data */ | ||
680 | for (i = 0; i < urb->number_of_packets; i++) { | ||
681 | fst = urb->iso_frame_desc[i].status; | ||
682 | flen = urb->iso_frame_desc[i].actual_length; | ||
683 | iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; | ||
684 | if (fst == 0) { | ||
685 | if (flen > 0) { /* if valid data... */ | ||
686 | if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */ | ||
687 | pdev->vsync = 2; | ||
688 | |||
689 | /* ...copy data to frame buffer, if possible */ | ||
690 | if (flen + fbuf->filled > pdev->frame_total_size) { | ||
691 | Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size); | ||
692 | pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */ | ||
693 | pdev->vframes_error++; | ||
694 | } | ||
695 | else { | ||
696 | memmove(fillptr, iso_buf, flen); | ||
697 | fillptr += flen; | ||
698 | } | ||
699 | } | ||
700 | fbuf->filled += flen; | ||
701 | } /* ..flen > 0 */ | ||
702 | |||
703 | if (flen < pdev->vlast_packet_size) { | ||
704 | /* Shorter packet... We probably have the end of an image-frame; | ||
705 | wake up read() process and let select()/poll() do something. | ||
706 | Decompression is done in user time over there. | ||
707 | */ | ||
708 | if (pdev->vsync == 2) { | ||
709 | /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus | ||
710 | frames on the USB wire after an exposure change. This conditition is | ||
711 | however detected in the cam and a bit is set in the header. | ||
712 | */ | ||
713 | if (pdev->type == 730) { | ||
714 | unsigned char *ptr = (unsigned char *)fbuf->data; | ||
715 | |||
716 | if (ptr[1] == 1 && ptr[0] & 0x10) { | ||
717 | #if PWC_DEBUG | ||
718 | Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence); | ||
719 | #endif | ||
720 | pdev->drop_frames += 2; | ||
721 | pdev->vframes_error++; | ||
722 | } | ||
723 | if ((ptr[0] ^ pdev->vmirror) & 0x01) { | ||
724 | if (ptr[0] & 0x01) | ||
725 | Info("Snapshot button pressed.\n"); | ||
726 | else | ||
727 | Info("Snapshot button released.\n"); | ||
728 | } | ||
729 | if ((ptr[0] ^ pdev->vmirror) & 0x02) { | ||
730 | if (ptr[0] & 0x02) | ||
731 | Info("Image is mirrored.\n"); | ||
732 | else | ||
733 | Info("Image is normal.\n"); | ||
734 | } | ||
735 | pdev->vmirror = ptr[0] & 0x03; | ||
736 | /* Sometimes the trailer of the 730 is still sent as a 4 byte packet | ||
737 | after a short frame; this condition is filtered out specifically. A 4 byte | ||
738 | frame doesn't make sense anyway. | ||
739 | So we get either this sequence: | ||
740 | drop_bit set -> 4 byte frame -> short frame -> good frame | ||
741 | Or this one: | ||
742 | drop_bit set -> short frame -> good frame | ||
743 | So we drop either 3 or 2 frames in all! | ||
744 | */ | ||
745 | if (fbuf->filled == 4) | ||
746 | pdev->drop_frames++; | ||
747 | } | ||
748 | |||
749 | /* In case we were instructed to drop the frame, do so silently. | ||
750 | The buffer pointers are not updated either (but the counters are reset below). | ||
751 | */ | ||
752 | if (pdev->drop_frames > 0) | ||
753 | pdev->drop_frames--; | ||
754 | else { | ||
755 | /* Check for underflow first */ | ||
756 | if (fbuf->filled < pdev->frame_total_size) { | ||
757 | Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled); | ||
758 | pdev->vframes_error++; | ||
759 | } | ||
760 | else { | ||
761 | /* Send only once per EOF */ | ||
762 | awake = 1; /* delay wake_ups */ | ||
763 | |||
764 | /* Find our next frame to fill. This will always succeed, since we | ||
765 | * nick a frame from either empty or full list, but if we had to | ||
766 | * take it from the full list, it means a frame got dropped. | ||
767 | */ | ||
768 | if (pwc_next_fill_frame(pdev)) { | ||
769 | pdev->vframes_dumped++; | ||
770 | if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) { | ||
771 | if (pdev->vframes_dumped < 20) | ||
772 | Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count); | ||
773 | if (pdev->vframes_dumped == 20) | ||
774 | Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count); | ||
775 | } | ||
776 | } | ||
777 | fbuf = pdev->fill_frame; | ||
778 | } | ||
779 | } /* !drop_frames */ | ||
780 | pdev->vframe_count++; | ||
781 | } | ||
782 | fbuf->filled = 0; | ||
783 | fillptr = fbuf->data; | ||
784 | pdev->vsync = 1; | ||
785 | } /* .. flen < last_packet_size */ | ||
786 | pdev->vlast_packet_size = flen; | ||
787 | } /* ..status == 0 */ | ||
788 | #if PWC_DEBUG | ||
789 | /* This is normally not interesting to the user, unless you are really debugging something */ | ||
790 | else { | ||
791 | static int iso_error = 0; | ||
792 | iso_error++; | ||
793 | if (iso_error < 20) | ||
794 | Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst); | ||
795 | } | ||
796 | #endif | ||
797 | } | ||
798 | |||
799 | handler_end: | ||
800 | if (awake) | ||
801 | wake_up_interruptible(&pdev->frameq); | ||
802 | |||
803 | urb->dev = pdev->udev; | ||
804 | i = usb_submit_urb(urb, GFP_ATOMIC); | ||
805 | if (i != 0) | ||
806 | Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); | ||
807 | } | ||
808 | |||
809 | |||
810 | static int pwc_isoc_init(struct pwc_device *pdev) | ||
811 | { | ||
812 | struct usb_device *udev; | ||
813 | struct urb *urb; | ||
814 | int i, j, ret; | ||
815 | |||
816 | struct usb_interface *intf; | ||
817 | struct usb_host_interface *idesc = NULL; | ||
818 | |||
819 | if (pdev == NULL) | ||
820 | return -EFAULT; | ||
821 | if (pdev->iso_init) | ||
822 | return 0; | ||
823 | pdev->vsync = 0; | ||
824 | udev = pdev->udev; | ||
825 | |||
826 | /* Get the current alternate interface, adjust packet size */ | ||
827 | if (!udev->actconfig) | ||
828 | return -EFAULT; | ||
829 | |||
830 | intf = usb_ifnum_to_if(udev, 0); | ||
831 | if (intf) | ||
832 | idesc = usb_altnum_to_altsetting(intf, pdev->valternate); | ||
833 | |||
834 | if (!idesc) | ||
835 | return -EFAULT; | ||
836 | |||
837 | /* Search video endpoint */ | ||
838 | pdev->vmax_packet_size = -1; | ||
839 | for (i = 0; i < idesc->desc.bNumEndpoints; i++) | ||
840 | if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) { | ||
841 | pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize); | ||
842 | break; | ||
843 | } | ||
844 | |||
845 | if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) { | ||
846 | Err("Failed to find packet size for video endpoint in current alternate setting.\n"); | ||
847 | return -ENFILE; /* Odd error, that should be noticeable */ | ||
848 | } | ||
849 | |||
850 | /* Set alternate interface */ | ||
851 | ret = 0; | ||
852 | Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate); | ||
853 | ret = usb_set_interface(pdev->udev, 0, pdev->valternate); | ||
854 | if (ret < 0) | ||
855 | return ret; | ||
856 | |||
857 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
858 | urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); | ||
859 | if (urb == NULL) { | ||
860 | Err("Failed to allocate urb %d\n", i); | ||
861 | ret = -ENOMEM; | ||
862 | break; | ||
863 | } | ||
864 | pdev->sbuf[i].urb = urb; | ||
865 | Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb); | ||
866 | } | ||
867 | if (ret) { | ||
868 | /* De-allocate in reverse order */ | ||
869 | while (i >= 0) { | ||
870 | if (pdev->sbuf[i].urb != NULL) | ||
871 | usb_free_urb(pdev->sbuf[i].urb); | ||
872 | pdev->sbuf[i].urb = NULL; | ||
873 | i--; | ||
874 | } | ||
875 | return ret; | ||
876 | } | ||
877 | |||
878 | /* init URB structure */ | ||
879 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
880 | urb = pdev->sbuf[i].urb; | ||
881 | |||
882 | urb->interval = 1; // devik | ||
883 | urb->dev = udev; | ||
884 | urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); | ||
885 | urb->transfer_flags = URB_ISO_ASAP; | ||
886 | urb->transfer_buffer = pdev->sbuf[i].data; | ||
887 | urb->transfer_buffer_length = ISO_BUFFER_SIZE; | ||
888 | urb->complete = pwc_isoc_handler; | ||
889 | urb->context = pdev; | ||
890 | urb->start_frame = 0; | ||
891 | urb->number_of_packets = ISO_FRAMES_PER_DESC; | ||
892 | for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { | ||
893 | urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; | ||
894 | urb->iso_frame_desc[j].length = pdev->vmax_packet_size; | ||
895 | } | ||
896 | } | ||
897 | |||
898 | /* link */ | ||
899 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
900 | ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL); | ||
901 | if (ret) | ||
902 | Err("isoc_init() submit_urb %d failed with error %d\n", i, ret); | ||
903 | else | ||
904 | Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb); | ||
905 | } | ||
906 | |||
907 | /* All is done... */ | ||
908 | pdev->iso_init = 1; | ||
909 | Trace(TRACE_OPEN, "<< pwc_isoc_init()\n"); | ||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | static void pwc_isoc_cleanup(struct pwc_device *pdev) | ||
914 | { | ||
915 | int i; | ||
916 | |||
917 | Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n"); | ||
918 | if (pdev == NULL) | ||
919 | return; | ||
920 | |||
921 | /* Unlinking ISOC buffers one by one */ | ||
922 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
923 | struct urb *urb; | ||
924 | |||
925 | urb = pdev->sbuf[i].urb; | ||
926 | if (urb != 0) { | ||
927 | if (pdev->iso_init) { | ||
928 | Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb); | ||
929 | usb_kill_urb(urb); | ||
930 | } | ||
931 | Trace(TRACE_MEMORY, "Freeing URB\n"); | ||
932 | usb_free_urb(urb); | ||
933 | pdev->sbuf[i].urb = NULL; | ||
934 | } | ||
935 | } | ||
936 | |||
937 | /* Stop camera, but only if we are sure the camera is still there (unplug | ||
938 | is signalled by EPIPE) | ||
939 | */ | ||
940 | if (pdev->error_status && pdev->error_status != EPIPE) { | ||
941 | Trace(TRACE_OPEN, "Setting alternate interface 0.\n"); | ||
942 | usb_set_interface(pdev->udev, 0, 0); | ||
943 | } | ||
944 | |||
945 | pdev->iso_init = 0; | ||
946 | Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n"); | ||
947 | } | ||
948 | |||
949 | int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot) | ||
950 | { | ||
951 | int ret, start; | ||
952 | |||
953 | /* Stop isoc stuff */ | ||
954 | pwc_isoc_cleanup(pdev); | ||
955 | /* Reset parameters */ | ||
956 | pwc_reset_buffers(pdev); | ||
957 | /* Try to set video mode... */ | ||
958 | start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot); | ||
959 | if (ret) { | ||
960 | Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n"); | ||
961 | /* That failed... restore old mode (we know that worked) */ | ||
962 | start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); | ||
963 | if (start) { | ||
964 | Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n"); | ||
965 | } | ||
966 | } | ||
967 | if (start == 0) | ||
968 | { | ||
969 | if (pwc_isoc_init(pdev) < 0) | ||
970 | { | ||
971 | Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n"); | ||
972 | ret = -EAGAIN; /* let's try again, who knows if it works a second time */ | ||
973 | } | ||
974 | } | ||
975 | pdev->drop_frames++; /* try to avoid garbage during switch */ | ||
976 | return ret; /* Return original error code */ | ||
977 | } | ||
978 | |||
979 | |||
980 | /***************************************************************************/ | ||
981 | /* Video4Linux functions */ | ||
982 | |||
983 | static int pwc_video_open(struct inode *inode, struct file *file) | ||
984 | { | ||
985 | int i; | ||
986 | struct video_device *vdev = video_devdata(file); | ||
987 | struct pwc_device *pdev; | ||
988 | |||
989 | Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev); | ||
990 | |||
991 | pdev = (struct pwc_device *)vdev->priv; | ||
992 | if (pdev == NULL) | ||
993 | BUG(); | ||
994 | if (pdev->vopen) | ||
995 | return -EBUSY; | ||
996 | |||
997 | down(&pdev->modlock); | ||
998 | if (!pdev->usb_init) { | ||
999 | Trace(TRACE_OPEN, "Doing first time initialization.\n"); | ||
1000 | pdev->usb_init = 1; | ||
1001 | |||
1002 | if (pwc_trace & TRACE_OPEN) | ||
1003 | { | ||
1004 | /* Query sensor type */ | ||
1005 | const char *sensor_type = NULL; | ||
1006 | int ret; | ||
1007 | |||
1008 | ret = pwc_get_cmos_sensor(pdev, &i); | ||
1009 | if (ret >= 0) | ||
1010 | { | ||
1011 | switch(i) { | ||
1012 | case 0x00: sensor_type = "Hyundai CMOS sensor"; break; | ||
1013 | case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break; | ||
1014 | case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break; | ||
1015 | case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break; | ||
1016 | case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break; | ||
1017 | case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break; | ||
1018 | case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break; | ||
1019 | case 0x40: sensor_type = "UPA 1021 sensor"; break; | ||
1020 | case 0x100: sensor_type = "VGA sensor"; break; | ||
1021 | case 0x101: sensor_type = "PAL MR sensor"; break; | ||
1022 | default: sensor_type = "unknown type of sensor"; break; | ||
1023 | } | ||
1024 | } | ||
1025 | if (sensor_type != NULL) | ||
1026 | Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | /* Turn on camera */ | ||
1031 | if (power_save) { | ||
1032 | i = pwc_camera_power(pdev, 1); | ||
1033 | if (i < 0) | ||
1034 | Info("Failed to restore power to the camera! (%d)\n", i); | ||
1035 | } | ||
1036 | /* Set LED on/off time */ | ||
1037 | if (pwc_set_leds(pdev, led_on, led_off) < 0) | ||
1038 | Info("Failed to set LED on/off time.\n"); | ||
1039 | |||
1040 | pwc_construct(pdev); /* set min/max sizes correct */ | ||
1041 | |||
1042 | /* So far, so good. Allocate memory. */ | ||
1043 | i = pwc_allocate_buffers(pdev); | ||
1044 | if (i < 0) { | ||
1045 | Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n"); | ||
1046 | up(&pdev->modlock); | ||
1047 | return i; | ||
1048 | } | ||
1049 | |||
1050 | /* Reset buffers & parameters */ | ||
1051 | pwc_reset_buffers(pdev); | ||
1052 | for (i = 0; i < default_mbufs; i++) | ||
1053 | pdev->image_used[i] = 0; | ||
1054 | pdev->vframe_count = 0; | ||
1055 | pdev->vframes_dumped = 0; | ||
1056 | pdev->vframes_error = 0; | ||
1057 | pdev->visoc_errors = 0; | ||
1058 | pdev->error_status = 0; | ||
1059 | #if PWC_DEBUG | ||
1060 | pdev->sequence = 0; | ||
1061 | #endif | ||
1062 | pwc_construct(pdev); /* set min/max sizes correct */ | ||
1063 | |||
1064 | /* Set some defaults */ | ||
1065 | pdev->vsnapshot = 0; | ||
1066 | |||
1067 | /* Start iso pipe for video; first try the last used video size | ||
1068 | (or the default one); if that fails try QCIF/10 or QSIF/10; | ||
1069 | it that fails too, give up. | ||
1070 | */ | ||
1071 | i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0); | ||
1072 | if (i) { | ||
1073 | Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n"); | ||
1074 | if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750) | ||
1075 | i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0); | ||
1076 | else | ||
1077 | i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0); | ||
1078 | } | ||
1079 | if (i) { | ||
1080 | Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n"); | ||
1081 | up(&pdev->modlock); | ||
1082 | return i; | ||
1083 | } | ||
1084 | |||
1085 | i = pwc_isoc_init(pdev); | ||
1086 | if (i) { | ||
1087 | Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i); | ||
1088 | up(&pdev->modlock); | ||
1089 | return i; | ||
1090 | } | ||
1091 | |||
1092 | pdev->vopen++; | ||
1093 | file->private_data = vdev; | ||
1094 | up(&pdev->modlock); | ||
1095 | Trace(TRACE_OPEN, "<< video_open() returns 0.\n"); | ||
1096 | return 0; | ||
1097 | } | ||
1098 | |||
1099 | /* Note that all cleanup is done in the reverse order as in _open */ | ||
1100 | static int pwc_video_close(struct inode *inode, struct file *file) | ||
1101 | { | ||
1102 | struct video_device *vdev = file->private_data; | ||
1103 | struct pwc_device *pdev; | ||
1104 | int i; | ||
1105 | |||
1106 | Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev); | ||
1107 | |||
1108 | pdev = (struct pwc_device *)vdev->priv; | ||
1109 | if (pdev->vopen == 0) | ||
1110 | Info("video_close() called on closed device?\n"); | ||
1111 | |||
1112 | /* Dump statistics, but only if a reasonable amount of frames were | ||
1113 | processed (to prevent endless log-entries in case of snap-shot | ||
1114 | programs) | ||
1115 | */ | ||
1116 | if (pdev->vframe_count > 20) | ||
1117 | Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); | ||
1118 | |||
1119 | switch (pdev->type) | ||
1120 | { | ||
1121 | case 675: | ||
1122 | case 680: | ||
1123 | case 690: | ||
1124 | case 720: | ||
1125 | case 730: | ||
1126 | case 740: | ||
1127 | case 750: | ||
1128 | /* pwc_dec23_exit(); *//* Timon & Kiara */ | ||
1129 | break; | ||
1130 | case 645: | ||
1131 | case 646: | ||
1132 | /* pwc_dec1_exit(); */ | ||
1133 | break; | ||
1134 | } | ||
1135 | |||
1136 | pwc_isoc_cleanup(pdev); | ||
1137 | pwc_free_buffers(pdev); | ||
1138 | |||
1139 | /* Turn off LEDS and power down camera, but only when not unplugged */ | ||
1140 | if (pdev->error_status != EPIPE) { | ||
1141 | /* Turn LEDs off */ | ||
1142 | if (pwc_set_leds(pdev, 0, 0) < 0) | ||
1143 | Info("Failed to set LED on/off time.\n"); | ||
1144 | if (power_save) { | ||
1145 | i = pwc_camera_power(pdev, 0); | ||
1146 | if (i < 0) | ||
1147 | Err("Failed to power down camera (%d)\n", i); | ||
1148 | } | ||
1149 | } | ||
1150 | pdev->vopen = 0; | ||
1151 | Trace(TRACE_OPEN, "<< video_close()\n"); | ||
1152 | return 0; | ||
1153 | } | ||
1154 | |||
1155 | /* | ||
1156 | * FIXME: what about two parallel reads ???? | ||
1157 | * ANSWER: Not supported. You can't open the device more than once, | ||
1158 | despite what the V4L1 interface says. First, I don't see | ||
1159 | the need, second there's no mechanism of alerting the | ||
1160 | 2nd/3rd/... process of events like changing image size. | ||
1161 | And I don't see the point of blocking that for the | ||
1162 | 2nd/3rd/... process. | ||
1163 | In multi-threaded environments reading parallel from any | ||
1164 | device is tricky anyhow. | ||
1165 | */ | ||
1166 | |||
1167 | static ssize_t pwc_video_read(struct file *file, char __user * buf, | ||
1168 | size_t count, loff_t *ppos) | ||
1169 | { | ||
1170 | struct video_device *vdev = file->private_data; | ||
1171 | struct pwc_device *pdev; | ||
1172 | int noblock = file->f_flags & O_NONBLOCK; | ||
1173 | DECLARE_WAITQUEUE(wait, current); | ||
1174 | int bytes_to_read; | ||
1175 | |||
1176 | Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count); | ||
1177 | if (vdev == NULL) | ||
1178 | return -EFAULT; | ||
1179 | pdev = vdev->priv; | ||
1180 | if (pdev == NULL) | ||
1181 | return -EFAULT; | ||
1182 | if (pdev->error_status) | ||
1183 | return -pdev->error_status; /* Something happened, report what. */ | ||
1184 | |||
1185 | /* In case we're doing partial reads, we don't have to wait for a frame */ | ||
1186 | if (pdev->image_read_pos == 0) { | ||
1187 | /* Do wait queueing according to the (doc)book */ | ||
1188 | add_wait_queue(&pdev->frameq, &wait); | ||
1189 | while (pdev->full_frames == NULL) { | ||
1190 | /* Check for unplugged/etc. here */ | ||
1191 | if (pdev->error_status) { | ||
1192 | remove_wait_queue(&pdev->frameq, &wait); | ||
1193 | set_current_state(TASK_RUNNING); | ||
1194 | return -pdev->error_status ; | ||
1195 | } | ||
1196 | if (noblock) { | ||
1197 | remove_wait_queue(&pdev->frameq, &wait); | ||
1198 | set_current_state(TASK_RUNNING); | ||
1199 | return -EWOULDBLOCK; | ||
1200 | } | ||
1201 | if (signal_pending(current)) { | ||
1202 | remove_wait_queue(&pdev->frameq, &wait); | ||
1203 | set_current_state(TASK_RUNNING); | ||
1204 | return -ERESTARTSYS; | ||
1205 | } | ||
1206 | schedule(); | ||
1207 | set_current_state(TASK_INTERRUPTIBLE); | ||
1208 | } | ||
1209 | remove_wait_queue(&pdev->frameq, &wait); | ||
1210 | set_current_state(TASK_RUNNING); | ||
1211 | |||
1212 | /* Decompress and release frame */ | ||
1213 | if (pwc_handle_frame(pdev)) | ||
1214 | return -EFAULT; | ||
1215 | } | ||
1216 | |||
1217 | Trace(TRACE_READ, "Copying data to user space.\n"); | ||
1218 | if (pdev->vpalette == VIDEO_PALETTE_RAW) | ||
1219 | bytes_to_read = pdev->frame_size; | ||
1220 | else | ||
1221 | bytes_to_read = pdev->view.size; | ||
1222 | |||
1223 | /* copy bytes to user space; we allow for partial reads */ | ||
1224 | if (count + pdev->image_read_pos > bytes_to_read) | ||
1225 | count = bytes_to_read - pdev->image_read_pos; | ||
1226 | if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count)) | ||
1227 | return -EFAULT; | ||
1228 | pdev->image_read_pos += count; | ||
1229 | if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */ | ||
1230 | pdev->image_read_pos = 0; | ||
1231 | pwc_next_image(pdev); | ||
1232 | } | ||
1233 | return count; | ||
1234 | } | ||
1235 | |||
1236 | static unsigned int pwc_video_poll(struct file *file, poll_table *wait) | ||
1237 | { | ||
1238 | struct video_device *vdev = file->private_data; | ||
1239 | struct pwc_device *pdev; | ||
1240 | |||
1241 | if (vdev == NULL) | ||
1242 | return -EFAULT; | ||
1243 | pdev = vdev->priv; | ||
1244 | if (pdev == NULL) | ||
1245 | return -EFAULT; | ||
1246 | |||
1247 | poll_wait(file, &pdev->frameq, wait); | ||
1248 | if (pdev->error_status) | ||
1249 | return POLLERR; | ||
1250 | if (pdev->full_frames != NULL) /* we have frames waiting */ | ||
1251 | return (POLLIN | POLLRDNORM); | ||
1252 | |||
1253 | return 0; | ||
1254 | } | ||
1255 | |||
1256 | static int pwc_video_do_ioctl(struct inode *inode, struct file *file, | ||
1257 | unsigned int cmd, void *arg) | ||
1258 | { | ||
1259 | struct video_device *vdev = file->private_data; | ||
1260 | struct pwc_device *pdev; | ||
1261 | DECLARE_WAITQUEUE(wait, current); | ||
1262 | |||
1263 | if (vdev == NULL) | ||
1264 | return -EFAULT; | ||
1265 | pdev = vdev->priv; | ||
1266 | if (pdev == NULL) | ||
1267 | return -EFAULT; | ||
1268 | |||
1269 | switch (cmd) { | ||
1270 | /* Query cabapilities */ | ||
1271 | case VIDIOCGCAP: | ||
1272 | { | ||
1273 | struct video_capability *caps = arg; | ||
1274 | |||
1275 | strcpy(caps->name, vdev->name); | ||
1276 | caps->type = VID_TYPE_CAPTURE; | ||
1277 | caps->channels = 1; | ||
1278 | caps->audios = 1; | ||
1279 | caps->minwidth = pdev->view_min.x; | ||
1280 | caps->minheight = pdev->view_min.y; | ||
1281 | caps->maxwidth = pdev->view_max.x; | ||
1282 | caps->maxheight = pdev->view_max.y; | ||
1283 | break; | ||
1284 | } | ||
1285 | |||
1286 | /* Channel functions (simulate 1 channel) */ | ||
1287 | case VIDIOCGCHAN: | ||
1288 | { | ||
1289 | struct video_channel *v = arg; | ||
1290 | |||
1291 | if (v->channel != 0) | ||
1292 | return -EINVAL; | ||
1293 | v->flags = 0; | ||
1294 | v->tuners = 0; | ||
1295 | v->type = VIDEO_TYPE_CAMERA; | ||
1296 | strcpy(v->name, "Webcam"); | ||
1297 | return 0; | ||
1298 | } | ||
1299 | |||
1300 | case VIDIOCSCHAN: | ||
1301 | { | ||
1302 | /* The spec says the argument is an integer, but | ||
1303 | the bttv driver uses a video_channel arg, which | ||
1304 | makes sense becasue it also has the norm flag. | ||
1305 | */ | ||
1306 | struct video_channel *v = arg; | ||
1307 | if (v->channel != 0) | ||
1308 | return -EINVAL; | ||
1309 | return 0; | ||
1310 | } | ||
1311 | |||
1312 | |||
1313 | /* Picture functions; contrast etc. */ | ||
1314 | case VIDIOCGPICT: | ||
1315 | { | ||
1316 | struct video_picture *p = arg; | ||
1317 | int val; | ||
1318 | |||
1319 | val = pwc_get_brightness(pdev); | ||
1320 | if (val >= 0) | ||
1321 | p->brightness = val; | ||
1322 | else | ||
1323 | p->brightness = 0xffff; | ||
1324 | val = pwc_get_contrast(pdev); | ||
1325 | if (val >= 0) | ||
1326 | p->contrast = val; | ||
1327 | else | ||
1328 | p->contrast = 0xffff; | ||
1329 | /* Gamma, Whiteness, what's the difference? :) */ | ||
1330 | val = pwc_get_gamma(pdev); | ||
1331 | if (val >= 0) | ||
1332 | p->whiteness = val; | ||
1333 | else | ||
1334 | p->whiteness = 0xffff; | ||
1335 | val = pwc_get_saturation(pdev); | ||
1336 | if (val >= 0) | ||
1337 | p->colour = val; | ||
1338 | else | ||
1339 | p->colour = 0xffff; | ||
1340 | p->depth = 24; | ||
1341 | p->palette = pdev->vpalette; | ||
1342 | p->hue = 0xFFFF; /* N/A */ | ||
1343 | break; | ||
1344 | } | ||
1345 | |||
1346 | case VIDIOCSPICT: | ||
1347 | { | ||
1348 | struct video_picture *p = arg; | ||
1349 | /* | ||
1350 | * FIXME: Suppose we are mid read | ||
1351 | ANSWER: No problem: the firmware of the camera | ||
1352 | can handle brightness/contrast/etc | ||
1353 | changes at _any_ time, and the palette | ||
1354 | is used exactly once in the uncompress | ||
1355 | routine. | ||
1356 | */ | ||
1357 | pwc_set_brightness(pdev, p->brightness); | ||
1358 | pwc_set_contrast(pdev, p->contrast); | ||
1359 | pwc_set_gamma(pdev, p->whiteness); | ||
1360 | pwc_set_saturation(pdev, p->colour); | ||
1361 | if (p->palette && p->palette != pdev->vpalette) { | ||
1362 | switch (p->palette) { | ||
1363 | case VIDEO_PALETTE_YUV420P: | ||
1364 | case VIDEO_PALETTE_RAW: | ||
1365 | pdev->vpalette = p->palette; | ||
1366 | return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); | ||
1367 | break; | ||
1368 | default: | ||
1369 | return -EINVAL; | ||
1370 | break; | ||
1371 | } | ||
1372 | } | ||
1373 | break; | ||
1374 | } | ||
1375 | |||
1376 | /* Window/size parameters */ | ||
1377 | case VIDIOCGWIN: | ||
1378 | { | ||
1379 | struct video_window *vw = arg; | ||
1380 | |||
1381 | vw->x = 0; | ||
1382 | vw->y = 0; | ||
1383 | vw->width = pdev->view.x; | ||
1384 | vw->height = pdev->view.y; | ||
1385 | vw->chromakey = 0; | ||
1386 | vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | | ||
1387 | (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0); | ||
1388 | break; | ||
1389 | } | ||
1390 | |||
1391 | case VIDIOCSWIN: | ||
1392 | { | ||
1393 | struct video_window *vw = arg; | ||
1394 | int fps, snapshot, ret; | ||
1395 | |||
1396 | fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; | ||
1397 | snapshot = vw->flags & PWC_FPS_SNAPSHOT; | ||
1398 | if (fps == 0) | ||
1399 | fps = pdev->vframes; | ||
1400 | if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot) | ||
1401 | return 0; | ||
1402 | ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot); | ||
1403 | if (ret) | ||
1404 | return ret; | ||
1405 | break; | ||
1406 | } | ||
1407 | |||
1408 | /* We don't have overlay support (yet) */ | ||
1409 | case VIDIOCGFBUF: | ||
1410 | { | ||
1411 | struct video_buffer *vb = arg; | ||
1412 | |||
1413 | memset(vb,0,sizeof(*vb)); | ||
1414 | break; | ||
1415 | } | ||
1416 | |||
1417 | /* mmap() functions */ | ||
1418 | case VIDIOCGMBUF: | ||
1419 | { | ||
1420 | /* Tell the user program how much memory is needed for a mmap() */ | ||
1421 | struct video_mbuf *vm = arg; | ||
1422 | int i; | ||
1423 | |||
1424 | memset(vm, 0, sizeof(*vm)); | ||
1425 | vm->size = default_mbufs * pdev->len_per_image; | ||
1426 | vm->frames = default_mbufs; /* double buffering should be enough for most applications */ | ||
1427 | for (i = 0; i < default_mbufs; i++) | ||
1428 | vm->offsets[i] = i * pdev->len_per_image; | ||
1429 | break; | ||
1430 | } | ||
1431 | |||
1432 | case VIDIOCMCAPTURE: | ||
1433 | { | ||
1434 | /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */ | ||
1435 | struct video_mmap *vm = arg; | ||
1436 | |||
1437 | Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format); | ||
1438 | if (vm->frame < 0 || vm->frame >= default_mbufs) | ||
1439 | return -EINVAL; | ||
1440 | |||
1441 | /* xawtv is nasty. It probes the available palettes | ||
1442 | by setting a very small image size and trying | ||
1443 | various palettes... The driver doesn't support | ||
1444 | such small images, so I'm working around it. | ||
1445 | */ | ||
1446 | if (vm->format) | ||
1447 | { | ||
1448 | switch (vm->format) | ||
1449 | { | ||
1450 | case VIDEO_PALETTE_YUV420P: | ||
1451 | case VIDEO_PALETTE_RAW: | ||
1452 | break; | ||
1453 | default: | ||
1454 | return -EINVAL; | ||
1455 | break; | ||
1456 | } | ||
1457 | } | ||
1458 | |||
1459 | if ((vm->width != pdev->view.x || vm->height != pdev->view.y) && | ||
1460 | (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) { | ||
1461 | int ret; | ||
1462 | |||
1463 | Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n"); | ||
1464 | ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot); | ||
1465 | if (ret) | ||
1466 | return ret; | ||
1467 | } /* ... size mismatch */ | ||
1468 | |||
1469 | /* FIXME: should we lock here? */ | ||
1470 | if (pdev->image_used[vm->frame]) | ||
1471 | return -EBUSY; /* buffer wasn't available. Bummer */ | ||
1472 | pdev->image_used[vm->frame] = 1; | ||
1473 | |||
1474 | /* Okay, we're done here. In the SYNC call we wait until a | ||
1475 | frame comes available, then expand image into the given | ||
1476 | buffer. | ||
1477 | In contrast to the CPiA cam the Philips cams deliver a | ||
1478 | constant stream, almost like a grabber card. Also, | ||
1479 | we have separate buffers for the rawdata and the image, | ||
1480 | meaning we can nearly always expand into the requested buffer. | ||
1481 | */ | ||
1482 | Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n"); | ||
1483 | break; | ||
1484 | } | ||
1485 | |||
1486 | case VIDIOCSYNC: | ||
1487 | { | ||
1488 | /* The doc says: "Whenever a buffer is used it should | ||
1489 | call VIDIOCSYNC to free this frame up and continue." | ||
1490 | |||
1491 | The only odd thing about this whole procedure is | ||
1492 | that MCAPTURE flags the buffer as "in use", and | ||
1493 | SYNC immediately unmarks it, while it isn't | ||
1494 | after SYNC that you know that the buffer actually | ||
1495 | got filled! So you better not start a CAPTURE in | ||
1496 | the same frame immediately (use double buffering). | ||
1497 | This is not a problem for this cam, since it has | ||
1498 | extra intermediate buffers, but a hardware | ||
1499 | grabber card will then overwrite the buffer | ||
1500 | you're working on. | ||
1501 | */ | ||
1502 | int *mbuf = arg; | ||
1503 | int ret; | ||
1504 | |||
1505 | Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf); | ||
1506 | |||
1507 | /* bounds check */ | ||
1508 | if (*mbuf < 0 || *mbuf >= default_mbufs) | ||
1509 | return -EINVAL; | ||
1510 | /* check if this buffer was requested anyway */ | ||
1511 | if (pdev->image_used[*mbuf] == 0) | ||
1512 | return -EINVAL; | ||
1513 | |||
1514 | /* Add ourselves to the frame wait-queue. | ||
1515 | |||
1516 | FIXME: needs auditing for safety. | ||
1517 | QUESTION: In what respect? I think that using the | ||
1518 | frameq is safe now. | ||
1519 | */ | ||
1520 | add_wait_queue(&pdev->frameq, &wait); | ||
1521 | while (pdev->full_frames == NULL) { | ||
1522 | if (pdev->error_status) { | ||
1523 | remove_wait_queue(&pdev->frameq, &wait); | ||
1524 | set_current_state(TASK_RUNNING); | ||
1525 | return -pdev->error_status; | ||
1526 | } | ||
1527 | |||
1528 | if (signal_pending(current)) { | ||
1529 | remove_wait_queue(&pdev->frameq, &wait); | ||
1530 | set_current_state(TASK_RUNNING); | ||
1531 | return -ERESTARTSYS; | ||
1532 | } | ||
1533 | schedule(); | ||
1534 | set_current_state(TASK_INTERRUPTIBLE); | ||
1535 | } | ||
1536 | remove_wait_queue(&pdev->frameq, &wait); | ||
1537 | set_current_state(TASK_RUNNING); | ||
1538 | |||
1539 | /* The frame is ready. Expand in the image buffer | ||
1540 | requested by the user. I don't care if you | ||
1541 | mmap() 5 buffers and request data in this order: | ||
1542 | buffer 4 2 3 0 1 2 3 0 4 3 1 . . . | ||
1543 | Grabber hardware may not be so forgiving. | ||
1544 | */ | ||
1545 | Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n"); | ||
1546 | pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */ | ||
1547 | /* Decompress, etc */ | ||
1548 | ret = pwc_handle_frame(pdev); | ||
1549 | pdev->image_used[*mbuf] = 0; | ||
1550 | if (ret) | ||
1551 | return -EFAULT; | ||
1552 | break; | ||
1553 | } | ||
1554 | |||
1555 | case VIDIOCGAUDIO: | ||
1556 | { | ||
1557 | struct video_audio *v = arg; | ||
1558 | |||
1559 | strcpy(v->name, "Microphone"); | ||
1560 | v->audio = -1; /* unknown audio minor */ | ||
1561 | v->flags = 0; | ||
1562 | v->mode = VIDEO_SOUND_MONO; | ||
1563 | v->volume = 0; | ||
1564 | v->bass = 0; | ||
1565 | v->treble = 0; | ||
1566 | v->balance = 0x8000; | ||
1567 | v->step = 1; | ||
1568 | break; | ||
1569 | } | ||
1570 | |||
1571 | case VIDIOCSAUDIO: | ||
1572 | { | ||
1573 | /* Dummy: nothing can be set */ | ||
1574 | break; | ||
1575 | } | ||
1576 | |||
1577 | case VIDIOCGUNIT: | ||
1578 | { | ||
1579 | struct video_unit *vu = arg; | ||
1580 | |||
1581 | vu->video = pdev->vdev->minor & 0x3F; | ||
1582 | vu->audio = -1; /* not known yet */ | ||
1583 | vu->vbi = -1; | ||
1584 | vu->radio = -1; | ||
1585 | vu->teletext = -1; | ||
1586 | break; | ||
1587 | } | ||
1588 | default: | ||
1589 | return pwc_ioctl(pdev, cmd, arg); | ||
1590 | } /* ..switch */ | ||
1591 | return 0; | ||
1592 | } | ||
1593 | |||
1594 | static int pwc_video_ioctl(struct inode *inode, struct file *file, | ||
1595 | unsigned int cmd, unsigned long arg) | ||
1596 | { | ||
1597 | return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); | ||
1598 | } | ||
1599 | |||
1600 | |||
1601 | static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) | ||
1602 | { | ||
1603 | struct video_device *vdev = file->private_data; | ||
1604 | struct pwc_device *pdev; | ||
1605 | unsigned long start = vma->vm_start; | ||
1606 | unsigned long size = vma->vm_end-vma->vm_start; | ||
1607 | unsigned long page, pos; | ||
1608 | |||
1609 | Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size); | ||
1610 | pdev = vdev->priv; | ||
1611 | |||
1612 | vma->vm_flags |= VM_IO; | ||
1613 | |||
1614 | pos = (unsigned long)pdev->image_data; | ||
1615 | while (size > 0) { | ||
1616 | page = vmalloc_to_pfn((void *)pos); | ||
1617 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) | ||
1618 | return -EAGAIN; | ||
1619 | |||
1620 | start += PAGE_SIZE; | ||
1621 | pos += PAGE_SIZE; | ||
1622 | if (size > PAGE_SIZE) | ||
1623 | size -= PAGE_SIZE; | ||
1624 | else | ||
1625 | size = 0; | ||
1626 | } | ||
1627 | |||
1628 | return 0; | ||
1629 | } | ||
1630 | |||
1631 | /***************************************************************************/ | ||
1632 | /* USB functions */ | ||
1633 | |||
1634 | /* This function gets called when a new device is plugged in or the usb core | ||
1635 | * is loaded. | ||
1636 | */ | ||
1637 | |||
1638 | static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
1639 | { | ||
1640 | struct usb_device *udev = interface_to_usbdev(intf); | ||
1641 | struct pwc_device *pdev = NULL; | ||
1642 | int vendor_id, product_id, type_id; | ||
1643 | int i, hint; | ||
1644 | int features = 0; | ||
1645 | int video_nr = -1; /* default: use next available device */ | ||
1646 | char serial_number[30], *name; | ||
1647 | |||
1648 | /* Check if we can handle this device */ | ||
1649 | Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", | ||
1650 | le16_to_cpu(udev->descriptor.idVendor), | ||
1651 | le16_to_cpu(udev->descriptor.idProduct), | ||
1652 | intf->altsetting->desc.bInterfaceNumber); | ||
1653 | |||
1654 | /* the interfaces are probed one by one. We are only interested in the | ||
1655 | video interface (0) now. | ||
1656 | Interface 1 is the Audio Control, and interface 2 Audio itself. | ||
1657 | */ | ||
1658 | if (intf->altsetting->desc.bInterfaceNumber > 0) | ||
1659 | return -ENODEV; | ||
1660 | |||
1661 | vendor_id = le16_to_cpu(udev->descriptor.idVendor); | ||
1662 | product_id = le16_to_cpu(udev->descriptor.idProduct); | ||
1663 | |||
1664 | if (vendor_id == 0x0471) { | ||
1665 | switch (product_id) { | ||
1666 | case 0x0302: | ||
1667 | Info("Philips PCA645VC USB webcam detected.\n"); | ||
1668 | name = "Philips 645 webcam"; | ||
1669 | type_id = 645; | ||
1670 | break; | ||
1671 | case 0x0303: | ||
1672 | Info("Philips PCA646VC USB webcam detected.\n"); | ||
1673 | name = "Philips 646 webcam"; | ||
1674 | type_id = 646; | ||
1675 | break; | ||
1676 | case 0x0304: | ||
1677 | Info("Askey VC010 type 2 USB webcam detected.\n"); | ||
1678 | name = "Askey VC010 webcam"; | ||
1679 | type_id = 646; | ||
1680 | break; | ||
1681 | case 0x0307: | ||
1682 | Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); | ||
1683 | name = "Philips 675 webcam"; | ||
1684 | type_id = 675; | ||
1685 | break; | ||
1686 | case 0x0308: | ||
1687 | Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); | ||
1688 | name = "Philips 680 webcam"; | ||
1689 | type_id = 680; | ||
1690 | break; | ||
1691 | case 0x030C: | ||
1692 | Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); | ||
1693 | name = "Philips 690 webcam"; | ||
1694 | type_id = 690; | ||
1695 | break; | ||
1696 | case 0x0310: | ||
1697 | Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n"); | ||
1698 | name = "Philips 730 webcam"; | ||
1699 | type_id = 730; | ||
1700 | break; | ||
1701 | case 0x0311: | ||
1702 | Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); | ||
1703 | name = "Philips 740 webcam"; | ||
1704 | type_id = 740; | ||
1705 | break; | ||
1706 | case 0x0312: | ||
1707 | Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); | ||
1708 | name = "Philips 750 webcam"; | ||
1709 | type_id = 750; | ||
1710 | break; | ||
1711 | case 0x0313: | ||
1712 | Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n"); | ||
1713 | name = "Philips 720K/40 webcam"; | ||
1714 | type_id = 720; | ||
1715 | break; | ||
1716 | default: | ||
1717 | return -ENODEV; | ||
1718 | break; | ||
1719 | } | ||
1720 | } | ||
1721 | else if (vendor_id == 0x069A) { | ||
1722 | switch(product_id) { | ||
1723 | case 0x0001: | ||
1724 | Info("Askey VC010 type 1 USB webcam detected.\n"); | ||
1725 | name = "Askey VC010 webcam"; | ||
1726 | type_id = 645; | ||
1727 | break; | ||
1728 | default: | ||
1729 | return -ENODEV; | ||
1730 | break; | ||
1731 | } | ||
1732 | } | ||
1733 | else if (vendor_id == 0x046d) { | ||
1734 | switch(product_id) { | ||
1735 | case 0x08b0: | ||
1736 | Info("Logitech QuickCam Pro 3000 USB webcam detected.\n"); | ||
1737 | name = "Logitech QuickCam Pro 3000"; | ||
1738 | type_id = 740; /* CCD sensor */ | ||
1739 | break; | ||
1740 | case 0x08b1: | ||
1741 | Info("Logitech QuickCam Notebook Pro USB webcam detected.\n"); | ||
1742 | name = "Logitech QuickCam Notebook Pro"; | ||
1743 | type_id = 740; /* CCD sensor */ | ||
1744 | break; | ||
1745 | case 0x08b2: | ||
1746 | Info("Logitech QuickCam 4000 Pro USB webcam detected.\n"); | ||
1747 | name = "Logitech QuickCam Pro 4000"; | ||
1748 | type_id = 740; /* CCD sensor */ | ||
1749 | break; | ||
1750 | case 0x08b3: | ||
1751 | Info("Logitech QuickCam Zoom USB webcam detected.\n"); | ||
1752 | name = "Logitech QuickCam Zoom"; | ||
1753 | type_id = 740; /* CCD sensor */ | ||
1754 | break; | ||
1755 | case 0x08B4: | ||
1756 | Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); | ||
1757 | name = "Logitech QuickCam Zoom"; | ||
1758 | type_id = 740; /* CCD sensor */ | ||
1759 | break; | ||
1760 | case 0x08b5: | ||
1761 | Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); | ||
1762 | name = "Logitech QuickCam Orbit"; | ||
1763 | type_id = 740; /* CCD sensor */ | ||
1764 | features |= FEATURE_MOTOR_PANTILT; | ||
1765 | break; | ||
1766 | case 0x08b6: | ||
1767 | case 0x08b7: | ||
1768 | case 0x08b8: | ||
1769 | Info("Logitech QuickCam detected (reserved ID).\n"); | ||
1770 | name = "Logitech QuickCam (res.)"; | ||
1771 | type_id = 730; /* Assuming CMOS */ | ||
1772 | break; | ||
1773 | default: | ||
1774 | return -ENODEV; | ||
1775 | break; | ||
1776 | } | ||
1777 | } | ||
1778 | else if (vendor_id == 0x055d) { | ||
1779 | /* I don't know the difference between the C10 and the C30; | ||
1780 | I suppose the difference is the sensor, but both cameras | ||
1781 | work equally well with a type_id of 675 | ||
1782 | */ | ||
1783 | switch(product_id) { | ||
1784 | case 0x9000: | ||
1785 | Info("Samsung MPC-C10 USB webcam detected.\n"); | ||
1786 | name = "Samsung MPC-C10"; | ||
1787 | type_id = 675; | ||
1788 | break; | ||
1789 | case 0x9001: | ||
1790 | Info("Samsung MPC-C30 USB webcam detected.\n"); | ||
1791 | name = "Samsung MPC-C30"; | ||
1792 | type_id = 675; | ||
1793 | break; | ||
1794 | default: | ||
1795 | return -ENODEV; | ||
1796 | break; | ||
1797 | } | ||
1798 | } | ||
1799 | else if (vendor_id == 0x041e) { | ||
1800 | switch(product_id) { | ||
1801 | case 0x400c: | ||
1802 | Info("Creative Labs Webcam 5 detected.\n"); | ||
1803 | name = "Creative Labs Webcam 5"; | ||
1804 | type_id = 730; | ||
1805 | break; | ||
1806 | case 0x4011: | ||
1807 | Info("Creative Labs Webcam Pro Ex detected.\n"); | ||
1808 | name = "Creative Labs Webcam Pro Ex"; | ||
1809 | type_id = 740; | ||
1810 | break; | ||
1811 | default: | ||
1812 | return -ENODEV; | ||
1813 | break; | ||
1814 | } | ||
1815 | } | ||
1816 | else if (vendor_id == 0x04cc) { | ||
1817 | switch(product_id) { | ||
1818 | case 0x8116: | ||
1819 | Info("Sotec Afina Eye USB webcam detected.\n"); | ||
1820 | name = "Sotec Afina Eye"; | ||
1821 | type_id = 730; | ||
1822 | break; | ||
1823 | default: | ||
1824 | return -ENODEV; | ||
1825 | break; | ||
1826 | } | ||
1827 | } | ||
1828 | else if (vendor_id == 0x06be) { | ||
1829 | switch(product_id) { | ||
1830 | case 0x8116: | ||
1831 | /* This is essentially the same cam as the Sotec Afina Eye */ | ||
1832 | Info("AME Co. Afina Eye USB webcam detected.\n"); | ||
1833 | name = "AME Co. Afina Eye"; | ||
1834 | type_id = 750; | ||
1835 | break; | ||
1836 | default: | ||
1837 | return -ENODEV; | ||
1838 | break; | ||
1839 | } | ||
1840 | |||
1841 | } | ||
1842 | else if (vendor_id == 0x0d81) { | ||
1843 | switch(product_id) { | ||
1844 | case 0x1900: | ||
1845 | Info("Visionite VCS-UC300 USB webcam detected.\n"); | ||
1846 | name = "Visionite VCS-UC300"; | ||
1847 | type_id = 740; /* CCD sensor */ | ||
1848 | break; | ||
1849 | case 0x1910: | ||
1850 | Info("Visionite VCS-UM100 USB webcam detected.\n"); | ||
1851 | name = "Visionite VCS-UM100"; | ||
1852 | type_id = 730; /* CMOS sensor */ | ||
1853 | break; | ||
1854 | default: | ||
1855 | return -ENODEV; | ||
1856 | break; | ||
1857 | } | ||
1858 | } | ||
1859 | else | ||
1860 | return -ENODEV; /* Not any of the know types; but the list keeps growing. */ | ||
1861 | |||
1862 | memset(serial_number, 0, 30); | ||
1863 | usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); | ||
1864 | Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number); | ||
1865 | |||
1866 | if (udev->descriptor.bNumConfigurations > 1) | ||
1867 | Info("Warning: more than 1 configuration available.\n"); | ||
1868 | |||
1869 | /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */ | ||
1870 | pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL); | ||
1871 | if (pdev == NULL) { | ||
1872 | Err("Oops, could not allocate memory for pwc_device.\n"); | ||
1873 | return -ENOMEM; | ||
1874 | } | ||
1875 | pdev->type = type_id; | ||
1876 | pdev->vsize = default_size; | ||
1877 | pdev->vframes = default_fps; | ||
1878 | strcpy(pdev->serial, serial_number); | ||
1879 | pdev->features = features; | ||
1880 | if (vendor_id == 0x046D && product_id == 0x08B5) | ||
1881 | { | ||
1882 | /* Logitech QuickCam Orbit | ||
1883 | The ranges have been determined experimentally; they may differ from cam to cam. | ||
1884 | Also, the exact ranges left-right and up-down are different for my cam | ||
1885 | */ | ||
1886 | pdev->angle_range.pan_min = -7000; | ||
1887 | pdev->angle_range.pan_max = 7000; | ||
1888 | pdev->angle_range.tilt_min = -3000; | ||
1889 | pdev->angle_range.tilt_max = 2500; | ||
1890 | } | ||
1891 | |||
1892 | init_MUTEX(&pdev->modlock); | ||
1893 | spin_lock_init(&pdev->ptrlock); | ||
1894 | |||
1895 | pdev->udev = udev; | ||
1896 | init_waitqueue_head(&pdev->frameq); | ||
1897 | pdev->vcompression = pwc_preferred_compression; | ||
1898 | |||
1899 | /* Allocate video_device structure */ | ||
1900 | pdev->vdev = video_device_alloc(); | ||
1901 | if (pdev->vdev == 0) | ||
1902 | { | ||
1903 | Err("Err, cannot allocate video_device struture. Failing probe."); | ||
1904 | kfree(pdev); | ||
1905 | return -ENOMEM; | ||
1906 | } | ||
1907 | memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); | ||
1908 | strcpy(pdev->vdev->name, name); | ||
1909 | pdev->vdev->owner = THIS_MODULE; | ||
1910 | video_set_drvdata(pdev->vdev, pdev); | ||
1911 | |||
1912 | pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); | ||
1913 | Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); | ||
1914 | |||
1915 | /* Now search device_hint[] table for a match, so we can hint a node number. */ | ||
1916 | for (hint = 0; hint < MAX_DEV_HINTS; hint++) { | ||
1917 | if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && | ||
1918 | (device_hint[hint].pdev == NULL)) { | ||
1919 | /* so far, so good... try serial number */ | ||
1920 | if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) { | ||
1921 | /* match! */ | ||
1922 | video_nr = device_hint[hint].device_node; | ||
1923 | Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr); | ||
1924 | break; | ||
1925 | } | ||
1926 | } | ||
1927 | } | ||
1928 | |||
1929 | pdev->vdev->release = video_device_release; | ||
1930 | i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); | ||
1931 | if (i < 0) { | ||
1932 | Err("Failed to register as video device (%d).\n", i); | ||
1933 | video_device_release(pdev->vdev); /* Drip... drip... drip... */ | ||
1934 | kfree(pdev); /* Oops, no memory leaks please */ | ||
1935 | return -EIO; | ||
1936 | } | ||
1937 | else { | ||
1938 | Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); | ||
1939 | } | ||
1940 | |||
1941 | /* occupy slot */ | ||
1942 | if (hint < MAX_DEV_HINTS) | ||
1943 | device_hint[hint].pdev = pdev; | ||
1944 | |||
1945 | Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev); | ||
1946 | usb_set_intfdata (intf, pdev); | ||
1947 | return 0; | ||
1948 | } | ||
1949 | |||
1950 | /* The user janked out the cable... */ | ||
1951 | static void usb_pwc_disconnect(struct usb_interface *intf) | ||
1952 | { | ||
1953 | struct pwc_device *pdev; | ||
1954 | int hint; | ||
1955 | |||
1956 | lock_kernel(); | ||
1957 | pdev = usb_get_intfdata (intf); | ||
1958 | usb_set_intfdata (intf, NULL); | ||
1959 | if (pdev == NULL) { | ||
1960 | Err("pwc_disconnect() Called without private pointer.\n"); | ||
1961 | goto disconnect_out; | ||
1962 | } | ||
1963 | if (pdev->udev == NULL) { | ||
1964 | Err("pwc_disconnect() already called for %p\n", pdev); | ||
1965 | goto disconnect_out; | ||
1966 | } | ||
1967 | if (pdev->udev != interface_to_usbdev(intf)) { | ||
1968 | Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); | ||
1969 | goto disconnect_out; | ||
1970 | } | ||
1971 | #ifdef PWC_MAGIC | ||
1972 | if (pdev->magic != PWC_MAGIC) { | ||
1973 | Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n"); | ||
1974 | goto disconnect_out; | ||
1975 | } | ||
1976 | #endif | ||
1977 | |||
1978 | /* We got unplugged; this is signalled by an EPIPE error code */ | ||
1979 | if (pdev->vopen) { | ||
1980 | Info("Disconnected while webcam is in use!\n"); | ||
1981 | pdev->error_status = EPIPE; | ||
1982 | } | ||
1983 | |||
1984 | /* Alert waiting processes */ | ||
1985 | wake_up_interruptible(&pdev->frameq); | ||
1986 | /* Wait until device is closed */ | ||
1987 | while (pdev->vopen) | ||
1988 | schedule(); | ||
1989 | /* Device is now closed, so we can safely unregister it */ | ||
1990 | Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n"); | ||
1991 | video_unregister_device(pdev->vdev); | ||
1992 | |||
1993 | /* Free memory (don't set pdev to 0 just yet) */ | ||
1994 | kfree(pdev); | ||
1995 | |||
1996 | disconnect_out: | ||
1997 | /* search device_hint[] table if we occupy a slot, by any chance */ | ||
1998 | for (hint = 0; hint < MAX_DEV_HINTS; hint++) | ||
1999 | if (device_hint[hint].pdev == pdev) | ||
2000 | device_hint[hint].pdev = NULL; | ||
2001 | |||
2002 | unlock_kernel(); | ||
2003 | } | ||
2004 | |||
2005 | |||
2006 | /* *grunt* We have to do atoi ourselves :-( */ | ||
2007 | static int pwc_atoi(const char *s) | ||
2008 | { | ||
2009 | int k = 0; | ||
2010 | |||
2011 | k = 0; | ||
2012 | while (*s != '\0' && *s >= '0' && *s <= '9') { | ||
2013 | k = 10 * k + (*s - '0'); | ||
2014 | s++; | ||
2015 | } | ||
2016 | return k; | ||
2017 | } | ||
2018 | |||
2019 | |||
2020 | /* | ||
2021 | * Initialization code & module stuff | ||
2022 | */ | ||
2023 | |||
2024 | static char size[10]; | ||
2025 | static int fps = 0; | ||
2026 | static int fbufs = 0; | ||
2027 | static int mbufs = 0; | ||
2028 | static int trace = -1; | ||
2029 | static int compression = -1; | ||
2030 | static int leds[2] = { -1, -1 }; | ||
2031 | static char *dev_hint[MAX_DEV_HINTS] = { }; | ||
2032 | |||
2033 | module_param_string(size, size, sizeof(size), 0); | ||
2034 | MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"); | ||
2035 | module_param(fps, int, 0000); | ||
2036 | MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); | ||
2037 | module_param(fbufs, int, 0000); | ||
2038 | MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); | ||
2039 | module_param(mbufs, int, 0000); | ||
2040 | MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); | ||
2041 | module_param(trace, int, 0000); | ||
2042 | MODULE_PARM_DESC(trace, "For debugging purposes"); | ||
2043 | module_param(power_save, bool, 0000); | ||
2044 | MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); | ||
2045 | module_param(compression, int, 0000); | ||
2046 | MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); | ||
2047 | module_param_array(leds, int, NULL, 0000); | ||
2048 | MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); | ||
2049 | module_param_array(dev_hint, charp, NULL, 0000); | ||
2050 | MODULE_PARM_DESC(dev_hint, "Device node hints"); | ||
2051 | |||
2052 | MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); | ||
2053 | MODULE_AUTHOR("Luc Saillard <luc@saillard.org>"); | ||
2054 | MODULE_LICENSE("GPL"); | ||
2055 | |||
2056 | static int __init usb_pwc_init(void) | ||
2057 | { | ||
2058 | int i, sz; | ||
2059 | char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; | ||
2060 | |||
2061 | Info("Philips webcam module version " PWC_VERSION " loaded.\n"); | ||
2062 | Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); | ||
2063 | Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); | ||
2064 | Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); | ||
2065 | |||
2066 | if (fps) { | ||
2067 | if (fps < 4 || fps > 30) { | ||
2068 | Err("Framerate out of bounds (4-30).\n"); | ||
2069 | return -EINVAL; | ||
2070 | } | ||
2071 | default_fps = fps; | ||
2072 | Info("Default framerate set to %d.\n", default_fps); | ||
2073 | } | ||
2074 | |||
2075 | if (size[0]) { | ||
2076 | /* string; try matching with array */ | ||
2077 | for (sz = 0; sz < PSZ_MAX; sz++) { | ||
2078 | if (!strcmp(sizenames[sz], size)) { /* Found! */ | ||
2079 | default_size = sz; | ||
2080 | break; | ||
2081 | } | ||
2082 | } | ||
2083 | if (sz == PSZ_MAX) { | ||
2084 | Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n"); | ||
2085 | return -EINVAL; | ||
2086 | } | ||
2087 | Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y); | ||
2088 | } | ||
2089 | if (mbufs) { | ||
2090 | if (mbufs < 1 || mbufs > MAX_IMAGES) { | ||
2091 | Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES); | ||
2092 | return -EINVAL; | ||
2093 | } | ||
2094 | default_mbufs = mbufs; | ||
2095 | Info("Number of image buffers set to %d.\n", default_mbufs); | ||
2096 | } | ||
2097 | if (fbufs) { | ||
2098 | if (fbufs < 2 || fbufs > MAX_FRAMES) { | ||
2099 | Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES); | ||
2100 | return -EINVAL; | ||
2101 | } | ||
2102 | default_fbufs = fbufs; | ||
2103 | Info("Number of frame buffers set to %d.\n", default_fbufs); | ||
2104 | } | ||
2105 | if (trace >= 0) { | ||
2106 | Info("Trace options: 0x%04x\n", trace); | ||
2107 | pwc_trace = trace; | ||
2108 | } | ||
2109 | if (compression >= 0) { | ||
2110 | if (compression > 3) { | ||
2111 | Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); | ||
2112 | return -EINVAL; | ||
2113 | } | ||
2114 | pwc_preferred_compression = compression; | ||
2115 | Info("Preferred compression set to %d.\n", pwc_preferred_compression); | ||
2116 | } | ||
2117 | if (power_save) | ||
2118 | Info("Enabling power save on open/close.\n"); | ||
2119 | if (leds[0] >= 0) | ||
2120 | led_on = leds[0]; | ||
2121 | if (leds[1] >= 0) | ||
2122 | led_off = leds[1]; | ||
2123 | |||
2124 | /* Big device node whoopla. Basically, it allows you to assign a | ||
2125 | device node (/dev/videoX) to a camera, based on its type | ||
2126 | & serial number. The format is [type[.serialnumber]:]node. | ||
2127 | |||
2128 | Any camera that isn't matched by these rules gets the next | ||
2129 | available free device node. | ||
2130 | */ | ||
2131 | for (i = 0; i < MAX_DEV_HINTS; i++) { | ||
2132 | char *s, *colon, *dot; | ||
2133 | |||
2134 | /* This loop also initializes the array */ | ||
2135 | device_hint[i].pdev = NULL; | ||
2136 | s = dev_hint[i]; | ||
2137 | if (s != NULL && *s != '\0') { | ||
2138 | device_hint[i].type = -1; /* wildcard */ | ||
2139 | strcpy(device_hint[i].serial_number, "*"); | ||
2140 | |||
2141 | /* parse string: chop at ':' & '/' */ | ||
2142 | colon = dot = s; | ||
2143 | while (*colon != '\0' && *colon != ':') | ||
2144 | colon++; | ||
2145 | while (*dot != '\0' && *dot != '.') | ||
2146 | dot++; | ||
2147 | /* Few sanity checks */ | ||
2148 | if (*dot != '\0' && dot > colon) { | ||
2149 | Err("Malformed camera hint: the colon must be after the dot.\n"); | ||
2150 | return -EINVAL; | ||
2151 | } | ||
2152 | |||
2153 | if (*colon == '\0') { | ||
2154 | /* No colon */ | ||
2155 | if (*dot != '\0') { | ||
2156 | Err("Malformed camera hint: no colon + device node given.\n"); | ||
2157 | return -EINVAL; | ||
2158 | } | ||
2159 | else { | ||
2160 | /* No type or serial number specified, just a number. */ | ||
2161 | device_hint[i].device_node = pwc_atoi(s); | ||
2162 | } | ||
2163 | } | ||
2164 | else { | ||
2165 | /* There's a colon, so we have at least a type and a device node */ | ||
2166 | device_hint[i].type = pwc_atoi(s); | ||
2167 | device_hint[i].device_node = pwc_atoi(colon + 1); | ||
2168 | if (*dot != '\0') { | ||
2169 | /* There's a serial number as well */ | ||
2170 | int k; | ||
2171 | |||
2172 | dot++; | ||
2173 | k = 0; | ||
2174 | while (*dot != ':' && k < 29) { | ||
2175 | device_hint[i].serial_number[k++] = *dot; | ||
2176 | dot++; | ||
2177 | } | ||
2178 | device_hint[i].serial_number[k] = '\0'; | ||
2179 | } | ||
2180 | } | ||
2181 | #if PWC_DEBUG | ||
2182 | Debug("device_hint[%d]:\n", i); | ||
2183 | Debug(" type : %d\n", device_hint[i].type); | ||
2184 | Debug(" serial# : %s\n", device_hint[i].serial_number); | ||
2185 | Debug(" node : %d\n", device_hint[i].device_node); | ||
2186 | #endif | ||
2187 | } | ||
2188 | else | ||
2189 | device_hint[i].type = 0; /* not filled */ | ||
2190 | } /* ..for MAX_DEV_HINTS */ | ||
2191 | |||
2192 | Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver); | ||
2193 | return usb_register(&pwc_driver); | ||
2194 | } | ||
2195 | |||
2196 | static void __exit usb_pwc_exit(void) | ||
2197 | { | ||
2198 | Trace(TRACE_MODULE, "Deregistering driver.\n"); | ||
2199 | usb_deregister(&pwc_driver); | ||
2200 | Info("Philips webcam module removed.\n"); | ||
2201 | } | ||
2202 | |||
2203 | module_init(usb_pwc_init); | ||
2204 | module_exit(usb_pwc_exit); | ||
2205 | |||
diff --git a/drivers/media/video/pwc/pwc-ioctl.h b/drivers/media/video/pwc/pwc-ioctl.h new file mode 100644 index 000000000000..5f9cb08bc02e --- /dev/null +++ b/drivers/media/video/pwc/pwc-ioctl.h | |||
@@ -0,0 +1,292 @@ | |||
1 | #ifndef PWC_IOCTL_H | ||
2 | #define PWC_IOCTL_H | ||
3 | |||
4 | /* (C) 2001-2004 Nemosoft Unv. | ||
5 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
6 | |||
7 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
8 | driver and thus may have bugs that are not present in the original version. | ||
9 | Please send bug reports and support requests to <luc@saillard.org>. | ||
10 | The decompression routines have been implemented by reverse-engineering the | ||
11 | Nemosoft binary pwcx module. Caveat emptor. | ||
12 | |||
13 | This program is free software; you can redistribute it and/or modify | ||
14 | it under the terms of the GNU General Public License as published by | ||
15 | the Free Software Foundation; either version 2 of the License, or | ||
16 | (at your option) any later version. | ||
17 | |||
18 | This program is distributed in the hope that it will be useful, | ||
19 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | GNU General Public License for more details. | ||
22 | |||
23 | You should have received a copy of the GNU General Public License | ||
24 | along with this program; if not, write to the Free Software | ||
25 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | */ | ||
27 | |||
28 | /* This is pwc-ioctl.h belonging to PWC 8.12.1 | ||
29 | It contains structures and defines to communicate from user space | ||
30 | directly to the driver. | ||
31 | */ | ||
32 | |||
33 | /* | ||
34 | Changes | ||
35 | 2001/08/03 Alvarado Added ioctl constants to access methods for | ||
36 | changing white balance and red/blue gains | ||
37 | 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE | ||
38 | 2003/12/13 Nemosft Unv. Some modifications to make interfacing to | ||
39 | PWCX easier | ||
40 | */ | ||
41 | |||
42 | /* These are private ioctl() commands, specific for the Philips webcams. | ||
43 | They contain functions not found in other webcams, and settings not | ||
44 | specified in the Video4Linux API. | ||
45 | |||
46 | The #define names are built up like follows: | ||
47 | VIDIOC VIDeo IOCtl prefix | ||
48 | PWC Philps WebCam | ||
49 | G optional: Get | ||
50 | S optional: Set | ||
51 | ... the function | ||
52 | */ | ||
53 | |||
54 | |||
55 | /* Enumeration of image sizes */ | ||
56 | #define PSZ_SQCIF 0x00 | ||
57 | #define PSZ_QSIF 0x01 | ||
58 | #define PSZ_QCIF 0x02 | ||
59 | #define PSZ_SIF 0x03 | ||
60 | #define PSZ_CIF 0x04 | ||
61 | #define PSZ_VGA 0x05 | ||
62 | #define PSZ_MAX 6 | ||
63 | |||
64 | |||
65 | /* The frame rate is encoded in the video_window.flags parameter using | ||
66 | the upper 16 bits, since some flags are defined nowadays. The following | ||
67 | defines provide a mask and shift to filter out this value. | ||
68 | |||
69 | In 'Snapshot' mode the camera freezes its automatic exposure and colour | ||
70 | balance controls. | ||
71 | */ | ||
72 | #define PWC_FPS_SHIFT 16 | ||
73 | #define PWC_FPS_MASK 0x00FF0000 | ||
74 | #define PWC_FPS_FRMASK 0x003F0000 | ||
75 | #define PWC_FPS_SNAPSHOT 0x00400000 | ||
76 | |||
77 | |||
78 | /* structure for transferring x & y coordinates */ | ||
79 | struct pwc_coord | ||
80 | { | ||
81 | int x, y; /* guess what */ | ||
82 | int size; /* size, or offset */ | ||
83 | }; | ||
84 | |||
85 | |||
86 | /* Used with VIDIOCPWCPROBE */ | ||
87 | struct pwc_probe | ||
88 | { | ||
89 | char name[32]; | ||
90 | int type; | ||
91 | }; | ||
92 | |||
93 | struct pwc_serial | ||
94 | { | ||
95 | char serial[30]; /* String with serial number. Contains terminating 0 */ | ||
96 | }; | ||
97 | |||
98 | /* pwc_whitebalance.mode values */ | ||
99 | #define PWC_WB_INDOOR 0 | ||
100 | #define PWC_WB_OUTDOOR 1 | ||
101 | #define PWC_WB_FL 2 | ||
102 | #define PWC_WB_MANUAL 3 | ||
103 | #define PWC_WB_AUTO 4 | ||
104 | |||
105 | /* Used with VIDIOCPWC[SG]AWB (Auto White Balance). | ||
106 | Set mode to one of the PWC_WB_* values above. | ||
107 | *red and *blue are the respective gains of these colour components inside | ||
108 | the camera; range 0..65535 | ||
109 | When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; | ||
110 | otherwise undefined. | ||
111 | 'read_red' and 'read_blue' are read-only. | ||
112 | */ | ||
113 | struct pwc_whitebalance | ||
114 | { | ||
115 | int mode; | ||
116 | int manual_red, manual_blue; /* R/W */ | ||
117 | int read_red, read_blue; /* R/O */ | ||
118 | }; | ||
119 | |||
120 | /* | ||
121 | 'control_speed' and 'control_delay' are used in automatic whitebalance mode, | ||
122 | and tell the camera how fast it should react to changes in lighting, and | ||
123 | with how much delay. Valid values are 0..65535. | ||
124 | */ | ||
125 | struct pwc_wb_speed | ||
126 | { | ||
127 | int control_speed; | ||
128 | int control_delay; | ||
129 | |||
130 | }; | ||
131 | |||
132 | /* Used with VIDIOCPWC[SG]LED */ | ||
133 | struct pwc_leds | ||
134 | { | ||
135 | int led_on; /* Led on-time; range = 0..25000 */ | ||
136 | int led_off; /* Led off-time; range = 0..25000 */ | ||
137 | }; | ||
138 | |||
139 | /* Image size (used with GREALSIZE) */ | ||
140 | struct pwc_imagesize | ||
141 | { | ||
142 | int width; | ||
143 | int height; | ||
144 | }; | ||
145 | |||
146 | /* Defines and structures for Motorized Pan & Tilt */ | ||
147 | #define PWC_MPT_PAN 0x01 | ||
148 | #define PWC_MPT_TILT 0x02 | ||
149 | #define PWC_MPT_TIMEOUT 0x04 /* for status */ | ||
150 | |||
151 | /* Set angles; when absolute != 0, the angle is absolute and the | ||
152 | driver calculates the relative offset for you. This can only | ||
153 | be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns | ||
154 | absolute angles. | ||
155 | */ | ||
156 | struct pwc_mpt_angles | ||
157 | { | ||
158 | int absolute; /* write-only */ | ||
159 | int pan; /* degrees * 100 */ | ||
160 | int tilt; /* degress * 100 */ | ||
161 | }; | ||
162 | |||
163 | /* Range of angles of the camera, both horizontally and vertically. | ||
164 | */ | ||
165 | struct pwc_mpt_range | ||
166 | { | ||
167 | int pan_min, pan_max; /* degrees * 100 */ | ||
168 | int tilt_min, tilt_max; | ||
169 | }; | ||
170 | |||
171 | struct pwc_mpt_status | ||
172 | { | ||
173 | int status; | ||
174 | int time_pan; | ||
175 | int time_tilt; | ||
176 | }; | ||
177 | |||
178 | |||
179 | /* This is used for out-of-kernel decompression. With it, you can get | ||
180 | all the necessary information to initialize and use the decompressor | ||
181 | routines in standalone applications. | ||
182 | */ | ||
183 | struct pwc_video_command | ||
184 | { | ||
185 | int type; /* camera type (645, 675, 730, etc.) */ | ||
186 | int release; /* release number */ | ||
187 | |||
188 | int size; /* one of PSZ_* */ | ||
189 | int alternate; | ||
190 | int command_len; /* length of USB video command */ | ||
191 | unsigned char command_buf[13]; /* Actual USB video command */ | ||
192 | int bandlength; /* >0 = compressed */ | ||
193 | int frame_size; /* Size of one (un)compressed frame */ | ||
194 | }; | ||
195 | |||
196 | /* Flags for PWCX subroutines. Not all modules honour all flags. */ | ||
197 | #define PWCX_FLAG_PLANAR 0x0001 | ||
198 | #define PWCX_FLAG_BAYER 0x0008 | ||
199 | |||
200 | |||
201 | /* IOCTL definitions */ | ||
202 | |||
203 | /* Restore user settings */ | ||
204 | #define VIDIOCPWCRUSER _IO('v', 192) | ||
205 | /* Save user settings */ | ||
206 | #define VIDIOCPWCSUSER _IO('v', 193) | ||
207 | /* Restore factory settings */ | ||
208 | #define VIDIOCPWCFACTORY _IO('v', 194) | ||
209 | |||
210 | /* You can manipulate the compression factor. A compression preference of 0 | ||
211 | means use uncompressed modes when available; 1 is low compression, 2 is | ||
212 | medium and 3 is high compression preferred. Of course, the higher the | ||
213 | compression, the lower the bandwidth used but more chance of artefacts | ||
214 | in the image. The driver automatically chooses a higher compression when | ||
215 | the preferred mode is not available. | ||
216 | */ | ||
217 | /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ | ||
218 | #define VIDIOCPWCSCQUAL _IOW('v', 195, int) | ||
219 | /* Get preferred compression quality */ | ||
220 | #define VIDIOCPWCGCQUAL _IOR('v', 195, int) | ||
221 | |||
222 | |||
223 | /* Retrieve serial number of camera */ | ||
224 | #define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) | ||
225 | |||
226 | /* This is a probe function; since so many devices are supported, it | ||
227 | becomes difficult to include all the names in programs that want to | ||
228 | check for the enhanced Philips stuff. So in stead, try this PROBE; | ||
229 | it returns a structure with the original name, and the corresponding | ||
230 | Philips type. | ||
231 | To use, fill the structure with zeroes, call PROBE and if that succeeds, | ||
232 | compare the name with that returned from VIDIOCGCAP; they should be the | ||
233 | same. If so, you can be assured it is a Philips (OEM) cam and the type | ||
234 | is valid. | ||
235 | */ | ||
236 | #define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) | ||
237 | |||
238 | /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ | ||
239 | #define VIDIOCPWCSAGC _IOW('v', 200, int) | ||
240 | /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ | ||
241 | #define VIDIOCPWCGAGC _IOR('v', 200, int) | ||
242 | /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ | ||
243 | #define VIDIOCPWCSSHUTTER _IOW('v', 201, int) | ||
244 | |||
245 | /* Color compensation (Auto White Balance) */ | ||
246 | #define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) | ||
247 | #define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) | ||
248 | |||
249 | /* Auto WB speed */ | ||
250 | #define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) | ||
251 | #define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) | ||
252 | |||
253 | /* LEDs on/off/blink; int range 0..65535 */ | ||
254 | #define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) | ||
255 | #define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) | ||
256 | |||
257 | /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ | ||
258 | #define VIDIOCPWCSCONTOUR _IOW('v', 206, int) | ||
259 | #define VIDIOCPWCGCONTOUR _IOR('v', 206, int) | ||
260 | |||
261 | /* Backlight compensation; 0 = off, otherwise on */ | ||
262 | #define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) | ||
263 | #define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) | ||
264 | |||
265 | /* Flickerless mode; = 0 off, otherwise on */ | ||
266 | #define VIDIOCPWCSFLICKER _IOW('v', 208, int) | ||
267 | #define VIDIOCPWCGFLICKER _IOR('v', 208, int) | ||
268 | |||
269 | /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ | ||
270 | #define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) | ||
271 | #define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) | ||
272 | |||
273 | /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ | ||
274 | #define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) | ||
275 | |||
276 | /* Motorized pan & tilt functions */ | ||
277 | #define VIDIOCPWCMPTRESET _IOW('v', 211, int) | ||
278 | #define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) | ||
279 | #define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) | ||
280 | #define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) | ||
281 | #define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) | ||
282 | |||
283 | /* Get the USB set-video command; needed for initializing libpwcx */ | ||
284 | #define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) | ||
285 | struct pwc_table_init_buffer { | ||
286 | int len; | ||
287 | char *buffer; | ||
288 | |||
289 | }; | ||
290 | #define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) | ||
291 | |||
292 | #endif | ||
diff --git a/drivers/media/video/pwc/pwc-kiara.c b/drivers/media/video/pwc/pwc-kiara.c new file mode 100644 index 000000000000..c498c68bace1 --- /dev/null +++ b/drivers/media/video/pwc/pwc-kiara.c | |||
@@ -0,0 +1,318 @@ | |||
1 | /* Linux driver for Philips webcam | ||
2 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
3 | |||
4 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
5 | driver and thus may have bugs that are not present in the original version. | ||
6 | Please send bug reports and support requests to <luc@saillard.org>. | ||
7 | The decompression routines have been implemented by reverse-engineering the | ||
8 | Nemosoft binary pwcx module. Caveat emptor. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2 of the License, or | ||
13 | (at your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | */ | ||
24 | |||
25 | |||
26 | /* This tables contains entries for the 730/740/750 (Kiara) camera, with | ||
27 | 4 different qualities (no compression, low, medium, high). | ||
28 | It lists the bandwidth requirements for said mode by its alternate interface | ||
29 | number. An alternate of 0 means that the mode is unavailable. | ||
30 | |||
31 | There are 6 * 4 * 4 entries: | ||
32 | 6 different resolutions subqcif, qsif, qcif, sif, cif, vga | ||
33 | 6 framerates: 5, 10, 15, 20, 25, 30 | ||
34 | 4 compression modi: none, low, medium, high | ||
35 | |||
36 | When an uncompressed mode is not available, the next available compressed mode | ||
37 | will be chosen (unless the decompressor is absent). Sometimes there are only | ||
38 | 1 or 2 compressed modes available; in that case entries are duplicated. | ||
39 | */ | ||
40 | |||
41 | |||
42 | #include "pwc-kiara.h" | ||
43 | #include "pwc-uncompress.h" | ||
44 | |||
45 | const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] = | ||
46 | { | ||
47 | /* SQCIF */ | ||
48 | { | ||
49 | /* 5 fps */ | ||
50 | { | ||
51 | {0, }, | ||
52 | {0, }, | ||
53 | {0, }, | ||
54 | {0, }, | ||
55 | }, | ||
56 | /* 10 fps */ | ||
57 | { | ||
58 | {0, }, | ||
59 | {0, }, | ||
60 | {0, }, | ||
61 | {0, }, | ||
62 | }, | ||
63 | /* 15 fps */ | ||
64 | { | ||
65 | {0, }, | ||
66 | {0, }, | ||
67 | {0, }, | ||
68 | {0, }, | ||
69 | }, | ||
70 | /* 20 fps */ | ||
71 | { | ||
72 | {0, }, | ||
73 | {0, }, | ||
74 | {0, }, | ||
75 | {0, }, | ||
76 | }, | ||
77 | /* 25 fps */ | ||
78 | { | ||
79 | {0, }, | ||
80 | {0, }, | ||
81 | {0, }, | ||
82 | {0, }, | ||
83 | }, | ||
84 | /* 30 fps */ | ||
85 | { | ||
86 | {0, }, | ||
87 | {0, }, | ||
88 | {0, }, | ||
89 | {0, }, | ||
90 | }, | ||
91 | }, | ||
92 | /* QSIF */ | ||
93 | { | ||
94 | /* 5 fps */ | ||
95 | { | ||
96 | {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, | ||
97 | {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, | ||
98 | {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, | ||
99 | {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, | ||
100 | }, | ||
101 | /* 10 fps */ | ||
102 | { | ||
103 | {2, 291, 0, {0x1C, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0x01, 0x80}}, | ||
104 | {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, | ||
105 | {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, | ||
106 | {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, | ||
107 | }, | ||
108 | /* 15 fps */ | ||
109 | { | ||
110 | {3, 437, 0, {0x1B, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x01, 0x80}}, | ||
111 | {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, | ||
112 | {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, | ||
113 | {1, 192, 420, {0x13, 0xF4, 0x30, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, | ||
114 | }, | ||
115 | /* 20 fps */ | ||
116 | { | ||
117 | {4, 589, 0, {0x1A, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4D, 0x02, 0x80}}, | ||
118 | {3, 448, 730, {0x12, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xC0, 0x01, 0x80}}, | ||
119 | {2, 292, 476, {0x12, 0xF4, 0x30, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0x01, 0x80}}, | ||
120 | {1, 192, 312, {0x12, 0xF4, 0x50, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, | ||
121 | }, | ||
122 | /* 25 fps */ | ||
123 | { | ||
124 | {5, 703, 0, {0x19, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x02, 0x80}}, | ||
125 | {3, 447, 610, {0x11, 0xF4, 0x30, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x28, 0xBF, 0x01, 0x80}}, | ||
126 | {2, 292, 398, {0x11, 0xF4, 0x50, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x28, 0x24, 0x01, 0x80}}, | ||
127 | {1, 193, 262, {0x11, 0xF4, 0x50, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x28, 0xC1, 0x00, 0x80}}, | ||
128 | }, | ||
129 | /* 30 fps */ | ||
130 | { | ||
131 | {8, 874, 0, {0x18, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x6A, 0x03, 0x80}}, | ||
132 | {5, 704, 730, {0x10, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x28, 0xC0, 0x02, 0x80}}, | ||
133 | {3, 448, 492, {0x10, 0xF4, 0x30, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x28, 0xC0, 0x01, 0x80}}, | ||
134 | {2, 292, 320, {0x10, 0xF4, 0x50, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x28, 0x24, 0x01, 0x80}}, | ||
135 | }, | ||
136 | }, | ||
137 | /* QCIF */ | ||
138 | { | ||
139 | /* 5 fps */ | ||
140 | { | ||
141 | {0, }, | ||
142 | {0, }, | ||
143 | {0, }, | ||
144 | {0, }, | ||
145 | }, | ||
146 | /* 10 fps */ | ||
147 | { | ||
148 | {0, }, | ||
149 | {0, }, | ||
150 | {0, }, | ||
151 | {0, }, | ||
152 | }, | ||
153 | /* 15 fps */ | ||
154 | { | ||
155 | {0, }, | ||
156 | {0, }, | ||
157 | {0, }, | ||
158 | {0, }, | ||
159 | }, | ||
160 | /* 20 fps */ | ||
161 | { | ||
162 | {0, }, | ||
163 | {0, }, | ||
164 | {0, }, | ||
165 | {0, }, | ||
166 | }, | ||
167 | /* 25 fps */ | ||
168 | { | ||
169 | {0, }, | ||
170 | {0, }, | ||
171 | {0, }, | ||
172 | {0, }, | ||
173 | }, | ||
174 | /* 30 fps */ | ||
175 | { | ||
176 | {0, }, | ||
177 | {0, }, | ||
178 | {0, }, | ||
179 | {0, }, | ||
180 | }, | ||
181 | }, | ||
182 | /* SIF */ | ||
183 | { | ||
184 | /* 5 fps */ | ||
185 | { | ||
186 | {4, 582, 0, {0x0D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x02, 0x80}}, | ||
187 | {3, 387, 1276, {0x05, 0xF4, 0x30, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x01, 0x80}}, | ||
188 | {2, 291, 960, {0x05, 0xF4, 0x30, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0x01, 0x80}}, | ||
189 | {1, 191, 630, {0x05, 0xF4, 0x50, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x18, 0xBF, 0x00, 0x80}}, | ||
190 | }, | ||
191 | /* 10 fps */ | ||
192 | { | ||
193 | {0, }, | ||
194 | {6, 775, 1278, {0x04, 0xF4, 0x30, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x03, 0x80}}, | ||
195 | {3, 447, 736, {0x04, 0xF4, 0x30, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x28, 0xBF, 0x01, 0x80}}, | ||
196 | {2, 292, 480, {0x04, 0xF4, 0x70, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x28, 0x24, 0x01, 0x80}}, | ||
197 | }, | ||
198 | /* 15 fps */ | ||
199 | { | ||
200 | {0, }, | ||
201 | {9, 955, 1050, {0x03, 0xF4, 0x30, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x03, 0x80}}, | ||
202 | {4, 592, 650, {0x03, 0xF4, 0x30, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x50, 0x02, 0x80}}, | ||
203 | {3, 448, 492, {0x03, 0xF4, 0x50, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x38, 0xC0, 0x01, 0x80}}, | ||
204 | }, | ||
205 | /* 20 fps */ | ||
206 | { | ||
207 | {0, }, | ||
208 | {9, 958, 782, {0x02, 0xF4, 0x30, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x03, 0x80}}, | ||
209 | {5, 703, 574, {0x02, 0xF4, 0x50, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x02, 0x80}}, | ||
210 | {3, 446, 364, {0x02, 0xF4, 0x90, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x38, 0xBE, 0x01, 0x80}}, | ||
211 | }, | ||
212 | /* 25 fps */ | ||
213 | { | ||
214 | {0, }, | ||
215 | {9, 958, 654, {0x01, 0xF4, 0x30, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x03, 0x80}}, | ||
216 | {6, 776, 530, {0x01, 0xF4, 0x50, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x03, 0x80}}, | ||
217 | {4, 592, 404, {0x01, 0xF4, 0x70, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x48, 0x50, 0x02, 0x80}}, | ||
218 | }, | ||
219 | /* 30 fps */ | ||
220 | { | ||
221 | {0, }, | ||
222 | {9, 957, 526, {0x00, 0xF4, 0x50, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x03, 0x80}}, | ||
223 | {6, 775, 426, {0x00, 0xF4, 0x70, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x03, 0x80}}, | ||
224 | {4, 590, 324, {0x00, 0x7A, 0x88, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x50, 0x4E, 0x02, 0x80}}, | ||
225 | }, | ||
226 | }, | ||
227 | /* CIF */ | ||
228 | { | ||
229 | /* 5 fps */ | ||
230 | { | ||
231 | {0, }, | ||
232 | {0, }, | ||
233 | {0, }, | ||
234 | {0, }, | ||
235 | }, | ||
236 | /* 10 fps */ | ||
237 | { | ||
238 | {0, }, | ||
239 | {0, }, | ||
240 | {0, }, | ||
241 | {0, }, | ||
242 | }, | ||
243 | /* 15 fps */ | ||
244 | { | ||
245 | {0, }, | ||
246 | {0, }, | ||
247 | {0, }, | ||
248 | {0, }, | ||
249 | }, | ||
250 | /* 20 fps */ | ||
251 | { | ||
252 | {0, }, | ||
253 | {0, }, | ||
254 | {0, }, | ||
255 | {0, }, | ||
256 | }, | ||
257 | /* 25 fps */ | ||
258 | { | ||
259 | {0, }, | ||
260 | {0, }, | ||
261 | {0, }, | ||
262 | {0, }, | ||
263 | }, | ||
264 | /* 30 fps */ | ||
265 | { | ||
266 | {0, }, | ||
267 | {0, }, | ||
268 | {0, }, | ||
269 | {0, }, | ||
270 | }, | ||
271 | }, | ||
272 | /* VGA */ | ||
273 | { | ||
274 | /* 5 fps */ | ||
275 | { | ||
276 | {0, }, | ||
277 | {6, 773, 1272, {0x25, 0xF4, 0x30, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}, | ||
278 | {4, 592, 976, {0x25, 0xF4, 0x50, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x02, 0x80}}, | ||
279 | {3, 448, 738, {0x25, 0xF4, 0x90, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x01, 0x80}}, | ||
280 | }, | ||
281 | /* 10 fps */ | ||
282 | { | ||
283 | {0, }, | ||
284 | {9, 956, 788, {0x24, 0xF4, 0x70, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x03, 0x80}}, | ||
285 | {6, 776, 640, {0x24, 0xF4, 0xB0, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x03, 0x80}}, | ||
286 | {4, 592, 488, {0x24, 0x7A, 0xE8, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x02, 0x80}}, | ||
287 | }, | ||
288 | /* 15 fps */ | ||
289 | { | ||
290 | {0, }, | ||
291 | {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, | ||
292 | {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, | ||
293 | {8, 895, 492, {0x23, 0x7A, 0xE8, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x03, 0x80}}, | ||
294 | }, | ||
295 | /* 20 fps */ | ||
296 | { | ||
297 | {0, }, | ||
298 | {0, }, | ||
299 | {0, }, | ||
300 | {0, }, | ||
301 | }, | ||
302 | /* 25 fps */ | ||
303 | { | ||
304 | {0, }, | ||
305 | {0, }, | ||
306 | {0, }, | ||
307 | {0, }, | ||
308 | }, | ||
309 | /* 30 fps */ | ||
310 | { | ||
311 | {0, }, | ||
312 | {0, }, | ||
313 | {0, }, | ||
314 | {0, }, | ||
315 | }, | ||
316 | }, | ||
317 | }; | ||
318 | |||
diff --git a/drivers/media/video/pwc/pwc-kiara.h b/drivers/media/video/pwc/pwc-kiara.h new file mode 100644 index 000000000000..12929abbb1f0 --- /dev/null +++ b/drivers/media/video/pwc/pwc-kiara.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* Linux driver for Philips webcam | ||
2 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
3 | |||
4 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
5 | driver and thus may have bugs that are not present in the original version. | ||
6 | Please send bug reports and support requests to <luc@saillard.org>. | ||
7 | The decompression routines have been implemented by reverse-engineering the | ||
8 | Nemosoft binary pwcx module. Caveat emptor. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2 of the License, or | ||
13 | (at your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | */ | ||
24 | |||
25 | /* Entries for the Kiara (730/740/750) camera */ | ||
26 | |||
27 | #ifndef PWC_KIARA_H | ||
28 | #define PWC_KIARA_H | ||
29 | |||
30 | #include "pwc-ioctl.h" | ||
31 | |||
32 | struct Kiara_table_entry | ||
33 | { | ||
34 | char alternate; /* USB alternate interface */ | ||
35 | unsigned short packetsize; /* Normal packet size */ | ||
36 | unsigned short bandlength; /* Bandlength when decompressing */ | ||
37 | unsigned char mode[12]; /* precomputed mode settings for cam */ | ||
38 | }; | ||
39 | |||
40 | const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4]; | ||
41 | const extern unsigned int KiaraRomTable[8][2][16][8]; | ||
42 | |||
43 | #endif | ||
44 | |||
45 | |||
diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/video/pwc/pwc-misc.c new file mode 100644 index 000000000000..b7a4bd3524c7 --- /dev/null +++ b/drivers/media/video/pwc/pwc-misc.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* Linux driver for Philips webcam | ||
2 | Various miscellaneous functions and tables. | ||
3 | (C) 1999-2003 Nemosoft Unv. | ||
4 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
5 | |||
6 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
7 | driver and thus may have bugs that are not present in the original version. | ||
8 | Please send bug reports and support requests to <luc@saillard.org>. | ||
9 | The decompression routines have been implemented by reverse-engineering the | ||
10 | Nemosoft binary pwcx module. Caveat emptor. | ||
11 | |||
12 | This program is free software; you can redistribute it and/or modify | ||
13 | it under the terms of the GNU General Public License as published by | ||
14 | the Free Software Foundation; either version 2 of the License, or | ||
15 | (at your option) any later version. | ||
16 | |||
17 | This program is distributed in the hope that it will be useful, | ||
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | GNU General Public License for more details. | ||
21 | |||
22 | You should have received a copy of the GNU General Public License | ||
23 | along with this program; if not, write to the Free Software | ||
24 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | */ | ||
26 | |||
27 | #include <linux/slab.h> | ||
28 | |||
29 | #include "pwc.h" | ||
30 | |||
31 | struct pwc_coord pwc_image_sizes[PSZ_MAX] = | ||
32 | { | ||
33 | { 128, 96, 0 }, | ||
34 | { 160, 120, 0 }, | ||
35 | { 176, 144, 0 }, | ||
36 | { 320, 240, 0 }, | ||
37 | { 352, 288, 0 }, | ||
38 | { 640, 480, 0 }, | ||
39 | }; | ||
40 | |||
41 | /* x,y -> PSZ_ */ | ||
42 | int pwc_decode_size(struct pwc_device *pdev, int width, int height) | ||
43 | { | ||
44 | int i, find; | ||
45 | |||
46 | /* Make sure we don't go beyond our max size. | ||
47 | NB: we have different limits for RAW and normal modes. In case | ||
48 | you don't have the decompressor loaded or use RAW mode, | ||
49 | the maximum viewable size is smaller. | ||
50 | */ | ||
51 | if (pdev->vpalette == VIDEO_PALETTE_RAW) | ||
52 | { | ||
53 | if (width > pdev->abs_max.x || height > pdev->abs_max.y) | ||
54 | { | ||
55 | Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n"); | ||
56 | return -1; | ||
57 | } | ||
58 | } | ||
59 | else | ||
60 | { | ||
61 | if (width > pdev->view_max.x || height > pdev->view_max.y) | ||
62 | { | ||
63 | Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n"); | ||
64 | return -1; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | /* Find the largest size supported by the camera that fits into the | ||
69 | requested size. | ||
70 | */ | ||
71 | find = -1; | ||
72 | for (i = 0; i < PSZ_MAX; i++) { | ||
73 | if (pdev->image_mask & (1 << i)) { | ||
74 | if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height) | ||
75 | find = i; | ||
76 | } | ||
77 | } | ||
78 | return find; | ||
79 | } | ||
80 | |||
81 | /* initialize variables depending on type and decompressor*/ | ||
82 | void pwc_construct(struct pwc_device *pdev) | ||
83 | { | ||
84 | switch(pdev->type) { | ||
85 | case 645: | ||
86 | case 646: | ||
87 | pdev->view_min.x = 128; | ||
88 | pdev->view_min.y = 96; | ||
89 | pdev->view_max.x = 352; | ||
90 | pdev->view_max.y = 288; | ||
91 | pdev->abs_max.x = 352; | ||
92 | pdev->abs_max.y = 288; | ||
93 | pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; | ||
94 | pdev->vcinterface = 2; | ||
95 | pdev->vendpoint = 4; | ||
96 | pdev->frame_header_size = 0; | ||
97 | pdev->frame_trailer_size = 0; | ||
98 | break; | ||
99 | case 675: | ||
100 | case 680: | ||
101 | case 690: | ||
102 | pdev->view_min.x = 128; | ||
103 | pdev->view_min.y = 96; | ||
104 | /* Anthill bug #38: PWC always reports max size, even without PWCX */ | ||
105 | pdev->view_max.x = 640; | ||
106 | pdev->view_max.y = 480; | ||
107 | pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; | ||
108 | pdev->abs_max.x = 640; | ||
109 | pdev->abs_max.y = 480; | ||
110 | pdev->vcinterface = 3; | ||
111 | pdev->vendpoint = 4; | ||
112 | pdev->frame_header_size = 0; | ||
113 | pdev->frame_trailer_size = 0; | ||
114 | break; | ||
115 | case 720: | ||
116 | case 730: | ||
117 | case 740: | ||
118 | case 750: | ||
119 | pdev->view_min.x = 160; | ||
120 | pdev->view_min.y = 120; | ||
121 | pdev->view_max.x = 640; | ||
122 | pdev->view_max.y = 480; | ||
123 | pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; | ||
124 | pdev->abs_max.x = 640; | ||
125 | pdev->abs_max.y = 480; | ||
126 | pdev->vcinterface = 3; | ||
127 | pdev->vendpoint = 5; | ||
128 | pdev->frame_header_size = TOUCAM_HEADER_SIZE; | ||
129 | pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE; | ||
130 | break; | ||
131 | } | ||
132 | Debug("type = %d\n",pdev->type); | ||
133 | pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */ | ||
134 | pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; | ||
135 | pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; | ||
136 | /* length of image, in YUV format; always allocate enough memory. */ | ||
137 | pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2; | ||
138 | } | ||
139 | |||
140 | |||
diff --git a/drivers/media/video/pwc/pwc-nala.h b/drivers/media/video/pwc/pwc-nala.h new file mode 100644 index 000000000000..e6c5cb69d03b --- /dev/null +++ b/drivers/media/video/pwc/pwc-nala.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* SQCIF */ | ||
2 | { | ||
3 | {0, 0, {0x04, 0x01, 0x03}}, | ||
4 | {8, 0, {0x05, 0x01, 0x03}}, | ||
5 | {7, 0, {0x08, 0x01, 0x03}}, | ||
6 | {7, 0, {0x0A, 0x01, 0x03}}, | ||
7 | {6, 0, {0x0C, 0x01, 0x03}}, | ||
8 | {5, 0, {0x0F, 0x01, 0x03}}, | ||
9 | {4, 0, {0x14, 0x01, 0x03}}, | ||
10 | {3, 0, {0x18, 0x01, 0x03}}, | ||
11 | }, | ||
12 | /* QSIF */ | ||
13 | { | ||
14 | {0}, | ||
15 | {0}, | ||
16 | {0}, | ||
17 | {0}, | ||
18 | {0}, | ||
19 | {0}, | ||
20 | {0}, | ||
21 | {0}, | ||
22 | }, | ||
23 | /* QCIF */ | ||
24 | { | ||
25 | {0, 0, {0x04, 0x01, 0x02}}, | ||
26 | {8, 0, {0x05, 0x01, 0x02}}, | ||
27 | {7, 0, {0x08, 0x01, 0x02}}, | ||
28 | {6, 0, {0x0A, 0x01, 0x02}}, | ||
29 | {5, 0, {0x0C, 0x01, 0x02}}, | ||
30 | {4, 0, {0x0F, 0x01, 0x02}}, | ||
31 | {1, 0, {0x14, 0x01, 0x02}}, | ||
32 | {1, 0, {0x18, 0x01, 0x02}}, | ||
33 | }, | ||
34 | /* SIF */ | ||
35 | { | ||
36 | {0}, | ||
37 | {0}, | ||
38 | {0}, | ||
39 | {0}, | ||
40 | {0}, | ||
41 | {0}, | ||
42 | {0}, | ||
43 | {0}, | ||
44 | }, | ||
45 | /* CIF */ | ||
46 | { | ||
47 | {4, 0, {0x04, 0x01, 0x01}}, | ||
48 | {7, 1, {0x05, 0x03, 0x01}}, | ||
49 | {6, 1, {0x08, 0x03, 0x01}}, | ||
50 | {4, 1, {0x0A, 0x03, 0x01}}, | ||
51 | {3, 1, {0x0C, 0x03, 0x01}}, | ||
52 | {2, 1, {0x0F, 0x03, 0x01}}, | ||
53 | {0}, | ||
54 | {0}, | ||
55 | }, | ||
56 | /* VGA */ | ||
57 | { | ||
58 | {0}, | ||
59 | {0}, | ||
60 | {0}, | ||
61 | {0}, | ||
62 | {0}, | ||
63 | {0}, | ||
64 | {0}, | ||
65 | {0}, | ||
66 | }, | ||
diff --git a/drivers/media/video/pwc/pwc-timon.c b/drivers/media/video/pwc/pwc-timon.c new file mode 100644 index 000000000000..dee967173d6c --- /dev/null +++ b/drivers/media/video/pwc/pwc-timon.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* Linux driver for Philips webcam | ||
2 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
3 | |||
4 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
5 | driver and thus may have bugs that are not present in the original version. | ||
6 | Please send bug reports and support requests to <luc@saillard.org>. | ||
7 | The decompression routines have been implemented by reverse-engineering the | ||
8 | Nemosoft binary pwcx module. Caveat emptor. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2 of the License, or | ||
13 | (at your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | */ | ||
24 | |||
25 | |||
26 | /* This tables contains entries for the 675/680/690 (Timon) camera, with | ||
27 | 4 different qualities (no compression, low, medium, high). | ||
28 | It lists the bandwidth requirements for said mode by its alternate interface | ||
29 | number. An alternate of 0 means that the mode is unavailable. | ||
30 | |||
31 | There are 6 * 4 * 4 entries: | ||
32 | 6 different resolutions subqcif, qsif, qcif, sif, cif, vga | ||
33 | 6 framerates: 5, 10, 15, 20, 25, 30 | ||
34 | 4 compression modi: none, low, medium, high | ||
35 | |||
36 | When an uncompressed mode is not available, the next available compressed mode | ||
37 | will be chosen (unless the decompressor is absent). Sometimes there are only | ||
38 | 1 or 2 compressed modes available; in that case entries are duplicated. | ||
39 | */ | ||
40 | |||
41 | #include "pwc-timon.h" | ||
42 | |||
43 | const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] = | ||
44 | { | ||
45 | /* SQCIF */ | ||
46 | { | ||
47 | /* 5 fps */ | ||
48 | { | ||
49 | {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, | ||
50 | {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, | ||
51 | {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, | ||
52 | {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, | ||
53 | }, | ||
54 | /* 10 fps */ | ||
55 | { | ||
56 | {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, | ||
57 | {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, | ||
58 | {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, | ||
59 | {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, | ||
60 | }, | ||
61 | /* 15 fps */ | ||
62 | { | ||
63 | {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, | ||
64 | {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, | ||
65 | {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, | ||
66 | {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, | ||
67 | }, | ||
68 | /* 20 fps */ | ||
69 | { | ||
70 | {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, | ||
71 | {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, | ||
72 | {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, | ||
73 | {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, | ||
74 | }, | ||
75 | /* 25 fps */ | ||
76 | { | ||
77 | {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, | ||
78 | {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, | ||
79 | {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, | ||
80 | {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, | ||
81 | }, | ||
82 | /* 30 fps */ | ||
83 | { | ||
84 | {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, | ||
85 | {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, | ||
86 | {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, | ||
87 | {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, | ||
88 | }, | ||
89 | }, | ||
90 | /* QSIF */ | ||
91 | { | ||
92 | /* 5 fps */ | ||
93 | { | ||
94 | {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, | ||
95 | {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, | ||
96 | {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, | ||
97 | {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, | ||
98 | }, | ||
99 | /* 10 fps */ | ||
100 | { | ||
101 | {2, 291, 0, {0x2C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0xA1, 0xC0, 0x02}}, | ||
102 | {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, | ||
103 | {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, | ||
104 | {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, | ||
105 | }, | ||
106 | /* 15 fps */ | ||
107 | { | ||
108 | {3, 437, 0, {0x2B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x6D, 0xC0, 0x02}}, | ||
109 | {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, | ||
110 | {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, | ||
111 | {1, 191, 420, {0x2B, 0xF4, 0x0D, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, | ||
112 | }, | ||
113 | /* 20 fps */ | ||
114 | { | ||
115 | {4, 588, 0, {0x2A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4C, 0x52, 0xC0, 0x02}}, | ||
116 | {3, 447, 730, {0x2A, 0xF4, 0x05, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, | ||
117 | {2, 292, 476, {0x2A, 0xF4, 0x0D, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, | ||
118 | {1, 192, 312, {0x2A, 0xF4, 0x1D, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, | ||
119 | }, | ||
120 | /* 25 fps */ | ||
121 | { | ||
122 | {5, 703, 0, {0x29, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x42, 0xC0, 0x02}}, | ||
123 | {3, 447, 610, {0x29, 0xF4, 0x05, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, | ||
124 | {2, 292, 398, {0x29, 0xF4, 0x0D, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, | ||
125 | {1, 192, 262, {0x29, 0xF4, 0x25, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, | ||
126 | }, | ||
127 | /* 30 fps */ | ||
128 | { | ||
129 | {8, 873, 0, {0x28, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x69, 0x37, 0xC0, 0x02}}, | ||
130 | {5, 704, 774, {0x28, 0xF4, 0x05, 0x18, 0x21, 0x17, 0x59, 0x0F, 0x18, 0xC0, 0x42, 0xC0, 0x02}}, | ||
131 | {3, 448, 492, {0x28, 0xF4, 0x05, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x18, 0xC0, 0x69, 0xC0, 0x02}}, | ||
132 | {2, 291, 320, {0x28, 0xF4, 0x1D, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, | ||
133 | }, | ||
134 | }, | ||
135 | /* QCIF */ | ||
136 | { | ||
137 | /* 5 fps */ | ||
138 | { | ||
139 | {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, | ||
140 | {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, | ||
141 | {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, | ||
142 | {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, | ||
143 | }, | ||
144 | /* 10 fps */ | ||
145 | { | ||
146 | {3, 385, 0, {0x0C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x81, 0x79, 0xC0, 0x02}}, | ||
147 | {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, | ||
148 | {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, | ||
149 | {1, 194, 532, {0x0C, 0xF4, 0x05, 0x10, 0x9A, 0x0F, 0xBE, 0x1B, 0x08, 0xC2, 0xF0, 0xC0, 0x02}}, | ||
150 | }, | ||
151 | /* 15 fps */ | ||
152 | { | ||
153 | {4, 577, 0, {0x0B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x41, 0x52, 0xC0, 0x02}}, | ||
154 | {3, 447, 818, {0x0B, 0xF4, 0x05, 0x19, 0x89, 0x18, 0xAD, 0x0F, 0x10, 0xBF, 0x69, 0xC0, 0x02}}, | ||
155 | {2, 292, 534, {0x0B, 0xF4, 0x05, 0x10, 0xA3, 0x0F, 0xC7, 0x19, 0x10, 0x24, 0xA1, 0xC0, 0x02}}, | ||
156 | {1, 195, 356, {0x0B, 0xF4, 0x15, 0x0B, 0x11, 0x0A, 0x35, 0x1E, 0x10, 0xC3, 0xF0, 0xC0, 0x02}}, | ||
157 | }, | ||
158 | /* 20 fps */ | ||
159 | { | ||
160 | {6, 776, 0, {0x0A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x08, 0x3F, 0xC0, 0x02}}, | ||
161 | {4, 591, 804, {0x0A, 0xF4, 0x05, 0x19, 0x1E, 0x18, 0x42, 0x0F, 0x18, 0x4F, 0x4E, 0xC0, 0x02}}, | ||
162 | {3, 447, 608, {0x0A, 0xF4, 0x05, 0x12, 0xFD, 0x12, 0x21, 0x15, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, | ||
163 | {2, 291, 396, {0x0A, 0xF4, 0x15, 0x0C, 0x5E, 0x0B, 0x82, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, | ||
164 | }, | ||
165 | /* 25 fps */ | ||
166 | { | ||
167 | {9, 928, 0, {0x09, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA0, 0x33, 0xC0, 0x02}}, | ||
168 | {5, 703, 800, {0x09, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x10, 0x18, 0xBF, 0x42, 0xC0, 0x02}}, | ||
169 | {3, 447, 508, {0x09, 0xF4, 0x0D, 0x0F, 0xD2, 0x0E, 0xF6, 0x1B, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, | ||
170 | {2, 292, 332, {0x09, 0xF4, 0x1D, 0x0A, 0x5A, 0x09, 0x7E, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, | ||
171 | }, | ||
172 | /* 30 fps */ | ||
173 | { | ||
174 | {0, }, | ||
175 | {9, 956, 876, {0x08, 0xF4, 0x05, 0x1B, 0x58, 0x1A, 0x7C, 0x0E, 0x20, 0xBC, 0x33, 0x10, 0x02}}, | ||
176 | {4, 592, 542, {0x08, 0xF4, 0x05, 0x10, 0xE4, 0x10, 0x08, 0x17, 0x20, 0x50, 0x4E, 0x10, 0x02}}, | ||
177 | {2, 291, 266, {0x08, 0xF4, 0x25, 0x08, 0x48, 0x07, 0x6C, 0x1E, 0x20, 0x23, 0xA1, 0x10, 0x02}}, | ||
178 | }, | ||
179 | }, | ||
180 | /* SIF */ | ||
181 | { | ||
182 | /* 5 fps */ | ||
183 | { | ||
184 | {4, 582, 0, {0x35, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x52, 0x60, 0x02}}, | ||
185 | {3, 387, 1276, {0x35, 0xF4, 0x05, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x79, 0x60, 0x02}}, | ||
186 | {2, 291, 960, {0x35, 0xF4, 0x0D, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0xA1, 0x60, 0x02}}, | ||
187 | {1, 191, 630, {0x35, 0xF4, 0x1D, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x08, 0xBF, 0xF4, 0x60, 0x02}}, | ||
188 | }, | ||
189 | /* 10 fps */ | ||
190 | { | ||
191 | {0, }, | ||
192 | {6, 775, 1278, {0x34, 0xF4, 0x05, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x3F, 0x10, 0x02}}, | ||
193 | {3, 447, 736, {0x34, 0xF4, 0x15, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x18, 0xBF, 0x69, 0x10, 0x02}}, | ||
194 | {2, 291, 480, {0x34, 0xF4, 0x2D, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x18, 0x23, 0xA1, 0x10, 0x02}}, | ||
195 | }, | ||
196 | /* 15 fps */ | ||
197 | { | ||
198 | {0, }, | ||
199 | {9, 955, 1050, {0x33, 0xF4, 0x05, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x33, 0x10, 0x02}}, | ||
200 | {4, 591, 650, {0x33, 0xF4, 0x15, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x4F, 0x4E, 0x10, 0x02}}, | ||
201 | {3, 448, 492, {0x33, 0xF4, 0x25, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x28, 0xC0, 0x69, 0x10, 0x02}}, | ||
202 | }, | ||
203 | /* 20 fps */ | ||
204 | { | ||
205 | {0, }, | ||
206 | {9, 958, 782, {0x32, 0xF4, 0x0D, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x33, 0xD0, 0x02}}, | ||
207 | {5, 703, 574, {0x32, 0xF4, 0x1D, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x42, 0xD0, 0x02}}, | ||
208 | {3, 446, 364, {0x32, 0xF4, 0x3D, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x30, 0xBE, 0x69, 0xD0, 0x02}}, | ||
209 | }, | ||
210 | /* 25 fps */ | ||
211 | { | ||
212 | {0, }, | ||
213 | {9, 958, 654, {0x31, 0xF4, 0x15, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x33, 0x90, 0x02}}, | ||
214 | {6, 776, 530, {0x31, 0xF4, 0x25, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x3F, 0x90, 0x02}}, | ||
215 | {4, 592, 404, {0x31, 0xF4, 0x35, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x38, 0x50, 0x4E, 0x90, 0x02}}, | ||
216 | }, | ||
217 | /* 30 fps */ | ||
218 | { | ||
219 | {0, }, | ||
220 | {9, 957, 526, {0x30, 0xF4, 0x25, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x33, 0x60, 0x02}}, | ||
221 | {6, 775, 426, {0x30, 0xF4, 0x35, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x3F, 0x60, 0x02}}, | ||
222 | {4, 590, 324, {0x30, 0x7A, 0x4B, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x40, 0x4E, 0x52, 0x60, 0x02}}, | ||
223 | }, | ||
224 | }, | ||
225 | /* CIF */ | ||
226 | { | ||
227 | /* 5 fps */ | ||
228 | { | ||
229 | {6, 771, 0, {0x15, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x3F, 0x80, 0x02}}, | ||
230 | {4, 465, 1278, {0x15, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x03, 0x18, 0xD1, 0x65, 0x80, 0x02}}, | ||
231 | {2, 291, 800, {0x15, 0xF4, 0x15, 0x18, 0xF4, 0x17, 0x3C, 0x05, 0x18, 0x23, 0xA1, 0x80, 0x02}}, | ||
232 | {1, 193, 528, {0x15, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x18, 0xC1, 0xF4, 0x80, 0x02}}, | ||
233 | }, | ||
234 | /* 10 fps */ | ||
235 | { | ||
236 | {0, }, | ||
237 | {9, 932, 1278, {0x14, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x04, 0x30, 0xA4, 0x33, 0x10, 0x02}}, | ||
238 | {4, 591, 812, {0x14, 0xF4, 0x15, 0x19, 0x56, 0x17, 0x9E, 0x06, 0x28, 0x4F, 0x4E, 0x10, 0x02}}, | ||
239 | {2, 291, 400, {0x14, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x28, 0x23, 0xA1, 0x10, 0x02}}, | ||
240 | }, | ||
241 | /* 15 fps */ | ||
242 | { | ||
243 | {0, }, | ||
244 | {9, 956, 876, {0x13, 0xF4, 0x0D, 0x1B, 0x58, 0x19, 0xA0, 0x05, 0x38, 0xBC, 0x33, 0x60, 0x02}}, | ||
245 | {5, 703, 644, {0x13, 0xF4, 0x1D, 0x14, 0x1C, 0x12, 0x64, 0x08, 0x38, 0xBF, 0x42, 0x60, 0x02}}, | ||
246 | {3, 448, 410, {0x13, 0xF4, 0x3D, 0x0C, 0xC4, 0x0B, 0x0C, 0x0E, 0x38, 0xC0, 0x69, 0x60, 0x02}}, | ||
247 | }, | ||
248 | /* 20 fps */ | ||
249 | { | ||
250 | {0, }, | ||
251 | {9, 956, 650, {0x12, 0xF4, 0x1D, 0x14, 0x4A, 0x12, 0x92, 0x09, 0x48, 0xBC, 0x33, 0x10, 0x03}}, | ||
252 | {6, 776, 528, {0x12, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x40, 0x08, 0x3F, 0x10, 0x03}}, | ||
253 | {4, 591, 402, {0x12, 0xF4, 0x3D, 0x0C, 0x8F, 0x0A, 0xD7, 0x0E, 0x40, 0x4F, 0x4E, 0x10, 0x03}}, | ||
254 | }, | ||
255 | /* 25 fps */ | ||
256 | { | ||
257 | {0, }, | ||
258 | {9, 956, 544, {0x11, 0xF4, 0x25, 0x10, 0xF4, 0x0F, 0x3C, 0x0A, 0x48, 0xBC, 0x33, 0xC0, 0x02}}, | ||
259 | {7, 840, 478, {0x11, 0xF4, 0x2D, 0x0E, 0xEB, 0x0D, 0x33, 0x0B, 0x48, 0x48, 0x3B, 0xC0, 0x02}}, | ||
260 | {5, 703, 400, {0x11, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x48, 0xBF, 0x42, 0xC0, 0x02}}, | ||
261 | }, | ||
262 | /* 30 fps */ | ||
263 | { | ||
264 | {0, }, | ||
265 | {9, 956, 438, {0x10, 0xF4, 0x35, 0x0D, 0xAC, 0x0B, 0xF4, 0x0D, 0x50, 0xBC, 0x33, 0x10, 0x02}}, | ||
266 | {7, 838, 384, {0x10, 0xF4, 0x45, 0x0B, 0xFD, 0x0A, 0x45, 0x0F, 0x50, 0x46, 0x3B, 0x10, 0x02}}, | ||
267 | {6, 773, 354, {0x10, 0x7A, 0x4B, 0x0B, 0x0C, 0x09, 0x80, 0x10, 0x50, 0x05, 0x3F, 0x10, 0x02}}, | ||
268 | }, | ||
269 | }, | ||
270 | /* VGA */ | ||
271 | { | ||
272 | /* 5 fps */ | ||
273 | { | ||
274 | {0, }, | ||
275 | {6, 773, 1272, {0x1D, 0xF4, 0x15, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x3F, 0x10, 0x02}}, | ||
276 | {4, 592, 976, {0x1D, 0xF4, 0x25, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x4E, 0x10, 0x02}}, | ||
277 | {3, 448, 738, {0x1D, 0xF4, 0x3D, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x69, 0x10, 0x02}}, | ||
278 | }, | ||
279 | /* 10 fps */ | ||
280 | { | ||
281 | {0, }, | ||
282 | {9, 956, 788, {0x1C, 0xF4, 0x35, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x33, 0x10, 0x02}}, | ||
283 | {6, 776, 640, {0x1C, 0x7A, 0x53, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x3F, 0x10, 0x02}}, | ||
284 | {4, 592, 488, {0x1C, 0x7A, 0x6B, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x4E, 0x10, 0x02}}, | ||
285 | }, | ||
286 | /* 15 fps */ | ||
287 | { | ||
288 | {0, }, | ||
289 | {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, | ||
290 | {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, | ||
291 | {8, 895, 492, {0x1B, 0x7A, 0x6B, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x37, 0x80, 0x02}}, | ||
292 | }, | ||
293 | /* 20 fps */ | ||
294 | { | ||
295 | {0, }, | ||
296 | {0, }, | ||
297 | {0, }, | ||
298 | {0, }, | ||
299 | }, | ||
300 | /* 25 fps */ | ||
301 | { | ||
302 | {0, }, | ||
303 | {0, }, | ||
304 | {0, }, | ||
305 | {0, }, | ||
306 | }, | ||
307 | /* 30 fps */ | ||
308 | { | ||
309 | {0, }, | ||
310 | {0, }, | ||
311 | {0, }, | ||
312 | {0, }, | ||
313 | }, | ||
314 | }, | ||
315 | }; | ||
316 | |||
diff --git a/drivers/media/video/pwc/pwc-timon.h b/drivers/media/video/pwc/pwc-timon.h new file mode 100644 index 000000000000..a86b3782a081 --- /dev/null +++ b/drivers/media/video/pwc/pwc-timon.h | |||
@@ -0,0 +1,61 @@ | |||
1 | /* Linux driver for Philips webcam | ||
2 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
3 | |||
4 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
5 | driver and thus may have bugs that are not present in the original version. | ||
6 | Please send bug reports and support requests to <luc@saillard.org>. | ||
7 | The decompression routines have been implemented by reverse-engineering the | ||
8 | Nemosoft binary pwcx module. Caveat emptor. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2 of the License, or | ||
13 | (at your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | */ | ||
24 | |||
25 | |||
26 | |||
27 | /* This tables contains entries for the 675/680/690 (Timon) camera, with | ||
28 | 4 different qualities (no compression, low, medium, high). | ||
29 | It lists the bandwidth requirements for said mode by its alternate interface | ||
30 | number. An alternate of 0 means that the mode is unavailable. | ||
31 | |||
32 | There are 6 * 4 * 4 entries: | ||
33 | 6 different resolutions subqcif, qsif, qcif, sif, cif, vga | ||
34 | 6 framerates: 5, 10, 15, 20, 25, 30 | ||
35 | 4 compression modi: none, low, medium, high | ||
36 | |||
37 | When an uncompressed mode is not available, the next available compressed mode | ||
38 | will be chosen (unless the decompressor is absent). Sometimes there are only | ||
39 | 1 or 2 compressed modes available; in that case entries are duplicated. | ||
40 | */ | ||
41 | |||
42 | #ifndef PWC_TIMON_H | ||
43 | #define PWC_TIMON_H | ||
44 | |||
45 | #include "pwc-ioctl.h" | ||
46 | |||
47 | struct Timon_table_entry | ||
48 | { | ||
49 | char alternate; /* USB alternate interface */ | ||
50 | unsigned short packetsize; /* Normal packet size */ | ||
51 | unsigned short bandlength; /* Bandlength when decompressing */ | ||
52 | unsigned char mode[13]; /* precomputed mode settings for cam */ | ||
53 | }; | ||
54 | |||
55 | const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4]; | ||
56 | const extern unsigned int TimonRomTable [16][2][16][8]; | ||
57 | |||
58 | |||
59 | #endif | ||
60 | |||
61 | |||
diff --git a/drivers/media/video/pwc/pwc-uncompress.c b/drivers/media/video/pwc/pwc-uncompress.c new file mode 100644 index 000000000000..ef4204eab6c4 --- /dev/null +++ b/drivers/media/video/pwc/pwc-uncompress.c | |||
@@ -0,0 +1,146 @@ | |||
1 | /* Linux driver for Philips webcam | ||
2 | Decompression frontend. | ||
3 | (C) 1999-2003 Nemosoft Unv. | ||
4 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
5 | |||
6 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
7 | driver and thus may have bugs that are not present in the original version. | ||
8 | Please send bug reports and support requests to <luc@saillard.org>. | ||
9 | The decompression routines have been implemented by reverse-engineering the | ||
10 | Nemosoft binary pwcx module. Caveat emptor. | ||
11 | |||
12 | This program is free software; you can redistribute it and/or modify | ||
13 | it under the terms of the GNU General Public License as published by | ||
14 | the Free Software Foundation; either version 2 of the License, or | ||
15 | (at your option) any later version. | ||
16 | |||
17 | This program is distributed in the hope that it will be useful, | ||
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | GNU General Public License for more details. | ||
21 | |||
22 | You should have received a copy of the GNU General Public License | ||
23 | along with this program; if not, write to the Free Software | ||
24 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | */ | ||
26 | |||
27 | #include <asm/current.h> | ||
28 | #include <asm/types.h> | ||
29 | |||
30 | #include "pwc.h" | ||
31 | #include "pwc-uncompress.h" | ||
32 | |||
33 | int pwc_decompress(struct pwc_device *pdev) | ||
34 | { | ||
35 | struct pwc_frame_buf *fbuf; | ||
36 | int n, line, col, stride; | ||
37 | void *yuv, *image; | ||
38 | u16 *src; | ||
39 | u16 *dsty, *dstu, *dstv; | ||
40 | |||
41 | if (pdev == NULL) | ||
42 | return -EFAULT; | ||
43 | #if defined(__KERNEL__) && defined(PWC_MAGIC) | ||
44 | if (pdev->magic != PWC_MAGIC) { | ||
45 | Err("pwc_decompress(): magic failed.\n"); | ||
46 | return -EFAULT; | ||
47 | } | ||
48 | #endif | ||
49 | |||
50 | fbuf = pdev->read_frame; | ||
51 | if (fbuf == NULL) | ||
52 | return -EFAULT; | ||
53 | image = pdev->image_ptr[pdev->fill_image]; | ||
54 | if (!image) | ||
55 | return -EFAULT; | ||
56 | |||
57 | yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ | ||
58 | |||
59 | /* Raw format; that's easy... */ | ||
60 | if (pdev->vpalette == VIDEO_PALETTE_RAW) | ||
61 | { | ||
62 | memcpy(image, yuv, pdev->frame_size); | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | if (pdev->vbandlength == 0) { | ||
67 | /* Uncompressed mode. We copy the data into the output buffer, | ||
68 | using the viewport size (which may be larger than the image | ||
69 | size). Unfortunately we have to do a bit of byte stuffing | ||
70 | to get the desired output format/size. | ||
71 | */ | ||
72 | /* | ||
73 | * We do some byte shuffling here to go from the | ||
74 | * native format to YUV420P. | ||
75 | */ | ||
76 | src = (u16 *)yuv; | ||
77 | n = pdev->view.x * pdev->view.y; | ||
78 | |||
79 | /* offset in Y plane */ | ||
80 | stride = pdev->view.x * pdev->offset.y + pdev->offset.x; | ||
81 | dsty = (u16 *)(image + stride); | ||
82 | |||
83 | /* offsets in U/V planes */ | ||
84 | stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2; | ||
85 | dstu = (u16 *)(image + n + stride); | ||
86 | dstv = (u16 *)(image + n + n / 4 + stride); | ||
87 | |||
88 | /* increment after each line */ | ||
89 | stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */ | ||
90 | |||
91 | for (line = 0; line < pdev->image.y; line++) { | ||
92 | for (col = 0; col < pdev->image.x; col += 4) { | ||
93 | *dsty++ = *src++; | ||
94 | *dsty++ = *src++; | ||
95 | if (line & 1) | ||
96 | *dstv++ = *src++; | ||
97 | else | ||
98 | *dstu++ = *src++; | ||
99 | } | ||
100 | dsty += stride; | ||
101 | if (line & 1) | ||
102 | dstv += (stride >> 1); | ||
103 | else | ||
104 | dstu += (stride >> 1); | ||
105 | } | ||
106 | } | ||
107 | else { | ||
108 | /* Compressed; the decompressor routines will write the data | ||
109 | in planar format immediately. | ||
110 | */ | ||
111 | int flags; | ||
112 | |||
113 | flags = PWCX_FLAG_PLANAR; | ||
114 | if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) | ||
115 | { | ||
116 | printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n"); | ||
117 | flags |= PWCX_FLAG_BAYER; | ||
118 | return -ENXIO; /* No such device or address: missing decompressor */ | ||
119 | } | ||
120 | |||
121 | #if 0 | ||
122 | switch (pdev->type) | ||
123 | { | ||
124 | case 675: | ||
125 | case 680: | ||
126 | case 690: | ||
127 | case 720: | ||
128 | case 730: | ||
129 | case 740: | ||
130 | case 750: | ||
131 | pwc_dec23_decompress(&pdev->image, &pdev->view, | ||
132 | &pdev->offset, yuv, image, flags, | ||
133 | pdev->decompress_data, pdev->vbandlength); | ||
134 | break; | ||
135 | case 645: | ||
136 | case 646: | ||
137 | /* TODO & FIXME */ | ||
138 | return -ENXIO; /* Missing decompressor */ | ||
139 | break; | ||
140 | } | ||
141 | #endif | ||
142 | } | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | |||
diff --git a/drivers/media/video/pwc/pwc-uncompress.h b/drivers/media/video/pwc/pwc-uncompress.h new file mode 100644 index 000000000000..d3b9250e4ed3 --- /dev/null +++ b/drivers/media/video/pwc/pwc-uncompress.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* (C) 1999-2003 Nemosoft Unv. | ||
2 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
3 | |||
4 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
5 | driver and thus may have bugs that are not present in the original version. | ||
6 | Please send bug reports and support requests to <luc@saillard.org>. | ||
7 | The decompression routines have been implemented by reverse-engineering the | ||
8 | Nemosoft binary pwcx module. Caveat emptor. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2 of the License, or | ||
13 | (at your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | */ | ||
24 | |||
25 | /* This file is the bridge between the kernel module and the plugin; it | ||
26 | describes the structures and datatypes used in both modules. Any | ||
27 | significant change should be reflected by increasing the | ||
28 | pwc_decompressor_version major number. | ||
29 | */ | ||
30 | #ifndef PWC_UNCOMPRESS_H | ||
31 | #define PWC_UNCOMPRESS_H | ||
32 | |||
33 | #include <linux/config.h> | ||
34 | |||
35 | #include "pwc-ioctl.h" | ||
36 | |||
37 | /* from pwc-dec.h */ | ||
38 | #define PWCX_FLAG_PLANAR 0x0001 | ||
39 | /* */ | ||
40 | |||
41 | #endif | ||
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h new file mode 100644 index 000000000000..6dd76bb3dff1 --- /dev/null +++ b/drivers/media/video/pwc/pwc.h | |||
@@ -0,0 +1,272 @@ | |||
1 | /* (C) 1999-2003 Nemosoft Unv. | ||
2 | (C) 2004 Luc Saillard (luc@saillard.org) | ||
3 | |||
4 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
5 | driver and thus may have bugs that are not present in the original version. | ||
6 | Please send bug reports and support requests to <luc@saillard.org>. | ||
7 | The decompression routines have been implemented by reverse-engineering the | ||
8 | Nemosoft binary pwcx module. Caveat emptor. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2 of the License, or | ||
13 | (at your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | */ | ||
24 | |||
25 | #ifndef PWC_H | ||
26 | #define PWC_H | ||
27 | |||
28 | #include <linux/config.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/usb.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <linux/videodev.h> | ||
33 | #include <linux/wait.h> | ||
34 | #include <linux/smp_lock.h> | ||
35 | #include <asm/semaphore.h> | ||
36 | #include <asm/errno.h> | ||
37 | |||
38 | #include "pwc-uncompress.h" | ||
39 | #include "pwc-ioctl.h" | ||
40 | |||
41 | /* Defines and structures for the Philips webcam */ | ||
42 | /* Used for checking memory corruption/pointer validation */ | ||
43 | #define PWC_MAGIC 0x89DC10ABUL | ||
44 | #undef PWC_MAGIC | ||
45 | |||
46 | /* Turn some debugging options on/off */ | ||
47 | #define PWC_DEBUG 0 | ||
48 | |||
49 | /* Trace certain actions in the driver */ | ||
50 | #define TRACE_MODULE 0x0001 | ||
51 | #define TRACE_PROBE 0x0002 | ||
52 | #define TRACE_OPEN 0x0004 | ||
53 | #define TRACE_READ 0x0008 | ||
54 | #define TRACE_MEMORY 0x0010 | ||
55 | #define TRACE_FLOW 0x0020 | ||
56 | #define TRACE_SIZE 0x0040 | ||
57 | #define TRACE_PWCX 0x0080 | ||
58 | #define TRACE_SEQUENCE 0x1000 | ||
59 | |||
60 | #define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A) | ||
61 | #define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A) | ||
62 | #define Info(A...) printk(KERN_INFO PWC_NAME " " A) | ||
63 | #define Err(A...) printk(KERN_ERR PWC_NAME " " A) | ||
64 | |||
65 | |||
66 | /* Defines for ToUCam cameras */ | ||
67 | #define TOUCAM_HEADER_SIZE 8 | ||
68 | #define TOUCAM_TRAILER_SIZE 4 | ||
69 | |||
70 | #define FEATURE_MOTOR_PANTILT 0x0001 | ||
71 | |||
72 | /* Version block */ | ||
73 | #define PWC_MAJOR 9 | ||
74 | #define PWC_MINOR 0 | ||
75 | #define PWC_VERSION "9.0.2-unofficial" | ||
76 | #define PWC_NAME "pwc" | ||
77 | |||
78 | /* Turn certain features on/off */ | ||
79 | #define PWC_INT_PIPE 0 | ||
80 | |||
81 | /* Ignore errors in the first N frames, to allow for startup delays */ | ||
82 | #define FRAME_LOWMARK 5 | ||
83 | |||
84 | /* Size and number of buffers for the ISO pipe. */ | ||
85 | #define MAX_ISO_BUFS 2 | ||
86 | #define ISO_FRAMES_PER_DESC 10 | ||
87 | #define ISO_MAX_FRAME_SIZE 960 | ||
88 | #define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) | ||
89 | |||
90 | /* Frame buffers: contains compressed or uncompressed video data. */ | ||
91 | #define MAX_FRAMES 5 | ||
92 | /* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */ | ||
93 | #define PWC_FRAME_SIZE (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE) | ||
94 | |||
95 | /* Absolute maximum number of buffers available for mmap() */ | ||
96 | #define MAX_IMAGES 10 | ||
97 | |||
98 | /* The following structures were based on cpia.h. Why reinvent the wheel? :-) */ | ||
99 | struct pwc_iso_buf | ||
100 | { | ||
101 | void *data; | ||
102 | int length; | ||
103 | int read; | ||
104 | struct urb *urb; | ||
105 | }; | ||
106 | |||
107 | /* intermediate buffers with raw data from the USB cam */ | ||
108 | struct pwc_frame_buf | ||
109 | { | ||
110 | void *data; | ||
111 | volatile int filled; /* number of bytes filled */ | ||
112 | struct pwc_frame_buf *next; /* list */ | ||
113 | #if PWC_DEBUG | ||
114 | int sequence; /* Sequence number */ | ||
115 | #endif | ||
116 | }; | ||
117 | |||
118 | struct pwc_device | ||
119 | { | ||
120 | struct video_device *vdev; | ||
121 | #ifdef PWC_MAGIC | ||
122 | int magic; | ||
123 | #endif | ||
124 | /* Pointer to our usb_device */ | ||
125 | struct usb_device *udev; | ||
126 | |||
127 | int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ | ||
128 | int release; /* release number */ | ||
129 | int features; /* feature bits */ | ||
130 | char serial[30]; /* serial number (string) */ | ||
131 | int error_status; /* set when something goes wrong with the cam (unplugged, USB errors) */ | ||
132 | int usb_init; /* set when the cam has been initialized over USB */ | ||
133 | |||
134 | /*** Video data ***/ | ||
135 | int vopen; /* flag */ | ||
136 | int vendpoint; /* video isoc endpoint */ | ||
137 | int vcinterface; /* video control interface */ | ||
138 | int valternate; /* alternate interface needed */ | ||
139 | int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ | ||
140 | int vpalette; /* palette: 420P, RAW or RGBBAYER */ | ||
141 | int vframe_count; /* received frames */ | ||
142 | int vframes_dumped; /* counter for dumped frames */ | ||
143 | int vframes_error; /* frames received in error */ | ||
144 | int vmax_packet_size; /* USB maxpacket size */ | ||
145 | int vlast_packet_size; /* for frame synchronisation */ | ||
146 | int visoc_errors; /* number of contiguous ISOC errors */ | ||
147 | int vcompression; /* desired compression factor */ | ||
148 | int vbandlength; /* compressed band length; 0 is uncompressed */ | ||
149 | char vsnapshot; /* snapshot mode */ | ||
150 | char vsync; /* used by isoc handler */ | ||
151 | char vmirror; /* for ToUCaM series */ | ||
152 | |||
153 | int cmd_len; | ||
154 | unsigned char cmd_buf[13]; | ||
155 | |||
156 | /* The image acquisition requires 3 to 4 steps: | ||
157 | 1. data is gathered in short packets from the USB controller | ||
158 | 2. data is synchronized and packed into a frame buffer | ||
159 | 3a. in case data is compressed, decompress it directly into image buffer | ||
160 | 3b. in case data is uncompressed, copy into image buffer with viewport | ||
161 | 4. data is transferred to the user process | ||
162 | |||
163 | Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... | ||
164 | We have in effect a back-to-back-double-buffer system. | ||
165 | */ | ||
166 | /* 1: isoc */ | ||
167 | struct pwc_iso_buf sbuf[MAX_ISO_BUFS]; | ||
168 | char iso_init; | ||
169 | |||
170 | /* 2: frame */ | ||
171 | struct pwc_frame_buf *fbuf; /* all frames */ | ||
172 | struct pwc_frame_buf *empty_frames, *empty_frames_tail; /* all empty frames */ | ||
173 | struct pwc_frame_buf *full_frames, *full_frames_tail; /* all filled frames */ | ||
174 | struct pwc_frame_buf *fill_frame; /* frame currently being filled */ | ||
175 | struct pwc_frame_buf *read_frame; /* frame currently read by user process */ | ||
176 | int frame_header_size, frame_trailer_size; | ||
177 | int frame_size; | ||
178 | int frame_total_size; /* including header & trailer */ | ||
179 | int drop_frames; | ||
180 | #if PWC_DEBUG | ||
181 | int sequence; /* Debugging aid */ | ||
182 | #endif | ||
183 | |||
184 | /* 3: decompression */ | ||
185 | struct pwc_decompressor *decompressor; /* function block with decompression routines */ | ||
186 | void *decompress_data; /* private data for decompression engine */ | ||
187 | |||
188 | /* 4: image */ | ||
189 | /* We have an 'image' and a 'view', where 'image' is the fixed-size image | ||
190 | as delivered by the camera, and 'view' is the size requested by the | ||
191 | program. The camera image is centered in this viewport, laced with | ||
192 | a gray or black border. view_min <= image <= view <= view_max; | ||
193 | */ | ||
194 | int image_mask; /* bitmask of supported sizes */ | ||
195 | struct pwc_coord view_min, view_max; /* minimum and maximum viewable sizes */ | ||
196 | struct pwc_coord abs_max; /* maximum supported size with compression */ | ||
197 | struct pwc_coord image, view; /* image and viewport size */ | ||
198 | struct pwc_coord offset; /* offset within the viewport */ | ||
199 | |||
200 | void *image_data; /* total buffer, which is subdivided into ... */ | ||
201 | void *image_ptr[MAX_IMAGES]; /* ...several images... */ | ||
202 | int fill_image; /* ...which are rotated. */ | ||
203 | int len_per_image; /* length per image */ | ||
204 | int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */ | ||
205 | int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */ | ||
206 | |||
207 | struct semaphore modlock; /* to prevent races in video_open(), etc */ | ||
208 | spinlock_t ptrlock; /* for manipulating the buffer pointers */ | ||
209 | |||
210 | /*** motorized pan/tilt feature */ | ||
211 | struct pwc_mpt_range angle_range; | ||
212 | int pan_angle; /* in degrees * 100 */ | ||
213 | int tilt_angle; /* absolute angle; 0,0 is home position */ | ||
214 | |||
215 | /*** Misc. data ***/ | ||
216 | wait_queue_head_t frameq; /* When waiting for a frame to finish... */ | ||
217 | #if PWC_INT_PIPE | ||
218 | void *usb_int_handler; /* for the interrupt endpoint */ | ||
219 | #endif | ||
220 | }; | ||
221 | |||
222 | |||
223 | #ifdef __cplusplus | ||
224 | extern "C" { | ||
225 | #endif | ||
226 | |||
227 | /* Global variable */ | ||
228 | extern int pwc_trace; | ||
229 | |||
230 | /** functions in pwc-if.c */ | ||
231 | int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot); | ||
232 | |||
233 | /** Functions in pwc-misc.c */ | ||
234 | /* sizes in pixels */ | ||
235 | extern struct pwc_coord pwc_image_sizes[PSZ_MAX]; | ||
236 | |||
237 | int pwc_decode_size(struct pwc_device *pdev, int width, int height); | ||
238 | void pwc_construct(struct pwc_device *pdev); | ||
239 | |||
240 | /** Functions in pwc-ctrl.c */ | ||
241 | /* Request a certain video mode. Returns < 0 if not possible */ | ||
242 | extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); | ||
243 | |||
244 | /* Various controls; should be obvious. Value 0..65535, or < 0 on error */ | ||
245 | extern int pwc_get_brightness(struct pwc_device *pdev); | ||
246 | extern int pwc_set_brightness(struct pwc_device *pdev, int value); | ||
247 | extern int pwc_get_contrast(struct pwc_device *pdev); | ||
248 | extern int pwc_set_contrast(struct pwc_device *pdev, int value); | ||
249 | extern int pwc_get_gamma(struct pwc_device *pdev); | ||
250 | extern int pwc_set_gamma(struct pwc_device *pdev, int value); | ||
251 | extern int pwc_get_saturation(struct pwc_device *pdev); | ||
252 | extern int pwc_set_saturation(struct pwc_device *pdev, int value); | ||
253 | extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); | ||
254 | extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); | ||
255 | |||
256 | /* Power down or up the camera; not supported by all models */ | ||
257 | extern int pwc_camera_power(struct pwc_device *pdev, int power); | ||
258 | |||
259 | /* Private ioctl()s; see pwc-ioctl.h */ | ||
260 | extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); | ||
261 | |||
262 | |||
263 | /** pwc-uncompress.c */ | ||
264 | /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ | ||
265 | extern int pwc_decompress(struct pwc_device *pdev); | ||
266 | |||
267 | #ifdef __cplusplus | ||
268 | } | ||
269 | #endif | ||
270 | |||
271 | |||
272 | #endif | ||
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c new file mode 100644 index 000000000000..f03ea7f89596 --- /dev/null +++ b/drivers/media/video/se401.c | |||
@@ -0,0 +1,1435 @@ | |||
1 | /* | ||
2 | * Endpoints (formerly known as AOX) se401 USB Camera Driver | ||
3 | * | ||
4 | * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org) | ||
5 | * | ||
6 | * Still somewhat based on the Linux ov511 driver. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
16 | * for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software Foundation, | ||
20 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | * | ||
23 | * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on | ||
24 | * their chipset available and supporting me while writing this driver. | ||
25 | * - Jeroen Vreeken | ||
26 | */ | ||
27 | |||
28 | static const char version[] = "0.24"; | ||
29 | |||
30 | #include <linux/config.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/vmalloc.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/pagemap.h> | ||
36 | #include <linux/usb.h> | ||
37 | #include "se401.h" | ||
38 | |||
39 | static int flickerless=0; | ||
40 | static int video_nr = -1; | ||
41 | |||
42 | static struct usb_device_id device_table [] = { | ||
43 | { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */ | ||
44 | { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */ | ||
45 | { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */ | ||
46 | { USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */ | ||
47 | { USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */ | ||
48 | { } | ||
49 | }; | ||
50 | |||
51 | MODULE_DEVICE_TABLE(usb, device_table); | ||
52 | |||
53 | MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>"); | ||
54 | MODULE_DESCRIPTION("SE401 USB Camera Driver"); | ||
55 | MODULE_LICENSE("GPL"); | ||
56 | module_param(flickerless, int, 0); | ||
57 | MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)"); | ||
58 | module_param(video_nr, int, 0); | ||
59 | |||
60 | static struct usb_driver se401_driver; | ||
61 | |||
62 | |||
63 | /********************************************************************** | ||
64 | * | ||
65 | * Memory management | ||
66 | * | ||
67 | **********************************************************************/ | ||
68 | static void *rvmalloc(unsigned long size) | ||
69 | { | ||
70 | void *mem; | ||
71 | unsigned long adr; | ||
72 | |||
73 | size = PAGE_ALIGN(size); | ||
74 | mem = vmalloc_32(size); | ||
75 | if (!mem) | ||
76 | return NULL; | ||
77 | |||
78 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
79 | adr = (unsigned long) mem; | ||
80 | while (size > 0) { | ||
81 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
82 | adr += PAGE_SIZE; | ||
83 | size -= PAGE_SIZE; | ||
84 | } | ||
85 | |||
86 | return mem; | ||
87 | } | ||
88 | |||
89 | static void rvfree(void *mem, unsigned long size) | ||
90 | { | ||
91 | unsigned long adr; | ||
92 | |||
93 | if (!mem) | ||
94 | return; | ||
95 | |||
96 | adr = (unsigned long) mem; | ||
97 | while ((long) size > 0) { | ||
98 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
99 | adr += PAGE_SIZE; | ||
100 | size -= PAGE_SIZE; | ||
101 | } | ||
102 | vfree(mem); | ||
103 | } | ||
104 | |||
105 | |||
106 | |||
107 | /**************************************************************************** | ||
108 | * | ||
109 | * se401 register read/write functions | ||
110 | * | ||
111 | ***************************************************************************/ | ||
112 | |||
113 | static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req, | ||
114 | unsigned short value, unsigned char *cp, int size) | ||
115 | { | ||
116 | return usb_control_msg ( | ||
117 | se401->dev, | ||
118 | set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0), | ||
119 | req, | ||
120 | (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
121 | value, | ||
122 | 0, | ||
123 | cp, | ||
124 | size, | ||
125 | 1000 | ||
126 | ); | ||
127 | } | ||
128 | |||
129 | static int se401_set_feature(struct usb_se401 *se401, unsigned short selector, | ||
130 | unsigned short param) | ||
131 | { | ||
132 | /* specs say that the selector (address) should go in the value field | ||
133 | and the param in index, but in the logs of the windows driver they do | ||
134 | this the other way around... | ||
135 | */ | ||
136 | return usb_control_msg ( | ||
137 | se401->dev, | ||
138 | usb_sndctrlpipe(se401->dev, 0), | ||
139 | SE401_REQ_SET_EXT_FEATURE, | ||
140 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
141 | param, | ||
142 | selector, | ||
143 | NULL, | ||
144 | 0, | ||
145 | 1000 | ||
146 | ); | ||
147 | } | ||
148 | |||
149 | static unsigned short se401_get_feature(struct usb_se401 *se401, | ||
150 | unsigned short selector) | ||
151 | { | ||
152 | /* For 'set' the selecetor should be in index, not sure if the spec is | ||
153 | wrong here to.... | ||
154 | */ | ||
155 | unsigned char cp[2]; | ||
156 | usb_control_msg ( | ||
157 | se401->dev, | ||
158 | usb_rcvctrlpipe(se401->dev, 0), | ||
159 | SE401_REQ_GET_EXT_FEATURE, | ||
160 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
161 | 0, | ||
162 | selector, | ||
163 | cp, | ||
164 | 2, | ||
165 | 1000 | ||
166 | ); | ||
167 | return cp[0]+cp[1]*256; | ||
168 | } | ||
169 | |||
170 | /**************************************************************************** | ||
171 | * | ||
172 | * Camera control | ||
173 | * | ||
174 | ***************************************************************************/ | ||
175 | |||
176 | |||
177 | static int se401_send_pict(struct usb_se401 *se401) | ||
178 | { | ||
179 | se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */ | ||
180 | se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */ | ||
181 | se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */ | ||
182 | se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */ | ||
183 | se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */ | ||
184 | se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */ | ||
185 | se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */ | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static void se401_set_exposure(struct usb_se401 *se401, int brightness) | ||
191 | { | ||
192 | int integration=brightness<<5; | ||
193 | |||
194 | if (flickerless==50) { | ||
195 | integration=integration-integration%106667; | ||
196 | } | ||
197 | if (flickerless==60) { | ||
198 | integration=integration-integration%88889; | ||
199 | } | ||
200 | se401->brightness=integration>>5; | ||
201 | se401->expose_h=(integration>>16)&0xff; | ||
202 | se401->expose_m=(integration>>8)&0xff; | ||
203 | se401->expose_l=integration&0xff; | ||
204 | } | ||
205 | |||
206 | static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p) | ||
207 | { | ||
208 | p->brightness=se401->brightness; | ||
209 | if (se401->enhance) { | ||
210 | p->whiteness=32768; | ||
211 | } else { | ||
212 | p->whiteness=0; | ||
213 | } | ||
214 | p->colour=65535; | ||
215 | p->contrast=65535; | ||
216 | p->hue=se401->rgain<<10; | ||
217 | p->palette=se401->palette; | ||
218 | p->depth=3; /* rgb24 */ | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | |||
223 | static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p) | ||
224 | { | ||
225 | if (p->palette != VIDEO_PALETTE_RGB24) | ||
226 | return 1; | ||
227 | se401->palette=p->palette; | ||
228 | if (p->hue!=se401->hue) { | ||
229 | se401->rgain= p->hue>>10; | ||
230 | se401->bgain= 0x40-(p->hue>>10); | ||
231 | se401->hue=p->hue; | ||
232 | } | ||
233 | if (p->brightness!=se401->brightness) { | ||
234 | se401_set_exposure(se401, p->brightness); | ||
235 | } | ||
236 | if (p->whiteness>=32768) { | ||
237 | se401->enhance=1; | ||
238 | } else { | ||
239 | se401->enhance=0; | ||
240 | } | ||
241 | se401_send_pict(se401); | ||
242 | se401_send_pict(se401); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | Hyundai have some really nice docs about this and other sensor related | ||
248 | stuff on their homepage: www.hei.co.kr | ||
249 | */ | ||
250 | static void se401_auto_resetlevel(struct usb_se401 *se401) | ||
251 | { | ||
252 | unsigned int ahrc, alrc; | ||
253 | int oldreset=se401->resetlevel; | ||
254 | |||
255 | /* For some reason this normally read-only register doesn't get reset | ||
256 | to zero after reading them just once... | ||
257 | */ | ||
258 | se401_get_feature(se401, HV7131_REG_HIREFNOH); | ||
259 | se401_get_feature(se401, HV7131_REG_HIREFNOL); | ||
260 | se401_get_feature(se401, HV7131_REG_LOREFNOH); | ||
261 | se401_get_feature(se401, HV7131_REG_LOREFNOL); | ||
262 | ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) + | ||
263 | se401_get_feature(se401, HV7131_REG_HIREFNOL); | ||
264 | alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) + | ||
265 | se401_get_feature(se401, HV7131_REG_LOREFNOL); | ||
266 | |||
267 | /* Not an exact science, but it seems to work pretty well... */ | ||
268 | if (alrc > 10) { | ||
269 | while (alrc>=10 && se401->resetlevel < 63) { | ||
270 | se401->resetlevel++; | ||
271 | alrc /=2; | ||
272 | } | ||
273 | } else if (ahrc > 20) { | ||
274 | while (ahrc>=20 && se401->resetlevel > 0) { | ||
275 | se401->resetlevel--; | ||
276 | ahrc /=2; | ||
277 | } | ||
278 | } | ||
279 | if (se401->resetlevel!=oldreset) | ||
280 | se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel); | ||
281 | |||
282 | return; | ||
283 | } | ||
284 | |||
285 | /* irq handler for snapshot button */ | ||
286 | static void se401_button_irq(struct urb *urb, struct pt_regs *regs) | ||
287 | { | ||
288 | struct usb_se401 *se401 = urb->context; | ||
289 | int status; | ||
290 | |||
291 | if (!se401->dev) { | ||
292 | info("ohoh: device vapourished"); | ||
293 | return; | ||
294 | } | ||
295 | |||
296 | switch (urb->status) { | ||
297 | case 0: | ||
298 | /* success */ | ||
299 | break; | ||
300 | case -ECONNRESET: | ||
301 | case -ENOENT: | ||
302 | case -ESHUTDOWN: | ||
303 | /* this urb is terminated, clean up */ | ||
304 | dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); | ||
305 | return; | ||
306 | default: | ||
307 | dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); | ||
308 | goto exit; | ||
309 | } | ||
310 | |||
311 | if (urb->actual_length >=2) { | ||
312 | if (se401->button) | ||
313 | se401->buttonpressed=1; | ||
314 | } | ||
315 | exit: | ||
316 | status = usb_submit_urb (urb, GFP_ATOMIC); | ||
317 | if (status) | ||
318 | err ("%s - usb_submit_urb failed with result %d", | ||
319 | __FUNCTION__, status); | ||
320 | } | ||
321 | |||
322 | static void se401_video_irq(struct urb *urb, struct pt_regs *regs) | ||
323 | { | ||
324 | struct usb_se401 *se401 = urb->context; | ||
325 | int length = urb->actual_length; | ||
326 | |||
327 | /* ohoh... */ | ||
328 | if (!se401->streaming) | ||
329 | return; | ||
330 | |||
331 | if (!se401->dev) { | ||
332 | info ("ohoh: device vapourished"); | ||
333 | return; | ||
334 | } | ||
335 | |||
336 | /* 0 sized packets happen if we are to fast, but sometimes the camera | ||
337 | keeps sending them forever... | ||
338 | */ | ||
339 | if (length && !urb->status) { | ||
340 | se401->nullpackets=0; | ||
341 | switch(se401->scratch[se401->scratch_next].state) { | ||
342 | case BUFFER_READY: | ||
343 | case BUFFER_BUSY: { | ||
344 | se401->dropped++; | ||
345 | break; | ||
346 | } | ||
347 | case BUFFER_UNUSED: { | ||
348 | memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length); | ||
349 | se401->scratch[se401->scratch_next].state=BUFFER_READY; | ||
350 | se401->scratch[se401->scratch_next].offset=se401->bayeroffset; | ||
351 | se401->scratch[se401->scratch_next].length=length; | ||
352 | if (waitqueue_active(&se401->wq)) { | ||
353 | wake_up_interruptible(&se401->wq); | ||
354 | } | ||
355 | se401->scratch_overflow=0; | ||
356 | se401->scratch_next++; | ||
357 | if (se401->scratch_next>=SE401_NUMSCRATCH) | ||
358 | se401->scratch_next=0; | ||
359 | break; | ||
360 | } | ||
361 | } | ||
362 | se401->bayeroffset+=length; | ||
363 | if (se401->bayeroffset>=se401->cheight*se401->cwidth) { | ||
364 | se401->bayeroffset=0; | ||
365 | } | ||
366 | } else { | ||
367 | se401->nullpackets++; | ||
368 | if (se401->nullpackets > SE401_MAX_NULLPACKETS) { | ||
369 | if (waitqueue_active(&se401->wq)) { | ||
370 | wake_up_interruptible(&se401->wq); | ||
371 | } | ||
372 | } | ||
373 | } | ||
374 | |||
375 | /* Resubmit urb for new data */ | ||
376 | urb->status=0; | ||
377 | urb->dev=se401->dev; | ||
378 | if(usb_submit_urb(urb, GFP_KERNEL)) | ||
379 | info("urb burned down"); | ||
380 | return; | ||
381 | } | ||
382 | |||
383 | static void se401_send_size(struct usb_se401 *se401, int width, int height) | ||
384 | { | ||
385 | int i=0; | ||
386 | int mode=0x03; /* No compression */ | ||
387 | int sendheight=height; | ||
388 | int sendwidth=width; | ||
389 | |||
390 | /* JangGu compression can only be used with the camera supported sizes, | ||
391 | but bayer seems to work with any size that fits on the sensor. | ||
392 | We check if we can use compression with the current size with either | ||
393 | 4 or 16 times subcapturing, if not we use uncompressed bayer data | ||
394 | but this will result in cutouts of the maximum size.... | ||
395 | */ | ||
396 | while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height)) | ||
397 | i++; | ||
398 | while (i<se401->sizes) { | ||
399 | if (se401->width[i]==width*2 && se401->height[i]==height*2) { | ||
400 | sendheight=se401->height[i]; | ||
401 | sendwidth=se401->width[i]; | ||
402 | mode=0x40; | ||
403 | } | ||
404 | if (se401->width[i]==width*4 && se401->height[i]==height*4) { | ||
405 | sendheight=se401->height[i]; | ||
406 | sendwidth=se401->width[i]; | ||
407 | mode=0x42; | ||
408 | } | ||
409 | i++; | ||
410 | } | ||
411 | |||
412 | se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0); | ||
413 | se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0); | ||
414 | se401_set_feature(se401, SE401_OPERATINGMODE, mode); | ||
415 | |||
416 | if (mode==0x03) { | ||
417 | se401->format=FMT_BAYER; | ||
418 | } else { | ||
419 | se401->format=FMT_JANGGU; | ||
420 | } | ||
421 | |||
422 | return; | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | In this function se401_send_pict is called several times, | ||
427 | for some reason (depending on the state of the sensor and the phase of | ||
428 | the moon :) doing this only in either place doesn't always work... | ||
429 | */ | ||
430 | static int se401_start_stream(struct usb_se401 *se401) | ||
431 | { | ||
432 | struct urb *urb; | ||
433 | int err=0, i; | ||
434 | se401->streaming=1; | ||
435 | |||
436 | se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0); | ||
437 | se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); | ||
438 | |||
439 | /* Set picture settings */ | ||
440 | se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */ | ||
441 | se401_send_pict(se401); | ||
442 | |||
443 | se401_send_size(se401, se401->cwidth, se401->cheight); | ||
444 | |||
445 | se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0); | ||
446 | |||
447 | /* Do some memory allocation */ | ||
448 | for (i=0; i<SE401_NUMFRAMES; i++) { | ||
449 | se401->frame[i].data=se401->fbuf + i * se401->maxframesize; | ||
450 | se401->frame[i].curpix=0; | ||
451 | } | ||
452 | for (i=0; i<SE401_NUMSBUF; i++) { | ||
453 | se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); | ||
454 | } | ||
455 | |||
456 | se401->bayeroffset=0; | ||
457 | se401->scratch_next=0; | ||
458 | se401->scratch_use=0; | ||
459 | se401->scratch_overflow=0; | ||
460 | for (i=0; i<SE401_NUMSCRATCH; i++) { | ||
461 | se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); | ||
462 | se401->scratch[i].state=BUFFER_UNUSED; | ||
463 | } | ||
464 | |||
465 | for (i=0; i<SE401_NUMSBUF; i++) { | ||
466 | urb=usb_alloc_urb(0, GFP_KERNEL); | ||
467 | if(!urb) | ||
468 | return -ENOMEM; | ||
469 | |||
470 | usb_fill_bulk_urb(urb, se401->dev, | ||
471 | usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT), | ||
472 | se401->sbuf[i].data, SE401_PACKETSIZE, | ||
473 | se401_video_irq, | ||
474 | se401); | ||
475 | |||
476 | se401->urb[i]=urb; | ||
477 | |||
478 | err=usb_submit_urb(se401->urb[i], GFP_KERNEL); | ||
479 | if(err) | ||
480 | err("urb burned down"); | ||
481 | } | ||
482 | |||
483 | se401->framecount=0; | ||
484 | |||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static int se401_stop_stream(struct usb_se401 *se401) | ||
489 | { | ||
490 | int i; | ||
491 | |||
492 | if (!se401->streaming || !se401->dev) | ||
493 | return 1; | ||
494 | |||
495 | se401->streaming=0; | ||
496 | |||
497 | se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0); | ||
498 | |||
499 | se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0); | ||
500 | se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0); | ||
501 | |||
502 | for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) { | ||
503 | usb_kill_urb(se401->urb[i]); | ||
504 | usb_free_urb(se401->urb[i]); | ||
505 | se401->urb[i]=NULL; | ||
506 | kfree(se401->sbuf[i].data); | ||
507 | } | ||
508 | for (i=0; i<SE401_NUMSCRATCH; i++) { | ||
509 | kfree(se401->scratch[i].data); | ||
510 | se401->scratch[i].data=NULL; | ||
511 | } | ||
512 | |||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static int se401_set_size(struct usb_se401 *se401, int width, int height) | ||
517 | { | ||
518 | int wasstreaming=se401->streaming; | ||
519 | /* Check to see if we need to change */ | ||
520 | if (se401->cwidth==width && se401->cheight==height) | ||
521 | return 0; | ||
522 | |||
523 | /* Check for a valid mode */ | ||
524 | if (!width || !height) | ||
525 | return 1; | ||
526 | if ((width & 1) || (height & 1)) | ||
527 | return 1; | ||
528 | if (width>se401->width[se401->sizes-1]) | ||
529 | return 1; | ||
530 | if (height>se401->height[se401->sizes-1]) | ||
531 | return 1; | ||
532 | |||
533 | /* Stop a current stream and start it again at the new size */ | ||
534 | if (wasstreaming) | ||
535 | se401_stop_stream(se401); | ||
536 | se401->cwidth=width; | ||
537 | se401->cheight=height; | ||
538 | if (wasstreaming) | ||
539 | se401_start_stream(se401); | ||
540 | return 0; | ||
541 | } | ||
542 | |||
543 | |||
544 | /**************************************************************************** | ||
545 | * | ||
546 | * Video Decoding | ||
547 | * | ||
548 | ***************************************************************************/ | ||
549 | |||
550 | /* | ||
551 | This shouldn't really be done in a v4l driver.... | ||
552 | But it does make the image look a lot more usable. | ||
553 | Basically it lifts the dark pixels more than the light pixels. | ||
554 | */ | ||
555 | static inline void enhance_picture(unsigned char *frame, int len) | ||
556 | { | ||
557 | while (len--) { | ||
558 | *frame=(((*frame^255)*(*frame^255))/255)^255; | ||
559 | frame++; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data) | ||
564 | { | ||
565 | struct se401_frame *frame=&se401->frame[se401->curframe]; | ||
566 | int linelength=se401->cwidth*3; | ||
567 | |||
568 | if (frame->curlinepix >= linelength) { | ||
569 | frame->curlinepix=0; | ||
570 | frame->curline+=linelength; | ||
571 | } | ||
572 | |||
573 | /* First three are absolute, all others relative. | ||
574 | * Format is rgb from right to left (mirrorred image), | ||
575 | * we flip it to get bgr from left to right. */ | ||
576 | if (frame->curlinepix < 3) { | ||
577 | *(frame->curline-frame->curlinepix)=1+data*4; | ||
578 | } else { | ||
579 | *(frame->curline-frame->curlinepix)= | ||
580 | *(frame->curline-frame->curlinepix+3)+data*4; | ||
581 | } | ||
582 | frame->curlinepix++; | ||
583 | } | ||
584 | |||
585 | static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength) | ||
586 | { | ||
587 | int pos=0; | ||
588 | int vlc_cod=0; | ||
589 | int vlc_size=0; | ||
590 | int vlc_data=0; | ||
591 | int bit_cur; | ||
592 | int bit; | ||
593 | data+=4; | ||
594 | while (pos < packetlength) { | ||
595 | bit_cur=8; | ||
596 | while (bit_cur && bit_exp) { | ||
597 | bit=((*data)>>(bit_cur-1))&1; | ||
598 | if (!vlc_cod) { | ||
599 | if (bit) { | ||
600 | vlc_size++; | ||
601 | } else { | ||
602 | if (!vlc_size) { | ||
603 | decode_JangGu_integrate(se401, 0); | ||
604 | } else { | ||
605 | vlc_cod=2; | ||
606 | vlc_data=0; | ||
607 | } | ||
608 | } | ||
609 | } else { | ||
610 | if (vlc_cod==2) { | ||
611 | if (!bit) | ||
612 | vlc_data = -(1<<vlc_size) + 1; | ||
613 | vlc_cod--; | ||
614 | } | ||
615 | vlc_size--; | ||
616 | vlc_data+=bit<<vlc_size; | ||
617 | if (!vlc_size) { | ||
618 | decode_JangGu_integrate(se401, vlc_data); | ||
619 | vlc_cod=0; | ||
620 | } | ||
621 | } | ||
622 | bit_cur--; | ||
623 | bit_exp--; | ||
624 | } | ||
625 | pos++; | ||
626 | data++; | ||
627 | } | ||
628 | } | ||
629 | |||
630 | static inline void decode_JangGu (struct usb_se401 *se401, struct se401_scratch *buffer) | ||
631 | { | ||
632 | unsigned char *data=buffer->data; | ||
633 | int len=buffer->length; | ||
634 | int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size; | ||
635 | int datapos=0; | ||
636 | |||
637 | /* New image? */ | ||
638 | if (!se401->frame[se401->curframe].curpix) { | ||
639 | se401->frame[se401->curframe].curlinepix=0; | ||
640 | se401->frame[se401->curframe].curline= | ||
641 | se401->frame[se401->curframe].data+ | ||
642 | se401->cwidth*3-1; | ||
643 | if (se401->frame[se401->curframe].grabstate==FRAME_READY) | ||
644 | se401->frame[se401->curframe].grabstate=FRAME_GRABBING; | ||
645 | se401->vlcdatapos=0; | ||
646 | } | ||
647 | while (datapos < len) { | ||
648 | size=1024-se401->vlcdatapos; | ||
649 | if (size+datapos > len) | ||
650 | size=len-datapos; | ||
651 | memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size); | ||
652 | se401->vlcdatapos+=size; | ||
653 | packetlength=0; | ||
654 | if (se401->vlcdatapos >= 4) { | ||
655 | bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8); | ||
656 | pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8); | ||
657 | frameinfo=se401->vlcdata[0]&0xc0; | ||
658 | packetlength=((bit_exp+47)>>4)<<1; | ||
659 | if (packetlength > 1024) { | ||
660 | se401->vlcdatapos=0; | ||
661 | datapos=len; | ||
662 | packetlength=0; | ||
663 | se401->error++; | ||
664 | se401->frame[se401->curframe].curpix=0; | ||
665 | } | ||
666 | } | ||
667 | if (packetlength && se401->vlcdatapos >= packetlength) { | ||
668 | decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength); | ||
669 | se401->frame[se401->curframe].curpix+=pix_exp*3; | ||
670 | datapos+=size-(se401->vlcdatapos-packetlength); | ||
671 | se401->vlcdatapos=0; | ||
672 | if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) { | ||
673 | if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) { | ||
674 | if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) { | ||
675 | se401->frame[se401->curframe].grabstate=FRAME_DONE; | ||
676 | se401->framecount++; | ||
677 | se401->readcount++; | ||
678 | } | ||
679 | if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) { | ||
680 | se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1); | ||
681 | } | ||
682 | } else { | ||
683 | se401->error++; | ||
684 | } | ||
685 | se401->frame[se401->curframe].curpix=0; | ||
686 | datapos=len; | ||
687 | } | ||
688 | } else { | ||
689 | datapos+=size; | ||
690 | } | ||
691 | } | ||
692 | } | ||
693 | |||
694 | static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer) | ||
695 | { | ||
696 | unsigned char *data=buffer->data; | ||
697 | int len=buffer->length; | ||
698 | int offset=buffer->offset; | ||
699 | int datasize=se401->cwidth*se401->cheight; | ||
700 | struct se401_frame *frame=&se401->frame[se401->curframe]; | ||
701 | |||
702 | unsigned char *framedata=frame->data, *curline, *nextline; | ||
703 | int width=se401->cwidth; | ||
704 | int blineoffset=0, bline; | ||
705 | int linelength=width*3, i; | ||
706 | |||
707 | |||
708 | if (frame->curpix==0) { | ||
709 | if (frame->grabstate==FRAME_READY) { | ||
710 | frame->grabstate=FRAME_GRABBING; | ||
711 | } | ||
712 | frame->curline=framedata+linelength; | ||
713 | frame->curlinepix=0; | ||
714 | } | ||
715 | |||
716 | if (offset!=frame->curpix) { | ||
717 | /* Regard frame as lost :( */ | ||
718 | frame->curpix=0; | ||
719 | se401->error++; | ||
720 | return; | ||
721 | } | ||
722 | |||
723 | /* Check if we have to much data */ | ||
724 | if (frame->curpix+len > datasize) { | ||
725 | len=datasize-frame->curpix; | ||
726 | } | ||
727 | if (se401->cheight%4) | ||
728 | blineoffset=1; | ||
729 | bline=frame->curpix/se401->cwidth+blineoffset; | ||
730 | |||
731 | curline=frame->curline; | ||
732 | nextline=curline+linelength; | ||
733 | if (nextline >= framedata+datasize*3) | ||
734 | nextline=curline; | ||
735 | while (len) { | ||
736 | if (frame->curlinepix>=width) { | ||
737 | frame->curlinepix-=width; | ||
738 | bline=frame->curpix/width+blineoffset; | ||
739 | curline+=linelength*2; | ||
740 | nextline+=linelength*2; | ||
741 | if (curline >= framedata+datasize*3) { | ||
742 | frame->curlinepix++; | ||
743 | curline-=3; | ||
744 | nextline-=3; | ||
745 | len--; | ||
746 | data++; | ||
747 | frame->curpix++; | ||
748 | } | ||
749 | if (nextline >= framedata+datasize*3) | ||
750 | nextline=curline; | ||
751 | } | ||
752 | if ((bline&1)) { | ||
753 | if ((frame->curlinepix&1)) { | ||
754 | *(curline+2)=*data; | ||
755 | *(curline-1)=*data; | ||
756 | *(nextline+2)=*data; | ||
757 | *(nextline-1)=*data; | ||
758 | } else { | ||
759 | *(curline+1)= | ||
760 | (*(curline+1)+*data)/2; | ||
761 | *(curline-2)= | ||
762 | (*(curline-2)+*data)/2; | ||
763 | *(nextline+1)=*data; | ||
764 | *(nextline-2)=*data; | ||
765 | } | ||
766 | } else { | ||
767 | if ((frame->curlinepix&1)) { | ||
768 | *(curline+1)= | ||
769 | (*(curline+1)+*data)/2; | ||
770 | *(curline-2)= | ||
771 | (*(curline-2)+*data)/2; | ||
772 | *(nextline+1)=*data; | ||
773 | *(nextline-2)=*data; | ||
774 | } else { | ||
775 | *curline=*data; | ||
776 | *(curline-3)=*data; | ||
777 | *nextline=*data; | ||
778 | *(nextline-3)=*data; | ||
779 | } | ||
780 | } | ||
781 | frame->curlinepix++; | ||
782 | curline-=3; | ||
783 | nextline-=3; | ||
784 | len--; | ||
785 | data++; | ||
786 | frame->curpix++; | ||
787 | } | ||
788 | frame->curline=curline; | ||
789 | |||
790 | if (frame->curpix>=datasize) { | ||
791 | /* Fix the top line */ | ||
792 | framedata+=linelength; | ||
793 | for (i=0; i<linelength; i++) { | ||
794 | framedata--; | ||
795 | *framedata=*(framedata+linelength); | ||
796 | } | ||
797 | /* Fix the left side (green is already present) */ | ||
798 | for (i=0; i<se401->cheight; i++) { | ||
799 | *framedata=*(framedata+3); | ||
800 | *(framedata+1)=*(framedata+4); | ||
801 | *(framedata+2)=*(framedata+5); | ||
802 | framedata+=linelength; | ||
803 | } | ||
804 | frame->curpix=0; | ||
805 | frame->grabstate=FRAME_DONE; | ||
806 | se401->framecount++; | ||
807 | se401->readcount++; | ||
808 | if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) { | ||
809 | se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1); | ||
810 | } | ||
811 | } | ||
812 | } | ||
813 | |||
814 | static int se401_newframe(struct usb_se401 *se401, int framenr) | ||
815 | { | ||
816 | DECLARE_WAITQUEUE(wait, current); | ||
817 | int errors=0; | ||
818 | |||
819 | while (se401->streaming && | ||
820 | (se401->frame[framenr].grabstate==FRAME_READY || | ||
821 | se401->frame[framenr].grabstate==FRAME_GRABBING) ) { | ||
822 | if(!se401->frame[framenr].curpix) { | ||
823 | errors++; | ||
824 | } | ||
825 | wait_interruptible( | ||
826 | se401->scratch[se401->scratch_use].state!=BUFFER_READY, | ||
827 | &se401->wq, | ||
828 | &wait | ||
829 | ); | ||
830 | if (se401->nullpackets > SE401_MAX_NULLPACKETS) { | ||
831 | se401->nullpackets=0; | ||
832 | info("to many null length packets, restarting capture"); | ||
833 | se401_stop_stream(se401); | ||
834 | se401_start_stream(se401); | ||
835 | } else { | ||
836 | if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) { | ||
837 | se401->frame[framenr].grabstate=FRAME_ERROR; | ||
838 | return -EIO; | ||
839 | } | ||
840 | se401->scratch[se401->scratch_use].state=BUFFER_BUSY; | ||
841 | if (se401->format==FMT_JANGGU) { | ||
842 | decode_JangGu(se401, &se401->scratch[se401->scratch_use]); | ||
843 | } else { | ||
844 | decode_bayer(se401, &se401->scratch[se401->scratch_use]); | ||
845 | } | ||
846 | se401->scratch[se401->scratch_use].state=BUFFER_UNUSED; | ||
847 | se401->scratch_use++; | ||
848 | if (se401->scratch_use>=SE401_NUMSCRATCH) | ||
849 | se401->scratch_use=0; | ||
850 | if (errors > SE401_MAX_ERRORS) { | ||
851 | errors=0; | ||
852 | info("to much errors, restarting capture"); | ||
853 | se401_stop_stream(se401); | ||
854 | se401_start_stream(se401); | ||
855 | } | ||
856 | } | ||
857 | } | ||
858 | |||
859 | if (se401->frame[framenr].grabstate==FRAME_DONE) | ||
860 | if (se401->enhance) | ||
861 | enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3); | ||
862 | return 0; | ||
863 | } | ||
864 | |||
865 | static void usb_se401_remove_disconnected (struct usb_se401 *se401) | ||
866 | { | ||
867 | int i; | ||
868 | |||
869 | se401->dev = NULL; | ||
870 | |||
871 | for (i=0; i<SE401_NUMSBUF; i++) | ||
872 | if (se401->urb[i]) { | ||
873 | usb_kill_urb(se401->urb[i]); | ||
874 | usb_free_urb(se401->urb[i]); | ||
875 | se401->urb[i] = NULL; | ||
876 | kfree(se401->sbuf[i].data); | ||
877 | } | ||
878 | for (i=0; i<SE401_NUMSCRATCH; i++) { | ||
879 | kfree(se401->scratch[i].data); | ||
880 | } | ||
881 | if (se401->inturb) { | ||
882 | usb_kill_urb(se401->inturb); | ||
883 | usb_free_urb(se401->inturb); | ||
884 | } | ||
885 | info("%s disconnected", se401->camera_name); | ||
886 | |||
887 | /* Free the memory */ | ||
888 | kfree(se401->width); | ||
889 | kfree(se401->height); | ||
890 | kfree(se401); | ||
891 | } | ||
892 | |||
893 | |||
894 | |||
895 | /**************************************************************************** | ||
896 | * | ||
897 | * Video4Linux | ||
898 | * | ||
899 | ***************************************************************************/ | ||
900 | |||
901 | |||
902 | static int se401_open(struct inode *inode, struct file *file) | ||
903 | { | ||
904 | struct video_device *dev = video_devdata(file); | ||
905 | struct usb_se401 *se401 = (struct usb_se401 *)dev; | ||
906 | int err = 0; | ||
907 | |||
908 | if (se401->user) | ||
909 | return -EBUSY; | ||
910 | se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES); | ||
911 | if (se401->fbuf) | ||
912 | file->private_data = dev; | ||
913 | else | ||
914 | err = -ENOMEM; | ||
915 | se401->user = !err; | ||
916 | |||
917 | return err; | ||
918 | } | ||
919 | |||
920 | static int se401_close(struct inode *inode, struct file *file) | ||
921 | { | ||
922 | struct video_device *dev = file->private_data; | ||
923 | struct usb_se401 *se401 = (struct usb_se401 *)dev; | ||
924 | int i; | ||
925 | |||
926 | rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES); | ||
927 | if (se401->removed) { | ||
928 | usb_se401_remove_disconnected(se401); | ||
929 | info("device unregistered"); | ||
930 | } else { | ||
931 | for (i=0; i<SE401_NUMFRAMES; i++) | ||
932 | se401->frame[i].grabstate=FRAME_UNUSED; | ||
933 | if (se401->streaming) | ||
934 | se401_stop_stream(se401); | ||
935 | se401->user=0; | ||
936 | } | ||
937 | file->private_data = NULL; | ||
938 | return 0; | ||
939 | } | ||
940 | |||
941 | static int se401_do_ioctl(struct inode *inode, struct file *file, | ||
942 | unsigned int cmd, void *arg) | ||
943 | { | ||
944 | struct video_device *vdev = file->private_data; | ||
945 | struct usb_se401 *se401 = (struct usb_se401 *)vdev; | ||
946 | |||
947 | if (!se401->dev) | ||
948 | return -EIO; | ||
949 | |||
950 | switch (cmd) { | ||
951 | case VIDIOCGCAP: | ||
952 | { | ||
953 | struct video_capability *b = arg; | ||
954 | strcpy(b->name, se401->camera_name); | ||
955 | b->type = VID_TYPE_CAPTURE; | ||
956 | b->channels = 1; | ||
957 | b->audios = 0; | ||
958 | b->maxwidth = se401->width[se401->sizes-1]; | ||
959 | b->maxheight = se401->height[se401->sizes-1]; | ||
960 | b->minwidth = se401->width[0]; | ||
961 | b->minheight = se401->height[0]; | ||
962 | return 0; | ||
963 | } | ||
964 | case VIDIOCGCHAN: | ||
965 | { | ||
966 | struct video_channel *v = arg; | ||
967 | |||
968 | if (v->channel != 0) | ||
969 | return -EINVAL; | ||
970 | v->flags = 0; | ||
971 | v->tuners = 0; | ||
972 | v->type = VIDEO_TYPE_CAMERA; | ||
973 | strcpy(v->name, "Camera"); | ||
974 | return 0; | ||
975 | } | ||
976 | case VIDIOCSCHAN: | ||
977 | { | ||
978 | struct video_channel *v = arg; | ||
979 | |||
980 | if (v->channel != 0) | ||
981 | return -EINVAL; | ||
982 | return 0; | ||
983 | } | ||
984 | case VIDIOCGPICT: | ||
985 | { | ||
986 | struct video_picture *p = arg; | ||
987 | |||
988 | se401_get_pict(se401, p); | ||
989 | return 0; | ||
990 | } | ||
991 | case VIDIOCSPICT: | ||
992 | { | ||
993 | struct video_picture *p = arg; | ||
994 | |||
995 | if (se401_set_pict(se401, p)) | ||
996 | return -EINVAL; | ||
997 | return 0; | ||
998 | } | ||
999 | case VIDIOCSWIN: | ||
1000 | { | ||
1001 | struct video_window *vw = arg; | ||
1002 | |||
1003 | if (vw->flags) | ||
1004 | return -EINVAL; | ||
1005 | if (vw->clipcount) | ||
1006 | return -EINVAL; | ||
1007 | if (se401_set_size(se401, vw->width, vw->height)) | ||
1008 | return -EINVAL; | ||
1009 | return 0; | ||
1010 | } | ||
1011 | case VIDIOCGWIN: | ||
1012 | { | ||
1013 | struct video_window *vw = arg; | ||
1014 | |||
1015 | vw->x = 0; /* FIXME */ | ||
1016 | vw->y = 0; | ||
1017 | vw->chromakey = 0; | ||
1018 | vw->flags = 0; | ||
1019 | vw->clipcount = 0; | ||
1020 | vw->width = se401->cwidth; | ||
1021 | vw->height = se401->cheight; | ||
1022 | return 0; | ||
1023 | } | ||
1024 | case VIDIOCGMBUF: | ||
1025 | { | ||
1026 | struct video_mbuf *vm = arg; | ||
1027 | int i; | ||
1028 | |||
1029 | memset(vm, 0, sizeof(*vm)); | ||
1030 | vm->size = SE401_NUMFRAMES * se401->maxframesize; | ||
1031 | vm->frames = SE401_NUMFRAMES; | ||
1032 | for (i=0; i<SE401_NUMFRAMES; i++) | ||
1033 | vm->offsets[i] = se401->maxframesize * i; | ||
1034 | return 0; | ||
1035 | } | ||
1036 | case VIDIOCMCAPTURE: | ||
1037 | { | ||
1038 | struct video_mmap *vm = arg; | ||
1039 | |||
1040 | if (vm->format != VIDEO_PALETTE_RGB24) | ||
1041 | return -EINVAL; | ||
1042 | if (vm->frame >= SE401_NUMFRAMES) | ||
1043 | return -EINVAL; | ||
1044 | if (se401->frame[vm->frame].grabstate != FRAME_UNUSED) | ||
1045 | return -EBUSY; | ||
1046 | |||
1047 | /* Is this according to the v4l spec??? */ | ||
1048 | if (se401_set_size(se401, vm->width, vm->height)) | ||
1049 | return -EINVAL; | ||
1050 | se401->frame[vm->frame].grabstate=FRAME_READY; | ||
1051 | |||
1052 | if (!se401->streaming) | ||
1053 | se401_start_stream(se401); | ||
1054 | |||
1055 | /* Set the picture properties */ | ||
1056 | if (se401->framecount==0) | ||
1057 | se401_send_pict(se401); | ||
1058 | /* Calibrate the reset level after a few frames. */ | ||
1059 | if (se401->framecount%20==1) | ||
1060 | se401_auto_resetlevel(se401); | ||
1061 | |||
1062 | return 0; | ||
1063 | } | ||
1064 | case VIDIOCSYNC: | ||
1065 | { | ||
1066 | int *frame = arg; | ||
1067 | int ret=0; | ||
1068 | |||
1069 | if(*frame <0 || *frame >= SE401_NUMFRAMES) | ||
1070 | return -EINVAL; | ||
1071 | |||
1072 | ret=se401_newframe(se401, *frame); | ||
1073 | se401->frame[*frame].grabstate=FRAME_UNUSED; | ||
1074 | return ret; | ||
1075 | } | ||
1076 | case VIDIOCGFBUF: | ||
1077 | { | ||
1078 | struct video_buffer *vb = arg; | ||
1079 | |||
1080 | memset(vb, 0, sizeof(*vb)); | ||
1081 | return 0; | ||
1082 | } | ||
1083 | case VIDIOCKEY: | ||
1084 | return 0; | ||
1085 | case VIDIOCCAPTURE: | ||
1086 | return -EINVAL; | ||
1087 | case VIDIOCSFBUF: | ||
1088 | return -EINVAL; | ||
1089 | case VIDIOCGTUNER: | ||
1090 | case VIDIOCSTUNER: | ||
1091 | return -EINVAL; | ||
1092 | case VIDIOCGFREQ: | ||
1093 | case VIDIOCSFREQ: | ||
1094 | return -EINVAL; | ||
1095 | case VIDIOCGAUDIO: | ||
1096 | case VIDIOCSAUDIO: | ||
1097 | return -EINVAL; | ||
1098 | default: | ||
1099 | return -ENOIOCTLCMD; | ||
1100 | } /* end switch */ | ||
1101 | |||
1102 | return 0; | ||
1103 | } | ||
1104 | |||
1105 | static int se401_ioctl(struct inode *inode, struct file *file, | ||
1106 | unsigned int cmd, unsigned long arg) | ||
1107 | { | ||
1108 | return video_usercopy(inode, file, cmd, arg, se401_do_ioctl); | ||
1109 | } | ||
1110 | |||
1111 | static ssize_t se401_read(struct file *file, char __user *buf, | ||
1112 | size_t count, loff_t *ppos) | ||
1113 | { | ||
1114 | int realcount=count, ret=0; | ||
1115 | struct video_device *dev = file->private_data; | ||
1116 | struct usb_se401 *se401 = (struct usb_se401 *)dev; | ||
1117 | |||
1118 | |||
1119 | if (se401->dev == NULL) | ||
1120 | return -EIO; | ||
1121 | if (realcount > se401->cwidth*se401->cheight*3) | ||
1122 | realcount=se401->cwidth*se401->cheight*3; | ||
1123 | |||
1124 | /* Shouldn't happen: */ | ||
1125 | if (se401->frame[0].grabstate==FRAME_GRABBING) | ||
1126 | return -EBUSY; | ||
1127 | se401->frame[0].grabstate=FRAME_READY; | ||
1128 | se401->frame[1].grabstate=FRAME_UNUSED; | ||
1129 | se401->curframe=0; | ||
1130 | |||
1131 | if (!se401->streaming) | ||
1132 | se401_start_stream(se401); | ||
1133 | |||
1134 | /* Set the picture properties */ | ||
1135 | if (se401->framecount==0) | ||
1136 | se401_send_pict(se401); | ||
1137 | /* Calibrate the reset level after a few frames. */ | ||
1138 | if (se401->framecount%20==1) | ||
1139 | se401_auto_resetlevel(se401); | ||
1140 | |||
1141 | ret=se401_newframe(se401, 0); | ||
1142 | |||
1143 | se401->frame[0].grabstate=FRAME_UNUSED; | ||
1144 | if (ret) | ||
1145 | return ret; | ||
1146 | if (copy_to_user(buf, se401->frame[0].data, realcount)) | ||
1147 | return -EFAULT; | ||
1148 | |||
1149 | return realcount; | ||
1150 | } | ||
1151 | |||
1152 | static int se401_mmap(struct file *file, struct vm_area_struct *vma) | ||
1153 | { | ||
1154 | struct video_device *dev = file->private_data; | ||
1155 | struct usb_se401 *se401 = (struct usb_se401 *)dev; | ||
1156 | unsigned long start = vma->vm_start; | ||
1157 | unsigned long size = vma->vm_end-vma->vm_start; | ||
1158 | unsigned long page, pos; | ||
1159 | |||
1160 | mutex_lock(&se401->lock); | ||
1161 | |||
1162 | if (se401->dev == NULL) { | ||
1163 | mutex_unlock(&se401->lock); | ||
1164 | return -EIO; | ||
1165 | } | ||
1166 | if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { | ||
1167 | mutex_unlock(&se401->lock); | ||
1168 | return -EINVAL; | ||
1169 | } | ||
1170 | pos = (unsigned long)se401->fbuf; | ||
1171 | while (size > 0) { | ||
1172 | page = vmalloc_to_pfn((void *)pos); | ||
1173 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { | ||
1174 | mutex_unlock(&se401->lock); | ||
1175 | return -EAGAIN; | ||
1176 | } | ||
1177 | start += PAGE_SIZE; | ||
1178 | pos += PAGE_SIZE; | ||
1179 | if (size > PAGE_SIZE) | ||
1180 | size -= PAGE_SIZE; | ||
1181 | else | ||
1182 | size = 0; | ||
1183 | } | ||
1184 | mutex_unlock(&se401->lock); | ||
1185 | |||
1186 | return 0; | ||
1187 | } | ||
1188 | |||
1189 | static struct file_operations se401_fops = { | ||
1190 | .owner = THIS_MODULE, | ||
1191 | .open = se401_open, | ||
1192 | .release = se401_close, | ||
1193 | .read = se401_read, | ||
1194 | .mmap = se401_mmap, | ||
1195 | .ioctl = se401_ioctl, | ||
1196 | .compat_ioctl = v4l_compat_ioctl32, | ||
1197 | .llseek = no_llseek, | ||
1198 | }; | ||
1199 | static struct video_device se401_template = { | ||
1200 | .owner = THIS_MODULE, | ||
1201 | .name = "se401 USB camera", | ||
1202 | .type = VID_TYPE_CAPTURE, | ||
1203 | .hardware = VID_HARDWARE_SE401, | ||
1204 | .fops = &se401_fops, | ||
1205 | }; | ||
1206 | |||
1207 | |||
1208 | |||
1209 | /***************************/ | ||
1210 | static int se401_init(struct usb_se401 *se401, int button) | ||
1211 | { | ||
1212 | int i=0, rc; | ||
1213 | unsigned char cp[0x40]; | ||
1214 | char temp[200]; | ||
1215 | |||
1216 | /* led on */ | ||
1217 | se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); | ||
1218 | |||
1219 | /* get camera descriptor */ | ||
1220 | rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp)); | ||
1221 | if (cp[1]!=0x41) { | ||
1222 | err("Wrong descriptor type"); | ||
1223 | return 1; | ||
1224 | } | ||
1225 | sprintf (temp, "ExtraFeatures: %d", cp[3]); | ||
1226 | |||
1227 | se401->sizes=cp[4]+cp[5]*256; | ||
1228 | se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); | ||
1229 | if (!se401->width) | ||
1230 | return 1; | ||
1231 | se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); | ||
1232 | if (!se401->height) { | ||
1233 | kfree(se401->width); | ||
1234 | return 1; | ||
1235 | } | ||
1236 | for (i=0; i<se401->sizes; i++) { | ||
1237 | se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256; | ||
1238 | se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256; | ||
1239 | } | ||
1240 | sprintf (temp, "%s Sizes:", temp); | ||
1241 | for (i=0; i<se401->sizes; i++) { | ||
1242 | sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]); | ||
1243 | } | ||
1244 | info("%s", temp); | ||
1245 | se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3; | ||
1246 | |||
1247 | rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp)); | ||
1248 | se401->cwidth=cp[0]+cp[1]*256; | ||
1249 | rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp)); | ||
1250 | se401->cheight=cp[0]+cp[1]*256; | ||
1251 | |||
1252 | if (!cp[2] && SE401_FORMAT_BAYER) { | ||
1253 | err("Bayer format not supported!"); | ||
1254 | return 1; | ||
1255 | } | ||
1256 | /* set output mode (BAYER) */ | ||
1257 | se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0); | ||
1258 | |||
1259 | rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp)); | ||
1260 | se401->brightness=cp[0]+cp[1]*256; | ||
1261 | /* some default values */ | ||
1262 | se401->resetlevel=0x2d; | ||
1263 | se401->rgain=0x20; | ||
1264 | se401->ggain=0x20; | ||
1265 | se401->bgain=0x20; | ||
1266 | se401_set_exposure(se401, 20000); | ||
1267 | se401->palette=VIDEO_PALETTE_RGB24; | ||
1268 | se401->enhance=1; | ||
1269 | se401->dropped=0; | ||
1270 | se401->error=0; | ||
1271 | se401->framecount=0; | ||
1272 | se401->readcount=0; | ||
1273 | |||
1274 | /* Start interrupt transfers for snapshot button */ | ||
1275 | if (button) { | ||
1276 | se401->inturb=usb_alloc_urb(0, GFP_KERNEL); | ||
1277 | if (!se401->inturb) { | ||
1278 | info("Allocation of inturb failed"); | ||
1279 | return 1; | ||
1280 | } | ||
1281 | usb_fill_int_urb(se401->inturb, se401->dev, | ||
1282 | usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT), | ||
1283 | &se401->button, sizeof(se401->button), | ||
1284 | se401_button_irq, | ||
1285 | se401, | ||
1286 | 8 | ||
1287 | ); | ||
1288 | if (usb_submit_urb(se401->inturb, GFP_KERNEL)) { | ||
1289 | info("int urb burned down"); | ||
1290 | return 1; | ||
1291 | } | ||
1292 | } else | ||
1293 | se401->inturb=NULL; | ||
1294 | |||
1295 | /* Flash the led */ | ||
1296 | se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0); | ||
1297 | se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); | ||
1298 | se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0); | ||
1299 | se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0); | ||
1300 | |||
1301 | return 0; | ||
1302 | } | ||
1303 | |||
1304 | static int se401_probe(struct usb_interface *intf, | ||
1305 | const struct usb_device_id *id) | ||
1306 | { | ||
1307 | struct usb_device *dev = interface_to_usbdev(intf); | ||
1308 | struct usb_interface_descriptor *interface; | ||
1309 | struct usb_se401 *se401; | ||
1310 | char *camera_name=NULL; | ||
1311 | int button=1; | ||
1312 | |||
1313 | /* We don't handle multi-config cameras */ | ||
1314 | if (dev->descriptor.bNumConfigurations != 1) | ||
1315 | return -ENODEV; | ||
1316 | |||
1317 | interface = &intf->cur_altsetting->desc; | ||
1318 | |||
1319 | /* Is it an se401? */ | ||
1320 | if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 && | ||
1321 | le16_to_cpu(dev->descriptor.idProduct) == 0x0004) { | ||
1322 | camera_name="Endpoints/Aox SE401"; | ||
1323 | } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 && | ||
1324 | le16_to_cpu(dev->descriptor.idProduct) == 0x030b) { | ||
1325 | camera_name="Philips PCVC665K"; | ||
1326 | } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && | ||
1327 | le16_to_cpu(dev->descriptor.idProduct) == 0x5001) { | ||
1328 | camera_name="Kensington VideoCAM 67014"; | ||
1329 | } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && | ||
1330 | le16_to_cpu(dev->descriptor.idProduct) == 0x5002) { | ||
1331 | camera_name="Kensington VideoCAM 6701(5/7)"; | ||
1332 | } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && | ||
1333 | le16_to_cpu(dev->descriptor.idProduct) == 0x5003) { | ||
1334 | camera_name="Kensington VideoCAM 67016"; | ||
1335 | button=0; | ||
1336 | } else | ||
1337 | return -ENODEV; | ||
1338 | |||
1339 | /* Checking vendor/product should be enough, but what the hell */ | ||
1340 | if (interface->bInterfaceClass != 0x00) | ||
1341 | return -ENODEV; | ||
1342 | if (interface->bInterfaceSubClass != 0x00) | ||
1343 | return -ENODEV; | ||
1344 | |||
1345 | /* We found one */ | ||
1346 | info("SE401 camera found: %s", camera_name); | ||
1347 | |||
1348 | if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) { | ||
1349 | err("couldn't kmalloc se401 struct"); | ||
1350 | return -ENOMEM; | ||
1351 | } | ||
1352 | |||
1353 | se401->dev = dev; | ||
1354 | se401->iface = interface->bInterfaceNumber; | ||
1355 | se401->camera_name = camera_name; | ||
1356 | |||
1357 | info("firmware version: %02x", le16_to_cpu(dev->descriptor.bcdDevice) & 255); | ||
1358 | |||
1359 | if (se401_init(se401, button)) { | ||
1360 | kfree(se401); | ||
1361 | return -EIO; | ||
1362 | } | ||
1363 | |||
1364 | memcpy(&se401->vdev, &se401_template, sizeof(se401_template)); | ||
1365 | memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name)); | ||
1366 | init_waitqueue_head(&se401->wq); | ||
1367 | mutex_init(&se401->lock); | ||
1368 | wmb(); | ||
1369 | |||
1370 | if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { | ||
1371 | kfree(se401); | ||
1372 | err("video_register_device failed"); | ||
1373 | return -EIO; | ||
1374 | } | ||
1375 | info("registered new video device: video%d", se401->vdev.minor); | ||
1376 | |||
1377 | usb_set_intfdata (intf, se401); | ||
1378 | return 0; | ||
1379 | } | ||
1380 | |||
1381 | static void se401_disconnect(struct usb_interface *intf) | ||
1382 | { | ||
1383 | struct usb_se401 *se401 = usb_get_intfdata (intf); | ||
1384 | |||
1385 | usb_set_intfdata (intf, NULL); | ||
1386 | if (se401) { | ||
1387 | video_unregister_device(&se401->vdev); | ||
1388 | if (!se401->user){ | ||
1389 | usb_se401_remove_disconnected(se401); | ||
1390 | } else { | ||
1391 | se401->frame[0].grabstate = FRAME_ERROR; | ||
1392 | se401->frame[0].grabstate = FRAME_ERROR; | ||
1393 | |||
1394 | se401->streaming = 0; | ||
1395 | |||
1396 | wake_up_interruptible(&se401->wq); | ||
1397 | se401->removed = 1; | ||
1398 | } | ||
1399 | } | ||
1400 | } | ||
1401 | |||
1402 | static struct usb_driver se401_driver = { | ||
1403 | .name = "se401", | ||
1404 | .id_table = device_table, | ||
1405 | .probe = se401_probe, | ||
1406 | .disconnect = se401_disconnect, | ||
1407 | }; | ||
1408 | |||
1409 | |||
1410 | |||
1411 | /**************************************************************************** | ||
1412 | * | ||
1413 | * Module routines | ||
1414 | * | ||
1415 | ***************************************************************************/ | ||
1416 | |||
1417 | static int __init usb_se401_init(void) | ||
1418 | { | ||
1419 | info("SE401 usb camera driver version %s registering", version); | ||
1420 | if (flickerless) | ||
1421 | if (flickerless!=50 && flickerless!=60) { | ||
1422 | info("Invallid flickerless value, use 0, 50 or 60."); | ||
1423 | return -1; | ||
1424 | } | ||
1425 | return usb_register(&se401_driver); | ||
1426 | } | ||
1427 | |||
1428 | static void __exit usb_se401_exit(void) | ||
1429 | { | ||
1430 | usb_deregister(&se401_driver); | ||
1431 | info("SE401 driver deregistered"); | ||
1432 | } | ||
1433 | |||
1434 | module_init(usb_se401_init); | ||
1435 | module_exit(usb_se401_exit); | ||
diff --git a/drivers/media/video/se401.h b/drivers/media/video/se401.h new file mode 100644 index 000000000000..e88a40d4c86a --- /dev/null +++ b/drivers/media/video/se401.h | |||
@@ -0,0 +1,234 @@ | |||
1 | |||
2 | #ifndef __LINUX_se401_H | ||
3 | #define __LINUX_se401_H | ||
4 | |||
5 | #include <asm/uaccess.h> | ||
6 | #include <linux/videodev.h> | ||
7 | #include <linux/smp_lock.h> | ||
8 | #include <linux/mutex.h> | ||
9 | |||
10 | #define se401_DEBUG /* Turn on debug messages */ | ||
11 | |||
12 | #ifdef se401_DEBUG | ||
13 | # define PDEBUG(level, fmt, args...) \ | ||
14 | if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args) | ||
15 | #else | ||
16 | # define PDEBUG(level, fmt, args...) do {} while(0) | ||
17 | #endif | ||
18 | |||
19 | /* An almost drop-in replacement for sleep_on_interruptible */ | ||
20 | #define wait_interruptible(test, queue, wait) \ | ||
21 | { \ | ||
22 | add_wait_queue(queue, wait); \ | ||
23 | set_current_state(TASK_INTERRUPTIBLE); \ | ||
24 | if (test) \ | ||
25 | schedule(); \ | ||
26 | remove_wait_queue(queue, wait); \ | ||
27 | set_current_state(TASK_RUNNING); \ | ||
28 | if (signal_pending(current)) \ | ||
29 | break; \ | ||
30 | } | ||
31 | |||
32 | #define SE401_REQ_GET_CAMERA_DESCRIPTOR 0x06 | ||
33 | #define SE401_REQ_START_CONTINUOUS_CAPTURE 0x41 | ||
34 | #define SE401_REQ_STOP_CONTINUOUS_CAPTURE 0x42 | ||
35 | #define SE401_REQ_CAPTURE_FRAME 0x43 | ||
36 | #define SE401_REQ_GET_BRT 0x44 | ||
37 | #define SE401_REQ_SET_BRT 0x45 | ||
38 | #define SE401_REQ_GET_WIDTH 0x4c | ||
39 | #define SE401_REQ_SET_WIDTH 0x4d | ||
40 | #define SE401_REQ_GET_HEIGHT 0x4e | ||
41 | #define SE401_REQ_SET_HEIGHT 0x4f | ||
42 | #define SE401_REQ_GET_OUTPUT_MODE 0x50 | ||
43 | #define SE401_REQ_SET_OUTPUT_MODE 0x51 | ||
44 | #define SE401_REQ_GET_EXT_FEATURE 0x52 | ||
45 | #define SE401_REQ_SET_EXT_FEATURE 0x53 | ||
46 | #define SE401_REQ_CAMERA_POWER 0x56 | ||
47 | #define SE401_REQ_LED_CONTROL 0x57 | ||
48 | #define SE401_REQ_BIOS 0xff | ||
49 | |||
50 | #define SE401_BIOS_READ 0x07 | ||
51 | |||
52 | #define SE401_FORMAT_BAYER 0x40 | ||
53 | |||
54 | /* Hyundai hv7131b registers | ||
55 | 7121 and 7141 should be the same (haven't really checked...) */ | ||
56 | /* Mode registers: */ | ||
57 | #define HV7131_REG_MODE_A 0x00 | ||
58 | #define HV7131_REG_MODE_B 0x01 | ||
59 | #define HV7131_REG_MODE_C 0x02 | ||
60 | /* Frame registers: */ | ||
61 | #define HV7131_REG_FRSU 0x10 | ||
62 | #define HV7131_REG_FRSL 0x11 | ||
63 | #define HV7131_REG_FCSU 0x12 | ||
64 | #define HV7131_REG_FCSL 0x13 | ||
65 | #define HV7131_REG_FWHU 0x14 | ||
66 | #define HV7131_REG_FWHL 0x15 | ||
67 | #define HV7131_REG_FWWU 0x16 | ||
68 | #define HV7131_REG_FWWL 0x17 | ||
69 | /* Timing registers: */ | ||
70 | #define HV7131_REG_THBU 0x20 | ||
71 | #define HV7131_REG_THBL 0x21 | ||
72 | #define HV7131_REG_TVBU 0x22 | ||
73 | #define HV7131_REG_TVBL 0x23 | ||
74 | #define HV7131_REG_TITU 0x25 | ||
75 | #define HV7131_REG_TITM 0x26 | ||
76 | #define HV7131_REG_TITL 0x27 | ||
77 | #define HV7131_REG_TMCD 0x28 | ||
78 | /* Adjust Registers: */ | ||
79 | #define HV7131_REG_ARLV 0x30 | ||
80 | #define HV7131_REG_ARCG 0x31 | ||
81 | #define HV7131_REG_AGCG 0x32 | ||
82 | #define HV7131_REG_ABCG 0x33 | ||
83 | #define HV7131_REG_APBV 0x34 | ||
84 | #define HV7131_REG_ASLP 0x54 | ||
85 | /* Offset Registers: */ | ||
86 | #define HV7131_REG_OFSR 0x50 | ||
87 | #define HV7131_REG_OFSG 0x51 | ||
88 | #define HV7131_REG_OFSB 0x52 | ||
89 | /* REset level statistics registers: */ | ||
90 | #define HV7131_REG_LOREFNOH 0x57 | ||
91 | #define HV7131_REG_LOREFNOL 0x58 | ||
92 | #define HV7131_REG_HIREFNOH 0x59 | ||
93 | #define HV7131_REG_HIREFNOL 0x5a | ||
94 | |||
95 | /* se401 registers */ | ||
96 | #define SE401_OPERATINGMODE 0x2000 | ||
97 | |||
98 | |||
99 | /* size of usb transfers */ | ||
100 | #define SE401_PACKETSIZE 4096 | ||
101 | /* number of queued bulk transfers to use, should be about 8 */ | ||
102 | #define SE401_NUMSBUF 1 | ||
103 | /* read the usb specs for this one :) */ | ||
104 | #define SE401_VIDEO_ENDPOINT 1 | ||
105 | #define SE401_BUTTON_ENDPOINT 2 | ||
106 | /* number of frames supported by the v4l part */ | ||
107 | #define SE401_NUMFRAMES 2 | ||
108 | /* scratch buffers for passing data to the decoders */ | ||
109 | #define SE401_NUMSCRATCH 32 | ||
110 | /* maximum amount of data in a JangGu packet */ | ||
111 | #define SE401_VLCDATALEN 1024 | ||
112 | /* number of nul sized packets to receive before kicking the camera */ | ||
113 | #define SE401_MAX_NULLPACKETS 4000 | ||
114 | /* number of decoding errors before kicking the camera */ | ||
115 | #define SE401_MAX_ERRORS 200 | ||
116 | |||
117 | struct usb_device; | ||
118 | |||
119 | struct se401_sbuf { | ||
120 | unsigned char *data; | ||
121 | }; | ||
122 | |||
123 | enum { | ||
124 | FRAME_UNUSED, /* Unused (no MCAPTURE) */ | ||
125 | FRAME_READY, /* Ready to start grabbing */ | ||
126 | FRAME_GRABBING, /* In the process of being grabbed into */ | ||
127 | FRAME_DONE, /* Finished grabbing, but not been synced yet */ | ||
128 | FRAME_ERROR, /* Something bad happened while processing */ | ||
129 | }; | ||
130 | |||
131 | enum { | ||
132 | FMT_BAYER, | ||
133 | FMT_JANGGU, | ||
134 | }; | ||
135 | |||
136 | enum { | ||
137 | BUFFER_UNUSED, | ||
138 | BUFFER_READY, | ||
139 | BUFFER_BUSY, | ||
140 | BUFFER_DONE, | ||
141 | }; | ||
142 | |||
143 | struct se401_scratch { | ||
144 | unsigned char *data; | ||
145 | volatile int state; | ||
146 | int offset; | ||
147 | int length; | ||
148 | }; | ||
149 | |||
150 | struct se401_frame { | ||
151 | unsigned char *data; /* Frame buffer */ | ||
152 | |||
153 | volatile int grabstate; /* State of grabbing */ | ||
154 | |||
155 | unsigned char *curline; | ||
156 | int curlinepix; | ||
157 | int curpix; | ||
158 | }; | ||
159 | |||
160 | struct usb_se401 { | ||
161 | struct video_device vdev; | ||
162 | |||
163 | /* Device structure */ | ||
164 | struct usb_device *dev; | ||
165 | |||
166 | unsigned char iface; | ||
167 | |||
168 | char *camera_name; | ||
169 | |||
170 | int change; | ||
171 | int brightness; | ||
172 | int hue; | ||
173 | int rgain; | ||
174 | int ggain; | ||
175 | int bgain; | ||
176 | int expose_h; | ||
177 | int expose_m; | ||
178 | int expose_l; | ||
179 | int resetlevel; | ||
180 | |||
181 | int enhance; | ||
182 | |||
183 | int format; | ||
184 | int sizes; | ||
185 | int *width; | ||
186 | int *height; | ||
187 | int cwidth; /* current width */ | ||
188 | int cheight; /* current height */ | ||
189 | int palette; | ||
190 | int maxframesize; | ||
191 | int cframesize; /* current framesize */ | ||
192 | |||
193 | struct mutex lock; | ||
194 | int user; /* user count for exclusive use */ | ||
195 | int removed; /* device disconnected */ | ||
196 | |||
197 | int streaming; /* Are we streaming video? */ | ||
198 | |||
199 | char *fbuf; /* Videodev buffer area */ | ||
200 | |||
201 | struct urb *urb[SE401_NUMSBUF]; | ||
202 | struct urb *inturb; | ||
203 | |||
204 | int button; | ||
205 | int buttonpressed; | ||
206 | |||
207 | int curframe; /* Current receiving frame */ | ||
208 | struct se401_frame frame[SE401_NUMFRAMES]; | ||
209 | int readcount; | ||
210 | int framecount; | ||
211 | int error; | ||
212 | int dropped; | ||
213 | |||
214 | int scratch_next; | ||
215 | int scratch_use; | ||
216 | int scratch_overflow; | ||
217 | struct se401_scratch scratch[SE401_NUMSCRATCH]; | ||
218 | |||
219 | /* Decoder specific data: */ | ||
220 | unsigned char vlcdata[SE401_VLCDATALEN]; | ||
221 | int vlcdatapos; | ||
222 | int bayeroffset; | ||
223 | |||
224 | struct se401_sbuf sbuf[SE401_NUMSBUF]; | ||
225 | |||
226 | wait_queue_head_t wq; /* Processes waiting */ | ||
227 | |||
228 | int nullpackets; | ||
229 | }; | ||
230 | |||
231 | |||
232 | |||
233 | #endif | ||
234 | |||
diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile new file mode 100644 index 000000000000..8bcb0f71d69f --- /dev/null +++ b/drivers/media/video/sn9c102/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \ | ||
2 | sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \ | ||
3 | sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \ | ||
4 | sn9c102_tas5130d1b.o | ||
5 | |||
6 | obj-$(CONFIG_USB_SN9C102) += sn9c102.o | ||
7 | |||
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h new file mode 100644 index 000000000000..1d70a62b9f23 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102.h | |||
@@ -0,0 +1,218 @@ | |||
1 | /*************************************************************************** | ||
2 | * V4L2 driver for SN9C10x PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program is distributed in the hope that it will be useful, * | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #ifndef _SN9C102_H_ | ||
22 | #define _SN9C102_H_ | ||
23 | |||
24 | #include <linux/version.h> | ||
25 | #include <linux/usb.h> | ||
26 | #include <linux/videodev2.h> | ||
27 | #include <media/v4l2-common.h> | ||
28 | #include <linux/device.h> | ||
29 | #include <linux/list.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/time.h> | ||
32 | #include <linux/wait.h> | ||
33 | #include <linux/types.h> | ||
34 | #include <linux/param.h> | ||
35 | #include <linux/rwsem.h> | ||
36 | #include <linux/mutex.h> | ||
37 | #include <linux/string.h> | ||
38 | #include <linux/stddef.h> | ||
39 | |||
40 | #include "sn9c102_sensor.h" | ||
41 | |||
42 | /*****************************************************************************/ | ||
43 | |||
44 | #define SN9C102_DEBUG | ||
45 | #define SN9C102_DEBUG_LEVEL 2 | ||
46 | #define SN9C102_MAX_DEVICES 64 | ||
47 | #define SN9C102_PRESERVE_IMGSCALE 0 | ||
48 | #define SN9C102_FORCE_MUNMAP 0 | ||
49 | #define SN9C102_MAX_FRAMES 32 | ||
50 | #define SN9C102_URBS 2 | ||
51 | #define SN9C102_ISO_PACKETS 7 | ||
52 | #define SN9C102_ALTERNATE_SETTING 8 | ||
53 | #define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS) | ||
54 | #define SN9C102_CTRL_TIMEOUT 300 | ||
55 | #define SN9C102_FRAME_TIMEOUT 2 | ||
56 | |||
57 | /*****************************************************************************/ | ||
58 | |||
59 | enum sn9c102_bridge { | ||
60 | BRIDGE_SN9C101 = 0x01, | ||
61 | BRIDGE_SN9C102 = 0x02, | ||
62 | BRIDGE_SN9C103 = 0x04, | ||
63 | }; | ||
64 | |||
65 | SN9C102_ID_TABLE | ||
66 | SN9C102_SENSOR_TABLE | ||
67 | |||
68 | enum sn9c102_frame_state { | ||
69 | F_UNUSED, | ||
70 | F_QUEUED, | ||
71 | F_GRABBING, | ||
72 | F_DONE, | ||
73 | F_ERROR, | ||
74 | }; | ||
75 | |||
76 | struct sn9c102_frame_t { | ||
77 | void* bufmem; | ||
78 | struct v4l2_buffer buf; | ||
79 | enum sn9c102_frame_state state; | ||
80 | struct list_head frame; | ||
81 | unsigned long vma_use_count; | ||
82 | }; | ||
83 | |||
84 | enum sn9c102_dev_state { | ||
85 | DEV_INITIALIZED = 0x01, | ||
86 | DEV_DISCONNECTED = 0x02, | ||
87 | DEV_MISCONFIGURED = 0x04, | ||
88 | }; | ||
89 | |||
90 | enum sn9c102_io_method { | ||
91 | IO_NONE, | ||
92 | IO_READ, | ||
93 | IO_MMAP, | ||
94 | }; | ||
95 | |||
96 | enum sn9c102_stream_state { | ||
97 | STREAM_OFF, | ||
98 | STREAM_INTERRUPT, | ||
99 | STREAM_ON, | ||
100 | }; | ||
101 | |||
102 | typedef char sn9c103_sof_header_t[18]; | ||
103 | typedef char sn9c102_sof_header_t[12]; | ||
104 | typedef char sn9c102_eof_header_t[4]; | ||
105 | |||
106 | struct sn9c102_sysfs_attr { | ||
107 | u8 reg, i2c_reg; | ||
108 | sn9c103_sof_header_t frame_header; | ||
109 | }; | ||
110 | |||
111 | struct sn9c102_module_param { | ||
112 | u8 force_munmap; | ||
113 | u16 frame_timeout; | ||
114 | }; | ||
115 | |||
116 | static DEFINE_MUTEX(sn9c102_sysfs_lock); | ||
117 | static DECLARE_RWSEM(sn9c102_disconnect); | ||
118 | |||
119 | struct sn9c102_device { | ||
120 | struct video_device* v4ldev; | ||
121 | |||
122 | enum sn9c102_bridge bridge; | ||
123 | struct sn9c102_sensor sensor; | ||
124 | |||
125 | struct usb_device* usbdev; | ||
126 | struct urb* urb[SN9C102_URBS]; | ||
127 | void* transfer_buffer[SN9C102_URBS]; | ||
128 | u8* control_buffer; | ||
129 | |||
130 | struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES]; | ||
131 | struct list_head inqueue, outqueue; | ||
132 | u32 frame_count, nbuffers, nreadbuffers; | ||
133 | |||
134 | enum sn9c102_io_method io; | ||
135 | enum sn9c102_stream_state stream; | ||
136 | |||
137 | struct v4l2_jpegcompression compression; | ||
138 | |||
139 | struct sn9c102_sysfs_attr sysfs; | ||
140 | sn9c103_sof_header_t sof_header; | ||
141 | u16 reg[63]; | ||
142 | |||
143 | struct sn9c102_module_param module_param; | ||
144 | |||
145 | enum sn9c102_dev_state state; | ||
146 | u8 users; | ||
147 | |||
148 | struct mutex dev_mutex, fileop_mutex; | ||
149 | spinlock_t queue_lock; | ||
150 | wait_queue_head_t open, wait_frame, wait_stream; | ||
151 | }; | ||
152 | |||
153 | /*****************************************************************************/ | ||
154 | |||
155 | struct sn9c102_device* | ||
156 | sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id) | ||
157 | { | ||
158 | if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id)) | ||
159 | return cam; | ||
160 | |||
161 | return NULL; | ||
162 | } | ||
163 | |||
164 | |||
165 | void | ||
166 | sn9c102_attach_sensor(struct sn9c102_device* cam, | ||
167 | struct sn9c102_sensor* sensor) | ||
168 | { | ||
169 | memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor)); | ||
170 | } | ||
171 | |||
172 | /*****************************************************************************/ | ||
173 | |||
174 | #undef DBG | ||
175 | #undef KDBG | ||
176 | #ifdef SN9C102_DEBUG | ||
177 | # define DBG(level, fmt, args...) \ | ||
178 | do { \ | ||
179 | if (debug >= (level)) { \ | ||
180 | if ((level) == 1) \ | ||
181 | dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ | ||
182 | else if ((level) == 2) \ | ||
183 | dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ | ||
184 | else if ((level) >= 3) \ | ||
185 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | ||
186 | __FUNCTION__, __LINE__ , ## args); \ | ||
187 | } \ | ||
188 | } while (0) | ||
189 | # define V4LDBG(level, name, cmd) \ | ||
190 | do { \ | ||
191 | if (debug >= (level)) \ | ||
192 | v4l_print_ioctl(name, cmd); \ | ||
193 | } while (0) | ||
194 | # define KDBG(level, fmt, args...) \ | ||
195 | do { \ | ||
196 | if (debug >= (level)) { \ | ||
197 | if ((level) == 1 || (level) == 2) \ | ||
198 | pr_info("sn9c102: " fmt "\n", ## args); \ | ||
199 | else if ((level) == 3) \ | ||
200 | pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__, \ | ||
201 | __LINE__ , ## args); \ | ||
202 | } \ | ||
203 | } while (0) | ||
204 | #else | ||
205 | # define DBG(level, fmt, args...) do {;} while(0) | ||
206 | # define V4LDBG(level, name, cmd) do {;} while(0) | ||
207 | # define KDBG(level, fmt, args...) do {;} while(0) | ||
208 | #endif | ||
209 | |||
210 | #undef PDBG | ||
211 | #define PDBG(fmt, args...) \ | ||
212 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | ||
213 | __FUNCTION__, __LINE__ , ## args) | ||
214 | |||
215 | #undef PDBGG | ||
216 | #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ | ||
217 | |||
218 | #endif /* _SN9C102_H_ */ | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c new file mode 100644 index 000000000000..4c6cc6395723 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_core.c | |||
@@ -0,0 +1,2919 @@ | |||
1 | /*************************************************************************** | ||
2 | * V4L2 driver for SN9C10x PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program is distributed in the hope that it will be useful, * | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/param.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | #include <linux/errno.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/device.h> | ||
29 | #include <linux/fs.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/compiler.h> | ||
32 | #include <linux/ioctl.h> | ||
33 | #include <linux/poll.h> | ||
34 | #include <linux/stat.h> | ||
35 | #include <linux/mm.h> | ||
36 | #include <linux/vmalloc.h> | ||
37 | #include <linux/page-flags.h> | ||
38 | #include <linux/byteorder/generic.h> | ||
39 | #include <asm/page.h> | ||
40 | #include <asm/uaccess.h> | ||
41 | |||
42 | #include "sn9c102.h" | ||
43 | |||
44 | /*****************************************************************************/ | ||
45 | |||
46 | #define SN9C102_MODULE_NAME "V4L2 driver for SN9C10x PC Camera Controllers" | ||
47 | #define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia" | ||
48 | #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" | ||
49 | #define SN9C102_MODULE_LICENSE "GPL" | ||
50 | #define SN9C102_MODULE_VERSION "1:1.27" | ||
51 | #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 27) | ||
52 | |||
53 | /*****************************************************************************/ | ||
54 | |||
55 | MODULE_DEVICE_TABLE(usb, sn9c102_id_table); | ||
56 | |||
57 | MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL); | ||
58 | MODULE_DESCRIPTION(SN9C102_MODULE_NAME); | ||
59 | MODULE_VERSION(SN9C102_MODULE_VERSION); | ||
60 | MODULE_LICENSE(SN9C102_MODULE_LICENSE); | ||
61 | |||
62 | static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1}; | ||
63 | module_param_array(video_nr, short, NULL, 0444); | ||
64 | MODULE_PARM_DESC(video_nr, | ||
65 | "\n<-1|n[,...]> Specify V4L2 minor mode number." | ||
66 | "\n -1 = use next available (default)" | ||
67 | "\n n = use minor number n (integer >= 0)" | ||
68 | "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES) | ||
69 | " cameras this way." | ||
70 | "\nFor example:" | ||
71 | "\nvideo_nr=-1,2,-1 would assign minor number 2 to" | ||
72 | "\nthe second camera and use auto for the first" | ||
73 | "\none and for every other camera." | ||
74 | "\n"); | ||
75 | |||
76 | static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = | ||
77 | SN9C102_FORCE_MUNMAP}; | ||
78 | module_param_array(force_munmap, bool, NULL, 0444); | ||
79 | MODULE_PARM_DESC(force_munmap, | ||
80 | "\n<0|1[,...]> Force the application to unmap previously" | ||
81 | "\nmapped buffer memory before calling any VIDIOC_S_CROP or" | ||
82 | "\nVIDIOC_S_FMT ioctl's. Not all the applications support" | ||
83 | "\nthis feature. This parameter is specific for each" | ||
84 | "\ndetected camera." | ||
85 | "\n 0 = do not force memory unmapping" | ||
86 | "\n 1 = force memory unmapping (save memory)" | ||
87 | "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." | ||
88 | "\n"); | ||
89 | |||
90 | static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] = | ||
91 | SN9C102_FRAME_TIMEOUT}; | ||
92 | module_param_array(frame_timeout, uint, NULL, 0644); | ||
93 | MODULE_PARM_DESC(frame_timeout, | ||
94 | "\n<n[,...]> Timeout for a video frame in seconds." | ||
95 | "\nThis parameter is specific for each detected camera." | ||
96 | "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"." | ||
97 | "\n"); | ||
98 | |||
99 | #ifdef SN9C102_DEBUG | ||
100 | static unsigned short debug = SN9C102_DEBUG_LEVEL; | ||
101 | module_param(debug, ushort, 0644); | ||
102 | MODULE_PARM_DESC(debug, | ||
103 | "\n<n> Debugging information level, from 0 to 3:" | ||
104 | "\n0 = none (use carefully)" | ||
105 | "\n1 = critical errors" | ||
106 | "\n2 = significant informations" | ||
107 | "\n3 = more verbose messages" | ||
108 | "\nLevel 3 is useful for testing only, when only " | ||
109 | "one device is used." | ||
110 | "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"." | ||
111 | "\n"); | ||
112 | #endif | ||
113 | |||
114 | /*****************************************************************************/ | ||
115 | |||
116 | static sn9c102_sof_header_t sn9c102_sof_header[] = { | ||
117 | {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00}, | ||
118 | {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01}, | ||
119 | }; | ||
120 | |||
121 | static sn9c103_sof_header_t sn9c103_sof_header[] = { | ||
122 | {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x20}, | ||
123 | }; | ||
124 | |||
125 | static sn9c102_eof_header_t sn9c102_eof_header[] = { | ||
126 | {0x00, 0x00, 0x00, 0x00}, | ||
127 | {0x40, 0x00, 0x00, 0x00}, | ||
128 | {0x80, 0x00, 0x00, 0x00}, | ||
129 | {0xc0, 0x00, 0x00, 0x00}, | ||
130 | }; | ||
131 | |||
132 | /*****************************************************************************/ | ||
133 | |||
134 | static u32 | ||
135 | sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, | ||
136 | enum sn9c102_io_method io) | ||
137 | { | ||
138 | struct v4l2_pix_format* p = &(cam->sensor.pix_format); | ||
139 | struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); | ||
140 | const size_t imagesize = cam->module_param.force_munmap || | ||
141 | io == IO_READ ? | ||
142 | (p->width * p->height * p->priv) / 8 : | ||
143 | (r->width * r->height * p->priv) / 8; | ||
144 | void* buff = NULL; | ||
145 | u32 i; | ||
146 | |||
147 | if (count > SN9C102_MAX_FRAMES) | ||
148 | count = SN9C102_MAX_FRAMES; | ||
149 | |||
150 | cam->nbuffers = count; | ||
151 | while (cam->nbuffers > 0) { | ||
152 | if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize)))) | ||
153 | break; | ||
154 | cam->nbuffers--; | ||
155 | } | ||
156 | |||
157 | for (i = 0; i < cam->nbuffers; i++) { | ||
158 | cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); | ||
159 | cam->frame[i].buf.index = i; | ||
160 | cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); | ||
161 | cam->frame[i].buf.length = imagesize; | ||
162 | cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
163 | cam->frame[i].buf.sequence = 0; | ||
164 | cam->frame[i].buf.field = V4L2_FIELD_NONE; | ||
165 | cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; | ||
166 | cam->frame[i].buf.flags = 0; | ||
167 | } | ||
168 | |||
169 | return cam->nbuffers; | ||
170 | } | ||
171 | |||
172 | |||
173 | static void sn9c102_release_buffers(struct sn9c102_device* cam) | ||
174 | { | ||
175 | if (cam->nbuffers) { | ||
176 | vfree(cam->frame[0].bufmem); | ||
177 | cam->nbuffers = 0; | ||
178 | } | ||
179 | cam->frame_current = NULL; | ||
180 | } | ||
181 | |||
182 | |||
183 | static void sn9c102_empty_framequeues(struct sn9c102_device* cam) | ||
184 | { | ||
185 | u32 i; | ||
186 | |||
187 | INIT_LIST_HEAD(&cam->inqueue); | ||
188 | INIT_LIST_HEAD(&cam->outqueue); | ||
189 | |||
190 | for (i = 0; i < SN9C102_MAX_FRAMES; i++) { | ||
191 | cam->frame[i].state = F_UNUSED; | ||
192 | cam->frame[i].buf.bytesused = 0; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | |||
197 | static void sn9c102_requeue_outqueue(struct sn9c102_device* cam) | ||
198 | { | ||
199 | struct sn9c102_frame_t *i; | ||
200 | |||
201 | list_for_each_entry(i, &cam->outqueue, frame) { | ||
202 | i->state = F_QUEUED; | ||
203 | list_add(&i->frame, &cam->inqueue); | ||
204 | } | ||
205 | |||
206 | INIT_LIST_HEAD(&cam->outqueue); | ||
207 | } | ||
208 | |||
209 | |||
210 | static void sn9c102_queue_unusedframes(struct sn9c102_device* cam) | ||
211 | { | ||
212 | unsigned long lock_flags; | ||
213 | u32 i; | ||
214 | |||
215 | for (i = 0; i < cam->nbuffers; i++) | ||
216 | if (cam->frame[i].state == F_UNUSED) { | ||
217 | cam->frame[i].state = F_QUEUED; | ||
218 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
219 | list_add_tail(&cam->frame[i].frame, &cam->inqueue); | ||
220 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | /*****************************************************************************/ | ||
225 | |||
226 | int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index) | ||
227 | { | ||
228 | struct usb_device* udev = cam->usbdev; | ||
229 | int i, res; | ||
230 | |||
231 | if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg)) | ||
232 | return -1; | ||
233 | |||
234 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
235 | index, 0, buff, sizeof(buff), | ||
236 | SN9C102_CTRL_TIMEOUT*sizeof(buff)); | ||
237 | if (res < 0) { | ||
238 | DBG(3, "Failed to write registers (index 0x%02X, error %d)", | ||
239 | index, res); | ||
240 | return -1; | ||
241 | } | ||
242 | |||
243 | for (i = 0; i < sizeof(buff); i++) | ||
244 | cam->reg[index+i] = buff[i]; | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | |||
250 | int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index) | ||
251 | { | ||
252 | struct usb_device* udev = cam->usbdev; | ||
253 | u8* buff = cam->control_buffer; | ||
254 | int res; | ||
255 | |||
256 | if (index >= ARRAY_SIZE(cam->reg)) | ||
257 | return -1; | ||
258 | |||
259 | *buff = value; | ||
260 | |||
261 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
262 | index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); | ||
263 | if (res < 0) { | ||
264 | DBG(3, "Failed to write a register (value 0x%02X, index " | ||
265 | "0x%02X, error %d)", value, index, res); | ||
266 | return -1; | ||
267 | } | ||
268 | |||
269 | cam->reg[index] = value; | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | |||
275 | /* NOTE: reading some registers always returns 0 */ | ||
276 | static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index) | ||
277 | { | ||
278 | struct usb_device* udev = cam->usbdev; | ||
279 | u8* buff = cam->control_buffer; | ||
280 | int res; | ||
281 | |||
282 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, | ||
283 | index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); | ||
284 | if (res < 0) | ||
285 | DBG(3, "Failed to read a register (index 0x%02X, error %d)", | ||
286 | index, res); | ||
287 | |||
288 | return (res >= 0) ? (int)(*buff) : -1; | ||
289 | } | ||
290 | |||
291 | |||
292 | int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index) | ||
293 | { | ||
294 | if (index >= ARRAY_SIZE(cam->reg)) | ||
295 | return -1; | ||
296 | |||
297 | return cam->reg[index]; | ||
298 | } | ||
299 | |||
300 | |||
301 | static int | ||
302 | sn9c102_i2c_wait(struct sn9c102_device* cam, struct sn9c102_sensor* sensor) | ||
303 | { | ||
304 | int i, r; | ||
305 | |||
306 | for (i = 1; i <= 5; i++) { | ||
307 | r = sn9c102_read_reg(cam, 0x08); | ||
308 | if (r < 0) | ||
309 | return -EIO; | ||
310 | if (r & 0x04) | ||
311 | return 0; | ||
312 | if (sensor->frequency & SN9C102_I2C_400KHZ) | ||
313 | udelay(5*16); | ||
314 | else | ||
315 | udelay(16*16); | ||
316 | } | ||
317 | return -EBUSY; | ||
318 | } | ||
319 | |||
320 | |||
321 | static int | ||
322 | sn9c102_i2c_detect_read_error(struct sn9c102_device* cam, | ||
323 | struct sn9c102_sensor* sensor) | ||
324 | { | ||
325 | int r; | ||
326 | r = sn9c102_read_reg(cam, 0x08); | ||
327 | return (r < 0 || (r >= 0 && !(r & 0x08))) ? -EIO : 0; | ||
328 | } | ||
329 | |||
330 | |||
331 | static int | ||
332 | sn9c102_i2c_detect_write_error(struct sn9c102_device* cam, | ||
333 | struct sn9c102_sensor* sensor) | ||
334 | { | ||
335 | int r; | ||
336 | r = sn9c102_read_reg(cam, 0x08); | ||
337 | return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0; | ||
338 | } | ||
339 | |||
340 | |||
341 | int | ||
342 | sn9c102_i2c_try_raw_read(struct sn9c102_device* cam, | ||
343 | struct sn9c102_sensor* sensor, u8 data0, u8 data1, | ||
344 | u8 n, u8 buffer[]) | ||
345 | { | ||
346 | struct usb_device* udev = cam->usbdev; | ||
347 | u8* data = cam->control_buffer; | ||
348 | int err = 0, res; | ||
349 | |||
350 | /* Write cycle */ | ||
351 | data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | | ||
352 | ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10; | ||
353 | data[1] = data0; /* I2C slave id */ | ||
354 | data[2] = data1; /* address */ | ||
355 | data[7] = 0x10; | ||
356 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
357 | 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); | ||
358 | if (res < 0) | ||
359 | err += res; | ||
360 | |||
361 | err += sn9c102_i2c_wait(cam, sensor); | ||
362 | |||
363 | /* Read cycle - n bytes */ | ||
364 | data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | | ||
365 | ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | | ||
366 | (n << 4) | 0x02; | ||
367 | data[1] = data0; | ||
368 | data[7] = 0x10; | ||
369 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
370 | 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); | ||
371 | if (res < 0) | ||
372 | err += res; | ||
373 | |||
374 | err += sn9c102_i2c_wait(cam, sensor); | ||
375 | |||
376 | /* The first read byte will be placed in data[4] */ | ||
377 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, | ||
378 | 0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT); | ||
379 | if (res < 0) | ||
380 | err += res; | ||
381 | |||
382 | err += sn9c102_i2c_detect_read_error(cam, sensor); | ||
383 | |||
384 | PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1, | ||
385 | data[4]); | ||
386 | |||
387 | if (err) { | ||
388 | DBG(3, "I2C read failed for %s image sensor", sensor->name); | ||
389 | return -1; | ||
390 | } | ||
391 | |||
392 | if (buffer) | ||
393 | memcpy(buffer, data, sizeof(buffer)); | ||
394 | |||
395 | return (int)data[4]; | ||
396 | } | ||
397 | |||
398 | |||
399 | int | ||
400 | sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, | ||
401 | struct sn9c102_sensor* sensor, u8 n, u8 data0, | ||
402 | u8 data1, u8 data2, u8 data3, u8 data4, u8 data5) | ||
403 | { | ||
404 | struct usb_device* udev = cam->usbdev; | ||
405 | u8* data = cam->control_buffer; | ||
406 | int err = 0, res; | ||
407 | |||
408 | /* Write cycle. It usually is address + value */ | ||
409 | data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | | ||
410 | ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | ||
411 | | ((n - 1) << 4); | ||
412 | data[1] = data0; | ||
413 | data[2] = data1; | ||
414 | data[3] = data2; | ||
415 | data[4] = data3; | ||
416 | data[5] = data4; | ||
417 | data[6] = data5; | ||
418 | data[7] = 0x14; | ||
419 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | ||
420 | 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); | ||
421 | if (res < 0) | ||
422 | err += res; | ||
423 | |||
424 | err += sn9c102_i2c_wait(cam, sensor); | ||
425 | err += sn9c102_i2c_detect_write_error(cam, sensor); | ||
426 | |||
427 | if (err) | ||
428 | DBG(3, "I2C write failed for %s image sensor", sensor->name); | ||
429 | |||
430 | PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, " | ||
431 | "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X", | ||
432 | n, data0, data1, data2, data3, data4, data5); | ||
433 | |||
434 | return err ? -1 : 0; | ||
435 | } | ||
436 | |||
437 | |||
438 | int | ||
439 | sn9c102_i2c_try_read(struct sn9c102_device* cam, | ||
440 | struct sn9c102_sensor* sensor, u8 address) | ||
441 | { | ||
442 | return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id, | ||
443 | address, 1, NULL); | ||
444 | } | ||
445 | |||
446 | |||
447 | int | ||
448 | sn9c102_i2c_try_write(struct sn9c102_device* cam, | ||
449 | struct sn9c102_sensor* sensor, u8 address, u8 value) | ||
450 | { | ||
451 | return sn9c102_i2c_try_raw_write(cam, sensor, 3, | ||
452 | sensor->i2c_slave_id, address, | ||
453 | value, 0, 0, 0); | ||
454 | } | ||
455 | |||
456 | |||
457 | int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address) | ||
458 | { | ||
459 | return sn9c102_i2c_try_read(cam, &cam->sensor, address); | ||
460 | } | ||
461 | |||
462 | |||
463 | int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value) | ||
464 | { | ||
465 | return sn9c102_i2c_try_write(cam, &cam->sensor, address, value); | ||
466 | } | ||
467 | |||
468 | /*****************************************************************************/ | ||
469 | |||
470 | static void* | ||
471 | sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) | ||
472 | { | ||
473 | size_t soflen = 0, i; | ||
474 | u8 j, n = 0; | ||
475 | |||
476 | switch (cam->bridge) { | ||
477 | case BRIDGE_SN9C101: | ||
478 | case BRIDGE_SN9C102: | ||
479 | soflen = sizeof(sn9c102_sof_header_t); | ||
480 | n = sizeof(sn9c102_sof_header) / soflen; | ||
481 | break; | ||
482 | case BRIDGE_SN9C103: | ||
483 | soflen = sizeof(sn9c103_sof_header_t); | ||
484 | n = sizeof(sn9c103_sof_header) / soflen; | ||
485 | } | ||
486 | |||
487 | for (i = 0; (len >= soflen) && (i <= len - soflen); i++) | ||
488 | for (j = 0; j < n; j++) | ||
489 | /* The invariable part of the header is 6 bytes long */ | ||
490 | if ((cam->bridge != BRIDGE_SN9C103 && | ||
491 | !memcmp(mem + i, sn9c102_sof_header[j], 6)) || | ||
492 | (cam->bridge == BRIDGE_SN9C103 && | ||
493 | !memcmp(mem + i, sn9c103_sof_header[j], 6))) { | ||
494 | memcpy(cam->sof_header, mem + i, soflen); | ||
495 | /* Skip the header */ | ||
496 | return mem + i + soflen; | ||
497 | } | ||
498 | |||
499 | return NULL; | ||
500 | } | ||
501 | |||
502 | |||
503 | static void* | ||
504 | sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) | ||
505 | { | ||
506 | size_t eoflen = sizeof(sn9c102_eof_header_t), i; | ||
507 | unsigned j, n = sizeof(sn9c102_eof_header) / eoflen; | ||
508 | |||
509 | if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
510 | return NULL; /* EOF header does not exist in compressed data */ | ||
511 | |||
512 | for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++) | ||
513 | for (j = 0; j < n; j++) | ||
514 | if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen)) | ||
515 | return mem + i; | ||
516 | |||
517 | return NULL; | ||
518 | } | ||
519 | |||
520 | |||
521 | static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs) | ||
522 | { | ||
523 | struct sn9c102_device* cam = urb->context; | ||
524 | struct sn9c102_frame_t** f; | ||
525 | size_t imagesize, soflen; | ||
526 | u8 i; | ||
527 | int err = 0; | ||
528 | |||
529 | if (urb->status == -ENOENT) | ||
530 | return; | ||
531 | |||
532 | f = &cam->frame_current; | ||
533 | |||
534 | if (cam->stream == STREAM_INTERRUPT) { | ||
535 | cam->stream = STREAM_OFF; | ||
536 | if ((*f)) | ||
537 | (*f)->state = F_QUEUED; | ||
538 | DBG(3, "Stream interrupted"); | ||
539 | wake_up(&cam->wait_stream); | ||
540 | } | ||
541 | |||
542 | if (cam->state & DEV_DISCONNECTED) | ||
543 | return; | ||
544 | |||
545 | if (cam->state & DEV_MISCONFIGURED) { | ||
546 | wake_up_interruptible(&cam->wait_frame); | ||
547 | return; | ||
548 | } | ||
549 | |||
550 | if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) | ||
551 | goto resubmit_urb; | ||
552 | |||
553 | if (!(*f)) | ||
554 | (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t, | ||
555 | frame); | ||
556 | |||
557 | imagesize = (cam->sensor.pix_format.width * | ||
558 | cam->sensor.pix_format.height * | ||
559 | cam->sensor.pix_format.priv) / 8; | ||
560 | |||
561 | soflen = (cam->bridge) == BRIDGE_SN9C103 ? | ||
562 | sizeof(sn9c103_sof_header_t) : | ||
563 | sizeof(sn9c102_sof_header_t); | ||
564 | |||
565 | for (i = 0; i < urb->number_of_packets; i++) { | ||
566 | unsigned int img, len, status; | ||
567 | void *pos, *sof, *eof; | ||
568 | |||
569 | len = urb->iso_frame_desc[i].actual_length; | ||
570 | status = urb->iso_frame_desc[i].status; | ||
571 | pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; | ||
572 | |||
573 | if (status) { | ||
574 | DBG(3, "Error in isochronous frame"); | ||
575 | (*f)->state = F_ERROR; | ||
576 | continue; | ||
577 | } | ||
578 | |||
579 | PDBGG("Isochrnous frame: length %u, #%u i", len, i); | ||
580 | |||
581 | redo: | ||
582 | sof = sn9c102_find_sof_header(cam, pos, len); | ||
583 | if (likely(!sof)) { | ||
584 | eof = sn9c102_find_eof_header(cam, pos, len); | ||
585 | if ((*f)->state == F_GRABBING) { | ||
586 | end_of_frame: | ||
587 | img = len; | ||
588 | |||
589 | if (eof) | ||
590 | img = (eof > pos) ? eof - pos - 1 : 0; | ||
591 | |||
592 | if ((*f)->buf.bytesused+img > imagesize) { | ||
593 | u32 b; | ||
594 | b = (*f)->buf.bytesused + img - | ||
595 | imagesize; | ||
596 | img = imagesize - (*f)->buf.bytesused; | ||
597 | DBG(3, "Expected EOF not found: " | ||
598 | "video frame cut"); | ||
599 | if (eof) | ||
600 | DBG(3, "Exceeded limit: +%u " | ||
601 | "bytes", (unsigned)(b)); | ||
602 | } | ||
603 | |||
604 | memcpy((*f)->bufmem + (*f)->buf.bytesused, pos, | ||
605 | img); | ||
606 | |||
607 | if ((*f)->buf.bytesused == 0) | ||
608 | do_gettimeofday(&(*f)->buf.timestamp); | ||
609 | |||
610 | (*f)->buf.bytesused += img; | ||
611 | |||
612 | if ((*f)->buf.bytesused == imagesize || | ||
613 | (cam->sensor.pix_format.pixelformat == | ||
614 | V4L2_PIX_FMT_SN9C10X && eof)) { | ||
615 | u32 b; | ||
616 | b = (*f)->buf.bytesused; | ||
617 | (*f)->state = F_DONE; | ||
618 | (*f)->buf.sequence= ++cam->frame_count; | ||
619 | spin_lock(&cam->queue_lock); | ||
620 | list_move_tail(&(*f)->frame, | ||
621 | &cam->outqueue); | ||
622 | if (!list_empty(&cam->inqueue)) | ||
623 | (*f) = list_entry( | ||
624 | cam->inqueue.next, | ||
625 | struct sn9c102_frame_t, | ||
626 | frame ); | ||
627 | else | ||
628 | (*f) = NULL; | ||
629 | spin_unlock(&cam->queue_lock); | ||
630 | memcpy(cam->sysfs.frame_header, | ||
631 | cam->sof_header, soflen); | ||
632 | DBG(3, "Video frame captured: %lu " | ||
633 | "bytes", (unsigned long)(b)); | ||
634 | |||
635 | if (!(*f)) | ||
636 | goto resubmit_urb; | ||
637 | |||
638 | } else if (eof) { | ||
639 | (*f)->state = F_ERROR; | ||
640 | DBG(3, "Not expected EOF after %lu " | ||
641 | "bytes of image data", | ||
642 | (unsigned long) | ||
643 | ((*f)->buf.bytesused)); | ||
644 | } | ||
645 | |||
646 | if (sof) /* (1) */ | ||
647 | goto start_of_frame; | ||
648 | |||
649 | } else if (eof) { | ||
650 | DBG(3, "EOF without SOF"); | ||
651 | continue; | ||
652 | |||
653 | } else { | ||
654 | PDBGG("Ignoring pointless isochronous frame"); | ||
655 | continue; | ||
656 | } | ||
657 | |||
658 | } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) { | ||
659 | start_of_frame: | ||
660 | (*f)->state = F_GRABBING; | ||
661 | (*f)->buf.bytesused = 0; | ||
662 | len -= (sof - pos); | ||
663 | pos = sof; | ||
664 | DBG(3, "SOF detected: new video frame"); | ||
665 | if (len) | ||
666 | goto redo; | ||
667 | |||
668 | } else if ((*f)->state == F_GRABBING) { | ||
669 | eof = sn9c102_find_eof_header(cam, pos, len); | ||
670 | if (eof && eof < sof) | ||
671 | goto end_of_frame; /* (1) */ | ||
672 | else { | ||
673 | if (cam->sensor.pix_format.pixelformat == | ||
674 | V4L2_PIX_FMT_SN9C10X) { | ||
675 | eof = sof - soflen; | ||
676 | goto end_of_frame; | ||
677 | } else { | ||
678 | DBG(3, "SOF before expected EOF after " | ||
679 | "%lu bytes of image data", | ||
680 | (unsigned long) | ||
681 | ((*f)->buf.bytesused)); | ||
682 | goto start_of_frame; | ||
683 | } | ||
684 | } | ||
685 | } | ||
686 | } | ||
687 | |||
688 | resubmit_urb: | ||
689 | urb->dev = cam->usbdev; | ||
690 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
691 | if (err < 0 && err != -EPERM) { | ||
692 | cam->state |= DEV_MISCONFIGURED; | ||
693 | DBG(1, "usb_submit_urb() failed"); | ||
694 | } | ||
695 | |||
696 | wake_up_interruptible(&cam->wait_frame); | ||
697 | } | ||
698 | |||
699 | |||
700 | static int sn9c102_start_transfer(struct sn9c102_device* cam) | ||
701 | { | ||
702 | struct usb_device *udev = cam->usbdev; | ||
703 | struct urb* urb; | ||
704 | const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512, | ||
705 | 680, 800, 900, 1023}; | ||
706 | const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512, | ||
707 | 680, 800, 900, 1003}; | ||
708 | const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ? | ||
709 | sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] : | ||
710 | sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING]; | ||
711 | s8 i, j; | ||
712 | int err = 0; | ||
713 | |||
714 | for (i = 0; i < SN9C102_URBS; i++) { | ||
715 | cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz, | ||
716 | GFP_KERNEL); | ||
717 | if (!cam->transfer_buffer[i]) { | ||
718 | err = -ENOMEM; | ||
719 | DBG(1, "Not enough memory"); | ||
720 | goto free_buffers; | ||
721 | } | ||
722 | } | ||
723 | |||
724 | for (i = 0; i < SN9C102_URBS; i++) { | ||
725 | urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL); | ||
726 | cam->urb[i] = urb; | ||
727 | if (!urb) { | ||
728 | err = -ENOMEM; | ||
729 | DBG(1, "usb_alloc_urb() failed"); | ||
730 | goto free_urbs; | ||
731 | } | ||
732 | urb->dev = udev; | ||
733 | urb->context = cam; | ||
734 | urb->pipe = usb_rcvisocpipe(udev, 1); | ||
735 | urb->transfer_flags = URB_ISO_ASAP; | ||
736 | urb->number_of_packets = SN9C102_ISO_PACKETS; | ||
737 | urb->complete = sn9c102_urb_complete; | ||
738 | urb->transfer_buffer = cam->transfer_buffer[i]; | ||
739 | urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS; | ||
740 | urb->interval = 1; | ||
741 | for (j = 0; j < SN9C102_ISO_PACKETS; j++) { | ||
742 | urb->iso_frame_desc[j].offset = psz * j; | ||
743 | urb->iso_frame_desc[j].length = psz; | ||
744 | } | ||
745 | } | ||
746 | |||
747 | /* Enable video */ | ||
748 | if (!(cam->reg[0x01] & 0x04)) { | ||
749 | err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01); | ||
750 | if (err) { | ||
751 | err = -EIO; | ||
752 | DBG(1, "I/O hardware error"); | ||
753 | goto free_urbs; | ||
754 | } | ||
755 | } | ||
756 | |||
757 | err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING); | ||
758 | if (err) { | ||
759 | DBG(1, "usb_set_interface() failed"); | ||
760 | goto free_urbs; | ||
761 | } | ||
762 | |||
763 | cam->frame_current = NULL; | ||
764 | |||
765 | for (i = 0; i < SN9C102_URBS; i++) { | ||
766 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); | ||
767 | if (err) { | ||
768 | for (j = i-1; j >= 0; j--) | ||
769 | usb_kill_urb(cam->urb[j]); | ||
770 | DBG(1, "usb_submit_urb() failed, error %d", err); | ||
771 | goto free_urbs; | ||
772 | } | ||
773 | } | ||
774 | |||
775 | return 0; | ||
776 | |||
777 | free_urbs: | ||
778 | for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++) | ||
779 | usb_free_urb(cam->urb[i]); | ||
780 | |||
781 | free_buffers: | ||
782 | for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++) | ||
783 | kfree(cam->transfer_buffer[i]); | ||
784 | |||
785 | return err; | ||
786 | } | ||
787 | |||
788 | |||
789 | static int sn9c102_stop_transfer(struct sn9c102_device* cam) | ||
790 | { | ||
791 | struct usb_device *udev = cam->usbdev; | ||
792 | s8 i; | ||
793 | int err = 0; | ||
794 | |||
795 | if (cam->state & DEV_DISCONNECTED) | ||
796 | return 0; | ||
797 | |||
798 | for (i = SN9C102_URBS-1; i >= 0; i--) { | ||
799 | usb_kill_urb(cam->urb[i]); | ||
800 | usb_free_urb(cam->urb[i]); | ||
801 | kfree(cam->transfer_buffer[i]); | ||
802 | } | ||
803 | |||
804 | err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ | ||
805 | if (err) | ||
806 | DBG(3, "usb_set_interface() failed"); | ||
807 | |||
808 | return err; | ||
809 | } | ||
810 | |||
811 | |||
812 | static int sn9c102_stream_interrupt(struct sn9c102_device* cam) | ||
813 | { | ||
814 | long timeout; | ||
815 | |||
816 | cam->stream = STREAM_INTERRUPT; | ||
817 | timeout = wait_event_timeout(cam->wait_stream, | ||
818 | (cam->stream == STREAM_OFF) || | ||
819 | (cam->state & DEV_DISCONNECTED), | ||
820 | SN9C102_URB_TIMEOUT); | ||
821 | if (cam->state & DEV_DISCONNECTED) | ||
822 | return -ENODEV; | ||
823 | else if (cam->stream != STREAM_OFF) { | ||
824 | cam->state |= DEV_MISCONFIGURED; | ||
825 | DBG(1, "URB timeout reached. The camera is misconfigured. " | ||
826 | "To use it, close and open /dev/video%d again.", | ||
827 | cam->v4ldev->minor); | ||
828 | return -EIO; | ||
829 | } | ||
830 | |||
831 | return 0; | ||
832 | } | ||
833 | |||
834 | /*****************************************************************************/ | ||
835 | |||
836 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
837 | static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count) | ||
838 | { | ||
839 | char str[5]; | ||
840 | char* endp; | ||
841 | unsigned long val; | ||
842 | |||
843 | if (len < 4) { | ||
844 | strncpy(str, buff, len); | ||
845 | str[len+1] = '\0'; | ||
846 | } else { | ||
847 | strncpy(str, buff, 4); | ||
848 | str[4] = '\0'; | ||
849 | } | ||
850 | |||
851 | val = simple_strtoul(str, &endp, 0); | ||
852 | |||
853 | *count = 0; | ||
854 | if (val <= 0xff) | ||
855 | *count = (ssize_t)(endp - str); | ||
856 | if ((*count) && (len == *count+1) && (buff[*count] == '\n')) | ||
857 | *count += 1; | ||
858 | |||
859 | return (u8)val; | ||
860 | } | ||
861 | |||
862 | /* | ||
863 | NOTE 1: being inside one of the following methods implies that the v4l | ||
864 | device exists for sure (see kobjects and reference counters) | ||
865 | NOTE 2: buffers are PAGE_SIZE long | ||
866 | */ | ||
867 | |||
868 | static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) | ||
869 | { | ||
870 | struct sn9c102_device* cam; | ||
871 | ssize_t count; | ||
872 | |||
873 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
874 | return -ERESTARTSYS; | ||
875 | |||
876 | cam = video_get_drvdata(to_video_device(cd)); | ||
877 | if (!cam) { | ||
878 | mutex_unlock(&sn9c102_sysfs_lock); | ||
879 | return -ENODEV; | ||
880 | } | ||
881 | |||
882 | count = sprintf(buf, "%u\n", cam->sysfs.reg); | ||
883 | |||
884 | mutex_unlock(&sn9c102_sysfs_lock); | ||
885 | |||
886 | return count; | ||
887 | } | ||
888 | |||
889 | |||
890 | static ssize_t | ||
891 | sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) | ||
892 | { | ||
893 | struct sn9c102_device* cam; | ||
894 | u8 index; | ||
895 | ssize_t count; | ||
896 | |||
897 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
898 | return -ERESTARTSYS; | ||
899 | |||
900 | cam = video_get_drvdata(to_video_device(cd)); | ||
901 | if (!cam) { | ||
902 | mutex_unlock(&sn9c102_sysfs_lock); | ||
903 | return -ENODEV; | ||
904 | } | ||
905 | |||
906 | index = sn9c102_strtou8(buf, len, &count); | ||
907 | if (index > 0x1f || !count) { | ||
908 | mutex_unlock(&sn9c102_sysfs_lock); | ||
909 | return -EINVAL; | ||
910 | } | ||
911 | |||
912 | cam->sysfs.reg = index; | ||
913 | |||
914 | DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg); | ||
915 | DBG(3, "Written bytes: %zd", count); | ||
916 | |||
917 | mutex_unlock(&sn9c102_sysfs_lock); | ||
918 | |||
919 | return count; | ||
920 | } | ||
921 | |||
922 | |||
923 | static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) | ||
924 | { | ||
925 | struct sn9c102_device* cam; | ||
926 | ssize_t count; | ||
927 | int val; | ||
928 | |||
929 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
930 | return -ERESTARTSYS; | ||
931 | |||
932 | cam = video_get_drvdata(to_video_device(cd)); | ||
933 | if (!cam) { | ||
934 | mutex_unlock(&sn9c102_sysfs_lock); | ||
935 | return -ENODEV; | ||
936 | } | ||
937 | |||
938 | if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) { | ||
939 | mutex_unlock(&sn9c102_sysfs_lock); | ||
940 | return -EIO; | ||
941 | } | ||
942 | |||
943 | count = sprintf(buf, "%d\n", val); | ||
944 | |||
945 | DBG(3, "Read bytes: %zd", count); | ||
946 | |||
947 | mutex_unlock(&sn9c102_sysfs_lock); | ||
948 | |||
949 | return count; | ||
950 | } | ||
951 | |||
952 | |||
953 | static ssize_t | ||
954 | sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) | ||
955 | { | ||
956 | struct sn9c102_device* cam; | ||
957 | u8 value; | ||
958 | ssize_t count; | ||
959 | int err; | ||
960 | |||
961 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
962 | return -ERESTARTSYS; | ||
963 | |||
964 | cam = video_get_drvdata(to_video_device(cd)); | ||
965 | if (!cam) { | ||
966 | mutex_unlock(&sn9c102_sysfs_lock); | ||
967 | return -ENODEV; | ||
968 | } | ||
969 | |||
970 | value = sn9c102_strtou8(buf, len, &count); | ||
971 | if (!count) { | ||
972 | mutex_unlock(&sn9c102_sysfs_lock); | ||
973 | return -EINVAL; | ||
974 | } | ||
975 | |||
976 | err = sn9c102_write_reg(cam, value, cam->sysfs.reg); | ||
977 | if (err) { | ||
978 | mutex_unlock(&sn9c102_sysfs_lock); | ||
979 | return -EIO; | ||
980 | } | ||
981 | |||
982 | DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X", | ||
983 | cam->sysfs.reg, value); | ||
984 | DBG(3, "Written bytes: %zd", count); | ||
985 | |||
986 | mutex_unlock(&sn9c102_sysfs_lock); | ||
987 | |||
988 | return count; | ||
989 | } | ||
990 | |||
991 | |||
992 | static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) | ||
993 | { | ||
994 | struct sn9c102_device* cam; | ||
995 | ssize_t count; | ||
996 | |||
997 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
998 | return -ERESTARTSYS; | ||
999 | |||
1000 | cam = video_get_drvdata(to_video_device(cd)); | ||
1001 | if (!cam) { | ||
1002 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1003 | return -ENODEV; | ||
1004 | } | ||
1005 | |||
1006 | count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg); | ||
1007 | |||
1008 | DBG(3, "Read bytes: %zd", count); | ||
1009 | |||
1010 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1011 | |||
1012 | return count; | ||
1013 | } | ||
1014 | |||
1015 | |||
1016 | static ssize_t | ||
1017 | sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) | ||
1018 | { | ||
1019 | struct sn9c102_device* cam; | ||
1020 | u8 index; | ||
1021 | ssize_t count; | ||
1022 | |||
1023 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
1024 | return -ERESTARTSYS; | ||
1025 | |||
1026 | cam = video_get_drvdata(to_video_device(cd)); | ||
1027 | if (!cam) { | ||
1028 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1029 | return -ENODEV; | ||
1030 | } | ||
1031 | |||
1032 | index = sn9c102_strtou8(buf, len, &count); | ||
1033 | if (!count) { | ||
1034 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1035 | return -EINVAL; | ||
1036 | } | ||
1037 | |||
1038 | cam->sysfs.i2c_reg = index; | ||
1039 | |||
1040 | DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg); | ||
1041 | DBG(3, "Written bytes: %zd", count); | ||
1042 | |||
1043 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1044 | |||
1045 | return count; | ||
1046 | } | ||
1047 | |||
1048 | |||
1049 | static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) | ||
1050 | { | ||
1051 | struct sn9c102_device* cam; | ||
1052 | ssize_t count; | ||
1053 | int val; | ||
1054 | |||
1055 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
1056 | return -ERESTARTSYS; | ||
1057 | |||
1058 | cam = video_get_drvdata(to_video_device(cd)); | ||
1059 | if (!cam) { | ||
1060 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1061 | return -ENODEV; | ||
1062 | } | ||
1063 | |||
1064 | if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) { | ||
1065 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1066 | return -ENOSYS; | ||
1067 | } | ||
1068 | |||
1069 | if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { | ||
1070 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1071 | return -EIO; | ||
1072 | } | ||
1073 | |||
1074 | count = sprintf(buf, "%d\n", val); | ||
1075 | |||
1076 | DBG(3, "Read bytes: %zd", count); | ||
1077 | |||
1078 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1079 | |||
1080 | return count; | ||
1081 | } | ||
1082 | |||
1083 | |||
1084 | static ssize_t | ||
1085 | sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) | ||
1086 | { | ||
1087 | struct sn9c102_device* cam; | ||
1088 | u8 value; | ||
1089 | ssize_t count; | ||
1090 | int err; | ||
1091 | |||
1092 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
1093 | return -ERESTARTSYS; | ||
1094 | |||
1095 | cam = video_get_drvdata(to_video_device(cd)); | ||
1096 | if (!cam) { | ||
1097 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1098 | return -ENODEV; | ||
1099 | } | ||
1100 | |||
1101 | if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) { | ||
1102 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1103 | return -ENOSYS; | ||
1104 | } | ||
1105 | |||
1106 | value = sn9c102_strtou8(buf, len, &count); | ||
1107 | if (!count) { | ||
1108 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1109 | return -EINVAL; | ||
1110 | } | ||
1111 | |||
1112 | err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value); | ||
1113 | if (err) { | ||
1114 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1115 | return -EIO; | ||
1116 | } | ||
1117 | |||
1118 | DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", | ||
1119 | cam->sysfs.i2c_reg, value); | ||
1120 | DBG(3, "Written bytes: %zd", count); | ||
1121 | |||
1122 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1123 | |||
1124 | return count; | ||
1125 | } | ||
1126 | |||
1127 | |||
1128 | static ssize_t | ||
1129 | sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) | ||
1130 | { | ||
1131 | struct sn9c102_device* cam; | ||
1132 | enum sn9c102_bridge bridge; | ||
1133 | ssize_t res = 0; | ||
1134 | u8 value; | ||
1135 | ssize_t count; | ||
1136 | |||
1137 | if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) | ||
1138 | return -ERESTARTSYS; | ||
1139 | |||
1140 | cam = video_get_drvdata(to_video_device(cd)); | ||
1141 | if (!cam) { | ||
1142 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1143 | return -ENODEV; | ||
1144 | } | ||
1145 | |||
1146 | bridge = cam->bridge; | ||
1147 | |||
1148 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1149 | |||
1150 | value = sn9c102_strtou8(buf, len, &count); | ||
1151 | if (!count) | ||
1152 | return -EINVAL; | ||
1153 | |||
1154 | switch (bridge) { | ||
1155 | case BRIDGE_SN9C101: | ||
1156 | case BRIDGE_SN9C102: | ||
1157 | if (value > 0x0f) | ||
1158 | return -EINVAL; | ||
1159 | if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0) | ||
1160 | res = sn9c102_store_val(cd, buf, len); | ||
1161 | break; | ||
1162 | case BRIDGE_SN9C103: | ||
1163 | if (value > 0x7f) | ||
1164 | return -EINVAL; | ||
1165 | if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0) | ||
1166 | res = sn9c102_store_val(cd, buf, len); | ||
1167 | break; | ||
1168 | } | ||
1169 | |||
1170 | return res; | ||
1171 | } | ||
1172 | |||
1173 | |||
1174 | static ssize_t | ||
1175 | sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) | ||
1176 | { | ||
1177 | ssize_t res = 0; | ||
1178 | u8 value; | ||
1179 | ssize_t count; | ||
1180 | |||
1181 | value = sn9c102_strtou8(buf, len, &count); | ||
1182 | if (!count || value > 0x7f) | ||
1183 | return -EINVAL; | ||
1184 | |||
1185 | if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0) | ||
1186 | res = sn9c102_store_val(cd, buf, len); | ||
1187 | |||
1188 | return res; | ||
1189 | } | ||
1190 | |||
1191 | |||
1192 | static ssize_t | ||
1193 | sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) | ||
1194 | { | ||
1195 | ssize_t res = 0; | ||
1196 | u8 value; | ||
1197 | ssize_t count; | ||
1198 | |||
1199 | value = sn9c102_strtou8(buf, len, &count); | ||
1200 | if (!count || value > 0x7f) | ||
1201 | return -EINVAL; | ||
1202 | |||
1203 | if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0) | ||
1204 | res = sn9c102_store_val(cd, buf, len); | ||
1205 | |||
1206 | return res; | ||
1207 | } | ||
1208 | |||
1209 | |||
1210 | static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf) | ||
1211 | { | ||
1212 | struct sn9c102_device* cam; | ||
1213 | ssize_t count; | ||
1214 | |||
1215 | cam = video_get_drvdata(to_video_device(cd)); | ||
1216 | if (!cam) | ||
1217 | return -ENODEV; | ||
1218 | |||
1219 | count = sizeof(cam->sysfs.frame_header); | ||
1220 | memcpy(buf, cam->sysfs.frame_header, count); | ||
1221 | |||
1222 | DBG(3, "Frame header, read bytes: %zd", count); | ||
1223 | |||
1224 | return count; | ||
1225 | } | ||
1226 | |||
1227 | |||
1228 | static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, | ||
1229 | sn9c102_show_reg, sn9c102_store_reg); | ||
1230 | static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, | ||
1231 | sn9c102_show_val, sn9c102_store_val); | ||
1232 | static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, | ||
1233 | sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); | ||
1234 | static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, | ||
1235 | sn9c102_show_i2c_val, sn9c102_store_i2c_val); | ||
1236 | static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); | ||
1237 | static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue); | ||
1238 | static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red); | ||
1239 | static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, | ||
1240 | sn9c102_show_frame_header, NULL); | ||
1241 | |||
1242 | |||
1243 | static void sn9c102_create_sysfs(struct sn9c102_device* cam) | ||
1244 | { | ||
1245 | struct video_device *v4ldev = cam->v4ldev; | ||
1246 | |||
1247 | video_device_create_file(v4ldev, &class_device_attr_reg); | ||
1248 | video_device_create_file(v4ldev, &class_device_attr_val); | ||
1249 | video_device_create_file(v4ldev, &class_device_attr_frame_header); | ||
1250 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) | ||
1251 | video_device_create_file(v4ldev, &class_device_attr_green); | ||
1252 | else if (cam->bridge == BRIDGE_SN9C103) { | ||
1253 | video_device_create_file(v4ldev, &class_device_attr_blue); | ||
1254 | video_device_create_file(v4ldev, &class_device_attr_red); | ||
1255 | } | ||
1256 | if (cam->sensor.sysfs_ops) { | ||
1257 | video_device_create_file(v4ldev, &class_device_attr_i2c_reg); | ||
1258 | video_device_create_file(v4ldev, &class_device_attr_i2c_val); | ||
1259 | } | ||
1260 | } | ||
1261 | #endif /* CONFIG_VIDEO_ADV_DEBUG */ | ||
1262 | |||
1263 | /*****************************************************************************/ | ||
1264 | |||
1265 | static int | ||
1266 | sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix) | ||
1267 | { | ||
1268 | int err = 0; | ||
1269 | |||
1270 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
1271 | err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18); | ||
1272 | else | ||
1273 | err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18); | ||
1274 | |||
1275 | return err ? -EIO : 0; | ||
1276 | } | ||
1277 | |||
1278 | |||
1279 | static int | ||
1280 | sn9c102_set_compression(struct sn9c102_device* cam, | ||
1281 | struct v4l2_jpegcompression* compression) | ||
1282 | { | ||
1283 | int err = 0; | ||
1284 | |||
1285 | if (compression->quality == 0) | ||
1286 | err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17); | ||
1287 | else if (compression->quality == 1) | ||
1288 | err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17); | ||
1289 | |||
1290 | return err ? -EIO : 0; | ||
1291 | } | ||
1292 | |||
1293 | |||
1294 | static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale) | ||
1295 | { | ||
1296 | u8 r = 0; | ||
1297 | int err = 0; | ||
1298 | |||
1299 | if (scale == 1) | ||
1300 | r = cam->reg[0x18] & 0xcf; | ||
1301 | else if (scale == 2) { | ||
1302 | r = cam->reg[0x18] & 0xcf; | ||
1303 | r |= 0x10; | ||
1304 | } else if (scale == 4) | ||
1305 | r = cam->reg[0x18] | 0x20; | ||
1306 | |||
1307 | err += sn9c102_write_reg(cam, r, 0x18); | ||
1308 | if (err) | ||
1309 | return -EIO; | ||
1310 | |||
1311 | PDBGG("Scaling factor: %u", scale); | ||
1312 | |||
1313 | return 0; | ||
1314 | } | ||
1315 | |||
1316 | |||
1317 | static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect) | ||
1318 | { | ||
1319 | struct sn9c102_sensor* s = &cam->sensor; | ||
1320 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left), | ||
1321 | v_start = (u8)(rect->top - s->cropcap.bounds.top), | ||
1322 | h_size = (u8)(rect->width / 16), | ||
1323 | v_size = (u8)(rect->height / 16); | ||
1324 | int err = 0; | ||
1325 | |||
1326 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
1327 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
1328 | err += sn9c102_write_reg(cam, h_size, 0x15); | ||
1329 | err += sn9c102_write_reg(cam, v_size, 0x16); | ||
1330 | if (err) | ||
1331 | return -EIO; | ||
1332 | |||
1333 | PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size " | ||
1334 | "%u %u %u %u", h_start, v_start, h_size, v_size); | ||
1335 | |||
1336 | return 0; | ||
1337 | } | ||
1338 | |||
1339 | |||
1340 | static int sn9c102_init(struct sn9c102_device* cam) | ||
1341 | { | ||
1342 | struct sn9c102_sensor* s = &cam->sensor; | ||
1343 | struct v4l2_control ctrl; | ||
1344 | struct v4l2_queryctrl *qctrl; | ||
1345 | struct v4l2_rect* rect; | ||
1346 | u8 i = 0; | ||
1347 | int err = 0; | ||
1348 | |||
1349 | if (!(cam->state & DEV_INITIALIZED)) { | ||
1350 | init_waitqueue_head(&cam->open); | ||
1351 | qctrl = s->qctrl; | ||
1352 | rect = &(s->cropcap.defrect); | ||
1353 | } else { /* use current values */ | ||
1354 | qctrl = s->_qctrl; | ||
1355 | rect = &(s->_rect); | ||
1356 | } | ||
1357 | |||
1358 | err += sn9c102_set_scale(cam, rect->width / s->pix_format.width); | ||
1359 | err += sn9c102_set_crop(cam, rect); | ||
1360 | if (err) | ||
1361 | return err; | ||
1362 | |||
1363 | if (s->init) { | ||
1364 | err = s->init(cam); | ||
1365 | if (err) { | ||
1366 | DBG(3, "Sensor initialization failed"); | ||
1367 | return err; | ||
1368 | } | ||
1369 | } | ||
1370 | |||
1371 | if (!(cam->state & DEV_INITIALIZED)) | ||
1372 | cam->compression.quality = cam->reg[0x17] & 0x01 ? 0 : 1; | ||
1373 | else | ||
1374 | err += sn9c102_set_compression(cam, &cam->compression); | ||
1375 | err += sn9c102_set_pix_format(cam, &s->pix_format); | ||
1376 | if (s->set_pix_format) | ||
1377 | err += s->set_pix_format(cam, &s->pix_format); | ||
1378 | if (err) | ||
1379 | return err; | ||
1380 | |||
1381 | if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
1382 | DBG(3, "Compressed video format is active, quality %d", | ||
1383 | cam->compression.quality); | ||
1384 | else | ||
1385 | DBG(3, "Uncompressed video format is active"); | ||
1386 | |||
1387 | if (s->set_crop) | ||
1388 | if ((err = s->set_crop(cam, rect))) { | ||
1389 | DBG(3, "set_crop() failed"); | ||
1390 | return err; | ||
1391 | } | ||
1392 | |||
1393 | if (s->set_ctrl) { | ||
1394 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
1395 | if (s->qctrl[i].id != 0 && | ||
1396 | !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { | ||
1397 | ctrl.id = s->qctrl[i].id; | ||
1398 | ctrl.value = qctrl[i].default_value; | ||
1399 | err = s->set_ctrl(cam, &ctrl); | ||
1400 | if (err) { | ||
1401 | DBG(3, "Set %s control failed", | ||
1402 | s->qctrl[i].name); | ||
1403 | return err; | ||
1404 | } | ||
1405 | DBG(3, "Image sensor supports '%s' control", | ||
1406 | s->qctrl[i].name); | ||
1407 | } | ||
1408 | } | ||
1409 | |||
1410 | if (!(cam->state & DEV_INITIALIZED)) { | ||
1411 | mutex_init(&cam->fileop_mutex); | ||
1412 | spin_lock_init(&cam->queue_lock); | ||
1413 | init_waitqueue_head(&cam->wait_frame); | ||
1414 | init_waitqueue_head(&cam->wait_stream); | ||
1415 | cam->nreadbuffers = 2; | ||
1416 | memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); | ||
1417 | memcpy(&(s->_rect), &(s->cropcap.defrect), | ||
1418 | sizeof(struct v4l2_rect)); | ||
1419 | cam->state |= DEV_INITIALIZED; | ||
1420 | } | ||
1421 | |||
1422 | DBG(2, "Initialization succeeded"); | ||
1423 | return 0; | ||
1424 | } | ||
1425 | |||
1426 | |||
1427 | static void sn9c102_release_resources(struct sn9c102_device* cam) | ||
1428 | { | ||
1429 | mutex_lock(&sn9c102_sysfs_lock); | ||
1430 | |||
1431 | DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); | ||
1432 | video_set_drvdata(cam->v4ldev, NULL); | ||
1433 | video_unregister_device(cam->v4ldev); | ||
1434 | |||
1435 | usb_put_dev(cam->usbdev); | ||
1436 | |||
1437 | mutex_unlock(&sn9c102_sysfs_lock); | ||
1438 | |||
1439 | kfree(cam->control_buffer); | ||
1440 | } | ||
1441 | |||
1442 | /*****************************************************************************/ | ||
1443 | |||
1444 | static int sn9c102_open(struct inode* inode, struct file* filp) | ||
1445 | { | ||
1446 | struct sn9c102_device* cam; | ||
1447 | int err = 0; | ||
1448 | |||
1449 | /* | ||
1450 | This is the only safe way to prevent race conditions with | ||
1451 | disconnect | ||
1452 | */ | ||
1453 | if (!down_read_trylock(&sn9c102_disconnect)) | ||
1454 | return -ERESTARTSYS; | ||
1455 | |||
1456 | cam = video_get_drvdata(video_devdata(filp)); | ||
1457 | |||
1458 | if (mutex_lock_interruptible(&cam->dev_mutex)) { | ||
1459 | up_read(&sn9c102_disconnect); | ||
1460 | return -ERESTARTSYS; | ||
1461 | } | ||
1462 | |||
1463 | if (cam->users) { | ||
1464 | DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); | ||
1465 | if ((filp->f_flags & O_NONBLOCK) || | ||
1466 | (filp->f_flags & O_NDELAY)) { | ||
1467 | err = -EWOULDBLOCK; | ||
1468 | goto out; | ||
1469 | } | ||
1470 | mutex_unlock(&cam->dev_mutex); | ||
1471 | err = wait_event_interruptible_exclusive(cam->open, | ||
1472 | cam->state & DEV_DISCONNECTED | ||
1473 | || !cam->users); | ||
1474 | if (err) { | ||
1475 | up_read(&sn9c102_disconnect); | ||
1476 | return err; | ||
1477 | } | ||
1478 | if (cam->state & DEV_DISCONNECTED) { | ||
1479 | up_read(&sn9c102_disconnect); | ||
1480 | return -ENODEV; | ||
1481 | } | ||
1482 | mutex_lock(&cam->dev_mutex); | ||
1483 | } | ||
1484 | |||
1485 | |||
1486 | if (cam->state & DEV_MISCONFIGURED) { | ||
1487 | err = sn9c102_init(cam); | ||
1488 | if (err) { | ||
1489 | DBG(1, "Initialization failed again. " | ||
1490 | "I will retry on next open()."); | ||
1491 | goto out; | ||
1492 | } | ||
1493 | cam->state &= ~DEV_MISCONFIGURED; | ||
1494 | } | ||
1495 | |||
1496 | if ((err = sn9c102_start_transfer(cam))) | ||
1497 | goto out; | ||
1498 | |||
1499 | filp->private_data = cam; | ||
1500 | cam->users++; | ||
1501 | cam->io = IO_NONE; | ||
1502 | cam->stream = STREAM_OFF; | ||
1503 | cam->nbuffers = 0; | ||
1504 | cam->frame_count = 0; | ||
1505 | sn9c102_empty_framequeues(cam); | ||
1506 | |||
1507 | DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); | ||
1508 | |||
1509 | out: | ||
1510 | mutex_unlock(&cam->dev_mutex); | ||
1511 | up_read(&sn9c102_disconnect); | ||
1512 | return err; | ||
1513 | } | ||
1514 | |||
1515 | |||
1516 | static int sn9c102_release(struct inode* inode, struct file* filp) | ||
1517 | { | ||
1518 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1519 | |||
1520 | mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ | ||
1521 | |||
1522 | sn9c102_stop_transfer(cam); | ||
1523 | |||
1524 | sn9c102_release_buffers(cam); | ||
1525 | |||
1526 | if (cam->state & DEV_DISCONNECTED) { | ||
1527 | sn9c102_release_resources(cam); | ||
1528 | mutex_unlock(&cam->dev_mutex); | ||
1529 | kfree(cam); | ||
1530 | return 0; | ||
1531 | } | ||
1532 | |||
1533 | cam->users--; | ||
1534 | wake_up_interruptible_nr(&cam->open, 1); | ||
1535 | |||
1536 | DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); | ||
1537 | |||
1538 | mutex_unlock(&cam->dev_mutex); | ||
1539 | |||
1540 | return 0; | ||
1541 | } | ||
1542 | |||
1543 | |||
1544 | static ssize_t | ||
1545 | sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | ||
1546 | { | ||
1547 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1548 | struct sn9c102_frame_t* f, * i; | ||
1549 | unsigned long lock_flags; | ||
1550 | long timeout; | ||
1551 | int err = 0; | ||
1552 | |||
1553 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
1554 | return -ERESTARTSYS; | ||
1555 | |||
1556 | if (cam->state & DEV_DISCONNECTED) { | ||
1557 | DBG(1, "Device not present"); | ||
1558 | mutex_unlock(&cam->fileop_mutex); | ||
1559 | return -ENODEV; | ||
1560 | } | ||
1561 | |||
1562 | if (cam->state & DEV_MISCONFIGURED) { | ||
1563 | DBG(1, "The camera is misconfigured. Close and open it " | ||
1564 | "again."); | ||
1565 | mutex_unlock(&cam->fileop_mutex); | ||
1566 | return -EIO; | ||
1567 | } | ||
1568 | |||
1569 | if (cam->io == IO_MMAP) { | ||
1570 | DBG(3, "Close and open the device again to choose " | ||
1571 | "the read method"); | ||
1572 | mutex_unlock(&cam->fileop_mutex); | ||
1573 | return -EINVAL; | ||
1574 | } | ||
1575 | |||
1576 | if (cam->io == IO_NONE) { | ||
1577 | if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) { | ||
1578 | DBG(1, "read() failed, not enough memory"); | ||
1579 | mutex_unlock(&cam->fileop_mutex); | ||
1580 | return -ENOMEM; | ||
1581 | } | ||
1582 | cam->io = IO_READ; | ||
1583 | cam->stream = STREAM_ON; | ||
1584 | } | ||
1585 | |||
1586 | if (list_empty(&cam->inqueue)) { | ||
1587 | if (!list_empty(&cam->outqueue)) | ||
1588 | sn9c102_empty_framequeues(cam); | ||
1589 | sn9c102_queue_unusedframes(cam); | ||
1590 | } | ||
1591 | |||
1592 | if (!count) { | ||
1593 | mutex_unlock(&cam->fileop_mutex); | ||
1594 | return 0; | ||
1595 | } | ||
1596 | |||
1597 | if (list_empty(&cam->outqueue)) { | ||
1598 | if (filp->f_flags & O_NONBLOCK) { | ||
1599 | mutex_unlock(&cam->fileop_mutex); | ||
1600 | return -EAGAIN; | ||
1601 | } | ||
1602 | timeout = wait_event_interruptible_timeout | ||
1603 | ( cam->wait_frame, | ||
1604 | (!list_empty(&cam->outqueue)) || | ||
1605 | (cam->state & DEV_DISCONNECTED) || | ||
1606 | (cam->state & DEV_MISCONFIGURED), | ||
1607 | cam->module_param.frame_timeout * | ||
1608 | 1000 * msecs_to_jiffies(1) ); | ||
1609 | if (timeout < 0) { | ||
1610 | mutex_unlock(&cam->fileop_mutex); | ||
1611 | return timeout; | ||
1612 | } | ||
1613 | if (cam->state & DEV_DISCONNECTED) { | ||
1614 | mutex_unlock(&cam->fileop_mutex); | ||
1615 | return -ENODEV; | ||
1616 | } | ||
1617 | if (!timeout || (cam->state & DEV_MISCONFIGURED)) { | ||
1618 | mutex_unlock(&cam->fileop_mutex); | ||
1619 | return -EIO; | ||
1620 | } | ||
1621 | } | ||
1622 | |||
1623 | f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame); | ||
1624 | |||
1625 | if (count > f->buf.bytesused) | ||
1626 | count = f->buf.bytesused; | ||
1627 | |||
1628 | if (copy_to_user(buf, f->bufmem, count)) { | ||
1629 | err = -EFAULT; | ||
1630 | goto exit; | ||
1631 | } | ||
1632 | *f_pos += count; | ||
1633 | |||
1634 | exit: | ||
1635 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
1636 | list_for_each_entry(i, &cam->outqueue, frame) | ||
1637 | i->state = F_UNUSED; | ||
1638 | INIT_LIST_HEAD(&cam->outqueue); | ||
1639 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
1640 | |||
1641 | sn9c102_queue_unusedframes(cam); | ||
1642 | |||
1643 | PDBGG("Frame #%lu, bytes read: %zu", | ||
1644 | (unsigned long)f->buf.index, count); | ||
1645 | |||
1646 | mutex_unlock(&cam->fileop_mutex); | ||
1647 | |||
1648 | return count; | ||
1649 | } | ||
1650 | |||
1651 | |||
1652 | static unsigned int sn9c102_poll(struct file *filp, poll_table *wait) | ||
1653 | { | ||
1654 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1655 | struct sn9c102_frame_t* f; | ||
1656 | unsigned long lock_flags; | ||
1657 | unsigned int mask = 0; | ||
1658 | |||
1659 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
1660 | return POLLERR; | ||
1661 | |||
1662 | if (cam->state & DEV_DISCONNECTED) { | ||
1663 | DBG(1, "Device not present"); | ||
1664 | goto error; | ||
1665 | } | ||
1666 | |||
1667 | if (cam->state & DEV_MISCONFIGURED) { | ||
1668 | DBG(1, "The camera is misconfigured. Close and open it " | ||
1669 | "again."); | ||
1670 | goto error; | ||
1671 | } | ||
1672 | |||
1673 | if (cam->io == IO_NONE) { | ||
1674 | if (!sn9c102_request_buffers(cam, cam->nreadbuffers, | ||
1675 | IO_READ)) { | ||
1676 | DBG(1, "poll() failed, not enough memory"); | ||
1677 | goto error; | ||
1678 | } | ||
1679 | cam->io = IO_READ; | ||
1680 | cam->stream = STREAM_ON; | ||
1681 | } | ||
1682 | |||
1683 | if (cam->io == IO_READ) { | ||
1684 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
1685 | list_for_each_entry(f, &cam->outqueue, frame) | ||
1686 | f->state = F_UNUSED; | ||
1687 | INIT_LIST_HEAD(&cam->outqueue); | ||
1688 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
1689 | sn9c102_queue_unusedframes(cam); | ||
1690 | } | ||
1691 | |||
1692 | poll_wait(filp, &cam->wait_frame, wait); | ||
1693 | |||
1694 | if (!list_empty(&cam->outqueue)) | ||
1695 | mask |= POLLIN | POLLRDNORM; | ||
1696 | |||
1697 | mutex_unlock(&cam->fileop_mutex); | ||
1698 | |||
1699 | return mask; | ||
1700 | |||
1701 | error: | ||
1702 | mutex_unlock(&cam->fileop_mutex); | ||
1703 | return POLLERR; | ||
1704 | } | ||
1705 | |||
1706 | |||
1707 | static void sn9c102_vm_open(struct vm_area_struct* vma) | ||
1708 | { | ||
1709 | struct sn9c102_frame_t* f = vma->vm_private_data; | ||
1710 | f->vma_use_count++; | ||
1711 | } | ||
1712 | |||
1713 | |||
1714 | static void sn9c102_vm_close(struct vm_area_struct* vma) | ||
1715 | { | ||
1716 | /* NOTE: buffers are not freed here */ | ||
1717 | struct sn9c102_frame_t* f = vma->vm_private_data; | ||
1718 | f->vma_use_count--; | ||
1719 | } | ||
1720 | |||
1721 | |||
1722 | static struct vm_operations_struct sn9c102_vm_ops = { | ||
1723 | .open = sn9c102_vm_open, | ||
1724 | .close = sn9c102_vm_close, | ||
1725 | }; | ||
1726 | |||
1727 | |||
1728 | static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) | ||
1729 | { | ||
1730 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1731 | unsigned long size = vma->vm_end - vma->vm_start, | ||
1732 | start = vma->vm_start; | ||
1733 | void *pos; | ||
1734 | u32 i; | ||
1735 | |||
1736 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
1737 | return -ERESTARTSYS; | ||
1738 | |||
1739 | if (cam->state & DEV_DISCONNECTED) { | ||
1740 | DBG(1, "Device not present"); | ||
1741 | mutex_unlock(&cam->fileop_mutex); | ||
1742 | return -ENODEV; | ||
1743 | } | ||
1744 | |||
1745 | if (cam->state & DEV_MISCONFIGURED) { | ||
1746 | DBG(1, "The camera is misconfigured. Close and open it " | ||
1747 | "again."); | ||
1748 | mutex_unlock(&cam->fileop_mutex); | ||
1749 | return -EIO; | ||
1750 | } | ||
1751 | |||
1752 | if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || | ||
1753 | size != PAGE_ALIGN(cam->frame[0].buf.length)) { | ||
1754 | mutex_unlock(&cam->fileop_mutex); | ||
1755 | return -EINVAL; | ||
1756 | } | ||
1757 | |||
1758 | for (i = 0; i < cam->nbuffers; i++) { | ||
1759 | if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) | ||
1760 | break; | ||
1761 | } | ||
1762 | if (i == cam->nbuffers) { | ||
1763 | mutex_unlock(&cam->fileop_mutex); | ||
1764 | return -EINVAL; | ||
1765 | } | ||
1766 | |||
1767 | vma->vm_flags |= VM_IO; | ||
1768 | vma->vm_flags |= VM_RESERVED; | ||
1769 | |||
1770 | pos = cam->frame[i].bufmem; | ||
1771 | while (size > 0) { /* size is page-aligned */ | ||
1772 | if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { | ||
1773 | mutex_unlock(&cam->fileop_mutex); | ||
1774 | return -EAGAIN; | ||
1775 | } | ||
1776 | start += PAGE_SIZE; | ||
1777 | pos += PAGE_SIZE; | ||
1778 | size -= PAGE_SIZE; | ||
1779 | } | ||
1780 | |||
1781 | vma->vm_ops = &sn9c102_vm_ops; | ||
1782 | vma->vm_private_data = &cam->frame[i]; | ||
1783 | |||
1784 | sn9c102_vm_open(vma); | ||
1785 | |||
1786 | mutex_unlock(&cam->fileop_mutex); | ||
1787 | |||
1788 | return 0; | ||
1789 | } | ||
1790 | |||
1791 | /*****************************************************************************/ | ||
1792 | |||
1793 | static int | ||
1794 | sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg) | ||
1795 | { | ||
1796 | struct v4l2_capability cap = { | ||
1797 | .driver = "sn9c102", | ||
1798 | .version = SN9C102_MODULE_VERSION_CODE, | ||
1799 | .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | | ||
1800 | V4L2_CAP_STREAMING, | ||
1801 | }; | ||
1802 | |||
1803 | strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); | ||
1804 | if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) | ||
1805 | strlcpy(cap.bus_info, cam->usbdev->dev.bus_id, | ||
1806 | sizeof(cap.bus_info)); | ||
1807 | |||
1808 | if (copy_to_user(arg, &cap, sizeof(cap))) | ||
1809 | return -EFAULT; | ||
1810 | |||
1811 | return 0; | ||
1812 | } | ||
1813 | |||
1814 | |||
1815 | static int | ||
1816 | sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg) | ||
1817 | { | ||
1818 | struct v4l2_input i; | ||
1819 | |||
1820 | if (copy_from_user(&i, arg, sizeof(i))) | ||
1821 | return -EFAULT; | ||
1822 | |||
1823 | if (i.index) | ||
1824 | return -EINVAL; | ||
1825 | |||
1826 | memset(&i, 0, sizeof(i)); | ||
1827 | strcpy(i.name, "Camera"); | ||
1828 | i.type = V4L2_INPUT_TYPE_CAMERA; | ||
1829 | |||
1830 | if (copy_to_user(arg, &i, sizeof(i))) | ||
1831 | return -EFAULT; | ||
1832 | |||
1833 | return 0; | ||
1834 | } | ||
1835 | |||
1836 | |||
1837 | static int | ||
1838 | sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg) | ||
1839 | { | ||
1840 | int index = 0; | ||
1841 | |||
1842 | if (copy_to_user(arg, &index, sizeof(index))) | ||
1843 | return -EFAULT; | ||
1844 | |||
1845 | return 0; | ||
1846 | } | ||
1847 | |||
1848 | |||
1849 | static int | ||
1850 | sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg) | ||
1851 | { | ||
1852 | int index; | ||
1853 | |||
1854 | if (copy_from_user(&index, arg, sizeof(index))) | ||
1855 | return -EFAULT; | ||
1856 | |||
1857 | if (index != 0) | ||
1858 | return -EINVAL; | ||
1859 | |||
1860 | return 0; | ||
1861 | } | ||
1862 | |||
1863 | |||
1864 | static int | ||
1865 | sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg) | ||
1866 | { | ||
1867 | struct sn9c102_sensor* s = &cam->sensor; | ||
1868 | struct v4l2_queryctrl qc; | ||
1869 | u8 i; | ||
1870 | |||
1871 | if (copy_from_user(&qc, arg, sizeof(qc))) | ||
1872 | return -EFAULT; | ||
1873 | |||
1874 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
1875 | if (qc.id && qc.id == s->qctrl[i].id) { | ||
1876 | memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); | ||
1877 | if (copy_to_user(arg, &qc, sizeof(qc))) | ||
1878 | return -EFAULT; | ||
1879 | return 0; | ||
1880 | } | ||
1881 | |||
1882 | return -EINVAL; | ||
1883 | } | ||
1884 | |||
1885 | |||
1886 | static int | ||
1887 | sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg) | ||
1888 | { | ||
1889 | struct sn9c102_sensor* s = &cam->sensor; | ||
1890 | struct v4l2_control ctrl; | ||
1891 | int err = 0; | ||
1892 | u8 i; | ||
1893 | |||
1894 | if (!s->get_ctrl && !s->set_ctrl) | ||
1895 | return -EINVAL; | ||
1896 | |||
1897 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
1898 | return -EFAULT; | ||
1899 | |||
1900 | if (!s->get_ctrl) { | ||
1901 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
1902 | if (ctrl.id && ctrl.id == s->qctrl[i].id) { | ||
1903 | ctrl.value = s->_qctrl[i].default_value; | ||
1904 | goto exit; | ||
1905 | } | ||
1906 | return -EINVAL; | ||
1907 | } else | ||
1908 | err = s->get_ctrl(cam, &ctrl); | ||
1909 | |||
1910 | exit: | ||
1911 | if (copy_to_user(arg, &ctrl, sizeof(ctrl))) | ||
1912 | return -EFAULT; | ||
1913 | |||
1914 | return err; | ||
1915 | } | ||
1916 | |||
1917 | |||
1918 | static int | ||
1919 | sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg) | ||
1920 | { | ||
1921 | struct sn9c102_sensor* s = &cam->sensor; | ||
1922 | struct v4l2_control ctrl; | ||
1923 | u8 i; | ||
1924 | int err = 0; | ||
1925 | |||
1926 | if (!s->set_ctrl) | ||
1927 | return -EINVAL; | ||
1928 | |||
1929 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
1930 | return -EFAULT; | ||
1931 | |||
1932 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
1933 | if (ctrl.id == s->qctrl[i].id) { | ||
1934 | if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) | ||
1935 | return -EINVAL; | ||
1936 | if (ctrl.value < s->qctrl[i].minimum || | ||
1937 | ctrl.value > s->qctrl[i].maximum) | ||
1938 | return -ERANGE; | ||
1939 | ctrl.value -= ctrl.value % s->qctrl[i].step; | ||
1940 | break; | ||
1941 | } | ||
1942 | |||
1943 | if ((err = s->set_ctrl(cam, &ctrl))) | ||
1944 | return err; | ||
1945 | |||
1946 | s->_qctrl[i].default_value = ctrl.value; | ||
1947 | |||
1948 | PDBGG("VIDIOC_S_CTRL: id %lu, value %lu", | ||
1949 | (unsigned long)ctrl.id, (unsigned long)ctrl.value); | ||
1950 | |||
1951 | return 0; | ||
1952 | } | ||
1953 | |||
1954 | |||
1955 | static int | ||
1956 | sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg) | ||
1957 | { | ||
1958 | struct v4l2_cropcap* cc = &(cam->sensor.cropcap); | ||
1959 | |||
1960 | cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1961 | cc->pixelaspect.numerator = 1; | ||
1962 | cc->pixelaspect.denominator = 1; | ||
1963 | |||
1964 | if (copy_to_user(arg, cc, sizeof(*cc))) | ||
1965 | return -EFAULT; | ||
1966 | |||
1967 | return 0; | ||
1968 | } | ||
1969 | |||
1970 | |||
1971 | static int | ||
1972 | sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg) | ||
1973 | { | ||
1974 | struct sn9c102_sensor* s = &cam->sensor; | ||
1975 | struct v4l2_crop crop = { | ||
1976 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
1977 | }; | ||
1978 | |||
1979 | memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); | ||
1980 | |||
1981 | if (copy_to_user(arg, &crop, sizeof(crop))) | ||
1982 | return -EFAULT; | ||
1983 | |||
1984 | return 0; | ||
1985 | } | ||
1986 | |||
1987 | |||
1988 | static int | ||
1989 | sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) | ||
1990 | { | ||
1991 | struct sn9c102_sensor* s = &cam->sensor; | ||
1992 | struct v4l2_crop crop; | ||
1993 | struct v4l2_rect* rect; | ||
1994 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
1995 | struct v4l2_pix_format* pix_format = &(s->pix_format); | ||
1996 | u8 scale; | ||
1997 | const enum sn9c102_stream_state stream = cam->stream; | ||
1998 | const u32 nbuffers = cam->nbuffers; | ||
1999 | u32 i; | ||
2000 | int err = 0; | ||
2001 | |||
2002 | if (copy_from_user(&crop, arg, sizeof(crop))) | ||
2003 | return -EFAULT; | ||
2004 | |||
2005 | rect = &(crop.c); | ||
2006 | |||
2007 | if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2008 | return -EINVAL; | ||
2009 | |||
2010 | if (cam->module_param.force_munmap) | ||
2011 | for (i = 0; i < cam->nbuffers; i++) | ||
2012 | if (cam->frame[i].vma_use_count) { | ||
2013 | DBG(3, "VIDIOC_S_CROP failed. " | ||
2014 | "Unmap the buffers first."); | ||
2015 | return -EINVAL; | ||
2016 | } | ||
2017 | |||
2018 | /* Preserve R,G or B origin */ | ||
2019 | rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L; | ||
2020 | rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L; | ||
2021 | |||
2022 | if (rect->width < 16) | ||
2023 | rect->width = 16; | ||
2024 | if (rect->height < 16) | ||
2025 | rect->height = 16; | ||
2026 | if (rect->width > bounds->width) | ||
2027 | rect->width = bounds->width; | ||
2028 | if (rect->height > bounds->height) | ||
2029 | rect->height = bounds->height; | ||
2030 | if (rect->left < bounds->left) | ||
2031 | rect->left = bounds->left; | ||
2032 | if (rect->top < bounds->top) | ||
2033 | rect->top = bounds->top; | ||
2034 | if (rect->left + rect->width > bounds->left + bounds->width) | ||
2035 | rect->left = bounds->left+bounds->width - rect->width; | ||
2036 | if (rect->top + rect->height > bounds->top + bounds->height) | ||
2037 | rect->top = bounds->top+bounds->height - rect->height; | ||
2038 | |||
2039 | rect->width &= ~15L; | ||
2040 | rect->height &= ~15L; | ||
2041 | |||
2042 | if (SN9C102_PRESERVE_IMGSCALE) { | ||
2043 | /* Calculate the actual scaling factor */ | ||
2044 | u32 a, b; | ||
2045 | a = rect->width * rect->height; | ||
2046 | b = pix_format->width * pix_format->height; | ||
2047 | scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; | ||
2048 | } else | ||
2049 | scale = 1; | ||
2050 | |||
2051 | if (cam->stream == STREAM_ON) | ||
2052 | if ((err = sn9c102_stream_interrupt(cam))) | ||
2053 | return err; | ||
2054 | |||
2055 | if (copy_to_user(arg, &crop, sizeof(crop))) { | ||
2056 | cam->stream = stream; | ||
2057 | return -EFAULT; | ||
2058 | } | ||
2059 | |||
2060 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
2061 | sn9c102_release_buffers(cam); | ||
2062 | |||
2063 | err = sn9c102_set_crop(cam, rect); | ||
2064 | if (s->set_crop) | ||
2065 | err += s->set_crop(cam, rect); | ||
2066 | err += sn9c102_set_scale(cam, scale); | ||
2067 | |||
2068 | if (err) { /* atomic, no rollback in ioctl() */ | ||
2069 | cam->state |= DEV_MISCONFIGURED; | ||
2070 | DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " | ||
2071 | "use the camera, close and open /dev/video%d again.", | ||
2072 | cam->v4ldev->minor); | ||
2073 | return -EIO; | ||
2074 | } | ||
2075 | |||
2076 | s->pix_format.width = rect->width/scale; | ||
2077 | s->pix_format.height = rect->height/scale; | ||
2078 | memcpy(&(s->_rect), rect, sizeof(*rect)); | ||
2079 | |||
2080 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
2081 | nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { | ||
2082 | cam->state |= DEV_MISCONFIGURED; | ||
2083 | DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " | ||
2084 | "use the camera, close and open /dev/video%d again.", | ||
2085 | cam->v4ldev->minor); | ||
2086 | return -ENOMEM; | ||
2087 | } | ||
2088 | |||
2089 | if (cam->io == IO_READ) | ||
2090 | sn9c102_empty_framequeues(cam); | ||
2091 | else if (cam->module_param.force_munmap) | ||
2092 | sn9c102_requeue_outqueue(cam); | ||
2093 | |||
2094 | cam->stream = stream; | ||
2095 | |||
2096 | return 0; | ||
2097 | } | ||
2098 | |||
2099 | |||
2100 | static int | ||
2101 | sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg) | ||
2102 | { | ||
2103 | struct v4l2_fmtdesc fmtd; | ||
2104 | |||
2105 | if (copy_from_user(&fmtd, arg, sizeof(fmtd))) | ||
2106 | return -EFAULT; | ||
2107 | |||
2108 | if (fmtd.index == 0) { | ||
2109 | strcpy(fmtd.description, "bayer rgb"); | ||
2110 | fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8; | ||
2111 | } else if (fmtd.index == 1) { | ||
2112 | strcpy(fmtd.description, "compressed"); | ||
2113 | fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; | ||
2114 | fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; | ||
2115 | } else | ||
2116 | return -EINVAL; | ||
2117 | |||
2118 | fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
2119 | memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); | ||
2120 | |||
2121 | if (copy_to_user(arg, &fmtd, sizeof(fmtd))) | ||
2122 | return -EFAULT; | ||
2123 | |||
2124 | return 0; | ||
2125 | } | ||
2126 | |||
2127 | |||
2128 | static int | ||
2129 | sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg) | ||
2130 | { | ||
2131 | struct v4l2_format format; | ||
2132 | struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); | ||
2133 | |||
2134 | if (copy_from_user(&format, arg, sizeof(format))) | ||
2135 | return -EFAULT; | ||
2136 | |||
2137 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2138 | return -EINVAL; | ||
2139 | |||
2140 | pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X) | ||
2141 | ? 0 : (pfmt->width * pfmt->priv) / 8; | ||
2142 | pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); | ||
2143 | pfmt->field = V4L2_FIELD_NONE; | ||
2144 | memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); | ||
2145 | |||
2146 | if (copy_to_user(arg, &format, sizeof(format))) | ||
2147 | return -EFAULT; | ||
2148 | |||
2149 | return 0; | ||
2150 | } | ||
2151 | |||
2152 | |||
2153 | static int | ||
2154 | sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, | ||
2155 | void __user * arg) | ||
2156 | { | ||
2157 | struct sn9c102_sensor* s = &cam->sensor; | ||
2158 | struct v4l2_format format; | ||
2159 | struct v4l2_pix_format* pix; | ||
2160 | struct v4l2_pix_format* pfmt = &(s->pix_format); | ||
2161 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
2162 | struct v4l2_rect rect; | ||
2163 | u8 scale; | ||
2164 | const enum sn9c102_stream_state stream = cam->stream; | ||
2165 | const u32 nbuffers = cam->nbuffers; | ||
2166 | u32 i; | ||
2167 | int err = 0; | ||
2168 | |||
2169 | if (copy_from_user(&format, arg, sizeof(format))) | ||
2170 | return -EFAULT; | ||
2171 | |||
2172 | pix = &(format.fmt.pix); | ||
2173 | |||
2174 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2175 | return -EINVAL; | ||
2176 | |||
2177 | memcpy(&rect, &(s->_rect), sizeof(rect)); | ||
2178 | |||
2179 | { /* calculate the actual scaling factor */ | ||
2180 | u32 a, b; | ||
2181 | a = rect.width * rect.height; | ||
2182 | b = pix->width * pix->height; | ||
2183 | scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; | ||
2184 | } | ||
2185 | |||
2186 | rect.width = scale * pix->width; | ||
2187 | rect.height = scale * pix->height; | ||
2188 | |||
2189 | if (rect.width < 16) | ||
2190 | rect.width = 16; | ||
2191 | if (rect.height < 16) | ||
2192 | rect.height = 16; | ||
2193 | if (rect.width > bounds->left + bounds->width - rect.left) | ||
2194 | rect.width = bounds->left + bounds->width - rect.left; | ||
2195 | if (rect.height > bounds->top + bounds->height - rect.top) | ||
2196 | rect.height = bounds->top + bounds->height - rect.top; | ||
2197 | |||
2198 | rect.width &= ~15L; | ||
2199 | rect.height &= ~15L; | ||
2200 | |||
2201 | { /* adjust the scaling factor */ | ||
2202 | u32 a, b; | ||
2203 | a = rect.width * rect.height; | ||
2204 | b = pix->width * pix->height; | ||
2205 | scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; | ||
2206 | } | ||
2207 | |||
2208 | pix->width = rect.width / scale; | ||
2209 | pix->height = rect.height / scale; | ||
2210 | |||
2211 | if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && | ||
2212 | pix->pixelformat != V4L2_PIX_FMT_SBGGR8) | ||
2213 | pix->pixelformat = pfmt->pixelformat; | ||
2214 | pix->priv = pfmt->priv; /* bpp */ | ||
2215 | pix->colorspace = pfmt->colorspace; | ||
2216 | pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
2217 | ? 0 : (pix->width * pix->priv) / 8; | ||
2218 | pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); | ||
2219 | pix->field = V4L2_FIELD_NONE; | ||
2220 | |||
2221 | if (cmd == VIDIOC_TRY_FMT) { | ||
2222 | if (copy_to_user(arg, &format, sizeof(format))) | ||
2223 | return -EFAULT; | ||
2224 | return 0; | ||
2225 | } | ||
2226 | |||
2227 | if (cam->module_param.force_munmap) | ||
2228 | for (i = 0; i < cam->nbuffers; i++) | ||
2229 | if (cam->frame[i].vma_use_count) { | ||
2230 | DBG(3, "VIDIOC_S_FMT failed. Unmap the " | ||
2231 | "buffers first."); | ||
2232 | return -EINVAL; | ||
2233 | } | ||
2234 | |||
2235 | if (cam->stream == STREAM_ON) | ||
2236 | if ((err = sn9c102_stream_interrupt(cam))) | ||
2237 | return err; | ||
2238 | |||
2239 | if (copy_to_user(arg, &format, sizeof(format))) { | ||
2240 | cam->stream = stream; | ||
2241 | return -EFAULT; | ||
2242 | } | ||
2243 | |||
2244 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
2245 | sn9c102_release_buffers(cam); | ||
2246 | |||
2247 | err += sn9c102_set_pix_format(cam, pix); | ||
2248 | err += sn9c102_set_crop(cam, &rect); | ||
2249 | if (s->set_pix_format) | ||
2250 | err += s->set_pix_format(cam, pix); | ||
2251 | if (s->set_crop) | ||
2252 | err += s->set_crop(cam, &rect); | ||
2253 | err += sn9c102_set_scale(cam, scale); | ||
2254 | |||
2255 | if (err) { /* atomic, no rollback in ioctl() */ | ||
2256 | cam->state |= DEV_MISCONFIGURED; | ||
2257 | DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " | ||
2258 | "use the camera, close and open /dev/video%d again.", | ||
2259 | cam->v4ldev->minor); | ||
2260 | return -EIO; | ||
2261 | } | ||
2262 | |||
2263 | memcpy(pfmt, pix, sizeof(*pix)); | ||
2264 | memcpy(&(s->_rect), &rect, sizeof(rect)); | ||
2265 | |||
2266 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
2267 | nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { | ||
2268 | cam->state |= DEV_MISCONFIGURED; | ||
2269 | DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " | ||
2270 | "use the camera, close and open /dev/video%d again.", | ||
2271 | cam->v4ldev->minor); | ||
2272 | return -ENOMEM; | ||
2273 | } | ||
2274 | |||
2275 | if (cam->io == IO_READ) | ||
2276 | sn9c102_empty_framequeues(cam); | ||
2277 | else if (cam->module_param.force_munmap) | ||
2278 | sn9c102_requeue_outqueue(cam); | ||
2279 | |||
2280 | cam->stream = stream; | ||
2281 | |||
2282 | return 0; | ||
2283 | } | ||
2284 | |||
2285 | |||
2286 | static int | ||
2287 | sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg) | ||
2288 | { | ||
2289 | if (copy_to_user(arg, &cam->compression, | ||
2290 | sizeof(cam->compression))) | ||
2291 | return -EFAULT; | ||
2292 | |||
2293 | return 0; | ||
2294 | } | ||
2295 | |||
2296 | |||
2297 | static int | ||
2298 | sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg) | ||
2299 | { | ||
2300 | struct v4l2_jpegcompression jc; | ||
2301 | const enum sn9c102_stream_state stream = cam->stream; | ||
2302 | int err = 0; | ||
2303 | |||
2304 | if (copy_from_user(&jc, arg, sizeof(jc))) | ||
2305 | return -EFAULT; | ||
2306 | |||
2307 | if (jc.quality != 0 && jc.quality != 1) | ||
2308 | return -EINVAL; | ||
2309 | |||
2310 | if (cam->stream == STREAM_ON) | ||
2311 | if ((err = sn9c102_stream_interrupt(cam))) | ||
2312 | return err; | ||
2313 | |||
2314 | err += sn9c102_set_compression(cam, &jc); | ||
2315 | if (err) { /* atomic, no rollback in ioctl() */ | ||
2316 | cam->state |= DEV_MISCONFIGURED; | ||
2317 | DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " | ||
2318 | "problems. To use the camera, close and open " | ||
2319 | "/dev/video%d again.", cam->v4ldev->minor); | ||
2320 | return -EIO; | ||
2321 | } | ||
2322 | |||
2323 | cam->compression.quality = jc.quality; | ||
2324 | |||
2325 | cam->stream = stream; | ||
2326 | |||
2327 | return 0; | ||
2328 | } | ||
2329 | |||
2330 | |||
2331 | static int | ||
2332 | sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg) | ||
2333 | { | ||
2334 | struct v4l2_requestbuffers rb; | ||
2335 | u32 i; | ||
2336 | int err; | ||
2337 | |||
2338 | if (copy_from_user(&rb, arg, sizeof(rb))) | ||
2339 | return -EFAULT; | ||
2340 | |||
2341 | if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
2342 | rb.memory != V4L2_MEMORY_MMAP) | ||
2343 | return -EINVAL; | ||
2344 | |||
2345 | if (cam->io == IO_READ) { | ||
2346 | DBG(3, "Close and open the device again to choose the mmap " | ||
2347 | "I/O method"); | ||
2348 | return -EINVAL; | ||
2349 | } | ||
2350 | |||
2351 | for (i = 0; i < cam->nbuffers; i++) | ||
2352 | if (cam->frame[i].vma_use_count) { | ||
2353 | DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are " | ||
2354 | "still mapped."); | ||
2355 | return -EINVAL; | ||
2356 | } | ||
2357 | |||
2358 | if (cam->stream == STREAM_ON) | ||
2359 | if ((err = sn9c102_stream_interrupt(cam))) | ||
2360 | return err; | ||
2361 | |||
2362 | sn9c102_empty_framequeues(cam); | ||
2363 | |||
2364 | sn9c102_release_buffers(cam); | ||
2365 | if (rb.count) | ||
2366 | rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP); | ||
2367 | |||
2368 | if (copy_to_user(arg, &rb, sizeof(rb))) { | ||
2369 | sn9c102_release_buffers(cam); | ||
2370 | cam->io = IO_NONE; | ||
2371 | return -EFAULT; | ||
2372 | } | ||
2373 | |||
2374 | cam->io = rb.count ? IO_MMAP : IO_NONE; | ||
2375 | |||
2376 | return 0; | ||
2377 | } | ||
2378 | |||
2379 | |||
2380 | static int | ||
2381 | sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg) | ||
2382 | { | ||
2383 | struct v4l2_buffer b; | ||
2384 | |||
2385 | if (copy_from_user(&b, arg, sizeof(b))) | ||
2386 | return -EFAULT; | ||
2387 | |||
2388 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
2389 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
2390 | return -EINVAL; | ||
2391 | |||
2392 | memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); | ||
2393 | |||
2394 | if (cam->frame[b.index].vma_use_count) | ||
2395 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
2396 | |||
2397 | if (cam->frame[b.index].state == F_DONE) | ||
2398 | b.flags |= V4L2_BUF_FLAG_DONE; | ||
2399 | else if (cam->frame[b.index].state != F_UNUSED) | ||
2400 | b.flags |= V4L2_BUF_FLAG_QUEUED; | ||
2401 | |||
2402 | if (copy_to_user(arg, &b, sizeof(b))) | ||
2403 | return -EFAULT; | ||
2404 | |||
2405 | return 0; | ||
2406 | } | ||
2407 | |||
2408 | |||
2409 | static int | ||
2410 | sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg) | ||
2411 | { | ||
2412 | struct v4l2_buffer b; | ||
2413 | unsigned long lock_flags; | ||
2414 | |||
2415 | if (copy_from_user(&b, arg, sizeof(b))) | ||
2416 | return -EFAULT; | ||
2417 | |||
2418 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
2419 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
2420 | return -EINVAL; | ||
2421 | |||
2422 | if (cam->frame[b.index].state != F_UNUSED) | ||
2423 | return -EINVAL; | ||
2424 | |||
2425 | cam->frame[b.index].state = F_QUEUED; | ||
2426 | |||
2427 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
2428 | list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); | ||
2429 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
2430 | |||
2431 | PDBGG("Frame #%lu queued", (unsigned long)b.index); | ||
2432 | |||
2433 | return 0; | ||
2434 | } | ||
2435 | |||
2436 | |||
2437 | static int | ||
2438 | sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, | ||
2439 | void __user * arg) | ||
2440 | { | ||
2441 | struct v4l2_buffer b; | ||
2442 | struct sn9c102_frame_t *f; | ||
2443 | unsigned long lock_flags; | ||
2444 | long timeout; | ||
2445 | |||
2446 | if (copy_from_user(&b, arg, sizeof(b))) | ||
2447 | return -EFAULT; | ||
2448 | |||
2449 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
2450 | return -EINVAL; | ||
2451 | |||
2452 | if (list_empty(&cam->outqueue)) { | ||
2453 | if (cam->stream == STREAM_OFF) | ||
2454 | return -EINVAL; | ||
2455 | if (filp->f_flags & O_NONBLOCK) | ||
2456 | return -EAGAIN; | ||
2457 | timeout = wait_event_interruptible_timeout | ||
2458 | ( cam->wait_frame, | ||
2459 | (!list_empty(&cam->outqueue)) || | ||
2460 | (cam->state & DEV_DISCONNECTED) || | ||
2461 | (cam->state & DEV_MISCONFIGURED), | ||
2462 | cam->module_param.frame_timeout * | ||
2463 | 1000 * msecs_to_jiffies(1) ); | ||
2464 | if (timeout < 0) | ||
2465 | return timeout; | ||
2466 | if (cam->state & DEV_DISCONNECTED) | ||
2467 | return -ENODEV; | ||
2468 | if (!timeout || (cam->state & DEV_MISCONFIGURED)) | ||
2469 | return -EIO; | ||
2470 | } | ||
2471 | |||
2472 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
2473 | f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame); | ||
2474 | list_del(cam->outqueue.next); | ||
2475 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
2476 | |||
2477 | f->state = F_UNUSED; | ||
2478 | |||
2479 | memcpy(&b, &f->buf, sizeof(b)); | ||
2480 | if (f->vma_use_count) | ||
2481 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
2482 | |||
2483 | if (copy_to_user(arg, &b, sizeof(b))) | ||
2484 | return -EFAULT; | ||
2485 | |||
2486 | PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); | ||
2487 | |||
2488 | return 0; | ||
2489 | } | ||
2490 | |||
2491 | |||
2492 | static int | ||
2493 | sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg) | ||
2494 | { | ||
2495 | int type; | ||
2496 | |||
2497 | if (copy_from_user(&type, arg, sizeof(type))) | ||
2498 | return -EFAULT; | ||
2499 | |||
2500 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
2501 | return -EINVAL; | ||
2502 | |||
2503 | if (list_empty(&cam->inqueue)) | ||
2504 | return -EINVAL; | ||
2505 | |||
2506 | cam->stream = STREAM_ON; | ||
2507 | |||
2508 | DBG(3, "Stream on"); | ||
2509 | |||
2510 | return 0; | ||
2511 | } | ||
2512 | |||
2513 | |||
2514 | static int | ||
2515 | sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg) | ||
2516 | { | ||
2517 | int type, err; | ||
2518 | |||
2519 | if (copy_from_user(&type, arg, sizeof(type))) | ||
2520 | return -EFAULT; | ||
2521 | |||
2522 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
2523 | return -EINVAL; | ||
2524 | |||
2525 | if (cam->stream == STREAM_ON) | ||
2526 | if ((err = sn9c102_stream_interrupt(cam))) | ||
2527 | return err; | ||
2528 | |||
2529 | sn9c102_empty_framequeues(cam); | ||
2530 | |||
2531 | DBG(3, "Stream off"); | ||
2532 | |||
2533 | return 0; | ||
2534 | } | ||
2535 | |||
2536 | |||
2537 | static int | ||
2538 | sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg) | ||
2539 | { | ||
2540 | struct v4l2_streamparm sp; | ||
2541 | |||
2542 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
2543 | return -EFAULT; | ||
2544 | |||
2545 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2546 | return -EINVAL; | ||
2547 | |||
2548 | sp.parm.capture.extendedmode = 0; | ||
2549 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
2550 | |||
2551 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
2552 | return -EFAULT; | ||
2553 | |||
2554 | return 0; | ||
2555 | } | ||
2556 | |||
2557 | |||
2558 | static int | ||
2559 | sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg) | ||
2560 | { | ||
2561 | struct v4l2_streamparm sp; | ||
2562 | |||
2563 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
2564 | return -EFAULT; | ||
2565 | |||
2566 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
2567 | return -EINVAL; | ||
2568 | |||
2569 | sp.parm.capture.extendedmode = 0; | ||
2570 | |||
2571 | if (sp.parm.capture.readbuffers == 0) | ||
2572 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
2573 | |||
2574 | if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES) | ||
2575 | sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES; | ||
2576 | |||
2577 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
2578 | return -EFAULT; | ||
2579 | |||
2580 | cam->nreadbuffers = sp.parm.capture.readbuffers; | ||
2581 | |||
2582 | return 0; | ||
2583 | } | ||
2584 | |||
2585 | |||
2586 | static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp, | ||
2587 | unsigned int cmd, void __user * arg) | ||
2588 | { | ||
2589 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
2590 | |||
2591 | switch (cmd) { | ||
2592 | |||
2593 | case VIDIOC_QUERYCAP: | ||
2594 | return sn9c102_vidioc_querycap(cam, arg); | ||
2595 | |||
2596 | case VIDIOC_ENUMINPUT: | ||
2597 | return sn9c102_vidioc_enuminput(cam, arg); | ||
2598 | |||
2599 | case VIDIOC_G_INPUT: | ||
2600 | return sn9c102_vidioc_g_input(cam, arg); | ||
2601 | |||
2602 | case VIDIOC_S_INPUT: | ||
2603 | return sn9c102_vidioc_s_input(cam, arg); | ||
2604 | |||
2605 | case VIDIOC_QUERYCTRL: | ||
2606 | return sn9c102_vidioc_query_ctrl(cam, arg); | ||
2607 | |||
2608 | case VIDIOC_G_CTRL: | ||
2609 | return sn9c102_vidioc_g_ctrl(cam, arg); | ||
2610 | |||
2611 | case VIDIOC_S_CTRL_OLD: | ||
2612 | case VIDIOC_S_CTRL: | ||
2613 | return sn9c102_vidioc_s_ctrl(cam, arg); | ||
2614 | |||
2615 | case VIDIOC_CROPCAP_OLD: | ||
2616 | case VIDIOC_CROPCAP: | ||
2617 | return sn9c102_vidioc_cropcap(cam, arg); | ||
2618 | |||
2619 | case VIDIOC_G_CROP: | ||
2620 | return sn9c102_vidioc_g_crop(cam, arg); | ||
2621 | |||
2622 | case VIDIOC_S_CROP: | ||
2623 | return sn9c102_vidioc_s_crop(cam, arg); | ||
2624 | |||
2625 | case VIDIOC_ENUM_FMT: | ||
2626 | return sn9c102_vidioc_enum_fmt(cam, arg); | ||
2627 | |||
2628 | case VIDIOC_G_FMT: | ||
2629 | return sn9c102_vidioc_g_fmt(cam, arg); | ||
2630 | |||
2631 | case VIDIOC_TRY_FMT: | ||
2632 | case VIDIOC_S_FMT: | ||
2633 | return sn9c102_vidioc_try_s_fmt(cam, cmd, arg); | ||
2634 | |||
2635 | case VIDIOC_G_JPEGCOMP: | ||
2636 | return sn9c102_vidioc_g_jpegcomp(cam, arg); | ||
2637 | |||
2638 | case VIDIOC_S_JPEGCOMP: | ||
2639 | return sn9c102_vidioc_s_jpegcomp(cam, arg); | ||
2640 | |||
2641 | case VIDIOC_REQBUFS: | ||
2642 | return sn9c102_vidioc_reqbufs(cam, arg); | ||
2643 | |||
2644 | case VIDIOC_QUERYBUF: | ||
2645 | return sn9c102_vidioc_querybuf(cam, arg); | ||
2646 | |||
2647 | case VIDIOC_QBUF: | ||
2648 | return sn9c102_vidioc_qbuf(cam, arg); | ||
2649 | |||
2650 | case VIDIOC_DQBUF: | ||
2651 | return sn9c102_vidioc_dqbuf(cam, filp, arg); | ||
2652 | |||
2653 | case VIDIOC_STREAMON: | ||
2654 | return sn9c102_vidioc_streamon(cam, arg); | ||
2655 | |||
2656 | case VIDIOC_STREAMOFF: | ||
2657 | return sn9c102_vidioc_streamoff(cam, arg); | ||
2658 | |||
2659 | case VIDIOC_G_PARM: | ||
2660 | return sn9c102_vidioc_g_parm(cam, arg); | ||
2661 | |||
2662 | case VIDIOC_S_PARM_OLD: | ||
2663 | case VIDIOC_S_PARM: | ||
2664 | return sn9c102_vidioc_s_parm(cam, arg); | ||
2665 | |||
2666 | case VIDIOC_G_STD: | ||
2667 | case VIDIOC_S_STD: | ||
2668 | case VIDIOC_QUERYSTD: | ||
2669 | case VIDIOC_ENUMSTD: | ||
2670 | case VIDIOC_QUERYMENU: | ||
2671 | return -EINVAL; | ||
2672 | |||
2673 | default: | ||
2674 | return -EINVAL; | ||
2675 | |||
2676 | } | ||
2677 | } | ||
2678 | |||
2679 | |||
2680 | static int sn9c102_ioctl(struct inode* inode, struct file* filp, | ||
2681 | unsigned int cmd, unsigned long arg) | ||
2682 | { | ||
2683 | struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); | ||
2684 | int err = 0; | ||
2685 | |||
2686 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
2687 | return -ERESTARTSYS; | ||
2688 | |||
2689 | if (cam->state & DEV_DISCONNECTED) { | ||
2690 | DBG(1, "Device not present"); | ||
2691 | mutex_unlock(&cam->fileop_mutex); | ||
2692 | return -ENODEV; | ||
2693 | } | ||
2694 | |||
2695 | if (cam->state & DEV_MISCONFIGURED) { | ||
2696 | DBG(1, "The camera is misconfigured. Close and open it " | ||
2697 | "again."); | ||
2698 | mutex_unlock(&cam->fileop_mutex); | ||
2699 | return -EIO; | ||
2700 | } | ||
2701 | |||
2702 | V4LDBG(3, "sn9c102", cmd); | ||
2703 | |||
2704 | err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); | ||
2705 | |||
2706 | mutex_unlock(&cam->fileop_mutex); | ||
2707 | |||
2708 | return err; | ||
2709 | } | ||
2710 | |||
2711 | /*****************************************************************************/ | ||
2712 | |||
2713 | static struct file_operations sn9c102_fops = { | ||
2714 | .owner = THIS_MODULE, | ||
2715 | .open = sn9c102_open, | ||
2716 | .release = sn9c102_release, | ||
2717 | .ioctl = sn9c102_ioctl, | ||
2718 | .read = sn9c102_read, | ||
2719 | .poll = sn9c102_poll, | ||
2720 | .mmap = sn9c102_mmap, | ||
2721 | .llseek = no_llseek, | ||
2722 | }; | ||
2723 | |||
2724 | /*****************************************************************************/ | ||
2725 | |||
2726 | /* It exists a single interface only. We do not need to validate anything. */ | ||
2727 | static int | ||
2728 | sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | ||
2729 | { | ||
2730 | struct usb_device *udev = interface_to_usbdev(intf); | ||
2731 | struct sn9c102_device* cam; | ||
2732 | static unsigned int dev_nr = 0; | ||
2733 | unsigned int i; | ||
2734 | int err = 0, r; | ||
2735 | |||
2736 | if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL))) | ||
2737 | return -ENOMEM; | ||
2738 | |||
2739 | cam->usbdev = udev; | ||
2740 | |||
2741 | if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) { | ||
2742 | DBG(1, "kmalloc() failed"); | ||
2743 | err = -ENOMEM; | ||
2744 | goto fail; | ||
2745 | } | ||
2746 | |||
2747 | if (!(cam->v4ldev = video_device_alloc())) { | ||
2748 | DBG(1, "video_device_alloc() failed"); | ||
2749 | err = -ENOMEM; | ||
2750 | goto fail; | ||
2751 | } | ||
2752 | |||
2753 | mutex_init(&cam->dev_mutex); | ||
2754 | |||
2755 | r = sn9c102_read_reg(cam, 0x00); | ||
2756 | if (r < 0 || r != 0x10) { | ||
2757 | DBG(1, "Sorry, this is not a SN9C10x based camera " | ||
2758 | "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct); | ||
2759 | err = -ENODEV; | ||
2760 | goto fail; | ||
2761 | } | ||
2762 | |||
2763 | cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ? | ||
2764 | BRIDGE_SN9C103 : BRIDGE_SN9C102; | ||
2765 | switch (cam->bridge) { | ||
2766 | case BRIDGE_SN9C101: | ||
2767 | case BRIDGE_SN9C102: | ||
2768 | DBG(2, "SN9C10[12] PC Camera Controller detected " | ||
2769 | "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct); | ||
2770 | break; | ||
2771 | case BRIDGE_SN9C103: | ||
2772 | DBG(2, "SN9C103 PC Camera Controller detected " | ||
2773 | "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct); | ||
2774 | break; | ||
2775 | } | ||
2776 | |||
2777 | for (i = 0; sn9c102_sensor_table[i]; i++) { | ||
2778 | err = sn9c102_sensor_table[i](cam); | ||
2779 | if (!err) | ||
2780 | break; | ||
2781 | } | ||
2782 | |||
2783 | if (!err) { | ||
2784 | DBG(2, "%s image sensor detected", cam->sensor.name); | ||
2785 | DBG(3, "Support for %s maintained by %s", | ||
2786 | cam->sensor.name, cam->sensor.maintainer); | ||
2787 | } else { | ||
2788 | DBG(1, "No supported image sensor detected"); | ||
2789 | err = -ENODEV; | ||
2790 | goto fail; | ||
2791 | } | ||
2792 | |||
2793 | if (sn9c102_init(cam)) { | ||
2794 | DBG(1, "Initialization failed. I will retry on open()."); | ||
2795 | cam->state |= DEV_MISCONFIGURED; | ||
2796 | } | ||
2797 | |||
2798 | strcpy(cam->v4ldev->name, "SN9C10x PC Camera"); | ||
2799 | cam->v4ldev->owner = THIS_MODULE; | ||
2800 | cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; | ||
2801 | cam->v4ldev->hardware = 0; | ||
2802 | cam->v4ldev->fops = &sn9c102_fops; | ||
2803 | cam->v4ldev->minor = video_nr[dev_nr]; | ||
2804 | cam->v4ldev->release = video_device_release; | ||
2805 | video_set_drvdata(cam->v4ldev, cam); | ||
2806 | |||
2807 | mutex_lock(&cam->dev_mutex); | ||
2808 | |||
2809 | err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, | ||
2810 | video_nr[dev_nr]); | ||
2811 | if (err) { | ||
2812 | DBG(1, "V4L2 device registration failed"); | ||
2813 | if (err == -ENFILE && video_nr[dev_nr] == -1) | ||
2814 | DBG(1, "Free /dev/videoX node not found"); | ||
2815 | video_nr[dev_nr] = -1; | ||
2816 | dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
2817 | mutex_unlock(&cam->dev_mutex); | ||
2818 | goto fail; | ||
2819 | } | ||
2820 | |||
2821 | DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); | ||
2822 | |||
2823 | cam->module_param.force_munmap = force_munmap[dev_nr]; | ||
2824 | cam->module_param.frame_timeout = frame_timeout[dev_nr]; | ||
2825 | |||
2826 | dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
2827 | |||
2828 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
2829 | sn9c102_create_sysfs(cam); | ||
2830 | DBG(2, "Optional device control through 'sysfs' interface ready"); | ||
2831 | #endif | ||
2832 | |||
2833 | usb_set_intfdata(intf, cam); | ||
2834 | |||
2835 | mutex_unlock(&cam->dev_mutex); | ||
2836 | |||
2837 | return 0; | ||
2838 | |||
2839 | fail: | ||
2840 | if (cam) { | ||
2841 | kfree(cam->control_buffer); | ||
2842 | if (cam->v4ldev) | ||
2843 | video_device_release(cam->v4ldev); | ||
2844 | kfree(cam); | ||
2845 | } | ||
2846 | return err; | ||
2847 | } | ||
2848 | |||
2849 | |||
2850 | static void sn9c102_usb_disconnect(struct usb_interface* intf) | ||
2851 | { | ||
2852 | struct sn9c102_device* cam = usb_get_intfdata(intf); | ||
2853 | |||
2854 | if (!cam) | ||
2855 | return; | ||
2856 | |||
2857 | down_write(&sn9c102_disconnect); | ||
2858 | |||
2859 | mutex_lock(&cam->dev_mutex); | ||
2860 | |||
2861 | DBG(2, "Disconnecting %s...", cam->v4ldev->name); | ||
2862 | |||
2863 | wake_up_interruptible_all(&cam->open); | ||
2864 | |||
2865 | if (cam->users) { | ||
2866 | DBG(2, "Device /dev/video%d is open! Deregistration and " | ||
2867 | "memory deallocation are deferred on close.", | ||
2868 | cam->v4ldev->minor); | ||
2869 | cam->state |= DEV_MISCONFIGURED; | ||
2870 | sn9c102_stop_transfer(cam); | ||
2871 | cam->state |= DEV_DISCONNECTED; | ||
2872 | wake_up_interruptible(&cam->wait_frame); | ||
2873 | wake_up(&cam->wait_stream); | ||
2874 | usb_get_dev(cam->usbdev); | ||
2875 | } else { | ||
2876 | cam->state |= DEV_DISCONNECTED; | ||
2877 | sn9c102_release_resources(cam); | ||
2878 | } | ||
2879 | |||
2880 | mutex_unlock(&cam->dev_mutex); | ||
2881 | |||
2882 | if (!cam->users) | ||
2883 | kfree(cam); | ||
2884 | |||
2885 | up_write(&sn9c102_disconnect); | ||
2886 | } | ||
2887 | |||
2888 | |||
2889 | static struct usb_driver sn9c102_usb_driver = { | ||
2890 | .name = "sn9c102", | ||
2891 | .id_table = sn9c102_id_table, | ||
2892 | .probe = sn9c102_usb_probe, | ||
2893 | .disconnect = sn9c102_usb_disconnect, | ||
2894 | }; | ||
2895 | |||
2896 | /*****************************************************************************/ | ||
2897 | |||
2898 | static int __init sn9c102_module_init(void) | ||
2899 | { | ||
2900 | int err = 0; | ||
2901 | |||
2902 | KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION); | ||
2903 | KDBG(3, SN9C102_MODULE_AUTHOR); | ||
2904 | |||
2905 | if ((err = usb_register(&sn9c102_usb_driver))) | ||
2906 | KDBG(1, "usb_register() failed"); | ||
2907 | |||
2908 | return err; | ||
2909 | } | ||
2910 | |||
2911 | |||
2912 | static void __exit sn9c102_module_exit(void) | ||
2913 | { | ||
2914 | usb_deregister(&sn9c102_usb_driver); | ||
2915 | } | ||
2916 | |||
2917 | |||
2918 | module_init(sn9c102_module_init); | ||
2919 | module_exit(sn9c102_module_exit); | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/drivers/media/video/sn9c102/sn9c102_hv7131d.c new file mode 100644 index 000000000000..46c12ec3ca62 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_hv7131d.c | |||
@@ -0,0 +1,271 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include "sn9c102_sensor.h" | ||
23 | |||
24 | |||
25 | static struct sn9c102_sensor hv7131d; | ||
26 | |||
27 | |||
28 | static int hv7131d_init(struct sn9c102_device* cam) | ||
29 | { | ||
30 | int err = 0; | ||
31 | |||
32 | err += sn9c102_write_reg(cam, 0x00, 0x10); | ||
33 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
34 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
35 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
36 | err += sn9c102_write_reg(cam, 0x0e, 0x18); | ||
37 | err += sn9c102_write_reg(cam, 0xf2, 0x19); | ||
38 | |||
39 | err += sn9c102_i2c_write(cam, 0x01, 0x04); | ||
40 | err += sn9c102_i2c_write(cam, 0x02, 0x00); | ||
41 | err += sn9c102_i2c_write(cam, 0x28, 0x00); | ||
42 | |||
43 | return err; | ||
44 | } | ||
45 | |||
46 | |||
47 | static int hv7131d_get_ctrl(struct sn9c102_device* cam, | ||
48 | struct v4l2_control* ctrl) | ||
49 | { | ||
50 | switch (ctrl->id) { | ||
51 | case V4L2_CID_EXPOSURE: | ||
52 | { | ||
53 | int r1 = sn9c102_i2c_read(cam, 0x26), | ||
54 | r2 = sn9c102_i2c_read(cam, 0x27); | ||
55 | if (r1 < 0 || r2 < 0) | ||
56 | return -EIO; | ||
57 | ctrl->value = (r1 << 8) | (r2 & 0xff); | ||
58 | } | ||
59 | return 0; | ||
60 | case V4L2_CID_RED_BALANCE: | ||
61 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0) | ||
62 | return -EIO; | ||
63 | ctrl->value = 0x3f - (ctrl->value & 0x3f); | ||
64 | return 0; | ||
65 | case V4L2_CID_BLUE_BALANCE: | ||
66 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0) | ||
67 | return -EIO; | ||
68 | ctrl->value = 0x3f - (ctrl->value & 0x3f); | ||
69 | return 0; | ||
70 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
71 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0) | ||
72 | return -EIO; | ||
73 | ctrl->value = 0x3f - (ctrl->value & 0x3f); | ||
74 | return 0; | ||
75 | case SN9C102_V4L2_CID_RESET_LEVEL: | ||
76 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0) | ||
77 | return -EIO; | ||
78 | ctrl->value &= 0x3f; | ||
79 | return 0; | ||
80 | case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE: | ||
81 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0) | ||
82 | return -EIO; | ||
83 | ctrl->value &= 0x07; | ||
84 | return 0; | ||
85 | default: | ||
86 | return -EINVAL; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | |||
91 | static int hv7131d_set_ctrl(struct sn9c102_device* cam, | ||
92 | const struct v4l2_control* ctrl) | ||
93 | { | ||
94 | int err = 0; | ||
95 | |||
96 | switch (ctrl->id) { | ||
97 | case V4L2_CID_EXPOSURE: | ||
98 | err += sn9c102_i2c_write(cam, 0x26, ctrl->value >> 8); | ||
99 | err += sn9c102_i2c_write(cam, 0x27, ctrl->value & 0xff); | ||
100 | break; | ||
101 | case V4L2_CID_RED_BALANCE: | ||
102 | err += sn9c102_i2c_write(cam, 0x31, 0x3f - ctrl->value); | ||
103 | break; | ||
104 | case V4L2_CID_BLUE_BALANCE: | ||
105 | err += sn9c102_i2c_write(cam, 0x33, 0x3f - ctrl->value); | ||
106 | break; | ||
107 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
108 | err += sn9c102_i2c_write(cam, 0x32, 0x3f - ctrl->value); | ||
109 | break; | ||
110 | case SN9C102_V4L2_CID_RESET_LEVEL: | ||
111 | err += sn9c102_i2c_write(cam, 0x30, ctrl->value); | ||
112 | break; | ||
113 | case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE: | ||
114 | err += sn9c102_i2c_write(cam, 0x34, ctrl->value); | ||
115 | break; | ||
116 | default: | ||
117 | return -EINVAL; | ||
118 | } | ||
119 | |||
120 | return err ? -EIO : 0; | ||
121 | } | ||
122 | |||
123 | |||
124 | static int hv7131d_set_crop(struct sn9c102_device* cam, | ||
125 | const struct v4l2_rect* rect) | ||
126 | { | ||
127 | struct sn9c102_sensor* s = &hv7131d; | ||
128 | int err = 0; | ||
129 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2, | ||
130 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; | ||
131 | |||
132 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
133 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
134 | |||
135 | return err; | ||
136 | } | ||
137 | |||
138 | |||
139 | static int hv7131d_set_pix_format(struct sn9c102_device* cam, | ||
140 | const struct v4l2_pix_format* pix) | ||
141 | { | ||
142 | int err = 0; | ||
143 | |||
144 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
145 | err += sn9c102_write_reg(cam, 0x42, 0x19); | ||
146 | else | ||
147 | err += sn9c102_write_reg(cam, 0xf2, 0x19); | ||
148 | |||
149 | return err; | ||
150 | } | ||
151 | |||
152 | |||
153 | static struct sn9c102_sensor hv7131d = { | ||
154 | .name = "HV7131D", | ||
155 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
156 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
157 | .frequency = SN9C102_I2C_100KHZ, | ||
158 | .interface = SN9C102_I2C_2WIRES, | ||
159 | .i2c_slave_id = 0x11, | ||
160 | .init = &hv7131d_init, | ||
161 | .qctrl = { | ||
162 | { | ||
163 | .id = V4L2_CID_EXPOSURE, | ||
164 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
165 | .name = "exposure", | ||
166 | .minimum = 0x0250, | ||
167 | .maximum = 0xffff, | ||
168 | .step = 0x0001, | ||
169 | .default_value = 0x0250, | ||
170 | .flags = 0, | ||
171 | }, | ||
172 | { | ||
173 | .id = V4L2_CID_RED_BALANCE, | ||
174 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
175 | .name = "red balance", | ||
176 | .minimum = 0x00, | ||
177 | .maximum = 0x3f, | ||
178 | .step = 0x01, | ||
179 | .default_value = 0x00, | ||
180 | .flags = 0, | ||
181 | }, | ||
182 | { | ||
183 | .id = V4L2_CID_BLUE_BALANCE, | ||
184 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
185 | .name = "blue balance", | ||
186 | .minimum = 0x00, | ||
187 | .maximum = 0x3f, | ||
188 | .step = 0x01, | ||
189 | .default_value = 0x20, | ||
190 | .flags = 0, | ||
191 | }, | ||
192 | { | ||
193 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
194 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
195 | .name = "green balance", | ||
196 | .minimum = 0x00, | ||
197 | .maximum = 0x3f, | ||
198 | .step = 0x01, | ||
199 | .default_value = 0x1e, | ||
200 | .flags = 0, | ||
201 | }, | ||
202 | { | ||
203 | .id = SN9C102_V4L2_CID_RESET_LEVEL, | ||
204 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
205 | .name = "reset level", | ||
206 | .minimum = 0x19, | ||
207 | .maximum = 0x3f, | ||
208 | .step = 0x01, | ||
209 | .default_value = 0x30, | ||
210 | .flags = 0, | ||
211 | }, | ||
212 | { | ||
213 | .id = SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE, | ||
214 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
215 | .name = "pixel bias voltage", | ||
216 | .minimum = 0x00, | ||
217 | .maximum = 0x07, | ||
218 | .step = 0x01, | ||
219 | .default_value = 0x02, | ||
220 | .flags = 0, | ||
221 | }, | ||
222 | }, | ||
223 | .get_ctrl = &hv7131d_get_ctrl, | ||
224 | .set_ctrl = &hv7131d_set_ctrl, | ||
225 | .cropcap = { | ||
226 | .bounds = { | ||
227 | .left = 0, | ||
228 | .top = 0, | ||
229 | .width = 640, | ||
230 | .height = 480, | ||
231 | }, | ||
232 | .defrect = { | ||
233 | .left = 0, | ||
234 | .top = 0, | ||
235 | .width = 640, | ||
236 | .height = 480, | ||
237 | }, | ||
238 | }, | ||
239 | .set_crop = &hv7131d_set_crop, | ||
240 | .pix_format = { | ||
241 | .width = 640, | ||
242 | .height = 480, | ||
243 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
244 | .priv = 8, | ||
245 | }, | ||
246 | .set_pix_format = &hv7131d_set_pix_format | ||
247 | }; | ||
248 | |||
249 | |||
250 | int sn9c102_probe_hv7131d(struct sn9c102_device* cam) | ||
251 | { | ||
252 | int r0 = 0, r1 = 0, err = 0; | ||
253 | |||
254 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
255 | err += sn9c102_write_reg(cam, 0x00, 0x01); | ||
256 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
257 | if (err) | ||
258 | return -EIO; | ||
259 | |||
260 | r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00); | ||
261 | r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01); | ||
262 | if (r0 < 0 || r1 < 0) | ||
263 | return -EIO; | ||
264 | |||
265 | if (r0 != 0x00 && r1 != 0x04) | ||
266 | return -ENODEV; | ||
267 | |||
268 | sn9c102_attach_sensor(cam, &hv7131d); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0343.c b/drivers/media/video/sn9c102/sn9c102_mi0343.c new file mode 100644 index 000000000000..d9aa7a61095d --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_mi0343.c | |||
@@ -0,0 +1,363 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include "sn9c102_sensor.h" | ||
23 | |||
24 | |||
25 | static struct sn9c102_sensor mi0343; | ||
26 | static u8 mi0343_i2c_data[5+1]; | ||
27 | |||
28 | |||
29 | static int mi0343_init(struct sn9c102_device* cam) | ||
30 | { | ||
31 | int err = 0; | ||
32 | |||
33 | err += sn9c102_write_reg(cam, 0x00, 0x10); | ||
34 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
35 | err += sn9c102_write_reg(cam, 0x0a, 0x14); | ||
36 | err += sn9c102_write_reg(cam, 0x40, 0x01); | ||
37 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
38 | err += sn9c102_write_reg(cam, 0x07, 0x18); | ||
39 | err += sn9c102_write_reg(cam, 0xa0, 0x19); | ||
40 | |||
41 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
42 | 0x0d, 0x00, 0x01, 0, 0); | ||
43 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
44 | 0x0d, 0x00, 0x00, 0, 0); | ||
45 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
46 | 0x03, 0x01, 0xe1, 0, 0); | ||
47 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
48 | 0x04, 0x02, 0x81, 0, 0); | ||
49 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
50 | 0x05, 0x00, 0x17, 0, 0); | ||
51 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
52 | 0x06, 0x00, 0x11, 0, 0); | ||
53 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
54 | 0x62, 0x04, 0x9a, 0, 0); | ||
55 | |||
56 | return err; | ||
57 | } | ||
58 | |||
59 | |||
60 | static int mi0343_get_ctrl(struct sn9c102_device* cam, | ||
61 | struct v4l2_control* ctrl) | ||
62 | { | ||
63 | switch (ctrl->id) { | ||
64 | case V4L2_CID_EXPOSURE: | ||
65 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | ||
66 | 0x09, 2+1, mi0343_i2c_data) < 0) | ||
67 | return -EIO; | ||
68 | ctrl->value = mi0343_i2c_data[2]; | ||
69 | return 0; | ||
70 | case V4L2_CID_GAIN: | ||
71 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | ||
72 | 0x35, 2+1, mi0343_i2c_data) < 0) | ||
73 | return -EIO; | ||
74 | break; | ||
75 | case V4L2_CID_HFLIP: | ||
76 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | ||
77 | 0x20, 2+1, mi0343_i2c_data) < 0) | ||
78 | return -EIO; | ||
79 | ctrl->value = mi0343_i2c_data[3] & 0x20 ? 1 : 0; | ||
80 | return 0; | ||
81 | case V4L2_CID_VFLIP: | ||
82 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | ||
83 | 0x20, 2+1, mi0343_i2c_data) < 0) | ||
84 | return -EIO; | ||
85 | ctrl->value = mi0343_i2c_data[3] & 0x80 ? 1 : 0; | ||
86 | return 0; | ||
87 | case V4L2_CID_RED_BALANCE: | ||
88 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | ||
89 | 0x2d, 2+1, mi0343_i2c_data) < 0) | ||
90 | return -EIO; | ||
91 | break; | ||
92 | case V4L2_CID_BLUE_BALANCE: | ||
93 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | ||
94 | 0x2c, 2+1, mi0343_i2c_data) < 0) | ||
95 | return -EIO; | ||
96 | break; | ||
97 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
98 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | ||
99 | 0x2e, 2+1, mi0343_i2c_data) < 0) | ||
100 | return -EIO; | ||
101 | break; | ||
102 | default: | ||
103 | return -EINVAL; | ||
104 | } | ||
105 | |||
106 | switch (ctrl->id) { | ||
107 | case V4L2_CID_GAIN: | ||
108 | case V4L2_CID_RED_BALANCE: | ||
109 | case V4L2_CID_BLUE_BALANCE: | ||
110 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
111 | ctrl->value = mi0343_i2c_data[3] | (mi0343_i2c_data[2] << 8); | ||
112 | if (ctrl->value >= 0x10 && ctrl->value <= 0x3f) | ||
113 | ctrl->value -= 0x10; | ||
114 | else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f) | ||
115 | ctrl->value -= 0x60; | ||
116 | else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff) | ||
117 | ctrl->value -= 0xe0; | ||
118 | } | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | |||
124 | static int mi0343_set_ctrl(struct sn9c102_device* cam, | ||
125 | const struct v4l2_control* ctrl) | ||
126 | { | ||
127 | u16 reg = 0; | ||
128 | int err = 0; | ||
129 | |||
130 | switch (ctrl->id) { | ||
131 | case V4L2_CID_GAIN: | ||
132 | case V4L2_CID_RED_BALANCE: | ||
133 | case V4L2_CID_BLUE_BALANCE: | ||
134 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
135 | if (ctrl->value <= (0x3f-0x10)) | ||
136 | reg = 0x10 + ctrl->value; | ||
137 | else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60))) | ||
138 | reg = 0x60 + (ctrl->value - (0x3f-0x10)); | ||
139 | else | ||
140 | reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60)); | ||
141 | break; | ||
142 | } | ||
143 | |||
144 | switch (ctrl->id) { | ||
145 | case V4L2_CID_EXPOSURE: | ||
146 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
147 | mi0343.i2c_slave_id, | ||
148 | 0x09, ctrl->value, 0x00, | ||
149 | 0, 0); | ||
150 | break; | ||
151 | case V4L2_CID_GAIN: | ||
152 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
153 | mi0343.i2c_slave_id, | ||
154 | 0x35, reg >> 8, reg & 0xff, | ||
155 | 0, 0); | ||
156 | break; | ||
157 | case V4L2_CID_HFLIP: | ||
158 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
159 | mi0343.i2c_slave_id, | ||
160 | 0x20, ctrl->value ? 0x40:0x00, | ||
161 | ctrl->value ? 0x20:0x00, | ||
162 | 0, 0); | ||
163 | break; | ||
164 | case V4L2_CID_VFLIP: | ||
165 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
166 | mi0343.i2c_slave_id, | ||
167 | 0x20, ctrl->value ? 0x80:0x00, | ||
168 | ctrl->value ? 0x80:0x00, | ||
169 | 0, 0); | ||
170 | break; | ||
171 | case V4L2_CID_RED_BALANCE: | ||
172 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
173 | mi0343.i2c_slave_id, | ||
174 | 0x2d, reg >> 8, reg & 0xff, | ||
175 | 0, 0); | ||
176 | break; | ||
177 | case V4L2_CID_BLUE_BALANCE: | ||
178 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
179 | mi0343.i2c_slave_id, | ||
180 | 0x2c, reg >> 8, reg & 0xff, | ||
181 | 0, 0); | ||
182 | break; | ||
183 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
184 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
185 | mi0343.i2c_slave_id, | ||
186 | 0x2b, reg >> 8, reg & 0xff, | ||
187 | 0, 0); | ||
188 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
189 | mi0343.i2c_slave_id, | ||
190 | 0x2e, reg >> 8, reg & 0xff, | ||
191 | 0, 0); | ||
192 | break; | ||
193 | default: | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | return err ? -EIO : 0; | ||
198 | } | ||
199 | |||
200 | |||
201 | static int mi0343_set_crop(struct sn9c102_device* cam, | ||
202 | const struct v4l2_rect* rect) | ||
203 | { | ||
204 | struct sn9c102_sensor* s = &mi0343; | ||
205 | int err = 0; | ||
206 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0, | ||
207 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; | ||
208 | |||
209 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
210 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
211 | |||
212 | return err; | ||
213 | } | ||
214 | |||
215 | |||
216 | static int mi0343_set_pix_format(struct sn9c102_device* cam, | ||
217 | const struct v4l2_pix_format* pix) | ||
218 | { | ||
219 | int err = 0; | ||
220 | |||
221 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { | ||
222 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
223 | mi0343.i2c_slave_id, | ||
224 | 0x0a, 0x00, 0x03, 0, 0); | ||
225 | err += sn9c102_write_reg(cam, 0x20, 0x19); | ||
226 | } else { | ||
227 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | ||
228 | mi0343.i2c_slave_id, | ||
229 | 0x0a, 0x00, 0x05, 0, 0); | ||
230 | err += sn9c102_write_reg(cam, 0xa0, 0x19); | ||
231 | } | ||
232 | |||
233 | return err; | ||
234 | } | ||
235 | |||
236 | |||
237 | static struct sn9c102_sensor mi0343 = { | ||
238 | .name = "MI-0343", | ||
239 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
240 | .frequency = SN9C102_I2C_100KHZ, | ||
241 | .interface = SN9C102_I2C_2WIRES, | ||
242 | .i2c_slave_id = 0x5d, | ||
243 | .init = &mi0343_init, | ||
244 | .qctrl = { | ||
245 | { | ||
246 | .id = V4L2_CID_EXPOSURE, | ||
247 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
248 | .name = "exposure", | ||
249 | .minimum = 0x00, | ||
250 | .maximum = 0x0f, | ||
251 | .step = 0x01, | ||
252 | .default_value = 0x06, | ||
253 | .flags = 0, | ||
254 | }, | ||
255 | { | ||
256 | .id = V4L2_CID_GAIN, | ||
257 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
258 | .name = "global gain", | ||
259 | .minimum = 0x00, | ||
260 | .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/ | ||
261 | .step = 0x01, | ||
262 | .default_value = 0x00, | ||
263 | .flags = 0, | ||
264 | }, | ||
265 | { | ||
266 | .id = V4L2_CID_HFLIP, | ||
267 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
268 | .name = "horizontal mirror", | ||
269 | .minimum = 0, | ||
270 | .maximum = 1, | ||
271 | .step = 1, | ||
272 | .default_value = 0, | ||
273 | .flags = 0, | ||
274 | }, | ||
275 | { | ||
276 | .id = V4L2_CID_VFLIP, | ||
277 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
278 | .name = "vertical mirror", | ||
279 | .minimum = 0, | ||
280 | .maximum = 1, | ||
281 | .step = 1, | ||
282 | .default_value = 0, | ||
283 | .flags = 0, | ||
284 | }, | ||
285 | { | ||
286 | .id = V4L2_CID_RED_BALANCE, | ||
287 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
288 | .name = "red balance", | ||
289 | .minimum = 0x00, | ||
290 | .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0), | ||
291 | .step = 0x01, | ||
292 | .default_value = 0x00, | ||
293 | .flags = 0, | ||
294 | }, | ||
295 | { | ||
296 | .id = V4L2_CID_BLUE_BALANCE, | ||
297 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
298 | .name = "blue balance", | ||
299 | .minimum = 0x00, | ||
300 | .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0), | ||
301 | .step = 0x01, | ||
302 | .default_value = 0x00, | ||
303 | .flags = 0, | ||
304 | }, | ||
305 | { | ||
306 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
307 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
308 | .name = "green balance", | ||
309 | .minimum = 0x00, | ||
310 | .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)), | ||
311 | .step = 0x01, | ||
312 | .default_value = 0x00, | ||
313 | .flags = 0, | ||
314 | }, | ||
315 | }, | ||
316 | .get_ctrl = &mi0343_get_ctrl, | ||
317 | .set_ctrl = &mi0343_set_ctrl, | ||
318 | .cropcap = { | ||
319 | .bounds = { | ||
320 | .left = 0, | ||
321 | .top = 0, | ||
322 | .width = 640, | ||
323 | .height = 480, | ||
324 | }, | ||
325 | .defrect = { | ||
326 | .left = 0, | ||
327 | .top = 0, | ||
328 | .width = 640, | ||
329 | .height = 480, | ||
330 | }, | ||
331 | }, | ||
332 | .set_crop = &mi0343_set_crop, | ||
333 | .pix_format = { | ||
334 | .width = 640, | ||
335 | .height = 480, | ||
336 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
337 | .priv = 8, | ||
338 | }, | ||
339 | .set_pix_format = &mi0343_set_pix_format | ||
340 | }; | ||
341 | |||
342 | |||
343 | int sn9c102_probe_mi0343(struct sn9c102_device* cam) | ||
344 | { | ||
345 | int err = 0; | ||
346 | |||
347 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
348 | err += sn9c102_write_reg(cam, 0x00, 0x01); | ||
349 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
350 | if (err) | ||
351 | return -EIO; | ||
352 | |||
353 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00, | ||
354 | 2, mi0343_i2c_data) < 0) | ||
355 | return -EIO; | ||
356 | |||
357 | if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3) | ||
358 | return -ENODEV; | ||
359 | |||
360 | sn9c102_attach_sensor(cam, &mi0343); | ||
361 | |||
362 | return 0; | ||
363 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c new file mode 100644 index 000000000000..42852b7cb042 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_ov7630.c | |||
@@ -0,0 +1,401 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2005-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include "sn9c102_sensor.h" | ||
23 | |||
24 | |||
25 | static struct sn9c102_sensor ov7630; | ||
26 | |||
27 | |||
28 | static int ov7630_init(struct sn9c102_device* cam) | ||
29 | { | ||
30 | int err = 0; | ||
31 | |||
32 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
33 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
34 | err += sn9c102_write_reg(cam, 0x0f, 0x18); | ||
35 | err += sn9c102_write_reg(cam, 0x50, 0x19); | ||
36 | |||
37 | err += sn9c102_i2c_write(cam, 0x12, 0x80); | ||
38 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | ||
39 | err += sn9c102_i2c_write(cam, 0x15, 0x34); | ||
40 | err += sn9c102_i2c_write(cam, 0x16, 0x03); | ||
41 | err += sn9c102_i2c_write(cam, 0x17, 0x1c); | ||
42 | err += sn9c102_i2c_write(cam, 0x18, 0xbd); | ||
43 | err += sn9c102_i2c_write(cam, 0x19, 0x06); | ||
44 | err += sn9c102_i2c_write(cam, 0x1a, 0xf6); | ||
45 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); | ||
46 | err += sn9c102_i2c_write(cam, 0x20, 0xf6); | ||
47 | err += sn9c102_i2c_write(cam, 0x23, 0xee); | ||
48 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); | ||
49 | err += sn9c102_i2c_write(cam, 0x27, 0x9a); | ||
50 | err += sn9c102_i2c_write(cam, 0x28, 0xa0); | ||
51 | err += sn9c102_i2c_write(cam, 0x29, 0x30); | ||
52 | err += sn9c102_i2c_write(cam, 0x2a, 0xa0); | ||
53 | err += sn9c102_i2c_write(cam, 0x2b, 0x1f); | ||
54 | err += sn9c102_i2c_write(cam, 0x2f, 0x3d); | ||
55 | err += sn9c102_i2c_write(cam, 0x30, 0x24); | ||
56 | err += sn9c102_i2c_write(cam, 0x32, 0x86); | ||
57 | err += sn9c102_i2c_write(cam, 0x60, 0xa9); | ||
58 | err += sn9c102_i2c_write(cam, 0x61, 0x42); | ||
59 | err += sn9c102_i2c_write(cam, 0x65, 0x00); | ||
60 | err += sn9c102_i2c_write(cam, 0x69, 0x38); | ||
61 | err += sn9c102_i2c_write(cam, 0x6f, 0x88); | ||
62 | err += sn9c102_i2c_write(cam, 0x70, 0x0b); | ||
63 | err += sn9c102_i2c_write(cam, 0x71, 0x00); | ||
64 | err += sn9c102_i2c_write(cam, 0x74, 0x21); | ||
65 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); | ||
66 | |||
67 | return err; | ||
68 | } | ||
69 | |||
70 | |||
71 | static int ov7630_set_ctrl(struct sn9c102_device* cam, | ||
72 | const struct v4l2_control* ctrl) | ||
73 | { | ||
74 | int err = 0; | ||
75 | |||
76 | switch (ctrl->id) { | ||
77 | case V4L2_CID_EXPOSURE: | ||
78 | err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2); | ||
79 | err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03); | ||
80 | break; | ||
81 | case V4L2_CID_RED_BALANCE: | ||
82 | err += sn9c102_i2c_write(cam, 0x02, ctrl->value); | ||
83 | break; | ||
84 | case V4L2_CID_BLUE_BALANCE: | ||
85 | err += sn9c102_i2c_write(cam, 0x01, ctrl->value); | ||
86 | break; | ||
87 | case V4L2_CID_GAIN: | ||
88 | err += sn9c102_i2c_write(cam, 0x00, ctrl->value); | ||
89 | break; | ||
90 | case V4L2_CID_CONTRAST: | ||
91 | err += ctrl->value ? sn9c102_i2c_write(cam, 0x05, | ||
92 | (ctrl->value-1) | 0x20) | ||
93 | : sn9c102_i2c_write(cam, 0x05, 0x00); | ||
94 | break; | ||
95 | case V4L2_CID_BRIGHTNESS: | ||
96 | err += sn9c102_i2c_write(cam, 0x06, ctrl->value); | ||
97 | break; | ||
98 | case V4L2_CID_SATURATION: | ||
99 | err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4); | ||
100 | break; | ||
101 | case V4L2_CID_HUE: | ||
102 | err += ctrl->value ? sn9c102_i2c_write(cam, 0x04, | ||
103 | (ctrl->value-1) | 0x20) | ||
104 | : sn9c102_i2c_write(cam, 0x04, 0x00); | ||
105 | break; | ||
106 | case V4L2_CID_DO_WHITE_BALANCE: | ||
107 | err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); | ||
108 | break; | ||
109 | case V4L2_CID_WHITENESS: | ||
110 | err += sn9c102_i2c_write(cam, 0x0d, ctrl->value); | ||
111 | break; | ||
112 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
113 | err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78); | ||
114 | break; | ||
115 | case V4L2_CID_AUTOGAIN: | ||
116 | err += sn9c102_i2c_write(cam, 0x13, ctrl->value); | ||
117 | break; | ||
118 | case V4L2_CID_VFLIP: | ||
119 | err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7)); | ||
120 | break; | ||
121 | case V4L2_CID_BLACK_LEVEL: | ||
122 | err += sn9c102_i2c_write(cam, 0x25, ctrl->value); | ||
123 | break; | ||
124 | case SN9C102_V4L2_CID_BRIGHT_LEVEL: | ||
125 | err += sn9c102_i2c_write(cam, 0x24, ctrl->value); | ||
126 | break; | ||
127 | case SN9C102_V4L2_CID_GAMMA: | ||
128 | err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80); | ||
129 | break; | ||
130 | case SN9C102_V4L2_CID_BAND_FILTER: | ||
131 | err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2); | ||
132 | break; | ||
133 | default: | ||
134 | return -EINVAL; | ||
135 | } | ||
136 | |||
137 | return err ? -EIO : 0; | ||
138 | } | ||
139 | |||
140 | |||
141 | static int ov7630_set_crop(struct sn9c102_device* cam, | ||
142 | const struct v4l2_rect* rect) | ||
143 | { | ||
144 | struct sn9c102_sensor* s = &ov7630; | ||
145 | int err = 0; | ||
146 | u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; | ||
147 | |||
148 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
149 | |||
150 | return err; | ||
151 | } | ||
152 | |||
153 | |||
154 | static int ov7630_set_pix_format(struct sn9c102_device* cam, | ||
155 | const struct v4l2_pix_format* pix) | ||
156 | { | ||
157 | int err = 0; | ||
158 | |||
159 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
160 | err += sn9c102_write_reg(cam, 0x20, 0x19); | ||
161 | else | ||
162 | err += sn9c102_write_reg(cam, 0x50, 0x19); | ||
163 | |||
164 | return err; | ||
165 | } | ||
166 | |||
167 | |||
168 | static struct sn9c102_sensor ov7630 = { | ||
169 | .name = "OV7630", | ||
170 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
171 | .sysfs_ops = SN9C102_I2C_WRITE, | ||
172 | .frequency = SN9C102_I2C_100KHZ, | ||
173 | .interface = SN9C102_I2C_2WIRES, | ||
174 | .i2c_slave_id = 0x21, | ||
175 | .init = &ov7630_init, | ||
176 | .qctrl = { | ||
177 | { | ||
178 | .id = V4L2_CID_GAIN, | ||
179 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
180 | .name = "global gain", | ||
181 | .minimum = 0x00, | ||
182 | .maximum = 0x3f, | ||
183 | .step = 0x01, | ||
184 | .default_value = 0x14, | ||
185 | .flags = 0, | ||
186 | }, | ||
187 | { | ||
188 | .id = V4L2_CID_HUE, | ||
189 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
190 | .name = "hue", | ||
191 | .minimum = 0x00, | ||
192 | .maximum = 0x1f+1, | ||
193 | .step = 0x01, | ||
194 | .default_value = 0x00, | ||
195 | .flags = 0, | ||
196 | }, | ||
197 | { | ||
198 | .id = V4L2_CID_SATURATION, | ||
199 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
200 | .name = "saturation", | ||
201 | .minimum = 0x00, | ||
202 | .maximum = 0x0f, | ||
203 | .step = 0x01, | ||
204 | .default_value = 0x08, | ||
205 | .flags = 0, | ||
206 | }, | ||
207 | { | ||
208 | .id = V4L2_CID_CONTRAST, | ||
209 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
210 | .name = "contrast", | ||
211 | .minimum = 0x00, | ||
212 | .maximum = 0x1f+1, | ||
213 | .step = 0x01, | ||
214 | .default_value = 0x00, | ||
215 | .flags = 0, | ||
216 | }, | ||
217 | { | ||
218 | .id = V4L2_CID_EXPOSURE, | ||
219 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
220 | .name = "exposure", | ||
221 | .minimum = 0x000, | ||
222 | .maximum = 0x3ff, | ||
223 | .step = 0x001, | ||
224 | .default_value = 0x83<<2, | ||
225 | .flags = 0, | ||
226 | }, | ||
227 | { | ||
228 | .id = V4L2_CID_RED_BALANCE, | ||
229 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
230 | .name = "red balance", | ||
231 | .minimum = 0x00, | ||
232 | .maximum = 0xff, | ||
233 | .step = 0x01, | ||
234 | .default_value = 0x3a, | ||
235 | .flags = 0, | ||
236 | }, | ||
237 | { | ||
238 | .id = V4L2_CID_BLUE_BALANCE, | ||
239 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
240 | .name = "blue balance", | ||
241 | .minimum = 0x00, | ||
242 | .maximum = 0xff, | ||
243 | .step = 0x01, | ||
244 | .default_value = 0x77, | ||
245 | .flags = 0, | ||
246 | }, | ||
247 | { | ||
248 | .id = V4L2_CID_BRIGHTNESS, | ||
249 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
250 | .name = "brightness", | ||
251 | .minimum = 0x00, | ||
252 | .maximum = 0xff, | ||
253 | .step = 0x01, | ||
254 | .default_value = 0xa0, | ||
255 | .flags = 0, | ||
256 | }, | ||
257 | { | ||
258 | .id = V4L2_CID_DO_WHITE_BALANCE, | ||
259 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
260 | .name = "white balance background: blue", | ||
261 | .minimum = 0x00, | ||
262 | .maximum = 0x3f, | ||
263 | .step = 0x01, | ||
264 | .default_value = 0x20, | ||
265 | .flags = 0, | ||
266 | }, | ||
267 | { | ||
268 | .id = V4L2_CID_WHITENESS, | ||
269 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
270 | .name = "white balance background: red", | ||
271 | .minimum = 0x00, | ||
272 | .maximum = 0x3f, | ||
273 | .step = 0x01, | ||
274 | .default_value = 0x20, | ||
275 | .flags = 0, | ||
276 | }, | ||
277 | { | ||
278 | .id = V4L2_CID_AUTO_WHITE_BALANCE, | ||
279 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
280 | .name = "auto white balance", | ||
281 | .minimum = 0x00, | ||
282 | .maximum = 0x01, | ||
283 | .step = 0x01, | ||
284 | .default_value = 0x01, | ||
285 | .flags = 0, | ||
286 | }, | ||
287 | { | ||
288 | .id = V4L2_CID_AUTOGAIN, | ||
289 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
290 | .name = "gain & exposure mode", | ||
291 | .minimum = 0x00, | ||
292 | .maximum = 0x03, | ||
293 | .step = 0x01, | ||
294 | .default_value = 0x00, | ||
295 | .flags = 0, | ||
296 | }, | ||
297 | { | ||
298 | .id = V4L2_CID_VFLIP, | ||
299 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
300 | .name = "vertical flip", | ||
301 | .minimum = 0x00, | ||
302 | .maximum = 0x01, | ||
303 | .step = 0x01, | ||
304 | .default_value = 0x01, | ||
305 | .flags = 0, | ||
306 | }, | ||
307 | { | ||
308 | .id = V4L2_CID_BLACK_LEVEL, | ||
309 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
310 | .name = "black pixel ratio", | ||
311 | .minimum = 0x01, | ||
312 | .maximum = 0x9a, | ||
313 | .step = 0x01, | ||
314 | .default_value = 0x8a, | ||
315 | .flags = 0, | ||
316 | }, | ||
317 | { | ||
318 | .id = SN9C102_V4L2_CID_BRIGHT_LEVEL, | ||
319 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
320 | .name = "bright pixel ratio", | ||
321 | .minimum = 0x01, | ||
322 | .maximum = 0x9a, | ||
323 | .step = 0x01, | ||
324 | .default_value = 0x10, | ||
325 | .flags = 0, | ||
326 | }, | ||
327 | { | ||
328 | .id = SN9C102_V4L2_CID_BAND_FILTER, | ||
329 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
330 | .name = "band filter", | ||
331 | .minimum = 0x00, | ||
332 | .maximum = 0x01, | ||
333 | .step = 0x01, | ||
334 | .default_value = 0x00, | ||
335 | .flags = 0, | ||
336 | }, | ||
337 | { | ||
338 | .id = SN9C102_V4L2_CID_GAMMA, | ||
339 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
340 | .name = "rgb gamma", | ||
341 | .minimum = 0x00, | ||
342 | .maximum = 0x01, | ||
343 | .step = 0x01, | ||
344 | .default_value = 0x00, | ||
345 | .flags = 0, | ||
346 | }, | ||
347 | }, | ||
348 | .set_ctrl = &ov7630_set_ctrl, | ||
349 | .cropcap = { | ||
350 | .bounds = { | ||
351 | .left = 0, | ||
352 | .top = 0, | ||
353 | .width = 640, | ||
354 | .height = 480, | ||
355 | }, | ||
356 | .defrect = { | ||
357 | .left = 0, | ||
358 | .top = 0, | ||
359 | .width = 640, | ||
360 | .height = 480, | ||
361 | }, | ||
362 | }, | ||
363 | .set_crop = &ov7630_set_crop, | ||
364 | .pix_format = { | ||
365 | .width = 640, | ||
366 | .height = 480, | ||
367 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
368 | .priv = 8, | ||
369 | }, | ||
370 | .set_pix_format = &ov7630_set_pix_format | ||
371 | }; | ||
372 | |||
373 | |||
374 | int sn9c102_probe_ov7630(struct sn9c102_device* cam) | ||
375 | { | ||
376 | const struct usb_device_id ov7630_id_table[] = { | ||
377 | { USB_DEVICE(0x0c45, 0x602c), }, | ||
378 | { USB_DEVICE(0x0c45, 0x602d), }, | ||
379 | { USB_DEVICE(0x0c45, 0x608f), }, | ||
380 | { USB_DEVICE(0x0c45, 0x60b0), }, | ||
381 | { } | ||
382 | }; | ||
383 | int err = 0; | ||
384 | |||
385 | if (!sn9c102_match_id(cam, ov7630_id_table)) | ||
386 | return -ENODEV; | ||
387 | |||
388 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
389 | err += sn9c102_write_reg(cam, 0x00, 0x01); | ||
390 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
391 | if (err) | ||
392 | return -EIO; | ||
393 | |||
394 | err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0); | ||
395 | if (err) | ||
396 | return -ENODEV; | ||
397 | |||
398 | sn9c102_attach_sensor(cam, &ov7630); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_pas106b.c b/drivers/media/video/sn9c102/sn9c102_pas106b.c new file mode 100644 index 000000000000..b1dee78abe04 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_pas106b.c | |||
@@ -0,0 +1,307 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include <linux/delay.h> | ||
23 | #include "sn9c102_sensor.h" | ||
24 | |||
25 | |||
26 | static struct sn9c102_sensor pas106b; | ||
27 | |||
28 | |||
29 | static int pas106b_init(struct sn9c102_device* cam) | ||
30 | { | ||
31 | int err = 0; | ||
32 | |||
33 | err += sn9c102_write_reg(cam, 0x00, 0x10); | ||
34 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
35 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
36 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
37 | err += sn9c102_write_reg(cam, 0x20, 0x19); | ||
38 | err += sn9c102_write_reg(cam, 0x09, 0x18); | ||
39 | |||
40 | err += sn9c102_i2c_write(cam, 0x02, 0x0c); | ||
41 | err += sn9c102_i2c_write(cam, 0x05, 0x5a); | ||
42 | err += sn9c102_i2c_write(cam, 0x06, 0x88); | ||
43 | err += sn9c102_i2c_write(cam, 0x07, 0x80); | ||
44 | err += sn9c102_i2c_write(cam, 0x10, 0x06); | ||
45 | err += sn9c102_i2c_write(cam, 0x11, 0x06); | ||
46 | err += sn9c102_i2c_write(cam, 0x12, 0x00); | ||
47 | err += sn9c102_i2c_write(cam, 0x14, 0x02); | ||
48 | err += sn9c102_i2c_write(cam, 0x13, 0x01); | ||
49 | |||
50 | msleep(400); | ||
51 | |||
52 | return err; | ||
53 | } | ||
54 | |||
55 | |||
56 | static int pas106b_get_ctrl(struct sn9c102_device* cam, | ||
57 | struct v4l2_control* ctrl) | ||
58 | { | ||
59 | switch (ctrl->id) { | ||
60 | case V4L2_CID_EXPOSURE: | ||
61 | { | ||
62 | int r1 = sn9c102_i2c_read(cam, 0x03), | ||
63 | r2 = sn9c102_i2c_read(cam, 0x04); | ||
64 | if (r1 < 0 || r2 < 0) | ||
65 | return -EIO; | ||
66 | ctrl->value = (r1 << 4) | (r2 & 0x0f); | ||
67 | } | ||
68 | return 0; | ||
69 | case V4L2_CID_RED_BALANCE: | ||
70 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) | ||
71 | return -EIO; | ||
72 | ctrl->value &= 0x1f; | ||
73 | return 0; | ||
74 | case V4L2_CID_BLUE_BALANCE: | ||
75 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) | ||
76 | return -EIO; | ||
77 | ctrl->value &= 0x1f; | ||
78 | return 0; | ||
79 | case V4L2_CID_GAIN: | ||
80 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0) | ||
81 | return -EIO; | ||
82 | ctrl->value &= 0x1f; | ||
83 | return 0; | ||
84 | case V4L2_CID_CONTRAST: | ||
85 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0) | ||
86 | return -EIO; | ||
87 | ctrl->value &= 0x07; | ||
88 | return 0; | ||
89 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
90 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0) | ||
91 | return -EIO; | ||
92 | ctrl->value = (ctrl->value & 0x1f) << 1; | ||
93 | return 0; | ||
94 | case SN9C102_V4L2_CID_DAC_MAGNITUDE: | ||
95 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0) | ||
96 | return -EIO; | ||
97 | ctrl->value &= 0xf8; | ||
98 | return 0; | ||
99 | default: | ||
100 | return -EINVAL; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | |||
105 | static int pas106b_set_ctrl(struct sn9c102_device* cam, | ||
106 | const struct v4l2_control* ctrl) | ||
107 | { | ||
108 | int err = 0; | ||
109 | |||
110 | switch (ctrl->id) { | ||
111 | case V4L2_CID_EXPOSURE: | ||
112 | err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4); | ||
113 | err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f); | ||
114 | break; | ||
115 | case V4L2_CID_RED_BALANCE: | ||
116 | err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); | ||
117 | break; | ||
118 | case V4L2_CID_BLUE_BALANCE: | ||
119 | err += sn9c102_i2c_write(cam, 0x09, ctrl->value); | ||
120 | break; | ||
121 | case V4L2_CID_GAIN: | ||
122 | err += sn9c102_i2c_write(cam, 0x0e, ctrl->value); | ||
123 | break; | ||
124 | case V4L2_CID_CONTRAST: | ||
125 | err += sn9c102_i2c_write(cam, 0x0f, ctrl->value); | ||
126 | break; | ||
127 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
128 | err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1); | ||
129 | err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1); | ||
130 | break; | ||
131 | case SN9C102_V4L2_CID_DAC_MAGNITUDE: | ||
132 | err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3); | ||
133 | break; | ||
134 | default: | ||
135 | return -EINVAL; | ||
136 | } | ||
137 | err += sn9c102_i2c_write(cam, 0x13, 0x01); | ||
138 | |||
139 | return err ? -EIO : 0; | ||
140 | } | ||
141 | |||
142 | |||
143 | static int pas106b_set_crop(struct sn9c102_device* cam, | ||
144 | const struct v4l2_rect* rect) | ||
145 | { | ||
146 | struct sn9c102_sensor* s = &pas106b; | ||
147 | int err = 0; | ||
148 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, | ||
149 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; | ||
150 | |||
151 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
152 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
153 | |||
154 | return err; | ||
155 | } | ||
156 | |||
157 | |||
158 | static int pas106b_set_pix_format(struct sn9c102_device* cam, | ||
159 | const struct v4l2_pix_format* pix) | ||
160 | { | ||
161 | int err = 0; | ||
162 | |||
163 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
164 | err += sn9c102_write_reg(cam, 0x2c, 0x17); | ||
165 | else | ||
166 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
167 | |||
168 | return err; | ||
169 | } | ||
170 | |||
171 | |||
172 | static struct sn9c102_sensor pas106b = { | ||
173 | .name = "PAS106B", | ||
174 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
175 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
176 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, | ||
177 | .interface = SN9C102_I2C_2WIRES, | ||
178 | .i2c_slave_id = 0x40, | ||
179 | .init = &pas106b_init, | ||
180 | .qctrl = { | ||
181 | { | ||
182 | .id = V4L2_CID_EXPOSURE, | ||
183 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
184 | .name = "exposure", | ||
185 | .minimum = 0x125, | ||
186 | .maximum = 0xfff, | ||
187 | .step = 0x001, | ||
188 | .default_value = 0x140, | ||
189 | .flags = 0, | ||
190 | }, | ||
191 | { | ||
192 | .id = V4L2_CID_GAIN, | ||
193 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
194 | .name = "global gain", | ||
195 | .minimum = 0x00, | ||
196 | .maximum = 0x1f, | ||
197 | .step = 0x01, | ||
198 | .default_value = 0x0d, | ||
199 | .flags = 0, | ||
200 | }, | ||
201 | { | ||
202 | .id = V4L2_CID_CONTRAST, | ||
203 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
204 | .name = "contrast", | ||
205 | .minimum = 0x00, | ||
206 | .maximum = 0x07, | ||
207 | .step = 0x01, | ||
208 | .default_value = 0x00, /* 0x00~0x03 have same effect */ | ||
209 | .flags = 0, | ||
210 | }, | ||
211 | { | ||
212 | .id = V4L2_CID_RED_BALANCE, | ||
213 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
214 | .name = "red balance", | ||
215 | .minimum = 0x00, | ||
216 | .maximum = 0x1f, | ||
217 | .step = 0x01, | ||
218 | .default_value = 0x04, | ||
219 | .flags = 0, | ||
220 | }, | ||
221 | { | ||
222 | .id = V4L2_CID_BLUE_BALANCE, | ||
223 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
224 | .name = "blue balance", | ||
225 | .minimum = 0x00, | ||
226 | .maximum = 0x1f, | ||
227 | .step = 0x01, | ||
228 | .default_value = 0x06, | ||
229 | .flags = 0, | ||
230 | }, | ||
231 | { | ||
232 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
233 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
234 | .name = "green balance", | ||
235 | .minimum = 0x00, | ||
236 | .maximum = 0x3e, | ||
237 | .step = 0x02, | ||
238 | .default_value = 0x02, | ||
239 | .flags = 0, | ||
240 | }, | ||
241 | { | ||
242 | .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, | ||
243 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
244 | .name = "DAC magnitude", | ||
245 | .minimum = 0x00, | ||
246 | .maximum = 0x1f, | ||
247 | .step = 0x01, | ||
248 | .default_value = 0x01, | ||
249 | .flags = 0, | ||
250 | }, | ||
251 | }, | ||
252 | .get_ctrl = &pas106b_get_ctrl, | ||
253 | .set_ctrl = &pas106b_set_ctrl, | ||
254 | .cropcap = { | ||
255 | .bounds = { | ||
256 | .left = 0, | ||
257 | .top = 0, | ||
258 | .width = 352, | ||
259 | .height = 288, | ||
260 | }, | ||
261 | .defrect = { | ||
262 | .left = 0, | ||
263 | .top = 0, | ||
264 | .width = 352, | ||
265 | .height = 288, | ||
266 | }, | ||
267 | }, | ||
268 | .set_crop = &pas106b_set_crop, | ||
269 | .pix_format = { | ||
270 | .width = 352, | ||
271 | .height = 288, | ||
272 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
273 | .priv = 8, /* we use this field as 'bits per pixel' */ | ||
274 | }, | ||
275 | .set_pix_format = &pas106b_set_pix_format | ||
276 | }; | ||
277 | |||
278 | |||
279 | int sn9c102_probe_pas106b(struct sn9c102_device* cam) | ||
280 | { | ||
281 | int r0 = 0, r1 = 0, err = 0; | ||
282 | unsigned int pid = 0; | ||
283 | |||
284 | /* | ||
285 | Minimal initialization to enable the I2C communication | ||
286 | NOTE: do NOT change the values! | ||
287 | */ | ||
288 | err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ | ||
289 | err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */ | ||
290 | err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ | ||
291 | if (err) | ||
292 | return -EIO; | ||
293 | |||
294 | r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00); | ||
295 | r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01); | ||
296 | |||
297 | if (r0 < 0 || r1 < 0) | ||
298 | return -EIO; | ||
299 | |||
300 | pid = (r0 << 11) | ((r1 & 0xf0) >> 4); | ||
301 | if (pid != 0x007) | ||
302 | return -ENODEV; | ||
303 | |||
304 | sn9c102_attach_sensor(cam, &pas106b); | ||
305 | |||
306 | return 0; | ||
307 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bca.c b/drivers/media/video/sn9c102/sn9c102_pas202bca.c new file mode 100644 index 000000000000..3453237055bb --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_pas202bca.c | |||
@@ -0,0 +1,238 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include <linux/delay.h> | ||
23 | #include "sn9c102_sensor.h" | ||
24 | |||
25 | |||
26 | static struct sn9c102_sensor pas202bca; | ||
27 | |||
28 | |||
29 | static int pas202bca_init(struct sn9c102_device* cam) | ||
30 | { | ||
31 | int err = 0; | ||
32 | |||
33 | err += sn9c102_write_reg(cam, 0x00, 0x10); | ||
34 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
35 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
36 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
37 | err += sn9c102_write_reg(cam, 0x30, 0x19); | ||
38 | err += sn9c102_write_reg(cam, 0x09, 0x18); | ||
39 | |||
40 | err += sn9c102_i2c_write(cam, 0x02, 0x14); | ||
41 | err += sn9c102_i2c_write(cam, 0x03, 0x40); | ||
42 | err += sn9c102_i2c_write(cam, 0x0d, 0x2c); | ||
43 | err += sn9c102_i2c_write(cam, 0x0e, 0x01); | ||
44 | err += sn9c102_i2c_write(cam, 0x0f, 0xa9); | ||
45 | err += sn9c102_i2c_write(cam, 0x10, 0x08); | ||
46 | err += sn9c102_i2c_write(cam, 0x13, 0x63); | ||
47 | err += sn9c102_i2c_write(cam, 0x15, 0x70); | ||
48 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | ||
49 | |||
50 | msleep(400); | ||
51 | |||
52 | return err; | ||
53 | } | ||
54 | |||
55 | |||
56 | static int pas202bca_set_pix_format(struct sn9c102_device* cam, | ||
57 | const struct v4l2_pix_format* pix) | ||
58 | { | ||
59 | int err = 0; | ||
60 | |||
61 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
62 | err += sn9c102_write_reg(cam, 0x24, 0x17); | ||
63 | else | ||
64 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
65 | |||
66 | return err; | ||
67 | } | ||
68 | |||
69 | |||
70 | static int pas202bca_set_ctrl(struct sn9c102_device* cam, | ||
71 | const struct v4l2_control* ctrl) | ||
72 | { | ||
73 | int err = 0; | ||
74 | |||
75 | switch (ctrl->id) { | ||
76 | case V4L2_CID_EXPOSURE: | ||
77 | err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6); | ||
78 | err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f); | ||
79 | break; | ||
80 | case V4L2_CID_RED_BALANCE: | ||
81 | err += sn9c102_i2c_write(cam, 0x09, ctrl->value); | ||
82 | break; | ||
83 | case V4L2_CID_BLUE_BALANCE: | ||
84 | err += sn9c102_i2c_write(cam, 0x07, ctrl->value); | ||
85 | break; | ||
86 | case V4L2_CID_GAIN: | ||
87 | err += sn9c102_i2c_write(cam, 0x10, ctrl->value); | ||
88 | break; | ||
89 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
90 | err += sn9c102_i2c_write(cam, 0x08, ctrl->value); | ||
91 | break; | ||
92 | case SN9C102_V4L2_CID_DAC_MAGNITUDE: | ||
93 | err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); | ||
94 | break; | ||
95 | default: | ||
96 | return -EINVAL; | ||
97 | } | ||
98 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | ||
99 | |||
100 | return err ? -EIO : 0; | ||
101 | } | ||
102 | |||
103 | |||
104 | static int pas202bca_set_crop(struct sn9c102_device* cam, | ||
105 | const struct v4l2_rect* rect) | ||
106 | { | ||
107 | struct sn9c102_sensor* s = &pas202bca; | ||
108 | int err = 0; | ||
109 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3, | ||
110 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; | ||
111 | |||
112 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
113 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
114 | |||
115 | return err; | ||
116 | } | ||
117 | |||
118 | |||
119 | static struct sn9c102_sensor pas202bca = { | ||
120 | .name = "PAS202BCA", | ||
121 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
122 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
123 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, | ||
124 | .interface = SN9C102_I2C_2WIRES, | ||
125 | .i2c_slave_id = 0x40, | ||
126 | .init = &pas202bca_init, | ||
127 | .qctrl = { | ||
128 | { | ||
129 | .id = V4L2_CID_EXPOSURE, | ||
130 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
131 | .name = "exposure", | ||
132 | .minimum = 0x01e5, | ||
133 | .maximum = 0x3fff, | ||
134 | .step = 0x0001, | ||
135 | .default_value = 0x01e5, | ||
136 | .flags = 0, | ||
137 | }, | ||
138 | { | ||
139 | .id = V4L2_CID_GAIN, | ||
140 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
141 | .name = "global gain", | ||
142 | .minimum = 0x00, | ||
143 | .maximum = 0x1f, | ||
144 | .step = 0x01, | ||
145 | .default_value = 0x0c, | ||
146 | .flags = 0, | ||
147 | }, | ||
148 | { | ||
149 | .id = V4L2_CID_RED_BALANCE, | ||
150 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
151 | .name = "red balance", | ||
152 | .minimum = 0x00, | ||
153 | .maximum = 0x0f, | ||
154 | .step = 0x01, | ||
155 | .default_value = 0x01, | ||
156 | .flags = 0, | ||
157 | }, | ||
158 | { | ||
159 | .id = V4L2_CID_BLUE_BALANCE, | ||
160 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
161 | .name = "blue balance", | ||
162 | .minimum = 0x00, | ||
163 | .maximum = 0x0f, | ||
164 | .step = 0x01, | ||
165 | .default_value = 0x05, | ||
166 | .flags = 0, | ||
167 | }, | ||
168 | { | ||
169 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
170 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
171 | .name = "green balance", | ||
172 | .minimum = 0x00, | ||
173 | .maximum = 0x0f, | ||
174 | .step = 0x01, | ||
175 | .default_value = 0x00, | ||
176 | .flags = 0, | ||
177 | }, | ||
178 | { | ||
179 | .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, | ||
180 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
181 | .name = "DAC magnitude", | ||
182 | .minimum = 0x00, | ||
183 | .maximum = 0xff, | ||
184 | .step = 0x01, | ||
185 | .default_value = 0x04, | ||
186 | .flags = 0, | ||
187 | }, | ||
188 | }, | ||
189 | .set_ctrl = &pas202bca_set_ctrl, | ||
190 | .cropcap = { | ||
191 | .bounds = { | ||
192 | .left = 0, | ||
193 | .top = 0, | ||
194 | .width = 640, | ||
195 | .height = 480, | ||
196 | }, | ||
197 | .defrect = { | ||
198 | .left = 0, | ||
199 | .top = 0, | ||
200 | .width = 640, | ||
201 | .height = 480, | ||
202 | }, | ||
203 | }, | ||
204 | .set_crop = &pas202bca_set_crop, | ||
205 | .pix_format = { | ||
206 | .width = 640, | ||
207 | .height = 480, | ||
208 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
209 | .priv = 8, | ||
210 | }, | ||
211 | .set_pix_format = &pas202bca_set_pix_format | ||
212 | }; | ||
213 | |||
214 | |||
215 | int sn9c102_probe_pas202bca(struct sn9c102_device* cam) | ||
216 | { | ||
217 | const struct usb_device_id pas202bca_id_table[] = { | ||
218 | { USB_DEVICE(0x0c45, 0x60af), }, | ||
219 | { } | ||
220 | }; | ||
221 | int err = 0; | ||
222 | |||
223 | if (!sn9c102_match_id(cam,pas202bca_id_table)) | ||
224 | return -ENODEV; | ||
225 | |||
226 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
227 | err += sn9c102_write_reg(cam, 0x40, 0x01); | ||
228 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
229 | if (err) | ||
230 | return -EIO; | ||
231 | |||
232 | if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */ | ||
233 | return -ENODEV; | ||
234 | |||
235 | sn9c102_attach_sensor(cam, &pas202bca); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c new file mode 100644 index 000000000000..d068616ab337 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c | |||
@@ -0,0 +1,293 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * | ||
6 | * <medaglia@undl.org.br> * | ||
7 | * http://cadu.homelinux.com:8080/ * | ||
8 | * * | ||
9 | * DAC Magnitude, exposure and green gain controls added by * | ||
10 | * Luca Risolia <luca.risolia@studio.unibo.it> * | ||
11 | * * | ||
12 | * This program is free software; you can redistribute it and/or modify * | ||
13 | * it under the terms of the GNU General Public License as published by * | ||
14 | * the Free Software Foundation; either version 2 of the License, or * | ||
15 | * (at your option) any later version. * | ||
16 | * * | ||
17 | * This program is distributed in the hope that it will be useful, * | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
20 | * GNU General Public License for more details. * | ||
21 | * * | ||
22 | * You should have received a copy of the GNU General Public License * | ||
23 | * along with this program; if not, write to the Free Software * | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
25 | ***************************************************************************/ | ||
26 | |||
27 | #include <linux/delay.h> | ||
28 | #include "sn9c102_sensor.h" | ||
29 | |||
30 | |||
31 | static struct sn9c102_sensor pas202bcb; | ||
32 | |||
33 | |||
34 | static int pas202bcb_init(struct sn9c102_device* cam) | ||
35 | { | ||
36 | int err = 0; | ||
37 | |||
38 | err += sn9c102_write_reg(cam, 0x00, 0x10); | ||
39 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
40 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
41 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
42 | err += sn9c102_write_reg(cam, 0x30, 0x19); | ||
43 | err += sn9c102_write_reg(cam, 0x09, 0x18); | ||
44 | |||
45 | err += sn9c102_i2c_write(cam, 0x02, 0x14); | ||
46 | err += sn9c102_i2c_write(cam, 0x03, 0x40); | ||
47 | err += sn9c102_i2c_write(cam, 0x0d, 0x2c); | ||
48 | err += sn9c102_i2c_write(cam, 0x0e, 0x01); | ||
49 | err += sn9c102_i2c_write(cam, 0x0f, 0xa9); | ||
50 | err += sn9c102_i2c_write(cam, 0x10, 0x08); | ||
51 | err += sn9c102_i2c_write(cam, 0x13, 0x63); | ||
52 | err += sn9c102_i2c_write(cam, 0x15, 0x70); | ||
53 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | ||
54 | |||
55 | msleep(400); | ||
56 | |||
57 | return err; | ||
58 | } | ||
59 | |||
60 | |||
61 | static int pas202bcb_get_ctrl(struct sn9c102_device* cam, | ||
62 | struct v4l2_control* ctrl) | ||
63 | { | ||
64 | switch (ctrl->id) { | ||
65 | case V4L2_CID_EXPOSURE: | ||
66 | { | ||
67 | int r1 = sn9c102_i2c_read(cam, 0x04), | ||
68 | r2 = sn9c102_i2c_read(cam, 0x05); | ||
69 | if (r1 < 0 || r2 < 0) | ||
70 | return -EIO; | ||
71 | ctrl->value = (r1 << 6) | (r2 & 0x3f); | ||
72 | } | ||
73 | return 0; | ||
74 | case V4L2_CID_RED_BALANCE: | ||
75 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) | ||
76 | return -EIO; | ||
77 | ctrl->value &= 0x0f; | ||
78 | return 0; | ||
79 | case V4L2_CID_BLUE_BALANCE: | ||
80 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0) | ||
81 | return -EIO; | ||
82 | ctrl->value &= 0x0f; | ||
83 | return 0; | ||
84 | case V4L2_CID_GAIN: | ||
85 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) | ||
86 | return -EIO; | ||
87 | ctrl->value &= 0x1f; | ||
88 | return 0; | ||
89 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
90 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0) | ||
91 | return -EIO; | ||
92 | ctrl->value &= 0x0f; | ||
93 | return 0; | ||
94 | case SN9C102_V4L2_CID_DAC_MAGNITUDE: | ||
95 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) | ||
96 | return -EIO; | ||
97 | return 0; | ||
98 | default: | ||
99 | return -EINVAL; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | |||
104 | static int pas202bcb_set_pix_format(struct sn9c102_device* cam, | ||
105 | const struct v4l2_pix_format* pix) | ||
106 | { | ||
107 | int err = 0; | ||
108 | |||
109 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
110 | err += sn9c102_write_reg(cam, 0x24, 0x17); | ||
111 | else | ||
112 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
113 | |||
114 | return err; | ||
115 | } | ||
116 | |||
117 | |||
118 | static int pas202bcb_set_ctrl(struct sn9c102_device* cam, | ||
119 | const struct v4l2_control* ctrl) | ||
120 | { | ||
121 | int err = 0; | ||
122 | |||
123 | switch (ctrl->id) { | ||
124 | case V4L2_CID_EXPOSURE: | ||
125 | err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6); | ||
126 | err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f); | ||
127 | break; | ||
128 | case V4L2_CID_RED_BALANCE: | ||
129 | err += sn9c102_i2c_write(cam, 0x09, ctrl->value); | ||
130 | break; | ||
131 | case V4L2_CID_BLUE_BALANCE: | ||
132 | err += sn9c102_i2c_write(cam, 0x07, ctrl->value); | ||
133 | break; | ||
134 | case V4L2_CID_GAIN: | ||
135 | err += sn9c102_i2c_write(cam, 0x10, ctrl->value); | ||
136 | break; | ||
137 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
138 | err += sn9c102_i2c_write(cam, 0x08, ctrl->value); | ||
139 | break; | ||
140 | case SN9C102_V4L2_CID_DAC_MAGNITUDE: | ||
141 | err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); | ||
142 | break; | ||
143 | default: | ||
144 | return -EINVAL; | ||
145 | } | ||
146 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | ||
147 | |||
148 | return err ? -EIO : 0; | ||
149 | } | ||
150 | |||
151 | |||
152 | static int pas202bcb_set_crop(struct sn9c102_device* cam, | ||
153 | const struct v4l2_rect* rect) | ||
154 | { | ||
155 | struct sn9c102_sensor* s = &pas202bcb; | ||
156 | int err = 0; | ||
157 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, | ||
158 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; | ||
159 | |||
160 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
161 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
162 | |||
163 | return err; | ||
164 | } | ||
165 | |||
166 | |||
167 | static struct sn9c102_sensor pas202bcb = { | ||
168 | .name = "PAS202BCB", | ||
169 | .maintainer = "Carlos Eduardo Medaglia Dyonisio " | ||
170 | "<medaglia@undl.org.br>", | ||
171 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
172 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, | ||
173 | .interface = SN9C102_I2C_2WIRES, | ||
174 | .i2c_slave_id = 0x40, | ||
175 | .init = &pas202bcb_init, | ||
176 | .qctrl = { | ||
177 | { | ||
178 | .id = V4L2_CID_EXPOSURE, | ||
179 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
180 | .name = "exposure", | ||
181 | .minimum = 0x01e5, | ||
182 | .maximum = 0x3fff, | ||
183 | .step = 0x0001, | ||
184 | .default_value = 0x01e5, | ||
185 | .flags = 0, | ||
186 | }, | ||
187 | { | ||
188 | .id = V4L2_CID_GAIN, | ||
189 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
190 | .name = "global gain", | ||
191 | .minimum = 0x00, | ||
192 | .maximum = 0x1f, | ||
193 | .step = 0x01, | ||
194 | .default_value = 0x0c, | ||
195 | .flags = 0, | ||
196 | }, | ||
197 | { | ||
198 | .id = V4L2_CID_RED_BALANCE, | ||
199 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
200 | .name = "red balance", | ||
201 | .minimum = 0x00, | ||
202 | .maximum = 0x0f, | ||
203 | .step = 0x01, | ||
204 | .default_value = 0x01, | ||
205 | .flags = 0, | ||
206 | }, | ||
207 | { | ||
208 | .id = V4L2_CID_BLUE_BALANCE, | ||
209 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
210 | .name = "blue balance", | ||
211 | .minimum = 0x00, | ||
212 | .maximum = 0x0f, | ||
213 | .step = 0x01, | ||
214 | .default_value = 0x05, | ||
215 | .flags = 0, | ||
216 | }, | ||
217 | { | ||
218 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
219 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
220 | .name = "green balance", | ||
221 | .minimum = 0x00, | ||
222 | .maximum = 0x0f, | ||
223 | .step = 0x01, | ||
224 | .default_value = 0x00, | ||
225 | .flags = 0, | ||
226 | }, | ||
227 | { | ||
228 | .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, | ||
229 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
230 | .name = "DAC magnitude", | ||
231 | .minimum = 0x00, | ||
232 | .maximum = 0xff, | ||
233 | .step = 0x01, | ||
234 | .default_value = 0x04, | ||
235 | .flags = 0, | ||
236 | }, | ||
237 | }, | ||
238 | .get_ctrl = &pas202bcb_get_ctrl, | ||
239 | .set_ctrl = &pas202bcb_set_ctrl, | ||
240 | .cropcap = { | ||
241 | .bounds = { | ||
242 | .left = 0, | ||
243 | .top = 0, | ||
244 | .width = 640, | ||
245 | .height = 480, | ||
246 | }, | ||
247 | .defrect = { | ||
248 | .left = 0, | ||
249 | .top = 0, | ||
250 | .width = 640, | ||
251 | .height = 480, | ||
252 | }, | ||
253 | }, | ||
254 | .set_crop = &pas202bcb_set_crop, | ||
255 | .pix_format = { | ||
256 | .width = 640, | ||
257 | .height = 480, | ||
258 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
259 | .priv = 8, | ||
260 | }, | ||
261 | .set_pix_format = &pas202bcb_set_pix_format | ||
262 | }; | ||
263 | |||
264 | |||
265 | int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) | ||
266 | { | ||
267 | int r0 = 0, r1 = 0, err = 0; | ||
268 | unsigned int pid = 0; | ||
269 | |||
270 | /* | ||
271 | * Minimal initialization to enable the I2C communication | ||
272 | * NOTE: do NOT change the values! | ||
273 | */ | ||
274 | err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ | ||
275 | err += sn9c102_write_reg(cam, 0x40, 0x01); /* sensor power on */ | ||
276 | err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ | ||
277 | if (err) | ||
278 | return -EIO; | ||
279 | |||
280 | r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00); | ||
281 | r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01); | ||
282 | |||
283 | if (r0 < 0 || r1 < 0) | ||
284 | return -EIO; | ||
285 | |||
286 | pid = (r0 << 4) | ((r1 & 0xf0) >> 4); | ||
287 | if (pid != 0x017) | ||
288 | return -ENODEV; | ||
289 | |||
290 | sn9c102_attach_sensor(cam, &pas202bcb); | ||
291 | |||
292 | return 0; | ||
293 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h new file mode 100644 index 000000000000..2afd9e9d09bb --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_sensor.h | |||
@@ -0,0 +1,389 @@ | |||
1 | /*************************************************************************** | ||
2 | * API for image sensors connected to the SN9C10x PC Camera Controllers * | ||
3 | * * | ||
4 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program is distributed in the hope that it will be useful, * | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #ifndef _SN9C102_SENSOR_H_ | ||
22 | #define _SN9C102_SENSOR_H_ | ||
23 | |||
24 | #include <linux/usb.h> | ||
25 | #include <linux/videodev.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/stddef.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <asm/types.h> | ||
30 | |||
31 | struct sn9c102_device; | ||
32 | struct sn9c102_sensor; | ||
33 | |||
34 | /*****************************************************************************/ | ||
35 | |||
36 | /* | ||
37 | OVERVIEW. | ||
38 | This is a small interface that allows you to add support for any CCD/CMOS | ||
39 | image sensors connected to the SN9C10X bridges. The entire API is documented | ||
40 | below. In the most general case, to support a sensor there are three steps | ||
41 | you have to follow: | ||
42 | 1) define the main "sn9c102_sensor" structure by setting the basic fields; | ||
43 | 2) write a probing function to be called by the core module when the USB | ||
44 | camera is recognized, then add both the USB ids and the name of that | ||
45 | function to the two corresponding tables SENSOR_TABLE and ID_TABLE (see | ||
46 | below); | ||
47 | 3) implement the methods that you want/need (and fill the rest of the main | ||
48 | structure accordingly). | ||
49 | "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do | ||
50 | NOT need to touch the source code of the core module for the things to work | ||
51 | properly, unless you find bugs or flaws in it. Finally, do not forget to | ||
52 | read the V4L2 API for completeness. | ||
53 | */ | ||
54 | |||
55 | /*****************************************************************************/ | ||
56 | |||
57 | /* | ||
58 | Probing functions: on success, you must attach the sensor to the camera | ||
59 | by calling sn9c102_attach_sensor() provided below. | ||
60 | To enable the I2C communication, you might need to perform a really basic | ||
61 | initialization of the SN9C10X chip by using the write function declared | ||
62 | ahead. | ||
63 | Functions must return 0 on success, the appropriate error otherwise. | ||
64 | */ | ||
65 | extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); | ||
66 | extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); | ||
67 | extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); | ||
68 | extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); | ||
69 | extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam); | ||
70 | extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); | ||
71 | extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); | ||
72 | extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); | ||
73 | |||
74 | /* | ||
75 | Add the above entries to this table. Be sure to add the entry in the right | ||
76 | place, since, on failure, the next probing routine is called according to | ||
77 | the order of the list below, from top to bottom. | ||
78 | */ | ||
79 | #define SN9C102_SENSOR_TABLE \ | ||
80 | static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \ | ||
81 | &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ \ | ||
82 | &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \ | ||
83 | &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \ | ||
84 | &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ \ | ||
85 | &sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \ | ||
86 | &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */ \ | ||
87 | &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \ | ||
88 | &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \ | ||
89 | NULL, \ | ||
90 | }; | ||
91 | |||
92 | /* Device identification */ | ||
93 | extern struct sn9c102_device* | ||
94 | sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id); | ||
95 | |||
96 | /* Attach a probed sensor to the camera. */ | ||
97 | extern void | ||
98 | sn9c102_attach_sensor(struct sn9c102_device* cam, | ||
99 | struct sn9c102_sensor* sensor); | ||
100 | |||
101 | /* | ||
102 | Each SN9C10x camera has proper PID/VID identifiers. | ||
103 | SN9C103 supports multiple interfaces, but we only handle the video class | ||
104 | interface. | ||
105 | */ | ||
106 | #define SN9C102_USB_DEVICE(vend, prod, intclass) \ | ||
107 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ | ||
108 | USB_DEVICE_ID_MATCH_INT_CLASS, \ | ||
109 | .idVendor = (vend), \ | ||
110 | .idProduct = (prod), \ | ||
111 | .bInterfaceClass = (intclass) | ||
112 | |||
113 | #define SN9C102_ID_TABLE \ | ||
114 | static const struct usb_device_id sn9c102_id_table[] = { \ | ||
115 | { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \ | ||
116 | { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */ \ | ||
117 | { USB_DEVICE(0x0c45, 0x6007), }, \ | ||
118 | { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */ \ | ||
119 | { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */ \ | ||
120 | { USB_DEVICE(0x0c45, 0x6024), }, \ | ||
121 | { USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */ \ | ||
122 | { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */ \ | ||
123 | { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \ | ||
124 | { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */ \ | ||
125 | { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */ \ | ||
126 | { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */ \ | ||
127 | { USB_DEVICE(0x0c45, 0x602d), }, \ | ||
128 | { USB_DEVICE(0x0c45, 0x602e), }, /* OV7630 */ \ | ||
129 | { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \ | ||
130 | { SN9C102_USB_DEVICE(0x0c45, 0x6080, 0xff), }, \ | ||
131 | { SN9C102_USB_DEVICE(0x0c45, 0x6082, 0xff), }, /* MI0343 & MI0360 */ \ | ||
132 | { SN9C102_USB_DEVICE(0x0c45, 0x6083, 0xff), }, /* HV7131[D|E1] */ \ | ||
133 | { SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), }, \ | ||
134 | { SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), }, \ | ||
135 | { SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), }, \ | ||
136 | { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */ \ | ||
137 | { SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */ \ | ||
138 | { SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */ \ | ||
139 | { SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), }, \ | ||
140 | { SN9C102_USB_DEVICE(0x0c45, 0x60a2, 0xff), }, \ | ||
141 | { SN9C102_USB_DEVICE(0x0c45, 0x60a3, 0xff), }, \ | ||
142 | { SN9C102_USB_DEVICE(0x0c45, 0x60a8, 0xff), }, /* PAS106B */ \ | ||
143 | { SN9C102_USB_DEVICE(0x0c45, 0x60aa, 0xff), }, /* TAS5130D1B */ \ | ||
144 | { SN9C102_USB_DEVICE(0x0c45, 0x60ab, 0xff), }, /* TAS5110C1B */ \ | ||
145 | { SN9C102_USB_DEVICE(0x0c45, 0x60ac, 0xff), }, \ | ||
146 | { SN9C102_USB_DEVICE(0x0c45, 0x60ae, 0xff), }, \ | ||
147 | { SN9C102_USB_DEVICE(0x0c45, 0x60af, 0xff), }, /* PAS202BCB */ \ | ||
148 | { SN9C102_USB_DEVICE(0x0c45, 0x60b0, 0xff), }, /* OV7630 (?) */ \ | ||
149 | { SN9C102_USB_DEVICE(0x0c45, 0x60b2, 0xff), }, \ | ||
150 | { SN9C102_USB_DEVICE(0x0c45, 0x60b3, 0xff), }, \ | ||
151 | { SN9C102_USB_DEVICE(0x0c45, 0x60b8, 0xff), }, \ | ||
152 | { SN9C102_USB_DEVICE(0x0c45, 0x60ba, 0xff), }, \ | ||
153 | { SN9C102_USB_DEVICE(0x0c45, 0x60bb, 0xff), }, \ | ||
154 | { SN9C102_USB_DEVICE(0x0c45, 0x60bc, 0xff), }, \ | ||
155 | { SN9C102_USB_DEVICE(0x0c45, 0x60be, 0xff), }, \ | ||
156 | { } \ | ||
157 | }; | ||
158 | |||
159 | /*****************************************************************************/ | ||
160 | |||
161 | /* | ||
162 | Read/write routines: they always return -1 on error, 0 or the read value | ||
163 | otherwise. NOTE that a real read operation is not supported by the SN9C10X | ||
164 | chip for some of its registers. To work around this problem, a pseudo-read | ||
165 | call is provided instead: it returns the last successfully written value | ||
166 | on the register (0 if it has never been written), the usual -1 on error. | ||
167 | */ | ||
168 | |||
169 | /* The "try" I2C I/O versions are used when probing the sensor */ | ||
170 | extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*, | ||
171 | u8 address, u8 value); | ||
172 | extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*, | ||
173 | u8 address); | ||
174 | |||
175 | /* | ||
176 | These must be used if and only if the sensor doesn't implement the standard | ||
177 | I2C protocol. There are a number of good reasons why you must use the | ||
178 | single-byte versions of these functions: do not abuse. The first function | ||
179 | writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C10X | ||
180 | chip. The second one programs the registers 0x09 and 0x10 with data0 and | ||
181 | data1, and places the n bytes read from the sensor register table in the | ||
182 | buffer pointed by 'buffer'. Both the functions return -1 on error; the write | ||
183 | version returns 0 on success, while the read version returns the first read | ||
184 | byte. | ||
185 | */ | ||
186 | extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, | ||
187 | struct sn9c102_sensor* sensor, u8 n, | ||
188 | u8 data0, u8 data1, u8 data2, u8 data3, | ||
189 | u8 data4, u8 data5); | ||
190 | extern int sn9c102_i2c_try_raw_read(struct sn9c102_device* cam, | ||
191 | struct sn9c102_sensor* sensor, u8 data0, | ||
192 | u8 data1, u8 n, u8 buffer[]); | ||
193 | |||
194 | /* To be used after the sensor struct has been attached to the camera struct */ | ||
195 | extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value); | ||
196 | extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address); | ||
197 | |||
198 | /* I/O on registers in the bridge. Could be used by the sensor methods too */ | ||
199 | extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index); | ||
200 | extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); | ||
201 | extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); | ||
202 | |||
203 | /* | ||
204 | NOTE: there are no exported debugging functions. To uniform the output you | ||
205 | must use the dev_info()/dev_warn()/dev_err() macros defined in device.h, | ||
206 | already included here, the argument being the struct device '&usbdev->dev' | ||
207 | of the sensor structure. Do NOT use these macros before the sensor is | ||
208 | attached or the kernel will crash! However, you should not need to notify | ||
209 | the user about common errors or other messages, since this is done by the | ||
210 | master module. | ||
211 | */ | ||
212 | |||
213 | /*****************************************************************************/ | ||
214 | |||
215 | enum sn9c102_i2c_sysfs_ops { | ||
216 | SN9C102_I2C_READ = 0x01, | ||
217 | SN9C102_I2C_WRITE = 0x02, | ||
218 | }; | ||
219 | |||
220 | enum sn9c102_i2c_frequency { /* sensors may support both the frequencies */ | ||
221 | SN9C102_I2C_100KHZ = 0x01, | ||
222 | SN9C102_I2C_400KHZ = 0x02, | ||
223 | }; | ||
224 | |||
225 | enum sn9c102_i2c_interface { | ||
226 | SN9C102_I2C_2WIRES, | ||
227 | SN9C102_I2C_3WIRES, | ||
228 | }; | ||
229 | |||
230 | #define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10 | ||
231 | |||
232 | struct sn9c102_sensor { | ||
233 | char name[32], /* sensor name */ | ||
234 | maintainer[64]; /* name of the mantainer <email> */ | ||
235 | |||
236 | /* Supported operations through the 'sysfs' interface */ | ||
237 | enum sn9c102_i2c_sysfs_ops sysfs_ops; | ||
238 | |||
239 | /* | ||
240 | These sensor capabilities must be provided if the SN9C10X controller | ||
241 | needs to communicate through the sensor serial interface by using | ||
242 | at least one of the i2c functions available. | ||
243 | */ | ||
244 | enum sn9c102_i2c_frequency frequency; | ||
245 | enum sn9c102_i2c_interface interface; | ||
246 | |||
247 | /* | ||
248 | This identifier must be provided if the image sensor implements | ||
249 | the standard I2C protocol. | ||
250 | */ | ||
251 | u8 i2c_slave_id; /* reg. 0x09 */ | ||
252 | |||
253 | /* | ||
254 | NOTE: Where not noted,most of the functions below are not mandatory. | ||
255 | Set to null if you do not implement them. If implemented, | ||
256 | they must return 0 on success, the proper error otherwise. | ||
257 | */ | ||
258 | |||
259 | int (*init)(struct sn9c102_device* cam); | ||
260 | /* | ||
261 | This function will be called after the sensor has been attached. | ||
262 | It should be used to initialize the sensor only, but may also | ||
263 | configure part of the SN9C10X chip if necessary. You don't need to | ||
264 | setup picture settings like brightness, contrast, etc.. here, if | ||
265 | the corrisponding controls are implemented (see below), since | ||
266 | they are adjusted in the core driver by calling the set_ctrl() | ||
267 | method after init(), where the arguments are the default values | ||
268 | specified in the v4l2_queryctrl list of supported controls; | ||
269 | Same suggestions apply for other settings, _if_ the corresponding | ||
270 | methods are present; if not, the initialization must configure the | ||
271 | sensor according to the default configuration structures below. | ||
272 | */ | ||
273 | |||
274 | struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS]; | ||
275 | /* | ||
276 | Optional list of default controls, defined as indicated in the | ||
277 | V4L2 API. Menu type controls are not handled by this interface. | ||
278 | */ | ||
279 | |||
280 | int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl); | ||
281 | int (*set_ctrl)(struct sn9c102_device* cam, | ||
282 | const struct v4l2_control* ctrl); | ||
283 | /* | ||
284 | You must implement at least the set_ctrl method if you have defined | ||
285 | the list above. The returned value must follow the V4L2 | ||
286 | specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER | ||
287 | are not supported by this driver, so do not implement them. Also, | ||
288 | you don't have to check whether the passed values are out of bounds, | ||
289 | given that this is done by the core module. | ||
290 | */ | ||
291 | |||
292 | struct v4l2_cropcap cropcap; | ||
293 | /* | ||
294 | Think the image sensor as a grid of R,G,B monochromatic pixels | ||
295 | disposed according to a particular Bayer pattern, which describes | ||
296 | the complete array of pixels, from (0,0) to (xmax, ymax). We will | ||
297 | use this coordinate system from now on. It is assumed the sensor | ||
298 | chip can be programmed to capture/transmit a subsection of that | ||
299 | array of pixels: we will call this subsection "active window". | ||
300 | It is not always true that the largest achievable active window can | ||
301 | cover the whole array of pixels. The V4L2 API defines another | ||
302 | area called "source rectangle", which, in turn, is a subrectangle of | ||
303 | the active window. The SN9C10X chip is always programmed to read the | ||
304 | source rectangle. | ||
305 | The bounds of both the active window and the source rectangle are | ||
306 | specified in the cropcap substructures 'bounds' and 'defrect'. | ||
307 | By default, the source rectangle should cover the largest possible | ||
308 | area. Again, it is not always true that the largest source rectangle | ||
309 | can cover the entire active window, although it is a rare case for | ||
310 | the hardware we have. The bounds of the source rectangle _must_ be | ||
311 | multiple of 16 and must use the same coordinate system as indicated | ||
312 | before; their centers shall align initially. | ||
313 | If necessary, the sensor chip must be initialized during init() to | ||
314 | set the bounds of the active sensor window; however, by default, it | ||
315 | usually covers the largest achievable area (maxwidth x maxheight) | ||
316 | of pixels, so no particular initialization is needed, if you have | ||
317 | defined the correct default bounds in the structures. | ||
318 | See the V4L2 API for further details. | ||
319 | NOTE: once you have defined the bounds of the active window | ||
320 | (struct cropcap.bounds) you must not change them.anymore. | ||
321 | Only 'bounds' and 'defrect' fields are mandatory, other fields | ||
322 | will be ignored. | ||
323 | */ | ||
324 | |||
325 | int (*set_crop)(struct sn9c102_device* cam, | ||
326 | const struct v4l2_rect* rect); | ||
327 | /* | ||
328 | To be called on VIDIOC_C_SETCROP. The core module always calls a | ||
329 | default routine which configures the appropriate SN9C10X regs (also | ||
330 | scaling), but you may need to override/adjust specific stuff. | ||
331 | 'rect' contains width and height values that are multiple of 16: in | ||
332 | case you override the default function, you always have to program | ||
333 | the chip to match those values; on error return the corresponding | ||
334 | error code without rolling back. | ||
335 | NOTE: in case, you must program the SN9C10X chip to get rid of | ||
336 | blank pixels or blank lines at the _start_ of each line or | ||
337 | frame after each HSYNC or VSYNC, so that the image starts with | ||
338 | real RGB data (see regs 0x12, 0x13) (having set H_SIZE and, | ||
339 | V_SIZE you don't have to care about blank pixels or blank | ||
340 | lines at the end of each line or frame). | ||
341 | */ | ||
342 | |||
343 | struct v4l2_pix_format pix_format; | ||
344 | /* | ||
345 | What you have to define here are: 1) initial 'width' and 'height' of | ||
346 | the target rectangle 2) the initial 'pixelformat', which can be | ||
347 | either V4L2_PIX_FMT_SN9C10X (for compressed video) or | ||
348 | V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the | ||
349 | number of bits per pixel for uncompressed video, 8 or 9 (despite the | ||
350 | current value of 'pixelformat'). | ||
351 | NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4 | ||
352 | of cropcap.defrect.width and cropcap.defrect.height. I | ||
353 | suggest 1/1. | ||
354 | NOTE 2: The initial compression quality is defined by the first bit | ||
355 | of reg 0x17 during the initialization of the image sensor. | ||
356 | NOTE 3: as said above, you have to program the SN9C10X chip to get | ||
357 | rid of any blank pixels, so that the output of the sensor | ||
358 | matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). | ||
359 | */ | ||
360 | |||
361 | int (*set_pix_format)(struct sn9c102_device* cam, | ||
362 | const struct v4l2_pix_format* pix); | ||
363 | /* | ||
364 | To be called on VIDIOC_S_FMT, when switching from the SBGGR8 to | ||
365 | SN9C10X pixel format or viceversa. On error return the corresponding | ||
366 | error code without rolling back. | ||
367 | */ | ||
368 | |||
369 | /* | ||
370 | Do NOT write to the data below, it's READ ONLY. It is used by the | ||
371 | core module to store successfully updated values of the above | ||
372 | settings, for rollbacks..etc..in case of errors during atomic I/O | ||
373 | */ | ||
374 | struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS]; | ||
375 | struct v4l2_rect _rect; | ||
376 | }; | ||
377 | |||
378 | /*****************************************************************************/ | ||
379 | |||
380 | /* Private ioctl's for control settings supported by some image sensors */ | ||
381 | #define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE | ||
382 | #define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1 | ||
383 | #define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2 | ||
384 | #define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3 | ||
385 | #define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4 | ||
386 | #define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5 | ||
387 | #define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6 | ||
388 | |||
389 | #endif /* _SN9C102_SENSOR_H_ */ | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c new file mode 100644 index 000000000000..2e08c552f40a --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c | |||
@@ -0,0 +1,159 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include "sn9c102_sensor.h" | ||
23 | |||
24 | |||
25 | static struct sn9c102_sensor tas5110c1b; | ||
26 | |||
27 | |||
28 | static int tas5110c1b_init(struct sn9c102_device* cam) | ||
29 | { | ||
30 | int err = 0; | ||
31 | |||
32 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
33 | err += sn9c102_write_reg(cam, 0x44, 0x01); | ||
34 | err += sn9c102_write_reg(cam, 0x00, 0x10); | ||
35 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
36 | err += sn9c102_write_reg(cam, 0x0a, 0x14); | ||
37 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
38 | err += sn9c102_write_reg(cam, 0x06, 0x18); | ||
39 | err += sn9c102_write_reg(cam, 0xfb, 0x19); | ||
40 | |||
41 | err += sn9c102_i2c_write(cam, 0xc0, 0x80); | ||
42 | |||
43 | return err; | ||
44 | } | ||
45 | |||
46 | |||
47 | static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, | ||
48 | const struct v4l2_control* ctrl) | ||
49 | { | ||
50 | int err = 0; | ||
51 | |||
52 | switch (ctrl->id) { | ||
53 | case V4L2_CID_GAIN: | ||
54 | err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); | ||
55 | break; | ||
56 | default: | ||
57 | return -EINVAL; | ||
58 | } | ||
59 | |||
60 | return err ? -EIO : 0; | ||
61 | } | ||
62 | |||
63 | |||
64 | static int tas5110c1b_set_crop(struct sn9c102_device* cam, | ||
65 | const struct v4l2_rect* rect) | ||
66 | { | ||
67 | struct sn9c102_sensor* s = &tas5110c1b; | ||
68 | int err = 0; | ||
69 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, | ||
70 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; | ||
71 | |||
72 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
73 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
74 | |||
75 | /* Don't change ! */ | ||
76 | err += sn9c102_write_reg(cam, 0x14, 0x1a); | ||
77 | err += sn9c102_write_reg(cam, 0x0a, 0x1b); | ||
78 | err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19); | ||
79 | |||
80 | return err; | ||
81 | } | ||
82 | |||
83 | |||
84 | static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, | ||
85 | const struct v4l2_pix_format* pix) | ||
86 | { | ||
87 | int err = 0; | ||
88 | |||
89 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
90 | err += sn9c102_write_reg(cam, 0x2b, 0x19); | ||
91 | else | ||
92 | err += sn9c102_write_reg(cam, 0xfb, 0x19); | ||
93 | |||
94 | return err; | ||
95 | } | ||
96 | |||
97 | |||
98 | static struct sn9c102_sensor tas5110c1b = { | ||
99 | .name = "TAS5110C1B", | ||
100 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
101 | .sysfs_ops = SN9C102_I2C_WRITE, | ||
102 | .frequency = SN9C102_I2C_100KHZ, | ||
103 | .interface = SN9C102_I2C_3WIRES, | ||
104 | .init = &tas5110c1b_init, | ||
105 | .qctrl = { | ||
106 | { | ||
107 | .id = V4L2_CID_GAIN, | ||
108 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
109 | .name = "global gain", | ||
110 | .minimum = 0x00, | ||
111 | .maximum = 0xf6, | ||
112 | .step = 0x01, | ||
113 | .default_value = 0x40, | ||
114 | .flags = 0, | ||
115 | }, | ||
116 | }, | ||
117 | .set_ctrl = &tas5110c1b_set_ctrl, | ||
118 | .cropcap = { | ||
119 | .bounds = { | ||
120 | .left = 0, | ||
121 | .top = 0, | ||
122 | .width = 352, | ||
123 | .height = 288, | ||
124 | }, | ||
125 | .defrect = { | ||
126 | .left = 0, | ||
127 | .top = 0, | ||
128 | .width = 352, | ||
129 | .height = 288, | ||
130 | }, | ||
131 | }, | ||
132 | .set_crop = &tas5110c1b_set_crop, | ||
133 | .pix_format = { | ||
134 | .width = 352, | ||
135 | .height = 288, | ||
136 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
137 | .priv = 8, | ||
138 | }, | ||
139 | .set_pix_format = &tas5110c1b_set_pix_format | ||
140 | }; | ||
141 | |||
142 | |||
143 | int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) | ||
144 | { | ||
145 | const struct usb_device_id tas5110c1b_id_table[] = { | ||
146 | { USB_DEVICE(0x0c45, 0x6001), }, | ||
147 | { USB_DEVICE(0x0c45, 0x6005), }, | ||
148 | { USB_DEVICE(0x0c45, 0x60ab), }, | ||
149 | { } | ||
150 | }; | ||
151 | |||
152 | /* Sensor detection is based on USB pid/vid */ | ||
153 | if (!sn9c102_match_id(cam, tas5110c1b_id_table)) | ||
154 | return -ENODEV; | ||
155 | |||
156 | sn9c102_attach_sensor(cam, &tas5110c1b); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c new file mode 100644 index 000000000000..c7b339740bbf --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c | |||
@@ -0,0 +1,169 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include "sn9c102_sensor.h" | ||
23 | |||
24 | |||
25 | static struct sn9c102_sensor tas5130d1b; | ||
26 | |||
27 | |||
28 | static int tas5130d1b_init(struct sn9c102_device* cam) | ||
29 | { | ||
30 | int err = 0; | ||
31 | |||
32 | err += sn9c102_write_reg(cam, 0x01, 0x01); | ||
33 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
34 | err += sn9c102_write_reg(cam, 0x04, 0x01); | ||
35 | err += sn9c102_write_reg(cam, 0x01, 0x10); | ||
36 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
37 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
38 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
39 | err += sn9c102_write_reg(cam, 0x07, 0x18); | ||
40 | |||
41 | return err; | ||
42 | } | ||
43 | |||
44 | |||
45 | static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, | ||
46 | const struct v4l2_control* ctrl) | ||
47 | { | ||
48 | int err = 0; | ||
49 | |||
50 | switch (ctrl->id) { | ||
51 | case V4L2_CID_GAIN: | ||
52 | err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); | ||
53 | break; | ||
54 | case V4L2_CID_EXPOSURE: | ||
55 | err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value); | ||
56 | break; | ||
57 | default: | ||
58 | return -EINVAL; | ||
59 | } | ||
60 | |||
61 | return err ? -EIO : 0; | ||
62 | } | ||
63 | |||
64 | |||
65 | static int tas5130d1b_set_crop(struct sn9c102_device* cam, | ||
66 | const struct v4l2_rect* rect) | ||
67 | { | ||
68 | struct sn9c102_sensor* s = &tas5130d1b; | ||
69 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104, | ||
70 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12; | ||
71 | int err = 0; | ||
72 | |||
73 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
74 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
75 | |||
76 | /* Do NOT change! */ | ||
77 | err += sn9c102_write_reg(cam, 0x1f, 0x1a); | ||
78 | err += sn9c102_write_reg(cam, 0x1a, 0x1b); | ||
79 | err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19); | ||
80 | |||
81 | return err; | ||
82 | } | ||
83 | |||
84 | |||
85 | static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, | ||
86 | const struct v4l2_pix_format* pix) | ||
87 | { | ||
88 | int err = 0; | ||
89 | |||
90 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
91 | err += sn9c102_write_reg(cam, 0x63, 0x19); | ||
92 | else | ||
93 | err += sn9c102_write_reg(cam, 0xf3, 0x19); | ||
94 | |||
95 | return err; | ||
96 | } | ||
97 | |||
98 | |||
99 | static struct sn9c102_sensor tas5130d1b = { | ||
100 | .name = "TAS5130D1B", | ||
101 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
102 | .sysfs_ops = SN9C102_I2C_WRITE, | ||
103 | .frequency = SN9C102_I2C_100KHZ, | ||
104 | .interface = SN9C102_I2C_3WIRES, | ||
105 | .init = &tas5130d1b_init, | ||
106 | .qctrl = { | ||
107 | { | ||
108 | .id = V4L2_CID_GAIN, | ||
109 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
110 | .name = "global gain", | ||
111 | .minimum = 0x00, | ||
112 | .maximum = 0xf6, | ||
113 | .step = 0x02, | ||
114 | .default_value = 0x00, | ||
115 | .flags = 0, | ||
116 | }, | ||
117 | { | ||
118 | .id = V4L2_CID_EXPOSURE, | ||
119 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
120 | .name = "exposure", | ||
121 | .minimum = 0x00, | ||
122 | .maximum = 0x47, | ||
123 | .step = 0x01, | ||
124 | .default_value = 0x00, | ||
125 | .flags = 0, | ||
126 | }, | ||
127 | }, | ||
128 | .set_ctrl = &tas5130d1b_set_ctrl, | ||
129 | .cropcap = { | ||
130 | .bounds = { | ||
131 | .left = 0, | ||
132 | .top = 0, | ||
133 | .width = 640, | ||
134 | .height = 480, | ||
135 | }, | ||
136 | .defrect = { | ||
137 | .left = 0, | ||
138 | .top = 0, | ||
139 | .width = 640, | ||
140 | .height = 480, | ||
141 | }, | ||
142 | }, | ||
143 | .set_crop = &tas5130d1b_set_crop, | ||
144 | .pix_format = { | ||
145 | .width = 640, | ||
146 | .height = 480, | ||
147 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
148 | .priv = 8, | ||
149 | }, | ||
150 | .set_pix_format = &tas5130d1b_set_pix_format | ||
151 | }; | ||
152 | |||
153 | |||
154 | int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam) | ||
155 | { | ||
156 | const struct usb_device_id tas5130d1b_id_table[] = { | ||
157 | { USB_DEVICE(0x0c45, 0x6025), }, | ||
158 | { USB_DEVICE(0x0c45, 0x60aa), }, | ||
159 | { } | ||
160 | }; | ||
161 | |||
162 | /* Sensor detection is based on USB pid/vid */ | ||
163 | if (!sn9c102_match_id(cam, tas5130d1b_id_table)) | ||
164 | return -ENODEV; | ||
165 | |||
166 | sn9c102_attach_sensor(cam, &tas5130d1b); | ||
167 | |||
168 | return 0; | ||
169 | } | ||
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c new file mode 100644 index 000000000000..9636da20748d --- /dev/null +++ b/drivers/media/video/stv680.c | |||
@@ -0,0 +1,1508 @@ | |||
1 | /* | ||
2 | * STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net) | ||
3 | * | ||
4 | * Thanks to STMicroelectronics for information on the usb commands, and | ||
5 | * to Steve Miller at STM for his help and encouragement while I was | ||
6 | * writing this driver. | ||
7 | * | ||
8 | * This driver is based heavily on the | ||
9 | * Endpoints (formerly known as AOX) se401 USB Camera Driver | ||
10 | * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org) | ||
11 | * | ||
12 | * Still somewhat based on the Linux ov511 driver. | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify it | ||
15 | * under the terms of the GNU General Public License as published by the | ||
16 | * Free Software Foundation; either version 2 of the License, or (at your | ||
17 | * option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, but | ||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
21 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
22 | * for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software Foundation, | ||
26 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
27 | * | ||
28 | * History: | ||
29 | * ver 0.1 October, 2001. Initial attempt. | ||
30 | * | ||
31 | * ver 0.2 November, 2001. Fixed asbility to resize, added brightness | ||
32 | * function, made more stable (?) | ||
33 | * | ||
34 | * ver 0.21 Nov, 2001. Added gamma correction and white balance, | ||
35 | * due to Alexander Schwartz. Still trying to | ||
36 | * improve stablility. Moved stuff into stv680.h | ||
37 | * | ||
38 | * ver 0.22 Nov, 2001. Added sharpen function (by Michael Sweet, | ||
39 | * mike@easysw.com) from GIMP, also used in pencam. | ||
40 | * Simple, fast, good integer math routine. | ||
41 | * | ||
42 | * ver 0.23 Dec, 2001 (gkh) | ||
43 | * Took out sharpen function, ran code through | ||
44 | * Lindent, and did other minor tweaks to get | ||
45 | * things to work properly with 2.5.1 | ||
46 | * | ||
47 | * ver 0.24 Jan, 2002 (kjs) | ||
48 | * Fixed the problem with webcam crashing after | ||
49 | * two pictures. Changed the way pic is halved to | ||
50 | * improve quality. Got rid of green line around | ||
51 | * frame. Fix brightness reset when changing size | ||
52 | * bug. Adjusted gamma filters slightly. | ||
53 | * | ||
54 | * ver 0.25 Jan, 2002 (kjs) | ||
55 | * Fixed a bug in which the driver sometimes attempted | ||
56 | * to set to a non-supported size. This allowed | ||
57 | * gnomemeeting to work. | ||
58 | * Fixed proc entry removal bug. | ||
59 | */ | ||
60 | |||
61 | #include <linux/config.h> | ||
62 | #include <linux/module.h> | ||
63 | #include <linux/init.h> | ||
64 | #include <linux/vmalloc.h> | ||
65 | #include <linux/slab.h> | ||
66 | #include <linux/pagemap.h> | ||
67 | #include <linux/errno.h> | ||
68 | #include <linux/videodev.h> | ||
69 | #include <linux/usb.h> | ||
70 | #include <linux/mutex.h> | ||
71 | |||
72 | #include "stv680.h" | ||
73 | |||
74 | static int video_nr = -1; | ||
75 | static int swapRGB = 0; /* default for auto sleect */ | ||
76 | static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */ | ||
77 | |||
78 | static unsigned int debug = 0; | ||
79 | |||
80 | #define PDEBUG(level, fmt, args...) \ | ||
81 | do { \ | ||
82 | if (debug >= level) \ | ||
83 | info("[%s:%d] " fmt, __FUNCTION__, __LINE__ , ## args); \ | ||
84 | } while (0) | ||
85 | |||
86 | |||
87 | /* | ||
88 | * Version Information | ||
89 | */ | ||
90 | #define DRIVER_VERSION "v0.25" | ||
91 | #define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>" | ||
92 | #define DRIVER_DESC "STV0680 USB Camera Driver" | ||
93 | |||
94 | MODULE_AUTHOR (DRIVER_AUTHOR); | ||
95 | MODULE_DESCRIPTION (DRIVER_DESC); | ||
96 | MODULE_LICENSE ("GPL"); | ||
97 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
98 | MODULE_PARM_DESC (debug, "Debug enabled or not"); | ||
99 | module_param(swapRGB_on, int, 0); | ||
100 | MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never"); | ||
101 | module_param(video_nr, int, 0); | ||
102 | |||
103 | /******************************************************************** | ||
104 | * | ||
105 | * Memory management | ||
106 | * | ||
107 | * This is a shameless copy from the USB-cpia driver (linux kernel | ||
108 | * version 2.3.29 or so, I have no idea what this code actually does ;). | ||
109 | * Actually it seems to be a copy of a shameless copy of the bttv-driver. | ||
110 | * Or that is a copy of a shameless copy of ... (To the powers: is there | ||
111 | * no generic kernel-function to do this sort of stuff?) | ||
112 | * | ||
113 | * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says | ||
114 | * there will be one, but apparentely not yet -jerdfelt | ||
115 | * | ||
116 | * So I copied it again for the ov511 driver -claudio | ||
117 | * | ||
118 | * Same for the se401 driver -Jeroen | ||
119 | * | ||
120 | * And the STV0680 driver - Kevin | ||
121 | ********************************************************************/ | ||
122 | static void *rvmalloc (unsigned long size) | ||
123 | { | ||
124 | void *mem; | ||
125 | unsigned long adr; | ||
126 | |||
127 | size = PAGE_ALIGN(size); | ||
128 | mem = vmalloc_32 (size); | ||
129 | if (!mem) | ||
130 | return NULL; | ||
131 | |||
132 | memset (mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
133 | adr = (unsigned long) mem; | ||
134 | while (size > 0) { | ||
135 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
136 | adr += PAGE_SIZE; | ||
137 | size -= PAGE_SIZE; | ||
138 | } | ||
139 | return mem; | ||
140 | } | ||
141 | |||
142 | static void rvfree (void *mem, unsigned long size) | ||
143 | { | ||
144 | unsigned long adr; | ||
145 | |||
146 | if (!mem) | ||
147 | return; | ||
148 | |||
149 | adr = (unsigned long) mem; | ||
150 | while ((long) size > 0) { | ||
151 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
152 | adr += PAGE_SIZE; | ||
153 | size -= PAGE_SIZE; | ||
154 | } | ||
155 | vfree (mem); | ||
156 | } | ||
157 | |||
158 | |||
159 | /********************************************************************* | ||
160 | * pencam read/write functions | ||
161 | ********************************************************************/ | ||
162 | |||
163 | static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size) | ||
164 | { | ||
165 | int ret = -1; | ||
166 | |||
167 | switch (set) { | ||
168 | case 0: /* 0xc1 */ | ||
169 | ret = usb_control_msg (stv680->udev, | ||
170 | usb_rcvctrlpipe (stv680->udev, 0), | ||
171 | req, | ||
172 | (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT), | ||
173 | value, 0, buffer, size, PENCAM_TIMEOUT); | ||
174 | break; | ||
175 | |||
176 | case 1: /* 0x41 */ | ||
177 | ret = usb_control_msg (stv680->udev, | ||
178 | usb_sndctrlpipe (stv680->udev, 0), | ||
179 | req, | ||
180 | (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT), | ||
181 | value, 0, buffer, size, PENCAM_TIMEOUT); | ||
182 | break; | ||
183 | |||
184 | case 2: /* 0x80 */ | ||
185 | ret = usb_control_msg (stv680->udev, | ||
186 | usb_rcvctrlpipe (stv680->udev, 0), | ||
187 | req, | ||
188 | (USB_DIR_IN | USB_RECIP_DEVICE), | ||
189 | value, 0, buffer, size, PENCAM_TIMEOUT); | ||
190 | break; | ||
191 | |||
192 | case 3: /* 0x40 */ | ||
193 | ret = usb_control_msg (stv680->udev, | ||
194 | usb_sndctrlpipe (stv680->udev, 0), | ||
195 | req, | ||
196 | (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE), | ||
197 | value, 0, buffer, size, PENCAM_TIMEOUT); | ||
198 | break; | ||
199 | |||
200 | } | ||
201 | if ((ret < 0) && (req != 0x0a)) { | ||
202 | PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret); | ||
203 | } | ||
204 | return ret; | ||
205 | } | ||
206 | |||
207 | static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate) | ||
208 | { | ||
209 | |||
210 | if (configuration != dev->udev->actconfig->desc.bConfigurationValue | ||
211 | || usb_reset_configuration (dev->udev) < 0) { | ||
212 | PDEBUG (1, "STV(e): FAILED to reset configuration %i", configuration); | ||
213 | return -1; | ||
214 | } | ||
215 | if (usb_set_interface (dev->udev, interface, alternate) < 0) { | ||
216 | PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate); | ||
217 | return -1; | ||
218 | } | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static int stv_stop_video (struct usb_stv *dev) | ||
223 | { | ||
224 | int i; | ||
225 | unsigned char *buf; | ||
226 | |||
227 | buf = kmalloc (40, GFP_KERNEL); | ||
228 | if (buf == NULL) { | ||
229 | PDEBUG (0, "STV(e): Out of (small buf) memory"); | ||
230 | return -1; | ||
231 | } | ||
232 | |||
233 | /* this is a high priority command; it stops all lower order commands */ | ||
234 | if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) { | ||
235 | i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02); /* Get Last Error; 2 = busy */ | ||
236 | PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buf[0], buf[1]); | ||
237 | } else { | ||
238 | PDEBUG (1, "STV(i): Camera reset to idle mode."); | ||
239 | } | ||
240 | |||
241 | if ((i = stv_set_config (dev, 1, 0, 0)) < 0) | ||
242 | PDEBUG (1, "STV(e): Reset config during exit failed"); | ||
243 | |||
244 | /* get current mode */ | ||
245 | buf[0] = 0xf0; | ||
246 | if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08) /* get mode */ | ||
247 | PDEBUG (0, "STV(e): Stop_video: problem setting original mode"); | ||
248 | if (dev->origMode != buf[0]) { | ||
249 | memset (buf, 0, 8); | ||
250 | buf[0] = (unsigned char) dev->origMode; | ||
251 | if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) { | ||
252 | PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed"); | ||
253 | i = -1; | ||
254 | } | ||
255 | buf[0] = 0xf0; | ||
256 | i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08); | ||
257 | if ((i != 0x08) || (buf[0] != dev->origMode)) { | ||
258 | PDEBUG (0, "STV(e): camera NOT set to original resolution."); | ||
259 | i = -1; | ||
260 | } else | ||
261 | PDEBUG (0, "STV(i): Camera set to original resolution"); | ||
262 | } | ||
263 | /* origMode */ | ||
264 | kfree(buf); | ||
265 | return i; | ||
266 | } | ||
267 | |||
268 | static int stv_set_video_mode (struct usb_stv *dev) | ||
269 | { | ||
270 | int i, stop_video = 1; | ||
271 | unsigned char *buf; | ||
272 | |||
273 | buf = kmalloc (40, GFP_KERNEL); | ||
274 | if (buf == NULL) { | ||
275 | PDEBUG (0, "STV(e): Out of (small buf) memory"); | ||
276 | return -1; | ||
277 | } | ||
278 | |||
279 | if ((i = stv_set_config (dev, 1, 0, 0)) < 0) { | ||
280 | kfree(buf); | ||
281 | return i; | ||
282 | } | ||
283 | |||
284 | i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12); | ||
285 | if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) { | ||
286 | PDEBUG (1, "STV(e): Could not get descriptor 0100."); | ||
287 | goto error; | ||
288 | } | ||
289 | |||
290 | /* set alternate interface 1 */ | ||
291 | if ((i = stv_set_config (dev, 1, 0, 1)) < 0) | ||
292 | goto error; | ||
293 | |||
294 | if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10) | ||
295 | goto error; | ||
296 | PDEBUG (1, "STV(i): Setting video mode."); | ||
297 | /* Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240) */ | ||
298 | if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) { | ||
299 | stop_video = 0; | ||
300 | goto error; | ||
301 | } | ||
302 | goto exit; | ||
303 | |||
304 | error: | ||
305 | kfree(buf); | ||
306 | if (stop_video == 1) | ||
307 | stv_stop_video (dev); | ||
308 | return -1; | ||
309 | |||
310 | exit: | ||
311 | kfree(buf); | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int stv_init (struct usb_stv *stv680) | ||
316 | { | ||
317 | int i = 0; | ||
318 | unsigned char *buffer; | ||
319 | unsigned long int bufsize; | ||
320 | |||
321 | buffer = kzalloc (40, GFP_KERNEL); | ||
322 | if (buffer == NULL) { | ||
323 | PDEBUG (0, "STV(e): Out of (small buf) memory"); | ||
324 | return -1; | ||
325 | } | ||
326 | udelay (100); | ||
327 | |||
328 | /* set config 1, interface 0, alternate 0 */ | ||
329 | if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) { | ||
330 | kfree(buffer); | ||
331 | PDEBUG (0, "STV(e): set config 1,0,0 failed"); | ||
332 | return -1; | ||
333 | } | ||
334 | /* ping camera to be sure STV0680 is present */ | ||
335 | if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02) | ||
336 | goto error; | ||
337 | if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) { | ||
338 | PDEBUG (1, "STV(e): camera ping failed!!"); | ||
339 | goto error; | ||
340 | } | ||
341 | |||
342 | /* get camera descriptor */ | ||
343 | if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09) | ||
344 | goto error; | ||
345 | i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22); | ||
346 | if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) { | ||
347 | PDEBUG (1, "STV(e): Could not get descriptor 0200."); | ||
348 | goto error; | ||
349 | } | ||
350 | if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02) | ||
351 | goto error; | ||
352 | if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24) | ||
353 | goto error; | ||
354 | if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10) | ||
355 | goto error; | ||
356 | |||
357 | stv680->SupportedModes = buffer[7]; | ||
358 | i = stv680->SupportedModes; | ||
359 | stv680->CIF = 0; | ||
360 | stv680->VGA = 0; | ||
361 | stv680->QVGA = 0; | ||
362 | if (i & 1) | ||
363 | stv680->CIF = 1; | ||
364 | if (i & 2) | ||
365 | stv680->VGA = 1; | ||
366 | if (i & 8) | ||
367 | stv680->QVGA = 1; | ||
368 | if (stv680->SupportedModes == 0) { | ||
369 | PDEBUG (0, "STV(e): There are NO supported STV680 modes!!"); | ||
370 | i = -1; | ||
371 | goto error; | ||
372 | } else { | ||
373 | if (stv680->CIF) | ||
374 | PDEBUG (0, "STV(i): CIF is supported"); | ||
375 | if (stv680->QVGA) | ||
376 | PDEBUG (0, "STV(i): QVGA is supported"); | ||
377 | } | ||
378 | /* FW rev, ASIC rev, sensor ID */ | ||
379 | PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]); | ||
380 | PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]); | ||
381 | PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4)); | ||
382 | |||
383 | /* set alternate interface 1 */ | ||
384 | if ((i = stv_set_config (stv680, 1, 0, 1)) < 0) | ||
385 | goto error; | ||
386 | |||
387 | if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10) | ||
388 | goto error; | ||
389 | if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08) | ||
390 | goto error; | ||
391 | i = buffer[3]; | ||
392 | PDEBUG (0, "STV(i): Camera has %i pictures.", i); | ||
393 | |||
394 | /* get current mode */ | ||
395 | if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08) | ||
396 | goto error; | ||
397 | stv680->origMode = buffer[0]; /* 01 = VGA, 03 = QVGA, 00 = CIF */ | ||
398 | |||
399 | /* This will attemp CIF mode, if supported. If not, set to QVGA */ | ||
400 | memset (buffer, 0, 8); | ||
401 | if (stv680->CIF) | ||
402 | buffer[0] = 0x00; | ||
403 | else if (stv680->QVGA) | ||
404 | buffer[0] = 0x03; | ||
405 | if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) { | ||
406 | PDEBUG (0, "STV(i): Set_Camera_Mode failed"); | ||
407 | i = -1; | ||
408 | goto error; | ||
409 | } | ||
410 | buffer[0] = 0xf0; | ||
411 | stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08); | ||
412 | if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) { | ||
413 | PDEBUG (0, "STV(e): Error setting camera video mode!"); | ||
414 | i = -1; | ||
415 | goto error; | ||
416 | } else { | ||
417 | if (buffer[0] == 0) { | ||
418 | stv680->VideoMode = 0x0000; | ||
419 | PDEBUG (0, "STV(i): Video Mode set to CIF"); | ||
420 | } | ||
421 | if (buffer[0] == 0x03) { | ||
422 | stv680->VideoMode = 0x0300; | ||
423 | PDEBUG (0, "STV(i): Video Mode set to QVGA"); | ||
424 | } | ||
425 | } | ||
426 | if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10) | ||
427 | goto error; | ||
428 | bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]); | ||
429 | stv680->cwidth = (buffer[4] << 8) | (buffer[5]); /* ->camera = 322, 356, 644 */ | ||
430 | stv680->cheight = (buffer[6] << 8) | (buffer[7]); /* ->camera = 242, 292, 484 */ | ||
431 | stv680->origGain = buffer[12]; | ||
432 | |||
433 | goto exit; | ||
434 | |||
435 | error: | ||
436 | i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02); /* Get Last Error */ | ||
437 | PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buffer[0], buffer[1]); | ||
438 | kfree(buffer); | ||
439 | return -1; | ||
440 | |||
441 | exit: | ||
442 | kfree(buffer); | ||
443 | |||
444 | /* video = 320x240, 352x288 */ | ||
445 | if (stv680->CIF == 1) { | ||
446 | stv680->maxwidth = 352; | ||
447 | stv680->maxheight = 288; | ||
448 | stv680->vwidth = 352; | ||
449 | stv680->vheight = 288; | ||
450 | } | ||
451 | if (stv680->QVGA == 1) { | ||
452 | stv680->maxwidth = 320; | ||
453 | stv680->maxheight = 240; | ||
454 | stv680->vwidth = 320; | ||
455 | stv680->vheight = 240; | ||
456 | } | ||
457 | |||
458 | stv680->rawbufsize = bufsize; /* must be ./. by 8 */ | ||
459 | stv680->maxframesize = bufsize * 3; /* RGB size */ | ||
460 | PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight); | ||
461 | PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize); | ||
462 | |||
463 | /* some default values */ | ||
464 | stv680->bulk_in_endpointAddr = 0x82; | ||
465 | stv680->dropped = 0; | ||
466 | stv680->error = 0; | ||
467 | stv680->framecount = 0; | ||
468 | stv680->readcount = 0; | ||
469 | stv680->streaming = 0; | ||
470 | /* bright, white, colour, hue, contrast are set by software, not in stv0680 */ | ||
471 | stv680->brightness = 32767; | ||
472 | stv680->chgbright = 0; | ||
473 | stv680->whiteness = 0; /* only for greyscale */ | ||
474 | stv680->colour = 32767; | ||
475 | stv680->contrast = 32767; | ||
476 | stv680->hue = 32767; | ||
477 | stv680->palette = STV_VIDEO_PALETTE; | ||
478 | stv680->depth = 24; /* rgb24 bits */ | ||
479 | if ((swapRGB_on == 0) && (swapRGB == 0)) | ||
480 | PDEBUG (1, "STV(i): swapRGB is (auto) OFF"); | ||
481 | else if ((swapRGB_on == 0) && (swapRGB == 1)) | ||
482 | PDEBUG (1, "STV(i): swapRGB is (auto) ON"); | ||
483 | else if (swapRGB_on == 1) | ||
484 | PDEBUG (1, "STV(i): swapRGB is (forced) ON"); | ||
485 | else if (swapRGB_on == -1) | ||
486 | PDEBUG (1, "STV(i): swapRGB is (forced) OFF"); | ||
487 | |||
488 | if (stv_set_video_mode (stv680) < 0) { | ||
489 | PDEBUG (0, "STV(e): Could not set video mode in stv_init"); | ||
490 | return -1; | ||
491 | } | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | /***************** last of pencam routines *******************/ | ||
497 | |||
498 | /**************************************************************************** | ||
499 | * sysfs | ||
500 | ***************************************************************************/ | ||
501 | #define stv680_file(name, variable, field) \ | ||
502 | static ssize_t show_##name(struct class_device *class_dev, char *buf) \ | ||
503 | { \ | ||
504 | struct video_device *vdev = to_video_device(class_dev); \ | ||
505 | struct usb_stv *stv = video_get_drvdata(vdev); \ | ||
506 | return sprintf(buf, field, stv->variable); \ | ||
507 | } \ | ||
508 | static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); | ||
509 | |||
510 | stv680_file(model, camera_name, "%s\n"); | ||
511 | stv680_file(in_use, user, "%d\n"); | ||
512 | stv680_file(streaming, streaming, "%d\n"); | ||
513 | stv680_file(palette, palette, "%i\n"); | ||
514 | stv680_file(frames_total, readcount, "%d\n"); | ||
515 | stv680_file(frames_read, framecount, "%d\n"); | ||
516 | stv680_file(packets_dropped, dropped, "%d\n"); | ||
517 | stv680_file(decoding_errors, error, "%d\n"); | ||
518 | |||
519 | static void stv680_create_sysfs_files(struct video_device *vdev) | ||
520 | { | ||
521 | video_device_create_file(vdev, &class_device_attr_model); | ||
522 | video_device_create_file(vdev, &class_device_attr_in_use); | ||
523 | video_device_create_file(vdev, &class_device_attr_streaming); | ||
524 | video_device_create_file(vdev, &class_device_attr_palette); | ||
525 | video_device_create_file(vdev, &class_device_attr_frames_total); | ||
526 | video_device_create_file(vdev, &class_device_attr_frames_read); | ||
527 | video_device_create_file(vdev, &class_device_attr_packets_dropped); | ||
528 | video_device_create_file(vdev, &class_device_attr_decoding_errors); | ||
529 | } | ||
530 | |||
531 | static void stv680_remove_sysfs_files(struct video_device *vdev) | ||
532 | { | ||
533 | video_device_remove_file(vdev, &class_device_attr_model); | ||
534 | video_device_remove_file(vdev, &class_device_attr_in_use); | ||
535 | video_device_remove_file(vdev, &class_device_attr_streaming); | ||
536 | video_device_remove_file(vdev, &class_device_attr_palette); | ||
537 | video_device_remove_file(vdev, &class_device_attr_frames_total); | ||
538 | video_device_remove_file(vdev, &class_device_attr_frames_read); | ||
539 | video_device_remove_file(vdev, &class_device_attr_packets_dropped); | ||
540 | video_device_remove_file(vdev, &class_device_attr_decoding_errors); | ||
541 | } | ||
542 | |||
543 | /******************************************************************** | ||
544 | * Camera control | ||
545 | *******************************************************************/ | ||
546 | |||
547 | static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p) | ||
548 | { | ||
549 | /* This sets values for v4l interface. max/min = 65535/0 */ | ||
550 | |||
551 | p->brightness = stv680->brightness; | ||
552 | p->whiteness = stv680->whiteness; /* greyscale */ | ||
553 | p->colour = stv680->colour; | ||
554 | p->contrast = stv680->contrast; | ||
555 | p->hue = stv680->hue; | ||
556 | p->palette = stv680->palette; | ||
557 | p->depth = stv680->depth; | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p) | ||
562 | { | ||
563 | /* See above stv680_get_pict */ | ||
564 | |||
565 | if (p->palette != STV_VIDEO_PALETTE) { | ||
566 | PDEBUG (2, "STV(e): Palette set error in _set_pic"); | ||
567 | return 1; | ||
568 | } | ||
569 | |||
570 | if (stv680->brightness != p->brightness) { | ||
571 | stv680->chgbright = 1; | ||
572 | stv680->brightness = p->brightness; | ||
573 | } | ||
574 | |||
575 | stv680->whiteness = p->whiteness; /* greyscale */ | ||
576 | stv680->colour = p->colour; | ||
577 | stv680->contrast = p->contrast; | ||
578 | stv680->hue = p->hue; | ||
579 | stv680->palette = p->palette; | ||
580 | stv680->depth = p->depth; | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static void stv680_video_irq (struct urb *urb, struct pt_regs *regs) | ||
586 | { | ||
587 | struct usb_stv *stv680 = urb->context; | ||
588 | int length = urb->actual_length; | ||
589 | |||
590 | if (length < stv680->rawbufsize) | ||
591 | PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length); | ||
592 | |||
593 | /* ohoh... */ | ||
594 | if (!stv680->streaming) | ||
595 | return; | ||
596 | |||
597 | if (!stv680->udev) { | ||
598 | PDEBUG (0, "STV(e): device vapourished in video_irq"); | ||
599 | return; | ||
600 | } | ||
601 | |||
602 | /* 0 sized packets happen if we are to fast, but sometimes the camera | ||
603 | keeps sending them forever... | ||
604 | */ | ||
605 | if (length && !urb->status) { | ||
606 | stv680->nullpackets = 0; | ||
607 | switch (stv680->scratch[stv680->scratch_next].state) { | ||
608 | case BUFFER_READY: | ||
609 | case BUFFER_BUSY: | ||
610 | stv680->dropped++; | ||
611 | break; | ||
612 | |||
613 | case BUFFER_UNUSED: | ||
614 | memcpy (stv680->scratch[stv680->scratch_next].data, | ||
615 | (unsigned char *) urb->transfer_buffer, length); | ||
616 | stv680->scratch[stv680->scratch_next].state = BUFFER_READY; | ||
617 | stv680->scratch[stv680->scratch_next].length = length; | ||
618 | if (waitqueue_active (&stv680->wq)) { | ||
619 | wake_up_interruptible (&stv680->wq); | ||
620 | } | ||
621 | stv680->scratch_overflow = 0; | ||
622 | stv680->scratch_next++; | ||
623 | if (stv680->scratch_next >= STV680_NUMSCRATCH) | ||
624 | stv680->scratch_next = 0; | ||
625 | break; | ||
626 | } /* switch */ | ||
627 | } else { | ||
628 | stv680->nullpackets++; | ||
629 | if (stv680->nullpackets > STV680_MAX_NULLPACKETS) { | ||
630 | if (waitqueue_active (&stv680->wq)) { | ||
631 | wake_up_interruptible (&stv680->wq); | ||
632 | } | ||
633 | } | ||
634 | } /* if - else */ | ||
635 | |||
636 | /* Resubmit urb for new data */ | ||
637 | urb->status = 0; | ||
638 | urb->dev = stv680->udev; | ||
639 | if (usb_submit_urb (urb, GFP_ATOMIC)) | ||
640 | PDEBUG (0, "STV(e): urb burned down in video irq"); | ||
641 | return; | ||
642 | } /* _video_irq */ | ||
643 | |||
644 | static int stv680_start_stream (struct usb_stv *stv680) | ||
645 | { | ||
646 | struct urb *urb; | ||
647 | int err = 0, i; | ||
648 | |||
649 | stv680->streaming = 1; | ||
650 | |||
651 | /* Do some memory allocation */ | ||
652 | for (i = 0; i < STV680_NUMFRAMES; i++) { | ||
653 | stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize; | ||
654 | stv680->frame[i].curpix = 0; | ||
655 | } | ||
656 | /* packet size = 4096 */ | ||
657 | for (i = 0; i < STV680_NUMSBUF; i++) { | ||
658 | stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL); | ||
659 | if (stv680->sbuf[i].data == NULL) { | ||
660 | PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i); | ||
661 | return -1; | ||
662 | } | ||
663 | } | ||
664 | |||
665 | stv680->scratch_next = 0; | ||
666 | stv680->scratch_use = 0; | ||
667 | stv680->scratch_overflow = 0; | ||
668 | for (i = 0; i < STV680_NUMSCRATCH; i++) { | ||
669 | stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL); | ||
670 | if (stv680->scratch[i].data == NULL) { | ||
671 | PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i); | ||
672 | return -1; | ||
673 | } | ||
674 | stv680->scratch[i].state = BUFFER_UNUSED; | ||
675 | } | ||
676 | |||
677 | for (i = 0; i < STV680_NUMSBUF; i++) { | ||
678 | urb = usb_alloc_urb (0, GFP_KERNEL); | ||
679 | if (!urb) | ||
680 | return -ENOMEM; | ||
681 | |||
682 | /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */ | ||
683 | usb_fill_bulk_urb (urb, stv680->udev, | ||
684 | usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr), | ||
685 | stv680->sbuf[i].data, stv680->rawbufsize, | ||
686 | stv680_video_irq, stv680); | ||
687 | stv680->urb[i] = urb; | ||
688 | err = usb_submit_urb (stv680->urb[i], GFP_KERNEL); | ||
689 | if (err) | ||
690 | PDEBUG (0, "STV(e): urb burned down in start stream"); | ||
691 | } /* i STV680_NUMSBUF */ | ||
692 | |||
693 | stv680->framecount = 0; | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | static int stv680_stop_stream (struct usb_stv *stv680) | ||
698 | { | ||
699 | int i; | ||
700 | |||
701 | if (!stv680->streaming || !stv680->udev) | ||
702 | return 1; | ||
703 | |||
704 | stv680->streaming = 0; | ||
705 | |||
706 | for (i = 0; i < STV680_NUMSBUF; i++) | ||
707 | if (stv680->urb[i]) { | ||
708 | usb_kill_urb (stv680->urb[i]); | ||
709 | usb_free_urb (stv680->urb[i]); | ||
710 | stv680->urb[i] = NULL; | ||
711 | kfree(stv680->sbuf[i].data); | ||
712 | } | ||
713 | for (i = 0; i < STV680_NUMSCRATCH; i++) { | ||
714 | kfree(stv680->scratch[i].data); | ||
715 | stv680->scratch[i].data = NULL; | ||
716 | } | ||
717 | |||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | static int stv680_set_size (struct usb_stv *stv680, int width, int height) | ||
722 | { | ||
723 | int wasstreaming = stv680->streaming; | ||
724 | |||
725 | /* Check to see if we need to change */ | ||
726 | if ((stv680->vwidth == width) && (stv680->vheight == height)) | ||
727 | return 0; | ||
728 | |||
729 | PDEBUG (1, "STV(i): size request for %i x %i", width, height); | ||
730 | /* Check for a valid mode */ | ||
731 | if ((!width || !height) || ((width & 1) || (height & 1))) { | ||
732 | PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight); | ||
733 | return 1; | ||
734 | } | ||
735 | |||
736 | if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) { | ||
737 | width = stv680->maxwidth / 2; | ||
738 | height = stv680->maxheight / 2; | ||
739 | } else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) { | ||
740 | width = 160; | ||
741 | height = 120; | ||
742 | } else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) { | ||
743 | width = 176; | ||
744 | height = 144; | ||
745 | } else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) { | ||
746 | width = 320; | ||
747 | height = 240; | ||
748 | } else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) { | ||
749 | width = 352; | ||
750 | height = 288; | ||
751 | } else { | ||
752 | PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight); | ||
753 | return 1; | ||
754 | } | ||
755 | |||
756 | /* Stop a current stream and start it again at the new size */ | ||
757 | if (wasstreaming) | ||
758 | stv680_stop_stream (stv680); | ||
759 | stv680->vwidth = width; | ||
760 | stv680->vheight = height; | ||
761 | PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight); | ||
762 | if (wasstreaming) | ||
763 | stv680_start_stream (stv680); | ||
764 | |||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | /********************************************************************** | ||
769 | * Video Decoding | ||
770 | **********************************************************************/ | ||
771 | |||
772 | /******* routines from the pencam program; hey, they work! ********/ | ||
773 | |||
774 | /* | ||
775 | * STV0680 Vision Camera Chipset Driver | ||
776 | * Copyright (C) 2000 Adam Harrison <adam@antispin.org> | ||
777 | */ | ||
778 | |||
779 | #define RED 0 | ||
780 | #define GREEN 1 | ||
781 | #define BLUE 2 | ||
782 | #define AD(x, y, w) (((y)*(w)+(x))*3) | ||
783 | |||
784 | static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer) | ||
785 | { | ||
786 | int x, y, i; | ||
787 | int w = stv680->cwidth; | ||
788 | int vw = stv680->cwidth, vh = stv680->cheight; | ||
789 | unsigned int p = 0; | ||
790 | int colour = 0, bayer = 0; | ||
791 | unsigned char *raw = buffer->data; | ||
792 | struct stv680_frame *frame = &stv680->frame[stv680->curframe]; | ||
793 | unsigned char *output = frame->data; | ||
794 | unsigned char *temp = frame->data; | ||
795 | int offset = buffer->offset; | ||
796 | |||
797 | if (frame->curpix == 0) { | ||
798 | if (frame->grabstate == FRAME_READY) { | ||
799 | frame->grabstate = FRAME_GRABBING; | ||
800 | } | ||
801 | } | ||
802 | if (offset != frame->curpix) { /* Regard frame as lost :( */ | ||
803 | frame->curpix = 0; | ||
804 | stv680->error++; | ||
805 | return; | ||
806 | } | ||
807 | |||
808 | if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) { | ||
809 | vw = 320; | ||
810 | vh = 240; | ||
811 | } | ||
812 | if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) { | ||
813 | vw = 352; | ||
814 | vh = 288; | ||
815 | } | ||
816 | |||
817 | memset (output, 0, 3 * vw * vh); /* clear output matrix. */ | ||
818 | |||
819 | for (y = 0; y < vh; y++) { | ||
820 | for (x = 0; x < vw; x++) { | ||
821 | if (x & 1) | ||
822 | p = *(raw + y * w + (x >> 1)); | ||
823 | else | ||
824 | p = *(raw + y * w + (x >> 1) + (w >> 1)); | ||
825 | |||
826 | if (y & 1) | ||
827 | bayer = 2; | ||
828 | else | ||
829 | bayer = 0; | ||
830 | if (x & 1) | ||
831 | bayer++; | ||
832 | |||
833 | switch (bayer) { | ||
834 | case 0: | ||
835 | case 3: | ||
836 | colour = 1; | ||
837 | break; | ||
838 | case 1: | ||
839 | colour = 0; | ||
840 | break; | ||
841 | case 2: | ||
842 | colour = 2; | ||
843 | break; | ||
844 | } | ||
845 | i = (y * vw + x) * 3; | ||
846 | *(output + i + colour) = (unsigned char) p; | ||
847 | } /* for x */ | ||
848 | |||
849 | } /* for y */ | ||
850 | |||
851 | /****** gamma correction plus hardcoded white balance */ | ||
852 | /* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code. | ||
853 | Correction values red[], green[], blue[], are generated by | ||
854 | (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. | ||
855 | White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and | ||
856 | converted to unsigned char. Values are in stv680.h */ | ||
857 | |||
858 | for (y = 0; y < vh; y++) { | ||
859 | for (x = 0; x < vw; x++) { | ||
860 | i = (y * vw + x) * 3; | ||
861 | *(output + i) = red[*(output + i)]; | ||
862 | *(output + i + 1) = green[*(output + i + 1)]; | ||
863 | *(output + i + 2) = blue[*(output + i + 2)]; | ||
864 | } | ||
865 | } | ||
866 | |||
867 | /****** bayer demosaic ******/ | ||
868 | for (y = 1; y < (vh - 1); y++) { | ||
869 | for (x = 1; x < (vw - 1); x++) { /* work out pixel type */ | ||
870 | if (y & 1) | ||
871 | bayer = 0; | ||
872 | else | ||
873 | bayer = 2; | ||
874 | if (!(x & 1)) | ||
875 | bayer++; | ||
876 | |||
877 | switch (bayer) { | ||
878 | case 0: /* green. blue lr, red tb */ | ||
879 | *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1; | ||
880 | *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1; | ||
881 | break; | ||
882 | |||
883 | case 1: /* blue. green lrtb, red diagonals */ | ||
884 | *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2; | ||
885 | *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2; | ||
886 | break; | ||
887 | |||
888 | case 2: /* red. green lrtb, blue diagonals */ | ||
889 | *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2; | ||
890 | *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2; | ||
891 | break; | ||
892 | |||
893 | case 3: /* green. red lr, blue tb */ | ||
894 | *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1; | ||
895 | *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1; | ||
896 | break; | ||
897 | } /* switch */ | ||
898 | } /* for x */ | ||
899 | } /* for y - end demosaic */ | ||
900 | |||
901 | /* fix top and bottom row, left and right side */ | ||
902 | i = vw * 3; | ||
903 | memcpy (output, (output + i), i); | ||
904 | memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i); | ||
905 | for (y = 0; y < vh; y++) { | ||
906 | i = y * vw * 3; | ||
907 | memcpy ((output + i), (output + i + 3), 3); | ||
908 | memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3); | ||
909 | } | ||
910 | |||
911 | /* process all raw data, then trim to size if necessary */ | ||
912 | if ((stv680->vwidth == 160) || (stv680->vwidth == 176)) { | ||
913 | i = 0; | ||
914 | for (y = 0; y < vh; y++) { | ||
915 | if (!(y & 1)) { | ||
916 | for (x = 0; x < vw; x++) { | ||
917 | p = (y * vw + x) * 3; | ||
918 | if (!(x & 1)) { | ||
919 | *(output + i) = *(output + p); | ||
920 | *(output + i + 1) = *(output + p + 1); | ||
921 | *(output + i + 2) = *(output + p + 2); | ||
922 | i += 3; | ||
923 | } | ||
924 | } /* for x */ | ||
925 | } | ||
926 | } /* for y */ | ||
927 | } | ||
928 | /* reset to proper width */ | ||
929 | if ((stv680->vwidth == 160)) { | ||
930 | vw = 160; | ||
931 | vh = 120; | ||
932 | } | ||
933 | if ((stv680->vwidth == 176)) { | ||
934 | vw = 176; | ||
935 | vh = 144; | ||
936 | } | ||
937 | |||
938 | /* output is RGB; some programs want BGR */ | ||
939 | /* swapRGB_on=0 -> program decides; swapRGB_on=1, always swap */ | ||
940 | /* swapRGB_on=-1, never swap */ | ||
941 | if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) { | ||
942 | for (y = 0; y < vh; y++) { | ||
943 | for (x = 0; x < vw; x++) { | ||
944 | i = (y * vw + x) * 3; | ||
945 | *(temp) = *(output + i); | ||
946 | *(output + i) = *(output + i + 2); | ||
947 | *(output + i + 2) = *(temp); | ||
948 | } | ||
949 | } | ||
950 | } | ||
951 | /* brightness */ | ||
952 | if (stv680->chgbright == 1) { | ||
953 | if (stv680->brightness >= 32767) { | ||
954 | p = (stv680->brightness - 32767) / 256; | ||
955 | for (x = 0; x < (vw * vh * 3); x++) { | ||
956 | if ((*(output + x) + (unsigned char) p) > 255) | ||
957 | *(output + x) = 255; | ||
958 | else | ||
959 | *(output + x) += (unsigned char) p; | ||
960 | } /* for */ | ||
961 | } else { | ||
962 | p = (32767 - stv680->brightness) / 256; | ||
963 | for (x = 0; x < (vw * vh * 3); x++) { | ||
964 | if ((unsigned char) p > *(output + x)) | ||
965 | *(output + x) = 0; | ||
966 | else | ||
967 | *(output + x) -= (unsigned char) p; | ||
968 | } /* for */ | ||
969 | } /* else */ | ||
970 | } | ||
971 | /* if */ | ||
972 | frame->curpix = 0; | ||
973 | frame->curlinepix = 0; | ||
974 | frame->grabstate = FRAME_DONE; | ||
975 | stv680->framecount++; | ||
976 | stv680->readcount++; | ||
977 | if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) { | ||
978 | stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1); | ||
979 | } | ||
980 | |||
981 | } /* bayer_unshuffle */ | ||
982 | |||
983 | /******* end routines from the pencam program *********/ | ||
984 | |||
985 | static int stv680_newframe (struct usb_stv *stv680, int framenr) | ||
986 | { | ||
987 | int errors = 0; | ||
988 | |||
989 | while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) { | ||
990 | if (!stv680->frame[framenr].curpix) { | ||
991 | errors++; | ||
992 | } | ||
993 | wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY)); | ||
994 | |||
995 | if (stv680->nullpackets > STV680_MAX_NULLPACKETS) { | ||
996 | stv680->nullpackets = 0; | ||
997 | PDEBUG (2, "STV(i): too many null length packets, restarting capture"); | ||
998 | stv680_stop_stream (stv680); | ||
999 | stv680_start_stream (stv680); | ||
1000 | } else { | ||
1001 | if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) { | ||
1002 | stv680->frame[framenr].grabstate = FRAME_ERROR; | ||
1003 | PDEBUG (2, "STV(e): FRAME_ERROR in _newframe"); | ||
1004 | return -EIO; | ||
1005 | } | ||
1006 | stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY; | ||
1007 | |||
1008 | bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]); | ||
1009 | |||
1010 | stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED; | ||
1011 | stv680->scratch_use++; | ||
1012 | if (stv680->scratch_use >= STV680_NUMSCRATCH) | ||
1013 | stv680->scratch_use = 0; | ||
1014 | if (errors > STV680_MAX_ERRORS) { | ||
1015 | errors = 0; | ||
1016 | PDEBUG (2, "STV(i): too many errors, restarting capture"); | ||
1017 | stv680_stop_stream (stv680); | ||
1018 | stv680_start_stream (stv680); | ||
1019 | } | ||
1020 | } /* else */ | ||
1021 | } /* while */ | ||
1022 | return 0; | ||
1023 | } | ||
1024 | |||
1025 | /********************************************************************* | ||
1026 | * Video4Linux | ||
1027 | *********************************************************************/ | ||
1028 | |||
1029 | static int stv_open (struct inode *inode, struct file *file) | ||
1030 | { | ||
1031 | struct video_device *dev = video_devdata(file); | ||
1032 | struct usb_stv *stv680 = video_get_drvdata(dev); | ||
1033 | int err = 0; | ||
1034 | |||
1035 | /* we are called with the BKL held */ | ||
1036 | stv680->user = 1; | ||
1037 | err = stv_init (stv680); /* main initialization routine for camera */ | ||
1038 | |||
1039 | if (err >= 0) { | ||
1040 | stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES); | ||
1041 | if (!stv680->fbuf) { | ||
1042 | PDEBUG (0, "STV(e): Could not rvmalloc frame bufer"); | ||
1043 | err = -ENOMEM; | ||
1044 | } | ||
1045 | file->private_data = dev; | ||
1046 | } | ||
1047 | if (err) | ||
1048 | stv680->user = 0; | ||
1049 | |||
1050 | return err; | ||
1051 | } | ||
1052 | |||
1053 | static int stv_close (struct inode *inode, struct file *file) | ||
1054 | { | ||
1055 | struct video_device *dev = file->private_data; | ||
1056 | struct usb_stv *stv680 = video_get_drvdata(dev); | ||
1057 | int i; | ||
1058 | |||
1059 | for (i = 0; i < STV680_NUMFRAMES; i++) | ||
1060 | stv680->frame[i].grabstate = FRAME_UNUSED; | ||
1061 | if (stv680->streaming) | ||
1062 | stv680_stop_stream (stv680); | ||
1063 | |||
1064 | if ((i = stv_stop_video (stv680)) < 0) | ||
1065 | PDEBUG (1, "STV(e): stop_video failed in stv_close"); | ||
1066 | |||
1067 | rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES); | ||
1068 | stv680->user = 0; | ||
1069 | |||
1070 | if (stv680->removed) { | ||
1071 | kfree(stv680); | ||
1072 | stv680 = NULL; | ||
1073 | PDEBUG (0, "STV(i): device unregistered"); | ||
1074 | } | ||
1075 | file->private_data = NULL; | ||
1076 | return 0; | ||
1077 | } | ||
1078 | |||
1079 | static int stv680_do_ioctl (struct inode *inode, struct file *file, | ||
1080 | unsigned int cmd, void *arg) | ||
1081 | { | ||
1082 | struct video_device *vdev = file->private_data; | ||
1083 | struct usb_stv *stv680 = video_get_drvdata(vdev); | ||
1084 | |||
1085 | if (!stv680->udev) | ||
1086 | return -EIO; | ||
1087 | |||
1088 | switch (cmd) { | ||
1089 | case VIDIOCGCAP:{ | ||
1090 | struct video_capability *b = arg; | ||
1091 | |||
1092 | strcpy (b->name, stv680->camera_name); | ||
1093 | b->type = VID_TYPE_CAPTURE; | ||
1094 | b->channels = 1; | ||
1095 | b->audios = 0; | ||
1096 | b->maxwidth = stv680->maxwidth; | ||
1097 | b->maxheight = stv680->maxheight; | ||
1098 | b->minwidth = stv680->maxwidth / 2; | ||
1099 | b->minheight = stv680->maxheight / 2; | ||
1100 | return 0; | ||
1101 | } | ||
1102 | case VIDIOCGCHAN:{ | ||
1103 | struct video_channel *v = arg; | ||
1104 | |||
1105 | if (v->channel != 0) | ||
1106 | return -EINVAL; | ||
1107 | v->flags = 0; | ||
1108 | v->tuners = 0; | ||
1109 | v->type = VIDEO_TYPE_CAMERA; | ||
1110 | strcpy (v->name, "STV Camera"); | ||
1111 | return 0; | ||
1112 | } | ||
1113 | case VIDIOCSCHAN:{ | ||
1114 | struct video_channel *v = arg; | ||
1115 | if (v->channel != 0) | ||
1116 | return -EINVAL; | ||
1117 | return 0; | ||
1118 | } | ||
1119 | case VIDIOCGPICT:{ | ||
1120 | struct video_picture *p = arg; | ||
1121 | |||
1122 | stv680_get_pict (stv680, p); | ||
1123 | return 0; | ||
1124 | } | ||
1125 | case VIDIOCSPICT:{ | ||
1126 | struct video_picture *p = arg; | ||
1127 | |||
1128 | if (stv680_set_pict (stv680, p)) | ||
1129 | return -EINVAL; | ||
1130 | return 0; | ||
1131 | } | ||
1132 | case VIDIOCSWIN:{ | ||
1133 | struct video_window *vw = arg; | ||
1134 | |||
1135 | if (vw->flags) | ||
1136 | return -EINVAL; | ||
1137 | if (vw->clipcount) | ||
1138 | return -EINVAL; | ||
1139 | if (vw->width != stv680->vwidth) { | ||
1140 | if (stv680_set_size (stv680, vw->width, vw->height)) { | ||
1141 | PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN"); | ||
1142 | return -EINVAL; | ||
1143 | } | ||
1144 | } | ||
1145 | return 0; | ||
1146 | } | ||
1147 | case VIDIOCGWIN:{ | ||
1148 | struct video_window *vw = arg; | ||
1149 | |||
1150 | vw->x = 0; /* FIXME */ | ||
1151 | vw->y = 0; | ||
1152 | vw->chromakey = 0; | ||
1153 | vw->flags = 0; | ||
1154 | vw->clipcount = 0; | ||
1155 | vw->width = stv680->vwidth; | ||
1156 | vw->height = stv680->vheight; | ||
1157 | return 0; | ||
1158 | } | ||
1159 | case VIDIOCGMBUF:{ | ||
1160 | struct video_mbuf *vm = arg; | ||
1161 | int i; | ||
1162 | |||
1163 | memset (vm, 0, sizeof (*vm)); | ||
1164 | vm->size = STV680_NUMFRAMES * stv680->maxframesize; | ||
1165 | vm->frames = STV680_NUMFRAMES; | ||
1166 | for (i = 0; i < STV680_NUMFRAMES; i++) | ||
1167 | vm->offsets[i] = stv680->maxframesize * i; | ||
1168 | return 0; | ||
1169 | } | ||
1170 | case VIDIOCMCAPTURE:{ | ||
1171 | struct video_mmap *vm = arg; | ||
1172 | |||
1173 | if (vm->format != STV_VIDEO_PALETTE) { | ||
1174 | PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)", | ||
1175 | vm->format, STV_VIDEO_PALETTE); | ||
1176 | if ((vm->format == 3) && (swapRGB_on == 0)) { | ||
1177 | PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON"); | ||
1178 | /* this may fix those apps (e.g., xawtv) that want BGR */ | ||
1179 | swapRGB = 1; | ||
1180 | } | ||
1181 | return -EINVAL; | ||
1182 | } | ||
1183 | if (vm->frame >= STV680_NUMFRAMES) { | ||
1184 | PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES"); | ||
1185 | return -EINVAL; | ||
1186 | } | ||
1187 | if ((stv680->frame[vm->frame].grabstate == FRAME_ERROR) | ||
1188 | || (stv680->frame[vm->frame].grabstate == FRAME_GRABBING)) { | ||
1189 | PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error", | ||
1190 | stv680->frame[vm->frame].grabstate); | ||
1191 | return -EBUSY; | ||
1192 | } | ||
1193 | /* Is this according to the v4l spec??? */ | ||
1194 | if (stv680->vwidth != vm->width) { | ||
1195 | if (stv680_set_size (stv680, vm->width, vm->height)) { | ||
1196 | PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed"); | ||
1197 | return -EINVAL; | ||
1198 | } | ||
1199 | } | ||
1200 | stv680->frame[vm->frame].grabstate = FRAME_READY; | ||
1201 | |||
1202 | if (!stv680->streaming) | ||
1203 | stv680_start_stream (stv680); | ||
1204 | |||
1205 | return 0; | ||
1206 | } | ||
1207 | case VIDIOCSYNC:{ | ||
1208 | int *frame = arg; | ||
1209 | int ret = 0; | ||
1210 | |||
1211 | if (*frame < 0 || *frame >= STV680_NUMFRAMES) { | ||
1212 | PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC"); | ||
1213 | return -EINVAL; | ||
1214 | } | ||
1215 | ret = stv680_newframe (stv680, *frame); | ||
1216 | stv680->frame[*frame].grabstate = FRAME_UNUSED; | ||
1217 | return ret; | ||
1218 | } | ||
1219 | case VIDIOCGFBUF:{ | ||
1220 | struct video_buffer *vb = arg; | ||
1221 | |||
1222 | memset (vb, 0, sizeof (*vb)); | ||
1223 | return 0; | ||
1224 | } | ||
1225 | case VIDIOCKEY: | ||
1226 | return 0; | ||
1227 | case VIDIOCCAPTURE: | ||
1228 | { | ||
1229 | PDEBUG (2, "STV(e): VIDIOCCAPTURE failed"); | ||
1230 | return -EINVAL; | ||
1231 | } | ||
1232 | case VIDIOCSFBUF: | ||
1233 | case VIDIOCGTUNER: | ||
1234 | case VIDIOCSTUNER: | ||
1235 | case VIDIOCGFREQ: | ||
1236 | case VIDIOCSFREQ: | ||
1237 | case VIDIOCGAUDIO: | ||
1238 | case VIDIOCSAUDIO: | ||
1239 | return -EINVAL; | ||
1240 | default: | ||
1241 | return -ENOIOCTLCMD; | ||
1242 | } /* end switch */ | ||
1243 | |||
1244 | return 0; | ||
1245 | } | ||
1246 | |||
1247 | static int stv680_ioctl(struct inode *inode, struct file *file, | ||
1248 | unsigned int cmd, unsigned long arg) | ||
1249 | { | ||
1250 | return video_usercopy(inode, file, cmd, arg, stv680_do_ioctl); | ||
1251 | } | ||
1252 | |||
1253 | static int stv680_mmap (struct file *file, struct vm_area_struct *vma) | ||
1254 | { | ||
1255 | struct video_device *dev = file->private_data; | ||
1256 | struct usb_stv *stv680 = video_get_drvdata(dev); | ||
1257 | unsigned long start = vma->vm_start; | ||
1258 | unsigned long size = vma->vm_end-vma->vm_start; | ||
1259 | unsigned long page, pos; | ||
1260 | |||
1261 | mutex_lock(&stv680->lock); | ||
1262 | |||
1263 | if (stv680->udev == NULL) { | ||
1264 | mutex_unlock(&stv680->lock); | ||
1265 | return -EIO; | ||
1266 | } | ||
1267 | if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1) | ||
1268 | & ~(PAGE_SIZE - 1))) { | ||
1269 | mutex_unlock(&stv680->lock); | ||
1270 | return -EINVAL; | ||
1271 | } | ||
1272 | pos = (unsigned long) stv680->fbuf; | ||
1273 | while (size > 0) { | ||
1274 | page = vmalloc_to_pfn((void *)pos); | ||
1275 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { | ||
1276 | mutex_unlock(&stv680->lock); | ||
1277 | return -EAGAIN; | ||
1278 | } | ||
1279 | start += PAGE_SIZE; | ||
1280 | pos += PAGE_SIZE; | ||
1281 | if (size > PAGE_SIZE) | ||
1282 | size -= PAGE_SIZE; | ||
1283 | else | ||
1284 | size = 0; | ||
1285 | } | ||
1286 | mutex_unlock(&stv680->lock); | ||
1287 | |||
1288 | return 0; | ||
1289 | } | ||
1290 | |||
1291 | static ssize_t stv680_read (struct file *file, char __user *buf, | ||
1292 | size_t count, loff_t *ppos) | ||
1293 | { | ||
1294 | struct video_device *dev = file->private_data; | ||
1295 | unsigned long int realcount = count; | ||
1296 | int ret = 0; | ||
1297 | struct usb_stv *stv680 = video_get_drvdata(dev); | ||
1298 | unsigned long int i; | ||
1299 | |||
1300 | if (STV680_NUMFRAMES != 2) { | ||
1301 | PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!"); | ||
1302 | return -1; | ||
1303 | } | ||
1304 | if (stv680->udev == NULL) | ||
1305 | return -EIO; | ||
1306 | if (realcount > (stv680->vwidth * stv680->vheight * 3)) | ||
1307 | realcount = stv680->vwidth * stv680->vheight * 3; | ||
1308 | |||
1309 | /* Shouldn't happen: */ | ||
1310 | if (stv680->frame[0].grabstate == FRAME_GRABBING) { | ||
1311 | PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read"); | ||
1312 | return -EBUSY; | ||
1313 | } | ||
1314 | stv680->frame[0].grabstate = FRAME_READY; | ||
1315 | stv680->frame[1].grabstate = FRAME_UNUSED; | ||
1316 | stv680->curframe = 0; | ||
1317 | |||
1318 | if (!stv680->streaming) | ||
1319 | stv680_start_stream (stv680); | ||
1320 | |||
1321 | if (!stv680->streaming) { | ||
1322 | ret = stv680_newframe (stv680, 0); /* ret should = 0 */ | ||
1323 | } | ||
1324 | |||
1325 | ret = stv680_newframe (stv680, 0); | ||
1326 | |||
1327 | if (!ret) { | ||
1328 | if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) { | ||
1329 | PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i); | ||
1330 | return -EFAULT; | ||
1331 | } | ||
1332 | } else { | ||
1333 | realcount = ret; | ||
1334 | } | ||
1335 | stv680->frame[0].grabstate = FRAME_UNUSED; | ||
1336 | return realcount; | ||
1337 | } /* stv680_read */ | ||
1338 | |||
1339 | static struct file_operations stv680_fops = { | ||
1340 | .owner = THIS_MODULE, | ||
1341 | .open = stv_open, | ||
1342 | .release = stv_close, | ||
1343 | .read = stv680_read, | ||
1344 | .mmap = stv680_mmap, | ||
1345 | .ioctl = stv680_ioctl, | ||
1346 | .compat_ioctl = v4l_compat_ioctl32, | ||
1347 | .llseek = no_llseek, | ||
1348 | }; | ||
1349 | static struct video_device stv680_template = { | ||
1350 | .owner = THIS_MODULE, | ||
1351 | .name = "STV0680 USB camera", | ||
1352 | .type = VID_TYPE_CAPTURE, | ||
1353 | .hardware = VID_HARDWARE_SE401, | ||
1354 | .fops = &stv680_fops, | ||
1355 | .release = video_device_release, | ||
1356 | .minor = -1, | ||
1357 | }; | ||
1358 | |||
1359 | static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id) | ||
1360 | { | ||
1361 | struct usb_device *dev = interface_to_usbdev(intf); | ||
1362 | struct usb_host_interface *interface; | ||
1363 | struct usb_stv *stv680 = NULL; | ||
1364 | char *camera_name = NULL; | ||
1365 | int retval = 0; | ||
1366 | |||
1367 | /* We don't handle multi-config cameras */ | ||
1368 | if (dev->descriptor.bNumConfigurations != 1) { | ||
1369 | PDEBUG (0, "STV(e): Number of Configurations != 1"); | ||
1370 | return -ENODEV; | ||
1371 | } | ||
1372 | |||
1373 | interface = &intf->altsetting[0]; | ||
1374 | /* Is it a STV680? */ | ||
1375 | if ((le16_to_cpu(dev->descriptor.idVendor) == USB_PENCAM_VENDOR_ID) && | ||
1376 | (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) { | ||
1377 | camera_name = "STV0680"; | ||
1378 | PDEBUG (0, "STV(i): STV0680 camera found."); | ||
1379 | } else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) && | ||
1380 | (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) { | ||
1381 | camera_name = "Creative WebCam Go Mini"; | ||
1382 | PDEBUG (0, "STV(i): Creative WebCam Go Mini found."); | ||
1383 | } else { | ||
1384 | PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values."); | ||
1385 | PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer."); | ||
1386 | retval = -ENODEV; | ||
1387 | goto error; | ||
1388 | } | ||
1389 | /* We found one */ | ||
1390 | if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) { | ||
1391 | PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct."); | ||
1392 | retval = -ENOMEM; | ||
1393 | goto error; | ||
1394 | } | ||
1395 | |||
1396 | stv680->udev = dev; | ||
1397 | stv680->camera_name = camera_name; | ||
1398 | |||
1399 | stv680->vdev = video_device_alloc(); | ||
1400 | if (!stv680->vdev) { | ||
1401 | retval = -ENOMEM; | ||
1402 | goto error; | ||
1403 | } | ||
1404 | memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template)); | ||
1405 | stv680->vdev->dev = &intf->dev; | ||
1406 | video_set_drvdata(stv680->vdev, stv680); | ||
1407 | |||
1408 | memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name)); | ||
1409 | init_waitqueue_head (&stv680->wq); | ||
1410 | mutex_init (&stv680->lock); | ||
1411 | wmb (); | ||
1412 | |||
1413 | if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { | ||
1414 | PDEBUG (0, "STV(e): video_register_device failed"); | ||
1415 | retval = -EIO; | ||
1416 | goto error_vdev; | ||
1417 | } | ||
1418 | PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor); | ||
1419 | |||
1420 | usb_set_intfdata (intf, stv680); | ||
1421 | stv680_create_sysfs_files(stv680->vdev); | ||
1422 | return 0; | ||
1423 | |||
1424 | error_vdev: | ||
1425 | video_device_release(stv680->vdev); | ||
1426 | error: | ||
1427 | kfree(stv680); | ||
1428 | return retval; | ||
1429 | } | ||
1430 | |||
1431 | static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680) | ||
1432 | { | ||
1433 | int i; | ||
1434 | |||
1435 | stv680->udev = NULL; | ||
1436 | stv680->frame[0].grabstate = FRAME_ERROR; | ||
1437 | stv680->frame[1].grabstate = FRAME_ERROR; | ||
1438 | stv680->streaming = 0; | ||
1439 | |||
1440 | wake_up_interruptible (&stv680->wq); | ||
1441 | |||
1442 | for (i = 0; i < STV680_NUMSBUF; i++) | ||
1443 | if (stv680->urb[i]) { | ||
1444 | usb_kill_urb (stv680->urb[i]); | ||
1445 | usb_free_urb (stv680->urb[i]); | ||
1446 | stv680->urb[i] = NULL; | ||
1447 | kfree(stv680->sbuf[i].data); | ||
1448 | } | ||
1449 | for (i = 0; i < STV680_NUMSCRATCH; i++) | ||
1450 | kfree(stv680->scratch[i].data); | ||
1451 | PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name); | ||
1452 | |||
1453 | /* Free the memory */ | ||
1454 | kfree(stv680); | ||
1455 | } | ||
1456 | |||
1457 | static void stv680_disconnect (struct usb_interface *intf) | ||
1458 | { | ||
1459 | struct usb_stv *stv680 = usb_get_intfdata (intf); | ||
1460 | |||
1461 | usb_set_intfdata (intf, NULL); | ||
1462 | |||
1463 | if (stv680) { | ||
1464 | /* We don't want people trying to open up the device */ | ||
1465 | if (stv680->vdev) { | ||
1466 | stv680_remove_sysfs_files(stv680->vdev); | ||
1467 | video_unregister_device(stv680->vdev); | ||
1468 | stv680->vdev = NULL; | ||
1469 | } | ||
1470 | if (!stv680->user) { | ||
1471 | usb_stv680_remove_disconnected (stv680); | ||
1472 | } else { | ||
1473 | stv680->removed = 1; | ||
1474 | } | ||
1475 | } | ||
1476 | } | ||
1477 | |||
1478 | static struct usb_driver stv680_driver = { | ||
1479 | .name = "stv680", | ||
1480 | .probe = stv680_probe, | ||
1481 | .disconnect = stv680_disconnect, | ||
1482 | .id_table = device_table | ||
1483 | }; | ||
1484 | |||
1485 | /******************************************************************** | ||
1486 | * Module routines | ||
1487 | ********************************************************************/ | ||
1488 | |||
1489 | static int __init usb_stv680_init (void) | ||
1490 | { | ||
1491 | if (usb_register (&stv680_driver) < 0) { | ||
1492 | PDEBUG (0, "STV(e): Could not setup STV0680 driver"); | ||
1493 | return -1; | ||
1494 | } | ||
1495 | PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION); | ||
1496 | |||
1497 | info(DRIVER_DESC " " DRIVER_VERSION); | ||
1498 | return 0; | ||
1499 | } | ||
1500 | |||
1501 | static void __exit usb_stv680_exit (void) | ||
1502 | { | ||
1503 | usb_deregister (&stv680_driver); | ||
1504 | PDEBUG (0, "STV(i): driver deregistered"); | ||
1505 | } | ||
1506 | |||
1507 | module_init (usb_stv680_init); | ||
1508 | module_exit (usb_stv680_exit); | ||
diff --git a/drivers/media/video/stv680.h b/drivers/media/video/stv680.h new file mode 100644 index 000000000000..ea46e0001e6d --- /dev/null +++ b/drivers/media/video/stv680.h | |||
@@ -0,0 +1,227 @@ | |||
1 | /**************************************************************************** | ||
2 | * | ||
3 | * Filename: stv680.h | ||
4 | * | ||
5 | * Description: | ||
6 | * This is a USB driver for STV0680 based usb video cameras. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | /* size of usb transfers */ | ||
25 | #define STV680_PACKETSIZE 4096 | ||
26 | |||
27 | /* number of queued bulk transfers to use, may have problems if > 1 */ | ||
28 | #define STV680_NUMSBUF 1 | ||
29 | |||
30 | /* number of frames supported by the v4l part */ | ||
31 | #define STV680_NUMFRAMES 2 | ||
32 | |||
33 | /* scratch buffers for passing data to the decoders: 2 or 4 are good */ | ||
34 | #define STV680_NUMSCRATCH 2 | ||
35 | |||
36 | /* number of nul sized packets to receive before kicking the camera */ | ||
37 | #define STV680_MAX_NULLPACKETS 200 | ||
38 | |||
39 | /* number of decoding errors before kicking the camera */ | ||
40 | #define STV680_MAX_ERRORS 100 | ||
41 | |||
42 | #define USB_PENCAM_VENDOR_ID 0x0553 | ||
43 | #define USB_PENCAM_PRODUCT_ID 0x0202 | ||
44 | |||
45 | #define USB_CREATIVEGOMINI_VENDOR_ID 0x041e | ||
46 | #define USB_CREATIVEGOMINI_PRODUCT_ID 0x4007 | ||
47 | |||
48 | #define PENCAM_TIMEOUT 1000 | ||
49 | /* fmt 4 */ | ||
50 | #define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24 | ||
51 | |||
52 | static struct usb_device_id device_table[] = { | ||
53 | {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)}, | ||
54 | {USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)}, | ||
55 | {} | ||
56 | }; | ||
57 | MODULE_DEVICE_TABLE (usb, device_table); | ||
58 | |||
59 | struct stv680_sbuf { | ||
60 | unsigned char *data; | ||
61 | }; | ||
62 | |||
63 | enum { | ||
64 | FRAME_UNUSED, /* Unused (no MCAPTURE) */ | ||
65 | FRAME_READY, /* Ready to start grabbing */ | ||
66 | FRAME_GRABBING, /* In the process of being grabbed into */ | ||
67 | FRAME_DONE, /* Finished grabbing, but not been synced yet */ | ||
68 | FRAME_ERROR, /* Something bad happened while processing */ | ||
69 | }; | ||
70 | |||
71 | enum { | ||
72 | BUFFER_UNUSED, | ||
73 | BUFFER_READY, | ||
74 | BUFFER_BUSY, | ||
75 | BUFFER_DONE, | ||
76 | }; | ||
77 | |||
78 | /* raw camera data <- sbuf (urb transfer buf) */ | ||
79 | struct stv680_scratch { | ||
80 | unsigned char *data; | ||
81 | volatile int state; | ||
82 | int offset; | ||
83 | int length; | ||
84 | }; | ||
85 | |||
86 | /* processed data for display ends up here, after bayer */ | ||
87 | struct stv680_frame { | ||
88 | unsigned char *data; /* Frame buffer */ | ||
89 | volatile int grabstate; /* State of grabbing */ | ||
90 | unsigned char *curline; | ||
91 | int curlinepix; | ||
92 | int curpix; | ||
93 | }; | ||
94 | |||
95 | /* this is almost the video structure uvd_t, with extra parameters for stv */ | ||
96 | struct usb_stv { | ||
97 | struct video_device *vdev; | ||
98 | |||
99 | struct usb_device *udev; | ||
100 | |||
101 | unsigned char bulk_in_endpointAddr; /* __u8 the address of the bulk in endpoint */ | ||
102 | char *camera_name; | ||
103 | |||
104 | unsigned int VideoMode; /* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */ | ||
105 | int SupportedModes; | ||
106 | int CIF; | ||
107 | int VGA; | ||
108 | int QVGA; | ||
109 | int cwidth; /* camera width */ | ||
110 | int cheight; /* camera height */ | ||
111 | int maxwidth; /* max video width */ | ||
112 | int maxheight; /* max video height */ | ||
113 | int vwidth; /* current width for video window */ | ||
114 | int vheight; /* current height for video window */ | ||
115 | unsigned long int rawbufsize; | ||
116 | unsigned long int maxframesize; /* rawbufsize * 3 for RGB */ | ||
117 | |||
118 | int origGain; | ||
119 | int origMode; /* original camera mode */ | ||
120 | |||
121 | struct mutex lock; /* to lock the structure */ | ||
122 | int user; /* user count for exclusive use */ | ||
123 | int removed; /* device disconnected */ | ||
124 | int streaming; /* Are we streaming video? */ | ||
125 | char *fbuf; /* Videodev buffer area */ | ||
126 | struct urb *urb[STV680_NUMSBUF]; /* # of queued bulk transfers */ | ||
127 | int curframe; /* Current receiving frame */ | ||
128 | struct stv680_frame frame[STV680_NUMFRAMES]; /* # frames supported by v4l part */ | ||
129 | int readcount; | ||
130 | int framecount; | ||
131 | int error; | ||
132 | int dropped; | ||
133 | int scratch_next; | ||
134 | int scratch_use; | ||
135 | int scratch_overflow; | ||
136 | struct stv680_scratch scratch[STV680_NUMSCRATCH]; /* for decoders */ | ||
137 | struct stv680_sbuf sbuf[STV680_NUMSBUF]; | ||
138 | |||
139 | unsigned int brightness; | ||
140 | unsigned int chgbright; | ||
141 | unsigned int whiteness; | ||
142 | unsigned int colour; | ||
143 | unsigned int contrast; | ||
144 | unsigned int hue; | ||
145 | unsigned int palette; | ||
146 | unsigned int depth; /* rgb24 in bits */ | ||
147 | |||
148 | wait_queue_head_t wq; /* Processes waiting */ | ||
149 | |||
150 | int nullpackets; | ||
151 | }; | ||
152 | |||
153 | |||
154 | static const unsigned char red[256] = { | ||
155 | 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, | ||
156 | 18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, | ||
157 | 44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, | ||
158 | 71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, | ||
159 | 88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, | ||
160 | 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, | ||
161 | 114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, | ||
162 | 125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, | ||
163 | 134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, | ||
164 | 143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, | ||
165 | 152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, | ||
166 | 159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, | ||
167 | 167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, | ||
168 | 173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, | ||
169 | 180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, | ||
170 | 187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, | ||
171 | 192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, | ||
172 | 198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, | ||
173 | 204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, | ||
174 | 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, | ||
175 | 215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, | ||
176 | 220, 220, 221, 221 | ||
177 | }; | ||
178 | |||
179 | static const unsigned char green[256] = { | ||
180 | 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, | ||
181 | 21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, | ||
182 | 50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, | ||
183 | 79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, | ||
184 | 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, | ||
185 | 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, | ||
186 | 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, | ||
187 | 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, | ||
188 | 150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, | ||
189 | 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, | ||
190 | 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, | ||
191 | 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, | ||
192 | 186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, | ||
193 | 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, | ||
194 | 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, | ||
195 | 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, | ||
196 | 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, | ||
197 | 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, | ||
198 | 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, | ||
199 | 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, | ||
200 | 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, | ||
201 | 245, 245, 246, 246 | ||
202 | }; | ||
203 | |||
204 | static const unsigned char blue[256] = { | ||
205 | 0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, | ||
206 | 23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, | ||
207 | 55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, | ||
208 | 86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, | ||
209 | 107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, | ||
210 | 125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, | ||
211 | 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, | ||
212 | 152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, | ||
213 | 165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, | ||
214 | 176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, | ||
215 | 185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, | ||
216 | 194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, | ||
217 | 204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, | ||
218 | 212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, | ||
219 | 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, | ||
220 | 228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, | ||
221 | 235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, | ||
222 | 243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, | ||
223 | 249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, | ||
224 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||
225 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||
226 | 255, 255, 255, 255 | ||
227 | }; | ||
diff --git a/drivers/media/video/usbvideo/Makefile b/drivers/media/video/usbvideo/Makefile new file mode 100644 index 000000000000..ed410a5ee8c9 --- /dev/null +++ b/drivers/media/video/usbvideo/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | obj-$(CONFIG_USB_IBMCAM) += ibmcam.o usbvideo.o ultracam.o | ||
2 | obj-$(CONFIG_USB_KONICAWC) += konicawc.o usbvideo.o | ||
3 | obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o | ||
4 | |||
diff --git a/drivers/media/video/usbvideo/ibmcam.c b/drivers/media/video/usbvideo/ibmcam.c new file mode 100644 index 000000000000..a42c22294124 --- /dev/null +++ b/drivers/media/video/usbvideo/ibmcam.c | |||
@@ -0,0 +1,3932 @@ | |||
1 | /* | ||
2 | * USB IBM C-It Video Camera driver | ||
3 | * | ||
4 | * Supports Xirlink C-It Video Camera, IBM PC Camera, | ||
5 | * IBM NetCamera and Veo Stingray. | ||
6 | * | ||
7 | * This driver is based on earlier work of: | ||
8 | * | ||
9 | * (C) Copyright 1999 Johannes Erdfelt | ||
10 | * (C) Copyright 1999 Randy Dunlap | ||
11 | * | ||
12 | * 5/24/00 Removed optional (and unnecessary) locking of the driver while | ||
13 | * the device remains plugged in. Corrected race conditions in ibmcam_open | ||
14 | * and ibmcam_probe() routines using this as a guideline: | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | |||
22 | #include "usbvideo.h" | ||
23 | |||
24 | #define IBMCAM_VENDOR_ID 0x0545 | ||
25 | #define IBMCAM_PRODUCT_ID 0x8080 | ||
26 | #define NETCAM_PRODUCT_ID 0x8002 /* IBM NetCamera, close to model 2 */ | ||
27 | #define VEO_800C_PRODUCT_ID 0x800C /* Veo Stingray, repackaged Model 2 */ | ||
28 | #define VEO_800D_PRODUCT_ID 0x800D /* Veo Stingray, repackaged Model 4 */ | ||
29 | |||
30 | #define MAX_IBMCAM 4 /* How many devices we allow to connect */ | ||
31 | #define USES_IBMCAM_PUTPIXEL 0 /* 0=Fast/oops 1=Slow/secure */ | ||
32 | |||
33 | /* Header signatures */ | ||
34 | |||
35 | /* Model 1 header: 00 FF 00 xx */ | ||
36 | #define HDRSIG_MODEL1_128x96 0x06 /* U Y V Y ... */ | ||
37 | #define HDRSIG_MODEL1_176x144 0x0e /* U Y V Y ... */ | ||
38 | #define HDRSIG_MODEL1_352x288 0x00 /* V Y U Y ... */ | ||
39 | |||
40 | #define IBMCAM_MODEL_1 1 /* XVP-501, 3 interfaces, rev. 0.02 */ | ||
41 | #define IBMCAM_MODEL_2 2 /* KSX-X9903, 2 interfaces, rev. 3.0a */ | ||
42 | #define IBMCAM_MODEL_3 3 /* KSX-X9902, 2 interfaces, rev. 3.01 */ | ||
43 | #define IBMCAM_MODEL_4 4 /* IBM NetCamera, 0545/8002/3.0a */ | ||
44 | |||
45 | /* Video sizes supported */ | ||
46 | #define VIDEOSIZE_128x96 VIDEOSIZE(128, 96) | ||
47 | #define VIDEOSIZE_176x144 VIDEOSIZE(176,144) | ||
48 | #define VIDEOSIZE_352x288 VIDEOSIZE(352,288) | ||
49 | #define VIDEOSIZE_320x240 VIDEOSIZE(320,240) | ||
50 | #define VIDEOSIZE_352x240 VIDEOSIZE(352,240) | ||
51 | #define VIDEOSIZE_640x480 VIDEOSIZE(640,480) | ||
52 | #define VIDEOSIZE_160x120 VIDEOSIZE(160,120) | ||
53 | |||
54 | /* Video sizes supported */ | ||
55 | enum { | ||
56 | SIZE_128x96 = 0, | ||
57 | SIZE_160x120, | ||
58 | SIZE_176x144, | ||
59 | SIZE_320x240, | ||
60 | SIZE_352x240, | ||
61 | SIZE_352x288, | ||
62 | SIZE_640x480, | ||
63 | /* Add/remove/rearrange items before this line */ | ||
64 | SIZE_LastItem | ||
65 | }; | ||
66 | |||
67 | /* | ||
68 | * This structure lives in uvd->user field. | ||
69 | */ | ||
70 | typedef struct { | ||
71 | int initialized; /* Had we already sent init sequence? */ | ||
72 | int camera_model; /* What type of IBM camera we got? */ | ||
73 | int has_hdr; | ||
74 | } ibmcam_t; | ||
75 | #define IBMCAM_T(uvd) ((ibmcam_t *)((uvd)->user_data)) | ||
76 | |||
77 | static struct usbvideo *cams; | ||
78 | |||
79 | static int debug; | ||
80 | |||
81 | static int flags; /* = FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */ | ||
82 | |||
83 | static const int min_canvasWidth = 8; | ||
84 | static const int min_canvasHeight = 4; | ||
85 | |||
86 | static int lighting = 1; /* Medium */ | ||
87 | |||
88 | #define SHARPNESS_MIN 0 | ||
89 | #define SHARPNESS_MAX 6 | ||
90 | static int sharpness = 4; /* Low noise, good details */ | ||
91 | |||
92 | #define FRAMERATE_MIN 0 | ||
93 | #define FRAMERATE_MAX 6 | ||
94 | static int framerate = -1; | ||
95 | |||
96 | static int size = SIZE_352x288; | ||
97 | |||
98 | /* | ||
99 | * Here we define several initialization variables. They may | ||
100 | * be used to automatically set color, hue, brightness and | ||
101 | * contrast to desired values. This is particularly useful in | ||
102 | * case of webcams (which have no controls and no on-screen | ||
103 | * output) and also when a client V4L software is used that | ||
104 | * does not have some of those controls. In any case it's | ||
105 | * good to have startup values as options. | ||
106 | * | ||
107 | * These values are all in [0..255] range. This simplifies | ||
108 | * operation. Note that actual values of V4L variables may | ||
109 | * be scaled up (as much as << 8). User can see that only | ||
110 | * on overlay output, however, or through a V4L client. | ||
111 | */ | ||
112 | static int init_brightness = 128; | ||
113 | static int init_contrast = 192; | ||
114 | static int init_color = 128; | ||
115 | static int init_hue = 128; | ||
116 | static int hue_correction = 128; | ||
117 | |||
118 | /* Settings for camera model 2 */ | ||
119 | static int init_model2_rg2 = -1; | ||
120 | static int init_model2_sat = -1; | ||
121 | static int init_model2_yb = -1; | ||
122 | |||
123 | /* 01.01.08 - Added for RCA video in support -LO */ | ||
124 | /* Settings for camera model 3 */ | ||
125 | static int init_model3_input = 0; | ||
126 | |||
127 | module_param(debug, int, 0); | ||
128 | MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); | ||
129 | module_param(flags, int, 0); | ||
130 | MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=separate frames, 6=clean frames"); | ||
131 | module_param(framerate, int, 0); | ||
132 | MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); | ||
133 | module_param(lighting, int, 0); | ||
134 | MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light"); | ||
135 | module_param(sharpness, int, 0); | ||
136 | MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)"); | ||
137 | module_param(size, int, 0); | ||
138 | MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480 (default=5)"); | ||
139 | module_param(init_brightness, int, 0); | ||
140 | MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); | ||
141 | module_param(init_contrast, int, 0); | ||
142 | MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); | ||
143 | module_param(init_color, int, 0); | ||
144 | MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); | ||
145 | module_param(init_hue, int, 0); | ||
146 | MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); | ||
147 | module_param(hue_correction, int, 0); | ||
148 | MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); | ||
149 | |||
150 | module_param(init_model2_rg2, int, 0); | ||
151 | MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)"); | ||
152 | module_param(init_model2_sat, int, 0); | ||
153 | MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)"); | ||
154 | module_param(init_model2_yb, int, 0); | ||
155 | MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)"); | ||
156 | |||
157 | /* 01.01.08 - Added for RCA video in support -LO */ | ||
158 | module_param(init_model3_input, int, 0); | ||
159 | MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA"); | ||
160 | |||
161 | MODULE_AUTHOR ("Dmitri"); | ||
162 | MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000"); | ||
163 | MODULE_LICENSE("GPL"); | ||
164 | |||
165 | /* Still mysterious i2c commands */ | ||
166 | static const unsigned short unknown_88 = 0x0088; | ||
167 | static const unsigned short unknown_89 = 0x0089; | ||
168 | static const unsigned short bright_3x[3] = { 0x0031, 0x0032, 0x0033 }; | ||
169 | static const unsigned short contrast_14 = 0x0014; | ||
170 | static const unsigned short light_27 = 0x0027; | ||
171 | static const unsigned short sharp_13 = 0x0013; | ||
172 | |||
173 | /* i2c commands for Model 2 cameras */ | ||
174 | static const unsigned short mod2_brightness = 0x001a; /* $5b .. $ee; default=$5a */ | ||
175 | static const unsigned short mod2_set_framerate = 0x001c; /* 0 (fast).. $1F (slow) */ | ||
176 | static const unsigned short mod2_color_balance_rg2 = 0x001e; /* 0 (red) .. $7F (green) */ | ||
177 | static const unsigned short mod2_saturation = 0x0020; /* 0 (b/w) - $7F (full color) */ | ||
178 | static const unsigned short mod2_color_balance_yb = 0x0022; /* 0..$7F, $50 is about right */ | ||
179 | static const unsigned short mod2_hue = 0x0024; /* 0..$7F, $70 is about right */ | ||
180 | static const unsigned short mod2_sensitivity = 0x0028; /* 0 (min) .. $1F (max) */ | ||
181 | |||
182 | struct struct_initData { | ||
183 | unsigned char req; | ||
184 | unsigned short value; | ||
185 | unsigned short index; | ||
186 | }; | ||
187 | |||
188 | /* | ||
189 | * ibmcam_size_to_videosize() | ||
190 | * | ||
191 | * This procedure converts module option 'size' into the actual | ||
192 | * videosize_t that defines the image size in pixels. We need | ||
193 | * simplified 'size' because user wants a simple enumerated list | ||
194 | * of choices, not an infinite set of possibilities. | ||
195 | */ | ||
196 | static videosize_t ibmcam_size_to_videosize(int size) | ||
197 | { | ||
198 | videosize_t vs = VIDEOSIZE_352x288; | ||
199 | RESTRICT_TO_RANGE(size, 0, (SIZE_LastItem-1)); | ||
200 | switch (size) { | ||
201 | case SIZE_128x96: | ||
202 | vs = VIDEOSIZE_128x96; | ||
203 | break; | ||
204 | case SIZE_160x120: | ||
205 | vs = VIDEOSIZE_160x120; | ||
206 | break; | ||
207 | case SIZE_176x144: | ||
208 | vs = VIDEOSIZE_176x144; | ||
209 | break; | ||
210 | case SIZE_320x240: | ||
211 | vs = VIDEOSIZE_320x240; | ||
212 | break; | ||
213 | case SIZE_352x240: | ||
214 | vs = VIDEOSIZE_352x240; | ||
215 | break; | ||
216 | case SIZE_352x288: | ||
217 | vs = VIDEOSIZE_352x288; | ||
218 | break; | ||
219 | case SIZE_640x480: | ||
220 | vs = VIDEOSIZE_640x480; | ||
221 | break; | ||
222 | default: | ||
223 | err("size=%d. is not valid", size); | ||
224 | break; | ||
225 | } | ||
226 | return vs; | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * ibmcam_find_header() | ||
231 | * | ||
232 | * Locate one of supported header markers in the queue. | ||
233 | * Once found, remove all preceding bytes AND the marker (4 bytes) | ||
234 | * from the data pump queue. Whatever follows must be video lines. | ||
235 | * | ||
236 | * History: | ||
237 | * 1/21/00 Created. | ||
238 | */ | ||
239 | static enum ParseState ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame here */ | ||
240 | { | ||
241 | struct usbvideo_frame *frame; | ||
242 | ibmcam_t *icam; | ||
243 | |||
244 | if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) { | ||
245 | err("ibmcam_find_header: Illegal frame %d.", uvd->curframe); | ||
246 | return scan_EndParse; | ||
247 | } | ||
248 | icam = IBMCAM_T(uvd); | ||
249 | assert(icam != NULL); | ||
250 | frame = &uvd->frame[uvd->curframe]; | ||
251 | icam->has_hdr = 0; | ||
252 | switch (icam->camera_model) { | ||
253 | case IBMCAM_MODEL_1: | ||
254 | { | ||
255 | const int marker_len = 4; | ||
256 | while (RingQueue_GetLength(&uvd->dp) >= marker_len) { | ||
257 | if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && | ||
258 | (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) && | ||
259 | (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00)) | ||
260 | { | ||
261 | #if 0 /* This code helps to detect new frame markers */ | ||
262 | info("Header sig: 00 FF 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 3)); | ||
263 | #endif | ||
264 | frame->header = RING_QUEUE_PEEK(&uvd->dp, 3); | ||
265 | if ((frame->header == HDRSIG_MODEL1_128x96) || | ||
266 | (frame->header == HDRSIG_MODEL1_176x144) || | ||
267 | (frame->header == HDRSIG_MODEL1_352x288)) | ||
268 | { | ||
269 | #if 0 | ||
270 | info("Header found."); | ||
271 | #endif | ||
272 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); | ||
273 | icam->has_hdr = 1; | ||
274 | break; | ||
275 | } | ||
276 | } | ||
277 | /* If we are still here then this doesn't look like a header */ | ||
278 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); | ||
279 | } | ||
280 | break; | ||
281 | } | ||
282 | case IBMCAM_MODEL_2: | ||
283 | case IBMCAM_MODEL_4: | ||
284 | { | ||
285 | int marker_len = 0; | ||
286 | switch (uvd->videosize) { | ||
287 | case VIDEOSIZE_176x144: | ||
288 | marker_len = 10; | ||
289 | break; | ||
290 | default: | ||
291 | marker_len = 2; | ||
292 | break; | ||
293 | } | ||
294 | while (RingQueue_GetLength(&uvd->dp) >= marker_len) { | ||
295 | if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && | ||
296 | (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF)) | ||
297 | { | ||
298 | #if 0 | ||
299 | info("Header found."); | ||
300 | #endif | ||
301 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); | ||
302 | icam->has_hdr = 1; | ||
303 | frame->header = HDRSIG_MODEL1_176x144; | ||
304 | break; | ||
305 | } | ||
306 | /* If we are still here then this doesn't look like a header */ | ||
307 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); | ||
308 | } | ||
309 | break; | ||
310 | } | ||
311 | case IBMCAM_MODEL_3: | ||
312 | { /* | ||
313 | * Headers: (one precedes every frame). nc=no compression, | ||
314 | * bq=best quality bf=best frame rate. | ||
315 | * | ||
316 | * 176x144: 00 FF 02 { 0A=nc CA=bq EA=bf } | ||
317 | * 320x240: 00 FF 02 { 08=nc 28=bq 68=bf } | ||
318 | * 640x480: 00 FF 03 { 08=nc 28=bq 68=bf } | ||
319 | * | ||
320 | * Bytes '00 FF' seem to indicate header. Other two bytes | ||
321 | * encode the frame type. This is a set of bit fields that | ||
322 | * encode image size, compression type etc. These fields | ||
323 | * do NOT contain frame number because all frames carry | ||
324 | * the same header. | ||
325 | */ | ||
326 | const int marker_len = 4; | ||
327 | while (RingQueue_GetLength(&uvd->dp) >= marker_len) { | ||
328 | if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && | ||
329 | (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) && | ||
330 | (RING_QUEUE_PEEK(&uvd->dp, 2) != 0xFF)) | ||
331 | { | ||
332 | /* | ||
333 | * Combine 2 bytes of frame type into one | ||
334 | * easy to use value | ||
335 | */ | ||
336 | unsigned long byte3, byte4; | ||
337 | |||
338 | byte3 = RING_QUEUE_PEEK(&uvd->dp, 2); | ||
339 | byte4 = RING_QUEUE_PEEK(&uvd->dp, 3); | ||
340 | frame->header = (byte3 << 8) | byte4; | ||
341 | #if 0 | ||
342 | info("Header found."); | ||
343 | #endif | ||
344 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); | ||
345 | icam->has_hdr = 1; | ||
346 | break; | ||
347 | } | ||
348 | /* If we are still here then this doesn't look like a header */ | ||
349 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); | ||
350 | } | ||
351 | break; | ||
352 | } | ||
353 | default: | ||
354 | break; | ||
355 | } | ||
356 | if (!icam->has_hdr) { | ||
357 | if (uvd->debug > 2) | ||
358 | info("Skipping frame, no header"); | ||
359 | return scan_EndParse; | ||
360 | } | ||
361 | |||
362 | /* Header found */ | ||
363 | icam->has_hdr = 1; | ||
364 | uvd->stats.header_count++; | ||
365 | frame->scanstate = ScanState_Lines; | ||
366 | frame->curline = 0; | ||
367 | |||
368 | if (flags & FLAGS_FORCE_TESTPATTERN) { | ||
369 | usbvideo_TestPattern(uvd, 1, 1); | ||
370 | return scan_NextFrame; | ||
371 | } | ||
372 | return scan_Continue; | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * ibmcam_parse_lines() | ||
377 | * | ||
378 | * Parse one line (interlaced) from the buffer, put | ||
379 | * decoded RGB value into the current frame buffer | ||
380 | * and add the written number of bytes (RGB) to | ||
381 | * the *pcopylen. | ||
382 | * | ||
383 | * History: | ||
384 | * 21-Jan-2000 Created. | ||
385 | * 12-Oct-2000 Reworked to reflect interlaced nature of the data. | ||
386 | */ | ||
387 | static enum ParseState ibmcam_parse_lines( | ||
388 | struct uvd *uvd, | ||
389 | struct usbvideo_frame *frame, | ||
390 | long *pcopylen) | ||
391 | { | ||
392 | unsigned char *f; | ||
393 | ibmcam_t *icam; | ||
394 | unsigned int len, scanLength, scanHeight, order_uv, order_yc; | ||
395 | int v4l_linesize; /* V4L line offset */ | ||
396 | const int hue_corr = (uvd->vpic.hue - 0x8000) >> 10; /* -32..+31 */ | ||
397 | const int hue2_corr = (hue_correction - 128) / 4; /* -32..+31 */ | ||
398 | const int ccm = 128; /* Color correction median - see below */ | ||
399 | int y, u, v, i, frame_done=0, color_corr; | ||
400 | static unsigned char lineBuffer[640*3]; | ||
401 | unsigned const char *chromaLine, *lumaLine; | ||
402 | |||
403 | assert(uvd != NULL); | ||
404 | assert(frame != NULL); | ||
405 | icam = IBMCAM_T(uvd); | ||
406 | assert(icam != NULL); | ||
407 | color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ | ||
408 | RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1); | ||
409 | |||
410 | v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; | ||
411 | |||
412 | if (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_4) { | ||
413 | /* Model 4 frame markers do not carry image size identification */ | ||
414 | switch (uvd->videosize) { | ||
415 | case VIDEOSIZE_128x96: | ||
416 | case VIDEOSIZE_160x120: | ||
417 | case VIDEOSIZE_176x144: | ||
418 | scanLength = VIDEOSIZE_X(uvd->videosize); | ||
419 | scanHeight = VIDEOSIZE_Y(uvd->videosize); | ||
420 | break; | ||
421 | default: | ||
422 | err("ibmcam_parse_lines: Wrong mode."); | ||
423 | return scan_Out; | ||
424 | } | ||
425 | order_yc = 1; /* order_yc: true=Yc false=cY ('c'=either U or V) */ | ||
426 | order_uv = 1; /* Always true in this algorithm */ | ||
427 | } else { | ||
428 | switch (frame->header) { | ||
429 | case HDRSIG_MODEL1_128x96: | ||
430 | scanLength = 128; | ||
431 | scanHeight = 96; | ||
432 | order_uv = 1; /* U Y V Y ... */ | ||
433 | break; | ||
434 | case HDRSIG_MODEL1_176x144: | ||
435 | scanLength = 176; | ||
436 | scanHeight = 144; | ||
437 | order_uv = 1; /* U Y V Y ... */ | ||
438 | break; | ||
439 | case HDRSIG_MODEL1_352x288: | ||
440 | scanLength = 352; | ||
441 | scanHeight = 288; | ||
442 | order_uv = 0; /* Y V Y V ... */ | ||
443 | break; | ||
444 | default: | ||
445 | err("Unknown header signature 00 FF 00 %02lX", frame->header); | ||
446 | return scan_NextFrame; | ||
447 | } | ||
448 | /* order_yc: true=Yc false=cY ('c'=either U or V) */ | ||
449 | order_yc = (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_2); | ||
450 | } | ||
451 | |||
452 | len = scanLength * 3; | ||
453 | assert(len <= sizeof(lineBuffer)); | ||
454 | |||
455 | /* | ||
456 | * Lines are organized this way: | ||
457 | * | ||
458 | * I420: | ||
459 | * ~~~~ | ||
460 | * <scanLength-> | ||
461 | * ___________________________________ | ||
462 | * |-----Y-----|---UVUVUV...UVUV-----| \ | ||
463 | * |-----------+---------------------| \ | ||
464 | * |<-- 176 -->|<------ 176*2 ------>| Total 72. lines (interlaced) | ||
465 | * |... ... | ... | / | ||
466 | * |<-- 352 -->|<------ 352*2 ------>| Total 144. lines (interlaced) | ||
467 | * |___________|_____________________| / | ||
468 | * \ \ | ||
469 | * lumaLine chromaLine | ||
470 | */ | ||
471 | |||
472 | /* Make sure there's enough data for the entire line */ | ||
473 | if (RingQueue_GetLength(&uvd->dp) < len) | ||
474 | return scan_Out; | ||
475 | |||
476 | /* Suck one line out of the ring queue */ | ||
477 | RingQueue_Dequeue(&uvd->dp, lineBuffer, len); | ||
478 | |||
479 | /* | ||
480 | * Make sure that our writing into output buffer | ||
481 | * will not exceed the buffer. Mind that we may write | ||
482 | * not into current output scanline but in several after | ||
483 | * it as well (if we enlarge image vertically.) | ||
484 | */ | ||
485 | if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request)) | ||
486 | return scan_NextFrame; | ||
487 | |||
488 | /* | ||
489 | * Now we are sure that entire line (representing all 'scanLength' | ||
490 | * pixels from the camera) is available in the buffer. We | ||
491 | * start copying the line left-aligned to the V4L buffer. | ||
492 | * If the camera line is shorter then we should pad the V4L | ||
493 | * buffer with something (black) to complete the line. | ||
494 | */ | ||
495 | assert(frame->data != NULL); | ||
496 | f = frame->data + (v4l_linesize * frame->curline); | ||
497 | |||
498 | /* | ||
499 | * To obtain chrominance data from the 'chromaLine' use this: | ||
500 | * v = chromaLine[0]; // 0-1:[0], 2-3:[4], 4-5:[8]... | ||
501 | * u = chromaLine[2]; // 0-1:[2], 2-3:[6], 4-5:[10]... | ||
502 | * | ||
503 | * Indices must be calculated this way: | ||
504 | * v_index = (i >> 1) << 2; | ||
505 | * u_index = (i >> 1) << 2 + 2; | ||
506 | * | ||
507 | * where 'i' is the column number [0..VIDEOSIZE_X(frame->request)-1] | ||
508 | */ | ||
509 | lumaLine = lineBuffer; | ||
510 | chromaLine = lineBuffer + scanLength; | ||
511 | for (i = 0; i < VIDEOSIZE_X(frame->request); i++) | ||
512 | { | ||
513 | unsigned char rv, gv, bv; /* RGB components */ | ||
514 | |||
515 | /* Check for various visual debugging hints (colorized pixels) */ | ||
516 | if ((flags & FLAGS_DISPLAY_HINTS) && (icam->has_hdr)) { | ||
517 | /* | ||
518 | * This is bad and should not happen. This means that | ||
519 | * we somehow overshoot the line and encountered new | ||
520 | * frame! Obviously our camera/V4L frame size is out | ||
521 | * of whack. This cyan dot will help you to figure | ||
522 | * out where exactly the new frame arrived. | ||
523 | */ | ||
524 | if (icam->has_hdr == 1) { | ||
525 | bv = 0; /* Yellow marker */ | ||
526 | gv = 0xFF; | ||
527 | rv = 0xFF; | ||
528 | } else { | ||
529 | bv = 0xFF; /* Cyan marker */ | ||
530 | gv = 0xFF; | ||
531 | rv = 0; | ||
532 | } | ||
533 | icam->has_hdr = 0; | ||
534 | goto make_pixel; | ||
535 | } | ||
536 | |||
537 | /* | ||
538 | * Check if we are still in range. We may be out of range if our | ||
539 | * V4L canvas is wider or taller than the camera "native" image. | ||
540 | * Then we quickly fill the remainder of the line with zeros to | ||
541 | * make black color and quit the horizontal scanning loop. | ||
542 | */ | ||
543 | if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) { | ||
544 | const int j = i * V4L_BYTES_PER_PIXEL; | ||
545 | #if USES_IBMCAM_PUTPIXEL | ||
546 | /* Refresh 'f' because we don't use it much with PUTPIXEL */ | ||
547 | f = frame->data + (v4l_linesize * frame->curline) + j; | ||
548 | #endif | ||
549 | memset(f, 0, v4l_linesize - j); | ||
550 | break; | ||
551 | } | ||
552 | |||
553 | y = lumaLine[i]; | ||
554 | if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */ | ||
555 | rv = gv = bv = y; | ||
556 | else { | ||
557 | int off_0, off_2; | ||
558 | |||
559 | off_0 = (i >> 1) << 2; | ||
560 | off_2 = off_0 + 2; | ||
561 | |||
562 | if (order_yc) { | ||
563 | off_0++; | ||
564 | off_2++; | ||
565 | } | ||
566 | if (!order_uv) { | ||
567 | off_0 += 2; | ||
568 | off_2 -= 2; | ||
569 | } | ||
570 | u = chromaLine[off_0] + hue_corr; | ||
571 | v = chromaLine[off_2] + hue2_corr; | ||
572 | |||
573 | /* Apply color correction */ | ||
574 | if (color_corr != 0) { | ||
575 | /* Magnify up to 2 times, reduce down to zero saturation */ | ||
576 | u = 128 + ((ccm + color_corr) * (u - 128)) / ccm; | ||
577 | v = 128 + ((ccm + color_corr) * (v - 128)) / ccm; | ||
578 | } | ||
579 | YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv); | ||
580 | } | ||
581 | |||
582 | make_pixel: | ||
583 | /* | ||
584 | * The purpose of creating the pixel here, in one, | ||
585 | * dedicated place is that we may need to make the | ||
586 | * pixel wider and taller than it actually is. This | ||
587 | * may be used if camera generates small frames for | ||
588 | * sake of frame rate (or any other reason.) | ||
589 | * | ||
590 | * The output data consists of B, G, R bytes | ||
591 | * (in this order). | ||
592 | */ | ||
593 | #if USES_IBMCAM_PUTPIXEL | ||
594 | RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); | ||
595 | #else | ||
596 | *f++ = bv; | ||
597 | *f++ = gv; | ||
598 | *f++ = rv; | ||
599 | #endif | ||
600 | /* | ||
601 | * Typically we do not decide within a legitimate frame | ||
602 | * that we want to end the frame. However debugging code | ||
603 | * may detect marker of new frame within the data. Then | ||
604 | * this condition activates. The 'data' pointer is already | ||
605 | * pointing at the new marker, so we'd better leave it as is. | ||
606 | */ | ||
607 | if (frame_done) | ||
608 | break; /* End scanning of lines */ | ||
609 | } | ||
610 | /* | ||
611 | * Account for number of bytes that we wrote into output V4L frame. | ||
612 | * We do it here, after we are done with the scanline, because we | ||
613 | * may fill more than one output scanline if we do vertical | ||
614 | * enlargement. | ||
615 | */ | ||
616 | frame->curline += 2; | ||
617 | if (pcopylen != NULL) | ||
618 | *pcopylen += 2 * v4l_linesize; | ||
619 | frame->deinterlace = Deinterlace_FillOddLines; | ||
620 | |||
621 | if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request))) | ||
622 | return scan_NextFrame; | ||
623 | else | ||
624 | return scan_Continue; | ||
625 | } | ||
626 | |||
627 | /* | ||
628 | * ibmcam_model2_320x240_parse_lines() | ||
629 | * | ||
630 | * This procedure deals with a weird RGB format that is produced by IBM | ||
631 | * camera model 2 in modes 320x240 and above; 'x' below is 159 or 175, | ||
632 | * depending on horizontal size of the picture: | ||
633 | * | ||
634 | * <--- 160 or 176 pairs of RA,RB bytes -----> | ||
635 | * *-----------------------------------------* \ | ||
636 | * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx | \ This is pair of horizontal lines, | ||
637 | * |-----+-----+-----+-----+ ... +-----+-----| *- or one interlaced line, total | ||
638 | * | B0 | G0 | B1 | G1 | ... | Bx | Gx | / 120 or 144 such pairs which yield | ||
639 | * |=====+=====+=====+=====+ ... +=====+=====| / 240 or 288 lines after deinterlacing. | ||
640 | * | ||
641 | * Each group of FOUR bytes (RAi, RBi, Bi, Gi) where i=0..frame_width/2-1 | ||
642 | * defines ONE pixel. Therefore this format yields 176x144 "decoded" | ||
643 | * resolution at best. I do not know why camera sends such format - the | ||
644 | * previous model (1) just used interlaced I420 and everyone was happy. | ||
645 | * | ||
646 | * I do not know what is the difference between RAi and RBi bytes. Both | ||
647 | * seemingly represent R component, but slightly vary in value (so that | ||
648 | * the picture looks a bit colored if one or another is used). I use | ||
649 | * them both as R component in attempt to at least partially recover the | ||
650 | * lost resolution. | ||
651 | */ | ||
652 | static enum ParseState ibmcam_model2_320x240_parse_lines( | ||
653 | struct uvd *uvd, | ||
654 | struct usbvideo_frame *frame, | ||
655 | long *pcopylen) | ||
656 | { | ||
657 | unsigned char *f, *la, *lb; | ||
658 | unsigned int len; | ||
659 | int v4l_linesize; /* V4L line offset */ | ||
660 | int i, j, frame_done=0, color_corr; | ||
661 | int scanLength, scanHeight; | ||
662 | static unsigned char lineBuffer[352*2]; | ||
663 | |||
664 | switch (uvd->videosize) { | ||
665 | case VIDEOSIZE_320x240: | ||
666 | case VIDEOSIZE_352x240: | ||
667 | case VIDEOSIZE_352x288: | ||
668 | scanLength = VIDEOSIZE_X(uvd->videosize); | ||
669 | scanHeight = VIDEOSIZE_Y(uvd->videosize); | ||
670 | break; | ||
671 | default: | ||
672 | err("ibmcam_model2_320x240_parse_lines: Wrong mode."); | ||
673 | return scan_Out; | ||
674 | } | ||
675 | |||
676 | color_corr = (uvd->vpic.colour) >> 8; /* 0..+255 */ | ||
677 | v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; | ||
678 | |||
679 | len = scanLength * 2; /* See explanation above */ | ||
680 | assert(len <= sizeof(lineBuffer)); | ||
681 | |||
682 | /* Make sure there's enough data for the entire line */ | ||
683 | if (RingQueue_GetLength(&uvd->dp) < len) | ||
684 | return scan_Out; | ||
685 | |||
686 | /* Suck one line out of the ring queue */ | ||
687 | RingQueue_Dequeue(&uvd->dp, lineBuffer, len); | ||
688 | |||
689 | /* | ||
690 | * Make sure that our writing into output buffer | ||
691 | * will not exceed the buffer. Mind that we may write | ||
692 | * not into current output scanline but in several after | ||
693 | * it as well (if we enlarge image vertically.) | ||
694 | */ | ||
695 | if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request)) | ||
696 | return scan_NextFrame; | ||
697 | |||
698 | la = lineBuffer; | ||
699 | lb = lineBuffer + scanLength; | ||
700 | |||
701 | /* | ||
702 | * Now we are sure that entire line (representing all | ||
703 | * VIDEOSIZE_X(frame->request) | ||
704 | * pixels from the camera) is available in the scratch buffer. We | ||
705 | * start copying the line left-aligned to the V4L buffer (which | ||
706 | * might be larger - not smaller, hopefully). If the camera | ||
707 | * line is shorter then we should pad the V4L buffer with something | ||
708 | * (black in this case) to complete the line. | ||
709 | */ | ||
710 | f = frame->data + (v4l_linesize * frame->curline); | ||
711 | |||
712 | /* Fill the 2-line strip */ | ||
713 | for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { | ||
714 | int y, rv, gv, bv; /* RGB components */ | ||
715 | |||
716 | j = i & (~1); | ||
717 | |||
718 | /* Check for various visual debugging hints (colorized pixels) */ | ||
719 | if ((flags & FLAGS_DISPLAY_HINTS) && (IBMCAM_T(uvd)->has_hdr)) { | ||
720 | if (IBMCAM_T(uvd)->has_hdr == 1) { | ||
721 | bv = 0; /* Yellow marker */ | ||
722 | gv = 0xFF; | ||
723 | rv = 0xFF; | ||
724 | } else { | ||
725 | bv = 0xFF; /* Cyan marker */ | ||
726 | gv = 0xFF; | ||
727 | rv = 0; | ||
728 | } | ||
729 | IBMCAM_T(uvd)->has_hdr = 0; | ||
730 | goto make_pixel; | ||
731 | } | ||
732 | |||
733 | /* | ||
734 | * Check if we are still in range. We may be out of range if our | ||
735 | * V4L canvas is wider or taller than the camera "native" image. | ||
736 | * Then we quickly fill the remainder of the line with zeros to | ||
737 | * make black color and quit the horizontal scanning loop. | ||
738 | */ | ||
739 | if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) { | ||
740 | const int j = i * V4L_BYTES_PER_PIXEL; | ||
741 | #if USES_IBMCAM_PUTPIXEL | ||
742 | /* Refresh 'f' because we don't use it much with PUTPIXEL */ | ||
743 | f = frame->data + (v4l_linesize * frame->curline) + j; | ||
744 | #endif | ||
745 | memset(f, 0, v4l_linesize - j); | ||
746 | break; | ||
747 | } | ||
748 | |||
749 | /* | ||
750 | * Here I use RA and RB components, one per physical pixel. | ||
751 | * This causes fine vertical grid on the picture but may improve | ||
752 | * horizontal resolution. If you prefer replicating, use this: | ||
753 | * rv = la[j + 0]; ... or ... rv = la[j + 1]; | ||
754 | * then the pixel will be replicated. | ||
755 | */ | ||
756 | rv = la[i]; | ||
757 | gv = lb[j + 1]; | ||
758 | bv = lb[j + 0]; | ||
759 | |||
760 | y = (rv + gv + bv) / 3; /* Brightness (badly calculated) */ | ||
761 | |||
762 | if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */ | ||
763 | rv = gv = bv = y; | ||
764 | else if (color_corr != 128) { | ||
765 | |||
766 | /* Calculate difference between color and brightness */ | ||
767 | rv -= y; | ||
768 | gv -= y; | ||
769 | bv -= y; | ||
770 | |||
771 | /* Scale differences */ | ||
772 | rv = (rv * color_corr) / 128; | ||
773 | gv = (gv * color_corr) / 128; | ||
774 | bv = (bv * color_corr) / 128; | ||
775 | |||
776 | /* Reapply brightness */ | ||
777 | rv += y; | ||
778 | gv += y; | ||
779 | bv += y; | ||
780 | |||
781 | /* Watch for overflows */ | ||
782 | RESTRICT_TO_RANGE(rv, 0, 255); | ||
783 | RESTRICT_TO_RANGE(gv, 0, 255); | ||
784 | RESTRICT_TO_RANGE(bv, 0, 255); | ||
785 | } | ||
786 | |||
787 | make_pixel: | ||
788 | RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); | ||
789 | } | ||
790 | /* | ||
791 | * Account for number of bytes that we wrote into output V4L frame. | ||
792 | * We do it here, after we are done with the scanline, because we | ||
793 | * may fill more than one output scanline if we do vertical | ||
794 | * enlargement. | ||
795 | */ | ||
796 | frame->curline += 2; | ||
797 | *pcopylen += v4l_linesize * 2; | ||
798 | frame->deinterlace = Deinterlace_FillOddLines; | ||
799 | |||
800 | if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request))) | ||
801 | return scan_NextFrame; | ||
802 | else | ||
803 | return scan_Continue; | ||
804 | } | ||
805 | |||
806 | static enum ParseState ibmcam_model3_parse_lines( | ||
807 | struct uvd *uvd, | ||
808 | struct usbvideo_frame *frame, | ||
809 | long *pcopylen) | ||
810 | { | ||
811 | unsigned char *data; | ||
812 | const unsigned char *color; | ||
813 | unsigned int len; | ||
814 | int v4l_linesize; /* V4L line offset */ | ||
815 | const int hue_corr = (uvd->vpic.hue - 0x8000) >> 10; /* -32..+31 */ | ||
816 | const int hue2_corr = (hue_correction - 128) / 4; /* -32..+31 */ | ||
817 | const int ccm = 128; /* Color correction median - see below */ | ||
818 | int i, u, v, rw, data_w=0, data_h=0, color_corr; | ||
819 | static unsigned char lineBuffer[640*3]; | ||
820 | |||
821 | color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ | ||
822 | RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1); | ||
823 | |||
824 | v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; | ||
825 | |||
826 | /* The header tells us what sort of data is in this frame */ | ||
827 | switch (frame->header) { | ||
828 | /* | ||
829 | * Uncompressed modes (that are easy to decode). | ||
830 | */ | ||
831 | case 0x0308: | ||
832 | data_w = 640; | ||
833 | data_h = 480; | ||
834 | break; | ||
835 | case 0x0208: | ||
836 | data_w = 320; | ||
837 | data_h = 240; | ||
838 | break; | ||
839 | case 0x020A: | ||
840 | data_w = 160; | ||
841 | data_h = 120; | ||
842 | break; | ||
843 | /* | ||
844 | * Compressed modes (ViCE - that I don't know how to decode). | ||
845 | */ | ||
846 | case 0x0328: /* 640x480, best quality compression */ | ||
847 | case 0x0368: /* 640x480, best frame rate compression */ | ||
848 | case 0x0228: /* 320x240, best quality compression */ | ||
849 | case 0x0268: /* 320x240, best frame rate compression */ | ||
850 | case 0x02CA: /* 160x120, best quality compression */ | ||
851 | case 0x02EA: /* 160x120, best frame rate compression */ | ||
852 | /* Do nothing with this - not supported */ | ||
853 | err("Unsupported mode $%04lx", frame->header); | ||
854 | return scan_NextFrame; | ||
855 | default: | ||
856 | /* Catch unknown headers, may help in learning new headers */ | ||
857 | err("Strange frame->header=$%08lx", frame->header); | ||
858 | return scan_NextFrame; | ||
859 | } | ||
860 | |||
861 | /* | ||
862 | * Make sure that our writing into output buffer | ||
863 | * will not exceed the buffer. Note that we may write | ||
864 | * not into current output scanline but in several after | ||
865 | * it as well (if we enlarge image vertically.) | ||
866 | */ | ||
867 | if ((frame->curline + 1) >= data_h) { | ||
868 | if (uvd->debug >= 3) | ||
869 | info("Reached line %d. (frame is done)", frame->curline); | ||
870 | return scan_NextFrame; | ||
871 | } | ||
872 | |||
873 | /* Make sure there's enough data for the entire line */ | ||
874 | len = 3 * data_w; /* <y-data> <uv-data> */ | ||
875 | assert(len <= sizeof(lineBuffer)); | ||
876 | |||
877 | /* Make sure there's enough data for the entire line */ | ||
878 | if (RingQueue_GetLength(&uvd->dp) < len) | ||
879 | return scan_Out; | ||
880 | |||
881 | /* Suck one line out of the ring queue */ | ||
882 | RingQueue_Dequeue(&uvd->dp, lineBuffer, len); | ||
883 | |||
884 | data = lineBuffer; | ||
885 | color = data + data_w; /* Point to where color planes begin */ | ||
886 | |||
887 | /* Bottom-to-top scanning */ | ||
888 | rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1; | ||
889 | RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1); | ||
890 | |||
891 | for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { | ||
892 | int y, rv, gv, bv; /* RGB components */ | ||
893 | |||
894 | if (i < data_w) { | ||
895 | y = data[i]; /* Luminosity is the first line */ | ||
896 | |||
897 | /* Apply static color correction */ | ||
898 | u = color[i*2] + hue_corr; | ||
899 | v = color[i*2 + 1] + hue2_corr; | ||
900 | |||
901 | /* Apply color correction */ | ||
902 | if (color_corr != 0) { | ||
903 | /* Magnify up to 2 times, reduce down to zero saturation */ | ||
904 | u = 128 + ((ccm + color_corr) * (u - 128)) / ccm; | ||
905 | v = 128 + ((ccm + color_corr) * (v - 128)) / ccm; | ||
906 | } | ||
907 | } else | ||
908 | y = 0, u = v = 128; | ||
909 | |||
910 | YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv); | ||
911 | RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* Done by deinterlacing now */ | ||
912 | } | ||
913 | frame->deinterlace = Deinterlace_FillEvenLines; | ||
914 | |||
915 | /* | ||
916 | * Account for number of bytes that we wrote into output V4L frame. | ||
917 | * We do it here, after we are done with the scanline, because we | ||
918 | * may fill more than one output scanline if we do vertical | ||
919 | * enlargement. | ||
920 | */ | ||
921 | frame->curline += 2; | ||
922 | *pcopylen += 2 * v4l_linesize; | ||
923 | |||
924 | if (frame->curline >= VIDEOSIZE_Y(frame->request)) { | ||
925 | if (uvd->debug >= 3) { | ||
926 | info("All requested lines (%ld.) done.", | ||
927 | VIDEOSIZE_Y(frame->request)); | ||
928 | } | ||
929 | return scan_NextFrame; | ||
930 | } else | ||
931 | return scan_Continue; | ||
932 | } | ||
933 | |||
934 | /* | ||
935 | * ibmcam_model4_128x96_parse_lines() | ||
936 | * | ||
937 | * This decoder is for one strange data format that is produced by Model 4 | ||
938 | * camera only in 128x96 mode. This is RGB format and here is its description. | ||
939 | * First of all, this is non-interlaced stream, meaning that all scan lines | ||
940 | * are present in the datastream. There are 96 consecutive blocks of data | ||
941 | * that describe all 96 lines of the image. Each block is 5*128 bytes long | ||
942 | * and carries R, G, B components. The format of the block is shown in the | ||
943 | * code below. First 128*2 bytes are interleaved R and G components. Then | ||
944 | * we have a gap (junk data) 64 bytes long. Then follow B and something | ||
945 | * else, also interleaved (this makes another 128*2 bytes). After that | ||
946 | * probably another 64 bytes of junk follow. | ||
947 | * | ||
948 | * History: | ||
949 | * 10-Feb-2001 Created. | ||
950 | */ | ||
951 | static enum ParseState ibmcam_model4_128x96_parse_lines( | ||
952 | struct uvd *uvd, | ||
953 | struct usbvideo_frame *frame, | ||
954 | long *pcopylen) | ||
955 | { | ||
956 | const unsigned char *data_rv, *data_gv, *data_bv; | ||
957 | unsigned int len; | ||
958 | int i, v4l_linesize; /* V4L line offset */ | ||
959 | const int data_w=128, data_h=96; | ||
960 | static unsigned char lineBuffer[128*5]; | ||
961 | |||
962 | v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; | ||
963 | |||
964 | /* | ||
965 | * Make sure that our writing into output buffer | ||
966 | * will not exceed the buffer. Note that we may write | ||
967 | * not into current output scanline but in several after | ||
968 | * it as well (if we enlarge image vertically.) | ||
969 | */ | ||
970 | if ((frame->curline + 1) >= data_h) { | ||
971 | if (uvd->debug >= 3) | ||
972 | info("Reached line %d. (frame is done)", frame->curline); | ||
973 | return scan_NextFrame; | ||
974 | } | ||
975 | |||
976 | /* | ||
977 | * RGRGRG .... RGRG_____________B?B?B? ... B?B?____________ | ||
978 | * <---- 128*2 ---><---- 64 ---><--- 128*2 ---><--- 64 ---> | ||
979 | */ | ||
980 | |||
981 | /* Make sure there's enough data for the entire line */ | ||
982 | len = 5 * data_w; | ||
983 | assert(len <= sizeof(lineBuffer)); | ||
984 | |||
985 | /* Make sure there's enough data for the entire line */ | ||
986 | if (RingQueue_GetLength(&uvd->dp) < len) | ||
987 | return scan_Out; | ||
988 | |||
989 | /* Suck one line out of the ring queue */ | ||
990 | RingQueue_Dequeue(&uvd->dp, lineBuffer, len); | ||
991 | |||
992 | data_rv = lineBuffer; | ||
993 | data_gv = lineBuffer + 1; | ||
994 | data_bv = lineBuffer + data_w*2 + data_w/2; | ||
995 | for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { | ||
996 | int rv, gv, bv; /* RGB components */ | ||
997 | if (i < data_w) { | ||
998 | const int j = i * 2; | ||
999 | gv = data_rv[j]; | ||
1000 | rv = data_gv[j]; | ||
1001 | bv = data_bv[j]; | ||
1002 | if (flags & FLAGS_MONOCHROME) { | ||
1003 | unsigned long y; | ||
1004 | y = rv + gv + bv; | ||
1005 | y /= 3; | ||
1006 | if (y > 0xFF) | ||
1007 | y = 0xFF; | ||
1008 | rv = gv = bv = (unsigned char) y; | ||
1009 | } | ||
1010 | } else { | ||
1011 | rv = gv = bv = 0; | ||
1012 | } | ||
1013 | RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); | ||
1014 | } | ||
1015 | frame->deinterlace = Deinterlace_None; | ||
1016 | frame->curline++; | ||
1017 | *pcopylen += v4l_linesize; | ||
1018 | |||
1019 | if (frame->curline >= VIDEOSIZE_Y(frame->request)) { | ||
1020 | if (uvd->debug >= 3) { | ||
1021 | info("All requested lines (%ld.) done.", | ||
1022 | VIDEOSIZE_Y(frame->request)); | ||
1023 | } | ||
1024 | return scan_NextFrame; | ||
1025 | } else | ||
1026 | return scan_Continue; | ||
1027 | } | ||
1028 | |||
1029 | /* | ||
1030 | * ibmcam_ProcessIsocData() | ||
1031 | * | ||
1032 | * Generic routine to parse the ring queue data. It employs either | ||
1033 | * ibmcam_find_header() or ibmcam_parse_lines() to do most | ||
1034 | * of work. | ||
1035 | * | ||
1036 | * History: | ||
1037 | * 1/21/00 Created. | ||
1038 | */ | ||
1039 | static void ibmcam_ProcessIsocData(struct uvd *uvd, | ||
1040 | struct usbvideo_frame *frame) | ||
1041 | { | ||
1042 | enum ParseState newstate; | ||
1043 | long copylen = 0; | ||
1044 | int mod = IBMCAM_T(uvd)->camera_model; | ||
1045 | |||
1046 | while (1) { | ||
1047 | newstate = scan_Out; | ||
1048 | if (RingQueue_GetLength(&uvd->dp) > 0) { | ||
1049 | if (frame->scanstate == ScanState_Scanning) { | ||
1050 | newstate = ibmcam_find_header(uvd); | ||
1051 | } else if (frame->scanstate == ScanState_Lines) { | ||
1052 | if ((mod == IBMCAM_MODEL_2) && | ||
1053 | ((uvd->videosize == VIDEOSIZE_352x288) || | ||
1054 | (uvd->videosize == VIDEOSIZE_320x240) || | ||
1055 | (uvd->videosize == VIDEOSIZE_352x240))) | ||
1056 | { | ||
1057 | newstate = ibmcam_model2_320x240_parse_lines( | ||
1058 | uvd, frame, ©len); | ||
1059 | } else if (mod == IBMCAM_MODEL_4) { | ||
1060 | /* | ||
1061 | * Model 4 cameras (IBM NetCamera) use Model 2 decoder (RGB) | ||
1062 | * for 320x240 and above; 160x120 and 176x144 uses Model 1 | ||
1063 | * decoder (YUV), and 128x96 mode uses ??? | ||
1064 | */ | ||
1065 | if ((uvd->videosize == VIDEOSIZE_352x288) || | ||
1066 | (uvd->videosize == VIDEOSIZE_320x240) || | ||
1067 | (uvd->videosize == VIDEOSIZE_352x240)) | ||
1068 | { | ||
1069 | newstate = ibmcam_model2_320x240_parse_lines(uvd, frame, ©len); | ||
1070 | } else if (uvd->videosize == VIDEOSIZE_128x96) { | ||
1071 | newstate = ibmcam_model4_128x96_parse_lines(uvd, frame, ©len); | ||
1072 | } else { | ||
1073 | newstate = ibmcam_parse_lines(uvd, frame, ©len); | ||
1074 | } | ||
1075 | } else if (mod == IBMCAM_MODEL_3) { | ||
1076 | newstate = ibmcam_model3_parse_lines(uvd, frame, ©len); | ||
1077 | } else { | ||
1078 | newstate = ibmcam_parse_lines(uvd, frame, ©len); | ||
1079 | } | ||
1080 | } | ||
1081 | } | ||
1082 | if (newstate == scan_Continue) | ||
1083 | continue; | ||
1084 | else if ((newstate == scan_NextFrame) || (newstate == scan_Out)) | ||
1085 | break; | ||
1086 | else | ||
1087 | return; /* scan_EndParse */ | ||
1088 | } | ||
1089 | |||
1090 | if (newstate == scan_NextFrame) { | ||
1091 | frame->frameState = FrameState_Done; | ||
1092 | uvd->curframe = -1; | ||
1093 | uvd->stats.frame_num++; | ||
1094 | if ((mod == IBMCAM_MODEL_2) || (mod == IBMCAM_MODEL_4)) { | ||
1095 | /* Need software contrast adjustment for those cameras */ | ||
1096 | frame->flags |= USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST; | ||
1097 | } | ||
1098 | } | ||
1099 | |||
1100 | /* Update the frame's uncompressed length. */ | ||
1101 | frame->seqRead_Length += copylen; | ||
1102 | |||
1103 | #if 0 | ||
1104 | { | ||
1105 | static unsigned char j=0; | ||
1106 | memset(frame->data, j++, uvd->max_frame_size); | ||
1107 | frame->frameState = FrameState_Ready; | ||
1108 | } | ||
1109 | #endif | ||
1110 | } | ||
1111 | |||
1112 | /* | ||
1113 | * ibmcam_veio() | ||
1114 | * | ||
1115 | * History: | ||
1116 | * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged. | ||
1117 | */ | ||
1118 | static int ibmcam_veio( | ||
1119 | struct uvd *uvd, | ||
1120 | unsigned char req, | ||
1121 | unsigned short value, | ||
1122 | unsigned short index) | ||
1123 | { | ||
1124 | static const char proc[] = "ibmcam_veio"; | ||
1125 | unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */; | ||
1126 | int i; | ||
1127 | |||
1128 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
1129 | return 0; | ||
1130 | |||
1131 | if (req == 1) { | ||
1132 | i = usb_control_msg( | ||
1133 | uvd->dev, | ||
1134 | usb_rcvctrlpipe(uvd->dev, 0), | ||
1135 | req, | ||
1136 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, | ||
1137 | value, | ||
1138 | index, | ||
1139 | cp, | ||
1140 | sizeof(cp), | ||
1141 | 1000); | ||
1142 | #if 0 | ||
1143 | info("USB => %02x%02x%02x%02x%02x%02x%02x%02x " | ||
1144 | "(req=$%02x val=$%04x ind=$%04x)", | ||
1145 | cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], | ||
1146 | req, value, index); | ||
1147 | #endif | ||
1148 | } else { | ||
1149 | i = usb_control_msg( | ||
1150 | uvd->dev, | ||
1151 | usb_sndctrlpipe(uvd->dev, 0), | ||
1152 | req, | ||
1153 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, | ||
1154 | value, | ||
1155 | index, | ||
1156 | NULL, | ||
1157 | 0, | ||
1158 | 1000); | ||
1159 | } | ||
1160 | if (i < 0) { | ||
1161 | err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.", | ||
1162 | proc, i); | ||
1163 | uvd->last_error = i; | ||
1164 | } | ||
1165 | return i; | ||
1166 | } | ||
1167 | |||
1168 | /* | ||
1169 | * ibmcam_calculate_fps() | ||
1170 | * | ||
1171 | * This procedure roughly calculates the real frame rate based | ||
1172 | * on FPS code (framerate=NNN option). Actual FPS differs | ||
1173 | * slightly depending on lighting conditions, so that actual frame | ||
1174 | * rate is determined by the camera. Since I don't know how to ask | ||
1175 | * the camera what FPS is now I have to use the FPS code instead. | ||
1176 | * | ||
1177 | * The FPS code is in range [0..6], 0 is slowest, 6 is fastest. | ||
1178 | * Corresponding real FPS should be in range [3..30] frames per second. | ||
1179 | * The conversion formula is obvious: | ||
1180 | * | ||
1181 | * real_fps = 3 + (fps_code * 4.5) | ||
1182 | * | ||
1183 | * History: | ||
1184 | * 1/18/00 Created. | ||
1185 | */ | ||
1186 | static int ibmcam_calculate_fps(struct uvd *uvd) | ||
1187 | { | ||
1188 | return 3 + framerate*4 + framerate/2; | ||
1189 | } | ||
1190 | |||
1191 | /* | ||
1192 | * ibmcam_send_FF_04_02() | ||
1193 | * | ||
1194 | * This procedure sends magic 3-command prefix to the camera. | ||
1195 | * The purpose of this prefix is not known. | ||
1196 | * | ||
1197 | * History: | ||
1198 | * 1/2/00 Created. | ||
1199 | */ | ||
1200 | static void ibmcam_send_FF_04_02(struct uvd *uvd) | ||
1201 | { | ||
1202 | ibmcam_veio(uvd, 0, 0x00FF, 0x0127); | ||
1203 | ibmcam_veio(uvd, 0, 0x0004, 0x0124); | ||
1204 | ibmcam_veio(uvd, 0, 0x0002, 0x0124); | ||
1205 | } | ||
1206 | |||
1207 | static void ibmcam_send_00_04_06(struct uvd *uvd) | ||
1208 | { | ||
1209 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
1210 | ibmcam_veio(uvd, 0, 0x0004, 0x0124); | ||
1211 | ibmcam_veio(uvd, 0, 0x0006, 0x0124); | ||
1212 | } | ||
1213 | |||
1214 | static void ibmcam_send_x_00(struct uvd *uvd, unsigned short x) | ||
1215 | { | ||
1216 | ibmcam_veio(uvd, 0, x, 0x0127); | ||
1217 | ibmcam_veio(uvd, 0, 0x0000, 0x0124); | ||
1218 | } | ||
1219 | |||
1220 | static void ibmcam_send_x_00_05(struct uvd *uvd, unsigned short x) | ||
1221 | { | ||
1222 | ibmcam_send_x_00(uvd, x); | ||
1223 | ibmcam_veio(uvd, 0, 0x0005, 0x0124); | ||
1224 | } | ||
1225 | |||
1226 | static void ibmcam_send_x_00_05_02(struct uvd *uvd, unsigned short x) | ||
1227 | { | ||
1228 | ibmcam_veio(uvd, 0, x, 0x0127); | ||
1229 | ibmcam_veio(uvd, 0, 0x0000, 0x0124); | ||
1230 | ibmcam_veio(uvd, 0, 0x0005, 0x0124); | ||
1231 | ibmcam_veio(uvd, 0, 0x0002, 0x0124); | ||
1232 | } | ||
1233 | |||
1234 | static void ibmcam_send_x_01_00_05(struct uvd *uvd, unsigned short x) | ||
1235 | { | ||
1236 | ibmcam_veio(uvd, 0, x, 0x0127); | ||
1237 | ibmcam_veio(uvd, 0, 0x0001, 0x0124); | ||
1238 | ibmcam_veio(uvd, 0, 0x0000, 0x0124); | ||
1239 | ibmcam_veio(uvd, 0, 0x0005, 0x0124); | ||
1240 | } | ||
1241 | |||
1242 | static void ibmcam_send_x_00_05_02_01(struct uvd *uvd, unsigned short x) | ||
1243 | { | ||
1244 | ibmcam_veio(uvd, 0, x, 0x0127); | ||
1245 | ibmcam_veio(uvd, 0, 0x0000, 0x0124); | ||
1246 | ibmcam_veio(uvd, 0, 0x0005, 0x0124); | ||
1247 | ibmcam_veio(uvd, 0, 0x0002, 0x0124); | ||
1248 | ibmcam_veio(uvd, 0, 0x0001, 0x0124); | ||
1249 | } | ||
1250 | |||
1251 | static void ibmcam_send_x_00_05_02_08_01(struct uvd *uvd, unsigned short x) | ||
1252 | { | ||
1253 | ibmcam_veio(uvd, 0, x, 0x0127); | ||
1254 | ibmcam_veio(uvd, 0, 0x0000, 0x0124); | ||
1255 | ibmcam_veio(uvd, 0, 0x0005, 0x0124); | ||
1256 | ibmcam_veio(uvd, 0, 0x0002, 0x0124); | ||
1257 | ibmcam_veio(uvd, 0, 0x0008, 0x0124); | ||
1258 | ibmcam_veio(uvd, 0, 0x0001, 0x0124); | ||
1259 | } | ||
1260 | |||
1261 | static void ibmcam_Packet_Format1(struct uvd *uvd, unsigned char fkey, unsigned char val) | ||
1262 | { | ||
1263 | ibmcam_send_x_01_00_05(uvd, unknown_88); | ||
1264 | ibmcam_send_x_00_05(uvd, fkey); | ||
1265 | ibmcam_send_x_00_05_02_08_01(uvd, val); | ||
1266 | ibmcam_send_x_00_05(uvd, unknown_88); | ||
1267 | ibmcam_send_x_00_05_02_01(uvd, fkey); | ||
1268 | ibmcam_send_x_00_05(uvd, unknown_89); | ||
1269 | ibmcam_send_x_00(uvd, fkey); | ||
1270 | ibmcam_send_00_04_06(uvd); | ||
1271 | ibmcam_veio(uvd, 1, 0x0000, 0x0126); | ||
1272 | ibmcam_send_FF_04_02(uvd); | ||
1273 | } | ||
1274 | |||
1275 | static void ibmcam_PacketFormat2(struct uvd *uvd, unsigned char fkey, unsigned char val) | ||
1276 | { | ||
1277 | ibmcam_send_x_01_00_05 (uvd, unknown_88); | ||
1278 | ibmcam_send_x_00_05 (uvd, fkey); | ||
1279 | ibmcam_send_x_00_05_02 (uvd, val); | ||
1280 | } | ||
1281 | |||
1282 | static void ibmcam_model2_Packet2(struct uvd *uvd) | ||
1283 | { | ||
1284 | ibmcam_veio(uvd, 0, 0x00ff, 0x012d); | ||
1285 | ibmcam_veio(uvd, 0, 0xfea3, 0x0124); | ||
1286 | } | ||
1287 | |||
1288 | static void ibmcam_model2_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2) | ||
1289 | { | ||
1290 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
1291 | ibmcam_veio(uvd, 0, 0x00ff, 0x012e); | ||
1292 | ibmcam_veio(uvd, 0, v1, 0x012f); | ||
1293 | ibmcam_veio(uvd, 0, 0x00ff, 0x0130); | ||
1294 | ibmcam_veio(uvd, 0, 0xc719, 0x0124); | ||
1295 | ibmcam_veio(uvd, 0, v2, 0x0127); | ||
1296 | |||
1297 | ibmcam_model2_Packet2(uvd); | ||
1298 | } | ||
1299 | |||
1300 | /* | ||
1301 | * ibmcam_model3_Packet1() | ||
1302 | * | ||
1303 | * 00_0078_012d | ||
1304 | * 00_0097_012f | ||
1305 | * 00_d141_0124 | ||
1306 | * 00_0096_0127 | ||
1307 | * 00_fea8_0124 | ||
1308 | */ | ||
1309 | static void ibmcam_model3_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2) | ||
1310 | { | ||
1311 | ibmcam_veio(uvd, 0, 0x0078, 0x012d); | ||
1312 | ibmcam_veio(uvd, 0, v1, 0x012f); | ||
1313 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
1314 | ibmcam_veio(uvd, 0, v2, 0x0127); | ||
1315 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
1316 | } | ||
1317 | |||
1318 | static void ibmcam_model4_BrightnessPacket(struct uvd *uvd, int i) | ||
1319 | { | ||
1320 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
1321 | ibmcam_veio(uvd, 0, 0x0026, 0x012f); | ||
1322 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
1323 | ibmcam_veio(uvd, 0, i, 0x0127); | ||
1324 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
1325 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
1326 | ibmcam_veio(uvd, 0, 0x0038, 0x012d); | ||
1327 | ibmcam_veio(uvd, 0, 0x0004, 0x012f); | ||
1328 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
1329 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
1330 | } | ||
1331 | |||
1332 | /* | ||
1333 | * ibmcam_adjust_contrast() | ||
1334 | * | ||
1335 | * The contrast value changes from 0 (high contrast) to 15 (low contrast). | ||
1336 | * This is in reverse to usual order of things (such as TV controls), so | ||
1337 | * we reverse it again here. | ||
1338 | * | ||
1339 | * TODO: we probably don't need to send the setup 5 times... | ||
1340 | * | ||
1341 | * History: | ||
1342 | * 1/2/00 Created. | ||
1343 | */ | ||
1344 | static void ibmcam_adjust_contrast(struct uvd *uvd) | ||
1345 | { | ||
1346 | unsigned char a_contrast = uvd->vpic.contrast >> 12; | ||
1347 | unsigned char new_contrast; | ||
1348 | |||
1349 | if (a_contrast >= 16) | ||
1350 | a_contrast = 15; | ||
1351 | new_contrast = 15 - a_contrast; | ||
1352 | if (new_contrast == uvd->vpic_old.contrast) | ||
1353 | return; | ||
1354 | uvd->vpic_old.contrast = new_contrast; | ||
1355 | switch (IBMCAM_T(uvd)->camera_model) { | ||
1356 | case IBMCAM_MODEL_1: | ||
1357 | { | ||
1358 | const int ntries = 5; | ||
1359 | int i; | ||
1360 | for (i=0; i < ntries; i++) { | ||
1361 | ibmcam_Packet_Format1(uvd, contrast_14, new_contrast); | ||
1362 | ibmcam_send_FF_04_02(uvd); | ||
1363 | } | ||
1364 | break; | ||
1365 | } | ||
1366 | case IBMCAM_MODEL_2: | ||
1367 | case IBMCAM_MODEL_4: | ||
1368 | /* Models 2, 4 do not have this control; implemented in software. */ | ||
1369 | break; | ||
1370 | case IBMCAM_MODEL_3: | ||
1371 | { /* Preset hardware values */ | ||
1372 | static const struct { | ||
1373 | unsigned short cv1; | ||
1374 | unsigned short cv2; | ||
1375 | unsigned short cv3; | ||
1376 | } cv[7] = { | ||
1377 | { 0x05, 0x05, 0x0f }, /* Minimum */ | ||
1378 | { 0x04, 0x04, 0x16 }, | ||
1379 | { 0x02, 0x03, 0x16 }, | ||
1380 | { 0x02, 0x08, 0x16 }, | ||
1381 | { 0x01, 0x0c, 0x16 }, | ||
1382 | { 0x01, 0x0e, 0x16 }, | ||
1383 | { 0x01, 0x10, 0x16 } /* Maximum */ | ||
1384 | }; | ||
1385 | int i = a_contrast / 2; | ||
1386 | RESTRICT_TO_RANGE(i, 0, 6); | ||
1387 | ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ | ||
1388 | ibmcam_model3_Packet1(uvd, 0x0067, cv[i].cv1); | ||
1389 | ibmcam_model3_Packet1(uvd, 0x005b, cv[i].cv2); | ||
1390 | ibmcam_model3_Packet1(uvd, 0x005c, cv[i].cv3); | ||
1391 | ibmcam_veio(uvd, 0, 0x0001, 0x0114); | ||
1392 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ | ||
1393 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
1394 | break; | ||
1395 | } | ||
1396 | default: | ||
1397 | break; | ||
1398 | } | ||
1399 | } | ||
1400 | |||
1401 | /* | ||
1402 | * ibmcam_change_lighting_conditions() | ||
1403 | * | ||
1404 | * Camera model 1: | ||
1405 | * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low. | ||
1406 | * | ||
1407 | * Camera model 2: | ||
1408 | * We have 16 levels of lighting, 0 for bright light and up to 15 for | ||
1409 | * low light. But values above 5 or so are useless because camera is | ||
1410 | * not really capable to produce anything worth viewing at such light. | ||
1411 | * This setting may be altered only in certain camera state. | ||
1412 | * | ||
1413 | * Low lighting forces slower FPS. Lighting is set as a module parameter. | ||
1414 | * | ||
1415 | * History: | ||
1416 | * 1/5/00 Created. | ||
1417 | * 2/20/00 Added support for Model 2 cameras. | ||
1418 | */ | ||
1419 | static void ibmcam_change_lighting_conditions(struct uvd *uvd) | ||
1420 | { | ||
1421 | static const char proc[] = "ibmcam_change_lighting_conditions"; | ||
1422 | |||
1423 | if (debug > 0) | ||
1424 | info("%s: Set lighting to %hu.", proc, lighting); | ||
1425 | |||
1426 | switch (IBMCAM_T(uvd)->camera_model) { | ||
1427 | case IBMCAM_MODEL_1: | ||
1428 | { | ||
1429 | const int ntries = 5; | ||
1430 | int i; | ||
1431 | for (i=0; i < ntries; i++) | ||
1432 | ibmcam_Packet_Format1(uvd, light_27, (unsigned short) lighting); | ||
1433 | break; | ||
1434 | } | ||
1435 | case IBMCAM_MODEL_2: | ||
1436 | #if 0 | ||
1437 | /* | ||
1438 | * This command apparently requires camera to be stopped. My | ||
1439 | * experiments showed that it -is- possible to alter the lighting | ||
1440 | * conditions setting "on the fly", but why bother? This setting does | ||
1441 | * not work reliably in all cases, so I decided simply to leave the | ||
1442 | * setting where Xirlink put it - in the camera setup phase. This code | ||
1443 | * is commented out because it does not work at -any- moment, so its | ||
1444 | * presence makes no sense. You may use it for experiments. | ||
1445 | */ | ||
1446 | ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop camera */ | ||
1447 | ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting); | ||
1448 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Start camera */ | ||
1449 | #endif | ||
1450 | break; | ||
1451 | case IBMCAM_MODEL_3: | ||
1452 | case IBMCAM_MODEL_4: | ||
1453 | default: | ||
1454 | break; | ||
1455 | } | ||
1456 | } | ||
1457 | |||
1458 | /* | ||
1459 | * ibmcam_set_sharpness() | ||
1460 | * | ||
1461 | * Cameras model 1 have internal smoothing feature. It is controlled by value in | ||
1462 | * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess). | ||
1463 | * Recommended value is 4. Cameras model 2 do not have this feature at all. | ||
1464 | */ | ||
1465 | static void ibmcam_set_sharpness(struct uvd *uvd) | ||
1466 | { | ||
1467 | static const char proc[] = "ibmcam_set_sharpness"; | ||
1468 | |||
1469 | switch (IBMCAM_T(uvd)->camera_model) { | ||
1470 | case IBMCAM_MODEL_1: | ||
1471 | { | ||
1472 | static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a }; | ||
1473 | unsigned short i, sv; | ||
1474 | |||
1475 | RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX); | ||
1476 | if (debug > 0) | ||
1477 | info("%s: Set sharpness to %hu.", proc, sharpness); | ||
1478 | |||
1479 | sv = sa[sharpness - SHARPNESS_MIN]; | ||
1480 | for (i=0; i < 2; i++) { | ||
1481 | ibmcam_send_x_01_00_05 (uvd, unknown_88); | ||
1482 | ibmcam_send_x_00_05 (uvd, sharp_13); | ||
1483 | ibmcam_send_x_00_05_02 (uvd, sv); | ||
1484 | } | ||
1485 | break; | ||
1486 | } | ||
1487 | case IBMCAM_MODEL_2: | ||
1488 | case IBMCAM_MODEL_4: | ||
1489 | /* Models 2, 4 do not have this control */ | ||
1490 | break; | ||
1491 | case IBMCAM_MODEL_3: | ||
1492 | { /* | ||
1493 | * "Use a table of magic numbers. | ||
1494 | * This setting doesn't really change much. | ||
1495 | * But that's how Windows does it." | ||
1496 | */ | ||
1497 | static const struct { | ||
1498 | unsigned short sv1; | ||
1499 | unsigned short sv2; | ||
1500 | unsigned short sv3; | ||
1501 | unsigned short sv4; | ||
1502 | } sv[7] = { | ||
1503 | { 0x00, 0x00, 0x05, 0x14 }, /* Smoothest */ | ||
1504 | { 0x01, 0x04, 0x05, 0x14 }, | ||
1505 | { 0x02, 0x04, 0x05, 0x14 }, | ||
1506 | { 0x03, 0x04, 0x05, 0x14 }, | ||
1507 | { 0x03, 0x05, 0x05, 0x14 }, | ||
1508 | { 0x03, 0x06, 0x05, 0x14 }, | ||
1509 | { 0x03, 0x07, 0x05, 0x14 } /* Sharpest */ | ||
1510 | }; | ||
1511 | RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX); | ||
1512 | RESTRICT_TO_RANGE(sharpness, 0, 6); | ||
1513 | ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ | ||
1514 | ibmcam_model3_Packet1(uvd, 0x0060, sv[sharpness].sv1); | ||
1515 | ibmcam_model3_Packet1(uvd, 0x0061, sv[sharpness].sv2); | ||
1516 | ibmcam_model3_Packet1(uvd, 0x0062, sv[sharpness].sv3); | ||
1517 | ibmcam_model3_Packet1(uvd, 0x0063, sv[sharpness].sv4); | ||
1518 | ibmcam_veio(uvd, 0, 0x0001, 0x0114); | ||
1519 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ | ||
1520 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
1521 | ibmcam_veio(uvd, 0, 0x0001, 0x0113); | ||
1522 | break; | ||
1523 | } | ||
1524 | default: | ||
1525 | break; | ||
1526 | } | ||
1527 | } | ||
1528 | |||
1529 | /* | ||
1530 | * ibmcam_set_brightness() | ||
1531 | * | ||
1532 | * This procedure changes brightness of the picture. | ||
1533 | */ | ||
1534 | static void ibmcam_set_brightness(struct uvd *uvd) | ||
1535 | { | ||
1536 | static const char proc[] = "ibmcam_set_brightness"; | ||
1537 | static const unsigned short n = 1; | ||
1538 | |||
1539 | if (debug > 0) | ||
1540 | info("%s: Set brightness to %hu.", proc, uvd->vpic.brightness); | ||
1541 | |||
1542 | switch (IBMCAM_T(uvd)->camera_model) { | ||
1543 | case IBMCAM_MODEL_1: | ||
1544 | { | ||
1545 | unsigned short i, j, bv[3]; | ||
1546 | bv[0] = bv[1] = bv[2] = uvd->vpic.brightness >> 10; | ||
1547 | if (bv[0] == (uvd->vpic_old.brightness >> 10)) | ||
1548 | return; | ||
1549 | uvd->vpic_old.brightness = bv[0]; | ||
1550 | for (j=0; j < 3; j++) | ||
1551 | for (i=0; i < n; i++) | ||
1552 | ibmcam_Packet_Format1(uvd, bright_3x[j], bv[j]); | ||
1553 | break; | ||
1554 | } | ||
1555 | case IBMCAM_MODEL_2: | ||
1556 | { | ||
1557 | unsigned short i, j; | ||
1558 | i = uvd->vpic.brightness >> 12; /* 0 .. 15 */ | ||
1559 | j = 0x60 + i * ((0xee - 0x60) / 16); /* 0x60 .. 0xee or so */ | ||
1560 | if (uvd->vpic_old.brightness == j) | ||
1561 | break; | ||
1562 | uvd->vpic_old.brightness = j; | ||
1563 | ibmcam_model2_Packet1(uvd, mod2_brightness, j); | ||
1564 | break; | ||
1565 | } | ||
1566 | case IBMCAM_MODEL_3: | ||
1567 | { | ||
1568 | /* Model 3: Brightness range 'i' in [0x0C..0x3F] */ | ||
1569 | unsigned short i = | ||
1570 | 0x0C + (uvd->vpic.brightness / (0xFFFF / (0x3F - 0x0C + 1))); | ||
1571 | RESTRICT_TO_RANGE(i, 0x0C, 0x3F); | ||
1572 | if (uvd->vpic_old.brightness == i) | ||
1573 | break; | ||
1574 | uvd->vpic_old.brightness = i; | ||
1575 | ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ | ||
1576 | ibmcam_model3_Packet1(uvd, 0x0036, i); | ||
1577 | ibmcam_veio(uvd, 0, 0x0001, 0x0114); | ||
1578 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ | ||
1579 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
1580 | ibmcam_veio(uvd, 0, 0x0001, 0x0113); | ||
1581 | break; | ||
1582 | } | ||
1583 | case IBMCAM_MODEL_4: | ||
1584 | { | ||
1585 | /* Model 4: Brightness range 'i' in [0x04..0xb4] */ | ||
1586 | unsigned short i = 0x04 + (uvd->vpic.brightness / (0xFFFF / (0xb4 - 0x04 + 1))); | ||
1587 | RESTRICT_TO_RANGE(i, 0x04, 0xb4); | ||
1588 | if (uvd->vpic_old.brightness == i) | ||
1589 | break; | ||
1590 | uvd->vpic_old.brightness = i; | ||
1591 | ibmcam_model4_BrightnessPacket(uvd, i); | ||
1592 | break; | ||
1593 | } | ||
1594 | default: | ||
1595 | break; | ||
1596 | } | ||
1597 | } | ||
1598 | |||
1599 | static void ibmcam_set_hue(struct uvd *uvd) | ||
1600 | { | ||
1601 | switch (IBMCAM_T(uvd)->camera_model) { | ||
1602 | case IBMCAM_MODEL_2: | ||
1603 | { | ||
1604 | unsigned short hue = uvd->vpic.hue >> 9; /* 0 .. 7F */ | ||
1605 | if (uvd->vpic_old.hue == hue) | ||
1606 | return; | ||
1607 | uvd->vpic_old.hue = hue; | ||
1608 | ibmcam_model2_Packet1(uvd, mod2_hue, hue); | ||
1609 | /* ibmcam_model2_Packet1(uvd, mod2_saturation, sat); */ | ||
1610 | break; | ||
1611 | } | ||
1612 | case IBMCAM_MODEL_3: | ||
1613 | { | ||
1614 | #if 0 /* This seems not to work. No problem, will fix programmatically */ | ||
1615 | unsigned short hue = 0x05 + (uvd->vpic.hue / (0xFFFF / (0x37 - 0x05 + 1))); | ||
1616 | RESTRICT_TO_RANGE(hue, 0x05, 0x37); | ||
1617 | if (uvd->vpic_old.hue == hue) | ||
1618 | return; | ||
1619 | uvd->vpic_old.hue = hue; | ||
1620 | ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ | ||
1621 | ibmcam_model3_Packet1(uvd, 0x007e, hue); | ||
1622 | ibmcam_veio(uvd, 0, 0x0001, 0x0114); | ||
1623 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ | ||
1624 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
1625 | ibmcam_veio(uvd, 0, 0x0001, 0x0113); | ||
1626 | #endif | ||
1627 | break; | ||
1628 | } | ||
1629 | case IBMCAM_MODEL_4: | ||
1630 | { | ||
1631 | unsigned short r_gain, g_gain, b_gain, hue; | ||
1632 | |||
1633 | /* | ||
1634 | * I am not sure r/g/b_gain variables exactly control gain | ||
1635 | * of those channels. Most likely they subtly change some | ||
1636 | * very internal image processing settings in the camera. | ||
1637 | * In any case, here is what they do, and feel free to tweak: | ||
1638 | * | ||
1639 | * r_gain: seriously affects red gain | ||
1640 | * g_gain: seriously affects green gain | ||
1641 | * b_gain: seriously affects blue gain | ||
1642 | * hue: changes average color from violet (0) to red (0xFF) | ||
1643 | * | ||
1644 | * These settings are preset for a decent white balance in | ||
1645 | * 320x240, 352x288 modes. Low-res modes exhibit higher contrast | ||
1646 | * and therefore may need different values here. | ||
1647 | */ | ||
1648 | hue = 20 + (uvd->vpic.hue >> 9); | ||
1649 | switch (uvd->videosize) { | ||
1650 | case VIDEOSIZE_128x96: | ||
1651 | r_gain = 90; | ||
1652 | g_gain = 166; | ||
1653 | b_gain = 175; | ||
1654 | break; | ||
1655 | case VIDEOSIZE_160x120: | ||
1656 | r_gain = 70; | ||
1657 | g_gain = 166; | ||
1658 | b_gain = 185; | ||
1659 | break; | ||
1660 | case VIDEOSIZE_176x144: | ||
1661 | r_gain = 160; | ||
1662 | g_gain = 175; | ||
1663 | b_gain = 185; | ||
1664 | break; | ||
1665 | default: | ||
1666 | r_gain = 120; | ||
1667 | g_gain = 166; | ||
1668 | b_gain = 175; | ||
1669 | break; | ||
1670 | } | ||
1671 | RESTRICT_TO_RANGE(hue, 1, 0x7f); | ||
1672 | |||
1673 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
1674 | ibmcam_veio(uvd, 0, 0x001e, 0x012f); | ||
1675 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
1676 | ibmcam_veio(uvd, 0, g_gain, 0x0127); /* Green gain */ | ||
1677 | ibmcam_veio(uvd, 0, r_gain, 0x012e); /* Red gain */ | ||
1678 | ibmcam_veio(uvd, 0, b_gain, 0x0130); /* Blue gain */ | ||
1679 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
1680 | ibmcam_veio(uvd, 0, hue, 0x012d); /* Hue */ | ||
1681 | ibmcam_veio(uvd, 0, 0xf545, 0x0124); | ||
1682 | break; | ||
1683 | } | ||
1684 | default: | ||
1685 | break; | ||
1686 | } | ||
1687 | } | ||
1688 | |||
1689 | /* | ||
1690 | * ibmcam_adjust_picture() | ||
1691 | * | ||
1692 | * This procedure gets called from V4L interface to update picture settings. | ||
1693 | * Here we change brightness and contrast. | ||
1694 | */ | ||
1695 | static void ibmcam_adjust_picture(struct uvd *uvd) | ||
1696 | { | ||
1697 | ibmcam_adjust_contrast(uvd); | ||
1698 | ibmcam_set_brightness(uvd); | ||
1699 | ibmcam_set_hue(uvd); | ||
1700 | } | ||
1701 | |||
1702 | static int ibmcam_model1_setup(struct uvd *uvd) | ||
1703 | { | ||
1704 | const int ntries = 5; | ||
1705 | int i; | ||
1706 | |||
1707 | ibmcam_veio(uvd, 1, 0x00, 0x0128); | ||
1708 | ibmcam_veio(uvd, 1, 0x00, 0x0100); | ||
1709 | ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */ | ||
1710 | ibmcam_veio(uvd, 1, 0x00, 0x0100); | ||
1711 | ibmcam_veio(uvd, 0, 0x81, 0x0100); /* LED Off */ | ||
1712 | ibmcam_veio(uvd, 1, 0x00, 0x0100); | ||
1713 | ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */ | ||
1714 | ibmcam_veio(uvd, 0, 0x01, 0x0108); | ||
1715 | |||
1716 | ibmcam_veio(uvd, 0, 0x03, 0x0112); | ||
1717 | ibmcam_veio(uvd, 1, 0x00, 0x0115); | ||
1718 | ibmcam_veio(uvd, 0, 0x06, 0x0115); | ||
1719 | ibmcam_veio(uvd, 1, 0x00, 0x0116); | ||
1720 | ibmcam_veio(uvd, 0, 0x44, 0x0116); | ||
1721 | ibmcam_veio(uvd, 1, 0x00, 0x0116); | ||
1722 | ibmcam_veio(uvd, 0, 0x40, 0x0116); | ||
1723 | ibmcam_veio(uvd, 1, 0x00, 0x0115); | ||
1724 | ibmcam_veio(uvd, 0, 0x0e, 0x0115); | ||
1725 | ibmcam_veio(uvd, 0, 0x19, 0x012c); | ||
1726 | |||
1727 | ibmcam_Packet_Format1(uvd, 0x00, 0x1e); | ||
1728 | ibmcam_Packet_Format1(uvd, 0x39, 0x0d); | ||
1729 | ibmcam_Packet_Format1(uvd, 0x39, 0x09); | ||
1730 | ibmcam_Packet_Format1(uvd, 0x3b, 0x00); | ||
1731 | ibmcam_Packet_Format1(uvd, 0x28, 0x22); | ||
1732 | ibmcam_Packet_Format1(uvd, light_27, 0); | ||
1733 | ibmcam_Packet_Format1(uvd, 0x2b, 0x1f); | ||
1734 | ibmcam_Packet_Format1(uvd, 0x39, 0x08); | ||
1735 | |||
1736 | for (i=0; i < ntries; i++) | ||
1737 | ibmcam_Packet_Format1(uvd, 0x2c, 0x00); | ||
1738 | |||
1739 | for (i=0; i < ntries; i++) | ||
1740 | ibmcam_Packet_Format1(uvd, 0x30, 0x14); | ||
1741 | |||
1742 | ibmcam_PacketFormat2(uvd, 0x39, 0x02); | ||
1743 | ibmcam_PacketFormat2(uvd, 0x01, 0xe1); | ||
1744 | ibmcam_PacketFormat2(uvd, 0x02, 0xcd); | ||
1745 | ibmcam_PacketFormat2(uvd, 0x03, 0xcd); | ||
1746 | ibmcam_PacketFormat2(uvd, 0x04, 0xfa); | ||
1747 | ibmcam_PacketFormat2(uvd, 0x3f, 0xff); | ||
1748 | ibmcam_PacketFormat2(uvd, 0x39, 0x00); | ||
1749 | |||
1750 | ibmcam_PacketFormat2(uvd, 0x39, 0x02); | ||
1751 | ibmcam_PacketFormat2(uvd, 0x0a, 0x37); | ||
1752 | ibmcam_PacketFormat2(uvd, 0x0b, 0xb8); | ||
1753 | ibmcam_PacketFormat2(uvd, 0x0c, 0xf3); | ||
1754 | ibmcam_PacketFormat2(uvd, 0x0d, 0xe3); | ||
1755 | ibmcam_PacketFormat2(uvd, 0x0e, 0x0d); | ||
1756 | ibmcam_PacketFormat2(uvd, 0x0f, 0xf2); | ||
1757 | ibmcam_PacketFormat2(uvd, 0x10, 0xd5); | ||
1758 | ibmcam_PacketFormat2(uvd, 0x11, 0xba); | ||
1759 | ibmcam_PacketFormat2(uvd, 0x12, 0x53); | ||
1760 | ibmcam_PacketFormat2(uvd, 0x3f, 0xff); | ||
1761 | ibmcam_PacketFormat2(uvd, 0x39, 0x00); | ||
1762 | |||
1763 | ibmcam_PacketFormat2(uvd, 0x39, 0x02); | ||
1764 | ibmcam_PacketFormat2(uvd, 0x16, 0x00); | ||
1765 | ibmcam_PacketFormat2(uvd, 0x17, 0x28); | ||
1766 | ibmcam_PacketFormat2(uvd, 0x18, 0x7d); | ||
1767 | ibmcam_PacketFormat2(uvd, 0x19, 0xbe); | ||
1768 | ibmcam_PacketFormat2(uvd, 0x3f, 0xff); | ||
1769 | ibmcam_PacketFormat2(uvd, 0x39, 0x00); | ||
1770 | |||
1771 | for (i=0; i < ntries; i++) | ||
1772 | ibmcam_Packet_Format1(uvd, 0x00, 0x18); | ||
1773 | for (i=0; i < ntries; i++) | ||
1774 | ibmcam_Packet_Format1(uvd, 0x13, 0x18); | ||
1775 | for (i=0; i < ntries; i++) | ||
1776 | ibmcam_Packet_Format1(uvd, 0x14, 0x06); | ||
1777 | |||
1778 | /* This is default brightness */ | ||
1779 | for (i=0; i < ntries; i++) | ||
1780 | ibmcam_Packet_Format1(uvd, 0x31, 0x37); | ||
1781 | for (i=0; i < ntries; i++) | ||
1782 | ibmcam_Packet_Format1(uvd, 0x32, 0x46); | ||
1783 | for (i=0; i < ntries; i++) | ||
1784 | ibmcam_Packet_Format1(uvd, 0x33, 0x55); | ||
1785 | |||
1786 | ibmcam_Packet_Format1(uvd, 0x2e, 0x04); | ||
1787 | for (i=0; i < ntries; i++) | ||
1788 | ibmcam_Packet_Format1(uvd, 0x2d, 0x04); | ||
1789 | for (i=0; i < ntries; i++) | ||
1790 | ibmcam_Packet_Format1(uvd, 0x29, 0x80); | ||
1791 | ibmcam_Packet_Format1(uvd, 0x2c, 0x01); | ||
1792 | ibmcam_Packet_Format1(uvd, 0x30, 0x17); | ||
1793 | ibmcam_Packet_Format1(uvd, 0x39, 0x08); | ||
1794 | for (i=0; i < ntries; i++) | ||
1795 | ibmcam_Packet_Format1(uvd, 0x34, 0x00); | ||
1796 | |||
1797 | ibmcam_veio(uvd, 0, 0x00, 0x0101); | ||
1798 | ibmcam_veio(uvd, 0, 0x00, 0x010a); | ||
1799 | |||
1800 | switch (uvd->videosize) { | ||
1801 | case VIDEOSIZE_128x96: | ||
1802 | ibmcam_veio(uvd, 0, 0x80, 0x0103); | ||
1803 | ibmcam_veio(uvd, 0, 0x60, 0x0105); | ||
1804 | ibmcam_veio(uvd, 0, 0x0c, 0x010b); | ||
1805 | ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */ | ||
1806 | ibmcam_veio(uvd, 0, 0x0b, 0x011d); | ||
1807 | ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */ | ||
1808 | ibmcam_veio(uvd, 0, 0x00, 0x0129); | ||
1809 | break; | ||
1810 | case VIDEOSIZE_176x144: | ||
1811 | ibmcam_veio(uvd, 0, 0xb0, 0x0103); | ||
1812 | ibmcam_veio(uvd, 0, 0x8f, 0x0105); | ||
1813 | ibmcam_veio(uvd, 0, 0x06, 0x010b); | ||
1814 | ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */ | ||
1815 | ibmcam_veio(uvd, 0, 0x0d, 0x011d); | ||
1816 | ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */ | ||
1817 | ibmcam_veio(uvd, 0, 0x03, 0x0129); | ||
1818 | break; | ||
1819 | case VIDEOSIZE_352x288: | ||
1820 | ibmcam_veio(uvd, 0, 0xb0, 0x0103); | ||
1821 | ibmcam_veio(uvd, 0, 0x90, 0x0105); | ||
1822 | ibmcam_veio(uvd, 0, 0x02, 0x010b); | ||
1823 | ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */ | ||
1824 | ibmcam_veio(uvd, 0, 0x05, 0x011d); | ||
1825 | ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */ | ||
1826 | ibmcam_veio(uvd, 0, 0x00, 0x0129); | ||
1827 | break; | ||
1828 | } | ||
1829 | |||
1830 | ibmcam_veio(uvd, 0, 0xff, 0x012b); | ||
1831 | |||
1832 | /* This is another brightness - don't know why */ | ||
1833 | for (i=0; i < ntries; i++) | ||
1834 | ibmcam_Packet_Format1(uvd, 0x31, 0xc3); | ||
1835 | for (i=0; i < ntries; i++) | ||
1836 | ibmcam_Packet_Format1(uvd, 0x32, 0xd2); | ||
1837 | for (i=0; i < ntries; i++) | ||
1838 | ibmcam_Packet_Format1(uvd, 0x33, 0xe1); | ||
1839 | |||
1840 | /* Default contrast */ | ||
1841 | for (i=0; i < ntries; i++) | ||
1842 | ibmcam_Packet_Format1(uvd, contrast_14, 0x0a); | ||
1843 | |||
1844 | /* Default sharpness */ | ||
1845 | for (i=0; i < 2; i++) | ||
1846 | ibmcam_PacketFormat2(uvd, sharp_13, 0x1a); /* Level 4 FIXME */ | ||
1847 | |||
1848 | /* Default lighting conditions */ | ||
1849 | ibmcam_Packet_Format1(uvd, light_27, lighting); /* 0=Bright 2=Low */ | ||
1850 | |||
1851 | /* Assorted init */ | ||
1852 | |||
1853 | switch (uvd->videosize) { | ||
1854 | case VIDEOSIZE_128x96: | ||
1855 | ibmcam_Packet_Format1(uvd, 0x2b, 0x1e); | ||
1856 | ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */ | ||
1857 | ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */ | ||
1858 | ibmcam_veio(uvd, 0, 0x36, 0x0102); | ||
1859 | ibmcam_veio(uvd, 0, 0x1a, 0x0104); | ||
1860 | ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */ | ||
1861 | ibmcam_veio(uvd, 0, 0x2b, 0x011c); | ||
1862 | ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */ | ||
1863 | #if 0 | ||
1864 | ibmcam_veio(uvd, 0, 0x00, 0x0106); | ||
1865 | ibmcam_veio(uvd, 0, 0x38, 0x0107); | ||
1866 | #else | ||
1867 | ibmcam_veio(uvd, 0, 0x02, 0x0106); | ||
1868 | ibmcam_veio(uvd, 0, 0x2a, 0x0107); | ||
1869 | #endif | ||
1870 | break; | ||
1871 | case VIDEOSIZE_176x144: | ||
1872 | ibmcam_Packet_Format1(uvd, 0x2b, 0x1e); | ||
1873 | ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */ | ||
1874 | ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */ | ||
1875 | ibmcam_veio(uvd, 0, 0x04, 0x0102); | ||
1876 | ibmcam_veio(uvd, 0, 0x02, 0x0104); | ||
1877 | ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */ | ||
1878 | ibmcam_veio(uvd, 0, 0x2b, 0x011c); | ||
1879 | ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */ | ||
1880 | ibmcam_veio(uvd, 0, 0x01, 0x0106); | ||
1881 | ibmcam_veio(uvd, 0, 0xca, 0x0107); | ||
1882 | break; | ||
1883 | case VIDEOSIZE_352x288: | ||
1884 | ibmcam_Packet_Format1(uvd, 0x2b, 0x1f); | ||
1885 | ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */ | ||
1886 | ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */ | ||
1887 | ibmcam_veio(uvd, 0, 0x08, 0x0102); | ||
1888 | ibmcam_veio(uvd, 0, 0x01, 0x0104); | ||
1889 | ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */ | ||
1890 | ibmcam_veio(uvd, 0, 0x2f, 0x011c); | ||
1891 | ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */ | ||
1892 | ibmcam_veio(uvd, 0, 0x03, 0x0106); | ||
1893 | ibmcam_veio(uvd, 0, 0xf6, 0x0107); | ||
1894 | break; | ||
1895 | } | ||
1896 | return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT); | ||
1897 | } | ||
1898 | |||
1899 | static int ibmcam_model2_setup(struct uvd *uvd) | ||
1900 | { | ||
1901 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); /* LED on */ | ||
1902 | ibmcam_veio(uvd, 1, 0x0000, 0x0116); | ||
1903 | ibmcam_veio(uvd, 0, 0x0060, 0x0116); | ||
1904 | ibmcam_veio(uvd, 0, 0x0002, 0x0112); | ||
1905 | ibmcam_veio(uvd, 0, 0x00bc, 0x012c); | ||
1906 | ibmcam_veio(uvd, 0, 0x0008, 0x012b); | ||
1907 | ibmcam_veio(uvd, 0, 0x0000, 0x0108); | ||
1908 | ibmcam_veio(uvd, 0, 0x0001, 0x0133); | ||
1909 | ibmcam_veio(uvd, 0, 0x0001, 0x0102); | ||
1910 | switch (uvd->videosize) { | ||
1911 | case VIDEOSIZE_176x144: | ||
1912 | ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */ | ||
1913 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ | ||
1914 | ibmcam_veio(uvd, 0, 0x0024, 0x0105); /* 176x144, 352x288 */ | ||
1915 | ibmcam_veio(uvd, 0, 0x00b9, 0x010a); /* Unique to this mode */ | ||
1916 | ibmcam_veio(uvd, 0, 0x0038, 0x0119); /* Unique to this mode */ | ||
1917 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ | ||
1918 | ibmcam_veio(uvd, 0, 0x0090, 0x0107); /* Unique to every mode*/ | ||
1919 | break; | ||
1920 | case VIDEOSIZE_320x240: | ||
1921 | ibmcam_veio(uvd, 0, 0x0028, 0x0103); /* Unique to this mode */ | ||
1922 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ | ||
1923 | ibmcam_veio(uvd, 0, 0x001e, 0x0105); /* 320x240, 352x240 */ | ||
1924 | ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */ | ||
1925 | ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */ | ||
1926 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ | ||
1927 | ibmcam_veio(uvd, 0, 0x0098, 0x0107); /* Unique to every mode*/ | ||
1928 | break; | ||
1929 | case VIDEOSIZE_352x240: | ||
1930 | ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */ | ||
1931 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ | ||
1932 | ibmcam_veio(uvd, 0, 0x001e, 0x0105); /* 320x240, 352x240 */ | ||
1933 | ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */ | ||
1934 | ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */ | ||
1935 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ | ||
1936 | ibmcam_veio(uvd, 0, 0x00da, 0x0107); /* Unique to every mode*/ | ||
1937 | break; | ||
1938 | case VIDEOSIZE_352x288: | ||
1939 | ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */ | ||
1940 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ | ||
1941 | ibmcam_veio(uvd, 0, 0x0024, 0x0105); /* 176x144, 352x288 */ | ||
1942 | ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */ | ||
1943 | ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */ | ||
1944 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ | ||
1945 | ibmcam_veio(uvd, 0, 0x00fe, 0x0107); /* Unique to every mode*/ | ||
1946 | break; | ||
1947 | } | ||
1948 | return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT); | ||
1949 | } | ||
1950 | |||
1951 | /* | ||
1952 | * ibmcam_model1_setup_after_video_if() | ||
1953 | * | ||
1954 | * This code adds finishing touches to the video data interface. | ||
1955 | * Here we configure the frame rate and turn on the LED. | ||
1956 | */ | ||
1957 | static void ibmcam_model1_setup_after_video_if(struct uvd *uvd) | ||
1958 | { | ||
1959 | unsigned short internal_frame_rate; | ||
1960 | |||
1961 | RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX); | ||
1962 | internal_frame_rate = FRAMERATE_MAX - framerate; /* 0=Fast 6=Slow */ | ||
1963 | ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */ | ||
1964 | ibmcam_veio(uvd, 0, internal_frame_rate, 0x0111); | ||
1965 | ibmcam_veio(uvd, 0, 0x01, 0x0114); | ||
1966 | ibmcam_veio(uvd, 0, 0xc0, 0x010c); | ||
1967 | } | ||
1968 | |||
1969 | static void ibmcam_model2_setup_after_video_if(struct uvd *uvd) | ||
1970 | { | ||
1971 | unsigned short setup_model2_rg2, setup_model2_sat, setup_model2_yb; | ||
1972 | |||
1973 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); /* LED on */ | ||
1974 | |||
1975 | switch (uvd->videosize) { | ||
1976 | case VIDEOSIZE_176x144: | ||
1977 | ibmcam_veio(uvd, 0, 0x0050, 0x0111); | ||
1978 | ibmcam_veio(uvd, 0, 0x00d0, 0x0111); | ||
1979 | break; | ||
1980 | case VIDEOSIZE_320x240: | ||
1981 | case VIDEOSIZE_352x240: | ||
1982 | case VIDEOSIZE_352x288: | ||
1983 | ibmcam_veio(uvd, 0, 0x0040, 0x0111); | ||
1984 | ibmcam_veio(uvd, 0, 0x00c0, 0x0111); | ||
1985 | break; | ||
1986 | } | ||
1987 | ibmcam_veio(uvd, 0, 0x009b, 0x010f); | ||
1988 | ibmcam_veio(uvd, 0, 0x00bb, 0x010f); | ||
1989 | |||
1990 | /* | ||
1991 | * Hardware settings, may affect CMOS sensor; not user controls! | ||
1992 | * ------------------------------------------------------------- | ||
1993 | * 0x0004: no effect | ||
1994 | * 0x0006: hardware effect | ||
1995 | * 0x0008: no effect | ||
1996 | * 0x000a: stops video stream, probably important h/w setting | ||
1997 | * 0x000c: changes color in hardware manner (not user setting) | ||
1998 | * 0x0012: changes number of colors (does not affect speed) | ||
1999 | * 0x002a: no effect | ||
2000 | * 0x002c: hardware setting (related to scan lines) | ||
2001 | * 0x002e: stops video stream, probably important h/w setting | ||
2002 | */ | ||
2003 | ibmcam_model2_Packet1(uvd, 0x000a, 0x005c); | ||
2004 | ibmcam_model2_Packet1(uvd, 0x0004, 0x0000); | ||
2005 | ibmcam_model2_Packet1(uvd, 0x0006, 0x00fb); | ||
2006 | ibmcam_model2_Packet1(uvd, 0x0008, 0x0000); | ||
2007 | ibmcam_model2_Packet1(uvd, 0x000c, 0x0009); | ||
2008 | ibmcam_model2_Packet1(uvd, 0x0012, 0x000a); | ||
2009 | ibmcam_model2_Packet1(uvd, 0x002a, 0x0000); | ||
2010 | ibmcam_model2_Packet1(uvd, 0x002c, 0x0000); | ||
2011 | ibmcam_model2_Packet1(uvd, 0x002e, 0x0008); | ||
2012 | |||
2013 | /* | ||
2014 | * Function 0x0030 pops up all over the place. Apparently | ||
2015 | * it is a hardware control register, with every bit assigned to | ||
2016 | * do something. | ||
2017 | */ | ||
2018 | ibmcam_model2_Packet1(uvd, 0x0030, 0x0000); | ||
2019 | |||
2020 | /* | ||
2021 | * Magic control of CMOS sensor. Only lower values like | ||
2022 | * 0-3 work, and picture shifts left or right. Don't change. | ||
2023 | */ | ||
2024 | switch (uvd->videosize) { | ||
2025 | case VIDEOSIZE_176x144: | ||
2026 | ibmcam_model2_Packet1(uvd, 0x0014, 0x0002); | ||
2027 | ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */ | ||
2028 | ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */ | ||
2029 | break; | ||
2030 | case VIDEOSIZE_320x240: | ||
2031 | ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); | ||
2032 | ibmcam_model2_Packet1(uvd, 0x0016, 0x0005); /* Horizontal shift */ | ||
2033 | ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Another hardware setting */ | ||
2034 | break; | ||
2035 | case VIDEOSIZE_352x240: | ||
2036 | /* This mode doesn't work as Windows programs it; changed to work */ | ||
2037 | ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); /* Windows sets this to 8 */ | ||
2038 | ibmcam_model2_Packet1(uvd, 0x0016, 0x0003); /* Horizontal shift */ | ||
2039 | ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Windows sets this to 0x0045 */ | ||
2040 | break; | ||
2041 | case VIDEOSIZE_352x288: | ||
2042 | ibmcam_model2_Packet1(uvd, 0x0014, 0x0003); | ||
2043 | ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */ | ||
2044 | ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */ | ||
2045 | break; | ||
2046 | } | ||
2047 | |||
2048 | ibmcam_model2_Packet1(uvd, mod2_brightness, 0x005a); | ||
2049 | |||
2050 | /* | ||
2051 | * We have our own frame rate setting varying from 0 (slowest) to 6 (fastest). | ||
2052 | * The camera model 2 allows frame rate in range [0..0x1F] where 0 is also the | ||
2053 | * slowest setting. However for all practical reasons high settings make no | ||
2054 | * sense because USB is not fast enough to support high FPS. Be aware that | ||
2055 | * the picture datastream will be severely disrupted if you ask for | ||
2056 | * frame rate faster than allowed for the video size - see below: | ||
2057 | * | ||
2058 | * Allowable ranges (obtained experimentally on OHCI, K6-3, 450 MHz): | ||
2059 | * ----------------------------------------------------------------- | ||
2060 | * 176x144: [6..31] | ||
2061 | * 320x240: [8..31] | ||
2062 | * 352x240: [10..31] | ||
2063 | * 352x288: [16..31] I have to raise lower threshold for stability... | ||
2064 | * | ||
2065 | * As usual, slower FPS provides better sensitivity. | ||
2066 | */ | ||
2067 | { | ||
2068 | short hw_fps=31, i_framerate; | ||
2069 | |||
2070 | RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX); | ||
2071 | i_framerate = FRAMERATE_MAX - framerate + FRAMERATE_MIN; | ||
2072 | switch (uvd->videosize) { | ||
2073 | case VIDEOSIZE_176x144: | ||
2074 | hw_fps = 6 + i_framerate*4; | ||
2075 | break; | ||
2076 | case VIDEOSIZE_320x240: | ||
2077 | hw_fps = 8 + i_framerate*3; | ||
2078 | break; | ||
2079 | case VIDEOSIZE_352x240: | ||
2080 | hw_fps = 10 + i_framerate*2; | ||
2081 | break; | ||
2082 | case VIDEOSIZE_352x288: | ||
2083 | hw_fps = 28 + i_framerate/2; | ||
2084 | break; | ||
2085 | } | ||
2086 | if (uvd->debug > 0) | ||
2087 | info("Framerate (hardware): %hd.", hw_fps); | ||
2088 | RESTRICT_TO_RANGE(hw_fps, 0, 31); | ||
2089 | ibmcam_model2_Packet1(uvd, mod2_set_framerate, hw_fps); | ||
2090 | } | ||
2091 | |||
2092 | /* | ||
2093 | * This setting does not visibly affect pictures; left it here | ||
2094 | * because it was present in Windows USB data stream. This function | ||
2095 | * does not allow arbitrary values and apparently is a bit mask, to | ||
2096 | * be activated only at appropriate time. Don't change it randomly! | ||
2097 | */ | ||
2098 | switch (uvd->videosize) { | ||
2099 | case VIDEOSIZE_176x144: | ||
2100 | ibmcam_model2_Packet1(uvd, 0x0026, 0x00c2); | ||
2101 | break; | ||
2102 | case VIDEOSIZE_320x240: | ||
2103 | ibmcam_model2_Packet1(uvd, 0x0026, 0x0044); | ||
2104 | break; | ||
2105 | case VIDEOSIZE_352x240: | ||
2106 | ibmcam_model2_Packet1(uvd, 0x0026, 0x0046); | ||
2107 | break; | ||
2108 | case VIDEOSIZE_352x288: | ||
2109 | ibmcam_model2_Packet1(uvd, 0x0026, 0x0048); | ||
2110 | break; | ||
2111 | } | ||
2112 | |||
2113 | ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting); | ||
2114 | |||
2115 | if (init_model2_rg2 >= 0) { | ||
2116 | RESTRICT_TO_RANGE(init_model2_rg2, 0, 255); | ||
2117 | setup_model2_rg2 = init_model2_rg2; | ||
2118 | } else | ||
2119 | setup_model2_rg2 = 0x002f; | ||
2120 | |||
2121 | if (init_model2_sat >= 0) { | ||
2122 | RESTRICT_TO_RANGE(init_model2_sat, 0, 255); | ||
2123 | setup_model2_sat = init_model2_sat; | ||
2124 | } else | ||
2125 | setup_model2_sat = 0x0034; | ||
2126 | |||
2127 | if (init_model2_yb >= 0) { | ||
2128 | RESTRICT_TO_RANGE(init_model2_yb, 0, 255); | ||
2129 | setup_model2_yb = init_model2_yb; | ||
2130 | } else | ||
2131 | setup_model2_yb = 0x00a0; | ||
2132 | |||
2133 | ibmcam_model2_Packet1(uvd, mod2_color_balance_rg2, setup_model2_rg2); | ||
2134 | ibmcam_model2_Packet1(uvd, mod2_saturation, setup_model2_sat); | ||
2135 | ibmcam_model2_Packet1(uvd, mod2_color_balance_yb, setup_model2_yb); | ||
2136 | ibmcam_model2_Packet1(uvd, mod2_hue, uvd->vpic.hue >> 9); /* 0 .. 7F */; | ||
2137 | |||
2138 | /* Hardware control command */ | ||
2139 | ibmcam_model2_Packet1(uvd, 0x0030, 0x0004); | ||
2140 | |||
2141 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go camera, go! */ | ||
2142 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
2143 | } | ||
2144 | |||
2145 | static void ibmcam_model4_setup_after_video_if(struct uvd *uvd) | ||
2146 | { | ||
2147 | switch (uvd->videosize) { | ||
2148 | case VIDEOSIZE_128x96: | ||
2149 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); | ||
2150 | ibmcam_veio(uvd, 0, 0x00c0, 0x0111); | ||
2151 | ibmcam_veio(uvd, 0, 0x00bc, 0x012c); | ||
2152 | ibmcam_veio(uvd, 0, 0x0080, 0x012b); | ||
2153 | ibmcam_veio(uvd, 0, 0x0000, 0x0108); | ||
2154 | ibmcam_veio(uvd, 0, 0x0001, 0x0133); | ||
2155 | ibmcam_veio(uvd, 0, 0x009b, 0x010f); | ||
2156 | ibmcam_veio(uvd, 0, 0x00bb, 0x010f); | ||
2157 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2158 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
2159 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2160 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2161 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2162 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2163 | ibmcam_veio(uvd, 0, 0x000a, 0x012f); | ||
2164 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2165 | ibmcam_veio(uvd, 0, 0x005c, 0x0127); | ||
2166 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2167 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2168 | ibmcam_veio(uvd, 0, 0x0004, 0x012f); | ||
2169 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2170 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2171 | ibmcam_veio(uvd, 0, 0x00fb, 0x012e); | ||
2172 | ibmcam_veio(uvd, 0, 0x0000, 0x0130); | ||
2173 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2174 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
2175 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
2176 | ibmcam_veio(uvd, 0, 0x000c, 0x0127); | ||
2177 | ibmcam_veio(uvd, 0, 0x0009, 0x012e); | ||
2178 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
2179 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2180 | ibmcam_veio(uvd, 0, 0x0012, 0x012f); | ||
2181 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2182 | ibmcam_veio(uvd, 0, 0x0008, 0x0127); | ||
2183 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2184 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2185 | ibmcam_veio(uvd, 0, 0x002a, 0x012d); | ||
2186 | ibmcam_veio(uvd, 0, 0x0000, 0x012f); | ||
2187 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2188 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
2189 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2190 | ibmcam_veio(uvd, 0, 0x0034, 0x012f); | ||
2191 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2192 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2193 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2194 | ibmcam_veio(uvd, 0, 0x0070, 0x0119); | ||
2195 | ibmcam_veio(uvd, 0, 0x00d2, 0x0107); | ||
2196 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
2197 | ibmcam_veio(uvd, 0, 0x005e, 0x0107); | ||
2198 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
2199 | ibmcam_veio(uvd, 0, 0x00d0, 0x0111); | ||
2200 | ibmcam_veio(uvd, 0, 0x0039, 0x010a); | ||
2201 | ibmcam_veio(uvd, 0, 0x0001, 0x0102); | ||
2202 | ibmcam_veio(uvd, 0, 0x0028, 0x0103); | ||
2203 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); | ||
2204 | ibmcam_veio(uvd, 0, 0x001e, 0x0105); | ||
2205 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2206 | ibmcam_veio(uvd, 0, 0x0016, 0x012f); | ||
2207 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2208 | ibmcam_veio(uvd, 0, 0x000a, 0x0127); | ||
2209 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2210 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2211 | ibmcam_veio(uvd, 0, 0x0014, 0x012d); | ||
2212 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
2213 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2214 | ibmcam_veio(uvd, 0, 0x00aa, 0x012e); | ||
2215 | ibmcam_veio(uvd, 0, 0x001a, 0x0130); | ||
2216 | ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); | ||
2217 | ibmcam_veio(uvd, 0, 0x005a, 0x012d); | ||
2218 | ibmcam_veio(uvd, 0, 0x9545, 0x0124); | ||
2219 | ibmcam_veio(uvd, 0, 0x00aa, 0x0127); | ||
2220 | ibmcam_veio(uvd, 0, 0x0018, 0x012e); | ||
2221 | ibmcam_veio(uvd, 0, 0x0043, 0x0130); | ||
2222 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2223 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
2224 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
2225 | ibmcam_veio(uvd, 0, 0x001c, 0x0127); | ||
2226 | ibmcam_veio(uvd, 0, 0x00eb, 0x012e); | ||
2227 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
2228 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2229 | ibmcam_veio(uvd, 0, 0x0032, 0x012f); | ||
2230 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2231 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2232 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2233 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2234 | ibmcam_veio(uvd, 0, 0x0036, 0x012d); | ||
2235 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
2236 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2237 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
2238 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2239 | ibmcam_veio(uvd, 0, 0x001e, 0x012f); | ||
2240 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2241 | ibmcam_veio(uvd, 0, 0x0017, 0x0127); | ||
2242 | ibmcam_veio(uvd, 0, 0x0013, 0x012e); | ||
2243 | ibmcam_veio(uvd, 0, 0x0031, 0x0130); | ||
2244 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2245 | ibmcam_veio(uvd, 0, 0x0017, 0x012d); | ||
2246 | ibmcam_veio(uvd, 0, 0x0078, 0x012f); | ||
2247 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2248 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2249 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2250 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2251 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
2252 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2253 | ibmcam_veio(uvd, 0, 0x0004, 0x0127); | ||
2254 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2255 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); | ||
2256 | break; | ||
2257 | case VIDEOSIZE_160x120: | ||
2258 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); | ||
2259 | ibmcam_veio(uvd, 0, 0x00c0, 0x0111); | ||
2260 | ibmcam_veio(uvd, 0, 0x00bc, 0x012c); | ||
2261 | ibmcam_veio(uvd, 0, 0x0080, 0x012b); | ||
2262 | ibmcam_veio(uvd, 0, 0x0000, 0x0108); | ||
2263 | ibmcam_veio(uvd, 0, 0x0001, 0x0133); | ||
2264 | ibmcam_veio(uvd, 0, 0x009b, 0x010f); | ||
2265 | ibmcam_veio(uvd, 0, 0x00bb, 0x010f); | ||
2266 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2267 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
2268 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2269 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2270 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2271 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2272 | ibmcam_veio(uvd, 0, 0x000a, 0x012f); | ||
2273 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2274 | ibmcam_veio(uvd, 0, 0x005c, 0x0127); | ||
2275 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2276 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2277 | ibmcam_veio(uvd, 0, 0x0004, 0x012f); | ||
2278 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2279 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2280 | ibmcam_veio(uvd, 0, 0x00fb, 0x012e); | ||
2281 | ibmcam_veio(uvd, 0, 0x0000, 0x0130); | ||
2282 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2283 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
2284 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
2285 | ibmcam_veio(uvd, 0, 0x000c, 0x0127); | ||
2286 | ibmcam_veio(uvd, 0, 0x0009, 0x012e); | ||
2287 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
2288 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2289 | ibmcam_veio(uvd, 0, 0x0012, 0x012f); | ||
2290 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2291 | ibmcam_veio(uvd, 0, 0x0008, 0x0127); | ||
2292 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2293 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2294 | ibmcam_veio(uvd, 0, 0x002a, 0x012d); | ||
2295 | ibmcam_veio(uvd, 0, 0x0000, 0x012f); | ||
2296 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2297 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
2298 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2299 | ibmcam_veio(uvd, 0, 0x0034, 0x012f); | ||
2300 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2301 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2302 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2303 | ibmcam_veio(uvd, 0, 0x0038, 0x0119); | ||
2304 | ibmcam_veio(uvd, 0, 0x00d8, 0x0107); | ||
2305 | ibmcam_veio(uvd, 0, 0x0002, 0x0106); | ||
2306 | ibmcam_veio(uvd, 0, 0x00d0, 0x0111); | ||
2307 | ibmcam_veio(uvd, 0, 0x00b9, 0x010a); | ||
2308 | ibmcam_veio(uvd, 0, 0x0001, 0x0102); | ||
2309 | ibmcam_veio(uvd, 0, 0x0028, 0x0103); | ||
2310 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); | ||
2311 | ibmcam_veio(uvd, 0, 0x001e, 0x0105); | ||
2312 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2313 | ibmcam_veio(uvd, 0, 0x0016, 0x012f); | ||
2314 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2315 | ibmcam_veio(uvd, 0, 0x000b, 0x0127); | ||
2316 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2317 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2318 | ibmcam_veio(uvd, 0, 0x0014, 0x012d); | ||
2319 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
2320 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2321 | ibmcam_veio(uvd, 0, 0x00aa, 0x012e); | ||
2322 | ibmcam_veio(uvd, 0, 0x001a, 0x0130); | ||
2323 | ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); | ||
2324 | ibmcam_veio(uvd, 0, 0x005a, 0x012d); | ||
2325 | ibmcam_veio(uvd, 0, 0x9545, 0x0124); | ||
2326 | ibmcam_veio(uvd, 0, 0x00aa, 0x0127); | ||
2327 | ibmcam_veio(uvd, 0, 0x0018, 0x012e); | ||
2328 | ibmcam_veio(uvd, 0, 0x0043, 0x0130); | ||
2329 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2330 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
2331 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
2332 | ibmcam_veio(uvd, 0, 0x001c, 0x0127); | ||
2333 | ibmcam_veio(uvd, 0, 0x00c7, 0x012e); | ||
2334 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
2335 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2336 | ibmcam_veio(uvd, 0, 0x0032, 0x012f); | ||
2337 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2338 | ibmcam_veio(uvd, 0, 0x0025, 0x0127); | ||
2339 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2340 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2341 | ibmcam_veio(uvd, 0, 0x0036, 0x012d); | ||
2342 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
2343 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2344 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
2345 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2346 | ibmcam_veio(uvd, 0, 0x001e, 0x012f); | ||
2347 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2348 | ibmcam_veio(uvd, 0, 0x0048, 0x0127); | ||
2349 | ibmcam_veio(uvd, 0, 0x0035, 0x012e); | ||
2350 | ibmcam_veio(uvd, 0, 0x00d0, 0x0130); | ||
2351 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2352 | ibmcam_veio(uvd, 0, 0x0048, 0x012d); | ||
2353 | ibmcam_veio(uvd, 0, 0x0090, 0x012f); | ||
2354 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2355 | ibmcam_veio(uvd, 0, 0x0001, 0x0127); | ||
2356 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2357 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2358 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
2359 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2360 | ibmcam_veio(uvd, 0, 0x0004, 0x0127); | ||
2361 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2362 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); | ||
2363 | break; | ||
2364 | case VIDEOSIZE_176x144: | ||
2365 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); | ||
2366 | ibmcam_veio(uvd, 0, 0x00c0, 0x0111); | ||
2367 | ibmcam_veio(uvd, 0, 0x00bc, 0x012c); | ||
2368 | ibmcam_veio(uvd, 0, 0x0080, 0x012b); | ||
2369 | ibmcam_veio(uvd, 0, 0x0000, 0x0108); | ||
2370 | ibmcam_veio(uvd, 0, 0x0001, 0x0133); | ||
2371 | ibmcam_veio(uvd, 0, 0x009b, 0x010f); | ||
2372 | ibmcam_veio(uvd, 0, 0x00bb, 0x010f); | ||
2373 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2374 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
2375 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2376 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2377 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2378 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2379 | ibmcam_veio(uvd, 0, 0x000a, 0x012f); | ||
2380 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2381 | ibmcam_veio(uvd, 0, 0x005c, 0x0127); | ||
2382 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2383 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2384 | ibmcam_veio(uvd, 0, 0x0004, 0x012f); | ||
2385 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2386 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2387 | ibmcam_veio(uvd, 0, 0x00fb, 0x012e); | ||
2388 | ibmcam_veio(uvd, 0, 0x0000, 0x0130); | ||
2389 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2390 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
2391 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
2392 | ibmcam_veio(uvd, 0, 0x000c, 0x0127); | ||
2393 | ibmcam_veio(uvd, 0, 0x0009, 0x012e); | ||
2394 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
2395 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2396 | ibmcam_veio(uvd, 0, 0x0012, 0x012f); | ||
2397 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2398 | ibmcam_veio(uvd, 0, 0x0008, 0x0127); | ||
2399 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2400 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2401 | ibmcam_veio(uvd, 0, 0x002a, 0x012d); | ||
2402 | ibmcam_veio(uvd, 0, 0x0000, 0x012f); | ||
2403 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2404 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
2405 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2406 | ibmcam_veio(uvd, 0, 0x0034, 0x012f); | ||
2407 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2408 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2409 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2410 | ibmcam_veio(uvd, 0, 0x0038, 0x0119); | ||
2411 | ibmcam_veio(uvd, 0, 0x00d6, 0x0107); | ||
2412 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
2413 | ibmcam_veio(uvd, 0, 0x0018, 0x0107); | ||
2414 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
2415 | ibmcam_veio(uvd, 0, 0x00d0, 0x0111); | ||
2416 | ibmcam_veio(uvd, 0, 0x00b9, 0x010a); | ||
2417 | ibmcam_veio(uvd, 0, 0x0001, 0x0102); | ||
2418 | ibmcam_veio(uvd, 0, 0x002c, 0x0103); | ||
2419 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); | ||
2420 | ibmcam_veio(uvd, 0, 0x0024, 0x0105); | ||
2421 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2422 | ibmcam_veio(uvd, 0, 0x0016, 0x012f); | ||
2423 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2424 | ibmcam_veio(uvd, 0, 0x0007, 0x0127); | ||
2425 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2426 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2427 | ibmcam_veio(uvd, 0, 0x0014, 0x012d); | ||
2428 | ibmcam_veio(uvd, 0, 0x0001, 0x012f); | ||
2429 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2430 | ibmcam_veio(uvd, 0, 0x00aa, 0x012e); | ||
2431 | ibmcam_veio(uvd, 0, 0x001a, 0x0130); | ||
2432 | ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); | ||
2433 | ibmcam_veio(uvd, 0, 0x005e, 0x012d); | ||
2434 | ibmcam_veio(uvd, 0, 0x9545, 0x0124); | ||
2435 | ibmcam_veio(uvd, 0, 0x00aa, 0x0127); | ||
2436 | ibmcam_veio(uvd, 0, 0x0018, 0x012e); | ||
2437 | ibmcam_veio(uvd, 0, 0x0049, 0x0130); | ||
2438 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2439 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
2440 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
2441 | ibmcam_veio(uvd, 0, 0x001c, 0x0127); | ||
2442 | ibmcam_veio(uvd, 0, 0x00c7, 0x012e); | ||
2443 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
2444 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2445 | ibmcam_veio(uvd, 0, 0x0032, 0x012f); | ||
2446 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2447 | ibmcam_veio(uvd, 0, 0x0028, 0x0127); | ||
2448 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2449 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2450 | ibmcam_veio(uvd, 0, 0x0036, 0x012d); | ||
2451 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
2452 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2453 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
2454 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2455 | ibmcam_veio(uvd, 0, 0x001e, 0x012f); | ||
2456 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2457 | ibmcam_veio(uvd, 0, 0x0010, 0x0127); | ||
2458 | ibmcam_veio(uvd, 0, 0x0013, 0x012e); | ||
2459 | ibmcam_veio(uvd, 0, 0x002a, 0x0130); | ||
2460 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2461 | ibmcam_veio(uvd, 0, 0x0010, 0x012d); | ||
2462 | ibmcam_veio(uvd, 0, 0x006d, 0x012f); | ||
2463 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2464 | ibmcam_veio(uvd, 0, 0x0001, 0x0127); | ||
2465 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2466 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2467 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
2468 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2469 | ibmcam_veio(uvd, 0, 0x0004, 0x0127); | ||
2470 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2471 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); | ||
2472 | break; | ||
2473 | case VIDEOSIZE_320x240: | ||
2474 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); | ||
2475 | ibmcam_veio(uvd, 0, 0x00c0, 0x0111); | ||
2476 | ibmcam_veio(uvd, 0, 0x00bc, 0x012c); | ||
2477 | ibmcam_veio(uvd, 0, 0x0080, 0x012b); | ||
2478 | ibmcam_veio(uvd, 0, 0x0000, 0x0108); | ||
2479 | ibmcam_veio(uvd, 0, 0x0001, 0x0133); | ||
2480 | ibmcam_veio(uvd, 0, 0x009b, 0x010f); | ||
2481 | ibmcam_veio(uvd, 0, 0x00bb, 0x010f); | ||
2482 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2483 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
2484 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2485 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2486 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2487 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2488 | ibmcam_veio(uvd, 0, 0x000a, 0x012f); | ||
2489 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2490 | ibmcam_veio(uvd, 0, 0x005c, 0x0127); | ||
2491 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2492 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2493 | ibmcam_veio(uvd, 0, 0x0004, 0x012f); | ||
2494 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2495 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2496 | ibmcam_veio(uvd, 0, 0x00fb, 0x012e); | ||
2497 | ibmcam_veio(uvd, 0, 0x0000, 0x0130); | ||
2498 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2499 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
2500 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
2501 | ibmcam_veio(uvd, 0, 0x000c, 0x0127); | ||
2502 | ibmcam_veio(uvd, 0, 0x0009, 0x012e); | ||
2503 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
2504 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2505 | ibmcam_veio(uvd, 0, 0x0012, 0x012f); | ||
2506 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2507 | ibmcam_veio(uvd, 0, 0x0008, 0x0127); | ||
2508 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2509 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2510 | ibmcam_veio(uvd, 0, 0x002a, 0x012d); | ||
2511 | ibmcam_veio(uvd, 0, 0x0000, 0x012f); | ||
2512 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2513 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
2514 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2515 | ibmcam_veio(uvd, 0, 0x0034, 0x012f); | ||
2516 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2517 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2518 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2519 | ibmcam_veio(uvd, 0, 0x0070, 0x0119); | ||
2520 | ibmcam_veio(uvd, 0, 0x00d2, 0x0107); | ||
2521 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
2522 | ibmcam_veio(uvd, 0, 0x005e, 0x0107); | ||
2523 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
2524 | ibmcam_veio(uvd, 0, 0x00d0, 0x0111); | ||
2525 | ibmcam_veio(uvd, 0, 0x0039, 0x010a); | ||
2526 | ibmcam_veio(uvd, 0, 0x0001, 0x0102); | ||
2527 | ibmcam_veio(uvd, 0, 0x0028, 0x0103); | ||
2528 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); | ||
2529 | ibmcam_veio(uvd, 0, 0x001e, 0x0105); | ||
2530 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2531 | ibmcam_veio(uvd, 0, 0x0016, 0x012f); | ||
2532 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2533 | ibmcam_veio(uvd, 0, 0x000a, 0x0127); | ||
2534 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2535 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2536 | ibmcam_veio(uvd, 0, 0x0014, 0x012d); | ||
2537 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
2538 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2539 | ibmcam_veio(uvd, 0, 0x00aa, 0x012e); | ||
2540 | ibmcam_veio(uvd, 0, 0x001a, 0x0130); | ||
2541 | ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); | ||
2542 | ibmcam_veio(uvd, 0, 0x005a, 0x012d); | ||
2543 | ibmcam_veio(uvd, 0, 0x9545, 0x0124); | ||
2544 | ibmcam_veio(uvd, 0, 0x00aa, 0x0127); | ||
2545 | ibmcam_veio(uvd, 0, 0x0018, 0x012e); | ||
2546 | ibmcam_veio(uvd, 0, 0x0043, 0x0130); | ||
2547 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2548 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
2549 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
2550 | ibmcam_veio(uvd, 0, 0x001c, 0x0127); | ||
2551 | ibmcam_veio(uvd, 0, 0x00eb, 0x012e); | ||
2552 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
2553 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2554 | ibmcam_veio(uvd, 0, 0x0032, 0x012f); | ||
2555 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2556 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2557 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2558 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2559 | ibmcam_veio(uvd, 0, 0x0036, 0x012d); | ||
2560 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
2561 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2562 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
2563 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2564 | ibmcam_veio(uvd, 0, 0x001e, 0x012f); | ||
2565 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2566 | ibmcam_veio(uvd, 0, 0x0017, 0x0127); | ||
2567 | ibmcam_veio(uvd, 0, 0x0013, 0x012e); | ||
2568 | ibmcam_veio(uvd, 0, 0x0031, 0x0130); | ||
2569 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2570 | ibmcam_veio(uvd, 0, 0x0017, 0x012d); | ||
2571 | ibmcam_veio(uvd, 0, 0x0078, 0x012f); | ||
2572 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2573 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2574 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2575 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2576 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
2577 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2578 | ibmcam_veio(uvd, 0, 0x0004, 0x0127); | ||
2579 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2580 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); | ||
2581 | break; | ||
2582 | case VIDEOSIZE_352x288: | ||
2583 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); | ||
2584 | ibmcam_veio(uvd, 0, 0x00c0, 0x0111); | ||
2585 | ibmcam_veio(uvd, 0, 0x00bc, 0x012c); | ||
2586 | ibmcam_veio(uvd, 0, 0x0080, 0x012b); | ||
2587 | ibmcam_veio(uvd, 0, 0x0000, 0x0108); | ||
2588 | ibmcam_veio(uvd, 0, 0x0001, 0x0133); | ||
2589 | ibmcam_veio(uvd, 0, 0x009b, 0x010f); | ||
2590 | ibmcam_veio(uvd, 0, 0x00bb, 0x010f); | ||
2591 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2592 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
2593 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2594 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2595 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2596 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2597 | ibmcam_veio(uvd, 0, 0x000a, 0x012f); | ||
2598 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2599 | ibmcam_veio(uvd, 0, 0x005c, 0x0127); | ||
2600 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2601 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2602 | ibmcam_veio(uvd, 0, 0x0004, 0x012f); | ||
2603 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2604 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2605 | ibmcam_veio(uvd, 0, 0x00fb, 0x012e); | ||
2606 | ibmcam_veio(uvd, 0, 0x0000, 0x0130); | ||
2607 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2608 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
2609 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
2610 | ibmcam_veio(uvd, 0, 0x000c, 0x0127); | ||
2611 | ibmcam_veio(uvd, 0, 0x0009, 0x012e); | ||
2612 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
2613 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2614 | ibmcam_veio(uvd, 0, 0x0012, 0x012f); | ||
2615 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2616 | ibmcam_veio(uvd, 0, 0x0008, 0x0127); | ||
2617 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2618 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2619 | ibmcam_veio(uvd, 0, 0x002a, 0x012d); | ||
2620 | ibmcam_veio(uvd, 0, 0x0000, 0x012f); | ||
2621 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2622 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
2623 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2624 | ibmcam_veio(uvd, 0, 0x0034, 0x012f); | ||
2625 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2626 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2627 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2628 | ibmcam_veio(uvd, 0, 0x0070, 0x0119); | ||
2629 | ibmcam_veio(uvd, 0, 0x00f2, 0x0107); | ||
2630 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
2631 | ibmcam_veio(uvd, 0, 0x008c, 0x0107); | ||
2632 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
2633 | ibmcam_veio(uvd, 0, 0x00c0, 0x0111); | ||
2634 | ibmcam_veio(uvd, 0, 0x0039, 0x010a); | ||
2635 | ibmcam_veio(uvd, 0, 0x0001, 0x0102); | ||
2636 | ibmcam_veio(uvd, 0, 0x002c, 0x0103); | ||
2637 | ibmcam_veio(uvd, 0, 0x0000, 0x0104); | ||
2638 | ibmcam_veio(uvd, 0, 0x0024, 0x0105); | ||
2639 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2640 | ibmcam_veio(uvd, 0, 0x0016, 0x012f); | ||
2641 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2642 | ibmcam_veio(uvd, 0, 0x0006, 0x0127); | ||
2643 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2644 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2645 | ibmcam_veio(uvd, 0, 0x0014, 0x012d); | ||
2646 | ibmcam_veio(uvd, 0, 0x0002, 0x012f); | ||
2647 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2648 | ibmcam_veio(uvd, 0, 0x00aa, 0x012e); | ||
2649 | ibmcam_veio(uvd, 0, 0x001a, 0x0130); | ||
2650 | ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); | ||
2651 | ibmcam_veio(uvd, 0, 0x005e, 0x012d); | ||
2652 | ibmcam_veio(uvd, 0, 0x9545, 0x0124); | ||
2653 | ibmcam_veio(uvd, 0, 0x00aa, 0x0127); | ||
2654 | ibmcam_veio(uvd, 0, 0x0018, 0x012e); | ||
2655 | ibmcam_veio(uvd, 0, 0x0049, 0x0130); | ||
2656 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2657 | ibmcam_veio(uvd, 0, 0x00aa, 0x012f); | ||
2658 | ibmcam_veio(uvd, 0, 0xd055, 0x0124); | ||
2659 | ibmcam_veio(uvd, 0, 0x001c, 0x0127); | ||
2660 | ibmcam_veio(uvd, 0, 0x00cf, 0x012e); | ||
2661 | ibmcam_veio(uvd, 0, 0xaa28, 0x0124); | ||
2662 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2663 | ibmcam_veio(uvd, 0, 0x0032, 0x012f); | ||
2664 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2665 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2666 | ibmcam_veio(uvd, 0, 0x00aa, 0x0130); | ||
2667 | ibmcam_veio(uvd, 0, 0x82a8, 0x0124); | ||
2668 | ibmcam_veio(uvd, 0, 0x0036, 0x012d); | ||
2669 | ibmcam_veio(uvd, 0, 0x0008, 0x012f); | ||
2670 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2671 | ibmcam_veio(uvd, 0, 0xfffa, 0x0124); | ||
2672 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2673 | ibmcam_veio(uvd, 0, 0x001e, 0x012f); | ||
2674 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2675 | ibmcam_veio(uvd, 0, 0x0010, 0x0127); | ||
2676 | ibmcam_veio(uvd, 0, 0x0013, 0x012e); | ||
2677 | ibmcam_veio(uvd, 0, 0x0025, 0x0130); | ||
2678 | ibmcam_veio(uvd, 0, 0x8a28, 0x0124); | ||
2679 | ibmcam_veio(uvd, 0, 0x0010, 0x012d); | ||
2680 | ibmcam_veio(uvd, 0, 0x0048, 0x012f); | ||
2681 | ibmcam_veio(uvd, 0, 0xd145, 0x0124); | ||
2682 | ibmcam_veio(uvd, 0, 0x0000, 0x0127); | ||
2683 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2684 | ibmcam_veio(uvd, 0, 0x00aa, 0x012d); | ||
2685 | ibmcam_veio(uvd, 0, 0x0038, 0x012f); | ||
2686 | ibmcam_veio(uvd, 0, 0xd141, 0x0124); | ||
2687 | ibmcam_veio(uvd, 0, 0x0004, 0x0127); | ||
2688 | ibmcam_veio(uvd, 0, 0xfea8, 0x0124); | ||
2689 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); | ||
2690 | break; | ||
2691 | } | ||
2692 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
2693 | } | ||
2694 | |||
2695 | static void ibmcam_model3_setup_after_video_if(struct uvd *uvd) | ||
2696 | { | ||
2697 | int i; | ||
2698 | /* | ||
2699 | * 01.01.08 - Added for RCA video in support -LO | ||
2700 | * This struct is used to init the Model3 cam to use the RCA video in port | ||
2701 | * instead of the CCD sensor. | ||
2702 | */ | ||
2703 | static const struct struct_initData initData[] = { | ||
2704 | {0, 0x0000, 0x010c}, | ||
2705 | {0, 0x0006, 0x012c}, | ||
2706 | {0, 0x0078, 0x012d}, | ||
2707 | {0, 0x0046, 0x012f}, | ||
2708 | {0, 0xd141, 0x0124}, | ||
2709 | {0, 0x0000, 0x0127}, | ||
2710 | {0, 0xfea8, 0x0124}, | ||
2711 | {1, 0x0000, 0x0116}, | ||
2712 | {0, 0x0064, 0x0116}, | ||
2713 | {1, 0x0000, 0x0115}, | ||
2714 | {0, 0x0003, 0x0115}, | ||
2715 | {0, 0x0008, 0x0123}, | ||
2716 | {0, 0x0000, 0x0117}, | ||
2717 | {0, 0x0000, 0x0112}, | ||
2718 | {0, 0x0080, 0x0100}, | ||
2719 | {0, 0x0000, 0x0100}, | ||
2720 | {1, 0x0000, 0x0116}, | ||
2721 | {0, 0x0060, 0x0116}, | ||
2722 | {0, 0x0002, 0x0112}, | ||
2723 | {0, 0x0000, 0x0123}, | ||
2724 | {0, 0x0001, 0x0117}, | ||
2725 | {0, 0x0040, 0x0108}, | ||
2726 | {0, 0x0019, 0x012c}, | ||
2727 | {0, 0x0040, 0x0116}, | ||
2728 | {0, 0x000a, 0x0115}, | ||
2729 | {0, 0x000b, 0x0115}, | ||
2730 | {0, 0x0078, 0x012d}, | ||
2731 | {0, 0x0046, 0x012f}, | ||
2732 | {0, 0xd141, 0x0124}, | ||
2733 | {0, 0x0000, 0x0127}, | ||
2734 | {0, 0xfea8, 0x0124}, | ||
2735 | {0, 0x0064, 0x0116}, | ||
2736 | {0, 0x0000, 0x0115}, | ||
2737 | {0, 0x0001, 0x0115}, | ||
2738 | {0, 0xffff, 0x0124}, | ||
2739 | {0, 0xfff9, 0x0124}, | ||
2740 | {0, 0x0086, 0x0127}, | ||
2741 | {0, 0xfff8, 0x0124}, | ||
2742 | {0, 0xfffd, 0x0124}, | ||
2743 | {0, 0x00aa, 0x0127}, | ||
2744 | {0, 0xfff8, 0x0124}, | ||
2745 | {0, 0xfffd, 0x0124}, | ||
2746 | {0, 0x0000, 0x0127}, | ||
2747 | {0, 0xfff8, 0x0124}, | ||
2748 | {0, 0xfffd, 0x0124}, | ||
2749 | {0, 0xfffa, 0x0124}, | ||
2750 | {0, 0xffff, 0x0124}, | ||
2751 | {0, 0xfff9, 0x0124}, | ||
2752 | {0, 0x0086, 0x0127}, | ||
2753 | {0, 0xfff8, 0x0124}, | ||
2754 | {0, 0xfffd, 0x0124}, | ||
2755 | {0, 0x00f2, 0x0127}, | ||
2756 | {0, 0xfff8, 0x0124}, | ||
2757 | {0, 0xfffd, 0x0124}, | ||
2758 | {0, 0x000f, 0x0127}, | ||
2759 | {0, 0xfff8, 0x0124}, | ||
2760 | {0, 0xfffd, 0x0124}, | ||
2761 | {0, 0xfffa, 0x0124}, | ||
2762 | {0, 0xffff, 0x0124}, | ||
2763 | {0, 0xfff9, 0x0124}, | ||
2764 | {0, 0x0086, 0x0127}, | ||
2765 | {0, 0xfff8, 0x0124}, | ||
2766 | {0, 0xfffd, 0x0124}, | ||
2767 | {0, 0x00f8, 0x0127}, | ||
2768 | {0, 0xfff8, 0x0124}, | ||
2769 | {0, 0xfffd, 0x0124}, | ||
2770 | {0, 0x00fc, 0x0127}, | ||
2771 | {0, 0xfff8, 0x0124}, | ||
2772 | {0, 0xfffd, 0x0124}, | ||
2773 | {0, 0xfffa, 0x0124}, | ||
2774 | {0, 0xffff, 0x0124}, | ||
2775 | {0, 0xfff9, 0x0124}, | ||
2776 | {0, 0x0086, 0x0127}, | ||
2777 | {0, 0xfff8, 0x0124}, | ||
2778 | {0, 0xfffd, 0x0124}, | ||
2779 | {0, 0x00f9, 0x0127}, | ||
2780 | {0, 0xfff8, 0x0124}, | ||
2781 | {0, 0xfffd, 0x0124}, | ||
2782 | {0, 0x003c, 0x0127}, | ||
2783 | {0, 0xfff8, 0x0124}, | ||
2784 | {0, 0xfffd, 0x0124}, | ||
2785 | {0, 0xfffa, 0x0124}, | ||
2786 | {0, 0xffff, 0x0124}, | ||
2787 | {0, 0xfff9, 0x0124}, | ||
2788 | {0, 0x0086, 0x0127}, | ||
2789 | {0, 0xfff8, 0x0124}, | ||
2790 | {0, 0xfffd, 0x0124}, | ||
2791 | {0, 0x0027, 0x0127}, | ||
2792 | {0, 0xfff8, 0x0124}, | ||
2793 | {0, 0xfffd, 0x0124}, | ||
2794 | {0, 0x0019, 0x0127}, | ||
2795 | {0, 0xfff8, 0x0124}, | ||
2796 | {0, 0xfffd, 0x0124}, | ||
2797 | {0, 0xfffa, 0x0124}, | ||
2798 | {0, 0xfff9, 0x0124}, | ||
2799 | {0, 0x0086, 0x0127}, | ||
2800 | {0, 0xfff8, 0x0124}, | ||
2801 | {0, 0xfffd, 0x0124}, | ||
2802 | {0, 0x0037, 0x0127}, | ||
2803 | {0, 0xfff8, 0x0124}, | ||
2804 | {0, 0xfffd, 0x0124}, | ||
2805 | {0, 0x0000, 0x0127}, | ||
2806 | {0, 0xfff8, 0x0124}, | ||
2807 | {0, 0xfffd, 0x0124}, | ||
2808 | {0, 0x0021, 0x0127}, | ||
2809 | {0, 0xfff8, 0x0124}, | ||
2810 | {0, 0xfffd, 0x0124}, | ||
2811 | {0, 0xfffa, 0x0124}, | ||
2812 | {0, 0xfff9, 0x0124}, | ||
2813 | {0, 0x0086, 0x0127}, | ||
2814 | {0, 0xfff8, 0x0124}, | ||
2815 | {0, 0xfffd, 0x0124}, | ||
2816 | {0, 0x0038, 0x0127}, | ||
2817 | {0, 0xfff8, 0x0124}, | ||
2818 | {0, 0xfffd, 0x0124}, | ||
2819 | {0, 0x0006, 0x0127}, | ||
2820 | {0, 0xfff8, 0x0124}, | ||
2821 | {0, 0xfffd, 0x0124}, | ||
2822 | {0, 0x0045, 0x0127}, | ||
2823 | {0, 0xfff8, 0x0124}, | ||
2824 | {0, 0xfffd, 0x0124}, | ||
2825 | {0, 0xfffa, 0x0124}, | ||
2826 | {0, 0xfff9, 0x0124}, | ||
2827 | {0, 0x0086, 0x0127}, | ||
2828 | {0, 0xfff8, 0x0124}, | ||
2829 | {0, 0xfffd, 0x0124}, | ||
2830 | {0, 0x0037, 0x0127}, | ||
2831 | {0, 0xfff8, 0x0124}, | ||
2832 | {0, 0xfffd, 0x0124}, | ||
2833 | {0, 0x0001, 0x0127}, | ||
2834 | {0, 0xfff8, 0x0124}, | ||
2835 | {0, 0xfffd, 0x0124}, | ||
2836 | {0, 0x002a, 0x0127}, | ||
2837 | {0, 0xfff8, 0x0124}, | ||
2838 | {0, 0xfffd, 0x0124}, | ||
2839 | {0, 0xfffa, 0x0124}, | ||
2840 | {0, 0xfff9, 0x0124}, | ||
2841 | {0, 0x0086, 0x0127}, | ||
2842 | {0, 0xfff8, 0x0124}, | ||
2843 | {0, 0xfffd, 0x0124}, | ||
2844 | {0, 0x0038, 0x0127}, | ||
2845 | {0, 0xfff8, 0x0124}, | ||
2846 | {0, 0xfffd, 0x0124}, | ||
2847 | {0, 0x0000, 0x0127}, | ||
2848 | {0, 0xfff8, 0x0124}, | ||
2849 | {0, 0xfffd, 0x0124}, | ||
2850 | {0, 0x000e, 0x0127}, | ||
2851 | {0, 0xfff8, 0x0124}, | ||
2852 | {0, 0xfffd, 0x0124}, | ||
2853 | {0, 0xfffa, 0x0124}, | ||
2854 | {0, 0xfff9, 0x0124}, | ||
2855 | {0, 0x0086, 0x0127}, | ||
2856 | {0, 0xfff8, 0x0124}, | ||
2857 | {0, 0xfffd, 0x0124}, | ||
2858 | {0, 0x0037, 0x0127}, | ||
2859 | {0, 0xfff8, 0x0124}, | ||
2860 | {0, 0xfffd, 0x0124}, | ||
2861 | {0, 0x0001, 0x0127}, | ||
2862 | {0, 0xfff8, 0x0124}, | ||
2863 | {0, 0xfffd, 0x0124}, | ||
2864 | {0, 0x002b, 0x0127}, | ||
2865 | {0, 0xfff8, 0x0124}, | ||
2866 | {0, 0xfffd, 0x0124}, | ||
2867 | {0, 0xfffa, 0x0124}, | ||
2868 | {0, 0xfff9, 0x0124}, | ||
2869 | {0, 0x0086, 0x0127}, | ||
2870 | {0, 0xfff8, 0x0124}, | ||
2871 | {0, 0xfffd, 0x0124}, | ||
2872 | {0, 0x0038, 0x0127}, | ||
2873 | {0, 0xfff8, 0x0124}, | ||
2874 | {0, 0xfffd, 0x0124}, | ||
2875 | {0, 0x0001, 0x0127}, | ||
2876 | {0, 0xfff8, 0x0124}, | ||
2877 | {0, 0xfffd, 0x0124}, | ||
2878 | {0, 0x00f4, 0x0127}, | ||
2879 | {0, 0xfff8, 0x0124}, | ||
2880 | {0, 0xfffd, 0x0124}, | ||
2881 | {0, 0xfffa, 0x0124}, | ||
2882 | {0, 0xfff9, 0x0124}, | ||
2883 | {0, 0x0086, 0x0127}, | ||
2884 | {0, 0xfff8, 0x0124}, | ||
2885 | {0, 0xfffd, 0x0124}, | ||
2886 | {0, 0x0037, 0x0127}, | ||
2887 | {0, 0xfff8, 0x0124}, | ||
2888 | {0, 0xfffd, 0x0124}, | ||
2889 | {0, 0x0001, 0x0127}, | ||
2890 | {0, 0xfff8, 0x0124}, | ||
2891 | {0, 0xfffd, 0x0124}, | ||
2892 | {0, 0x002c, 0x0127}, | ||
2893 | {0, 0xfff8, 0x0124}, | ||
2894 | {0, 0xfffd, 0x0124}, | ||
2895 | {0, 0xfffa, 0x0124}, | ||
2896 | {0, 0xfff9, 0x0124}, | ||
2897 | {0, 0x0086, 0x0127}, | ||
2898 | {0, 0xfff8, 0x0124}, | ||
2899 | {0, 0xfffd, 0x0124}, | ||
2900 | {0, 0x0038, 0x0127}, | ||
2901 | {0, 0xfff8, 0x0124}, | ||
2902 | {0, 0xfffd, 0x0124}, | ||
2903 | {0, 0x0001, 0x0127}, | ||
2904 | {0, 0xfff8, 0x0124}, | ||
2905 | {0, 0xfffd, 0x0124}, | ||
2906 | {0, 0x0004, 0x0127}, | ||
2907 | {0, 0xfff8, 0x0124}, | ||
2908 | {0, 0xfffd, 0x0124}, | ||
2909 | {0, 0xfffa, 0x0124}, | ||
2910 | {0, 0xfff9, 0x0124}, | ||
2911 | {0, 0x0086, 0x0127}, | ||
2912 | {0, 0xfff8, 0x0124}, | ||
2913 | {0, 0xfffd, 0x0124}, | ||
2914 | {0, 0x0037, 0x0127}, | ||
2915 | {0, 0xfff8, 0x0124}, | ||
2916 | {0, 0xfffd, 0x0124}, | ||
2917 | {0, 0x0001, 0x0127}, | ||
2918 | {0, 0xfff8, 0x0124}, | ||
2919 | {0, 0xfffd, 0x0124}, | ||
2920 | {0, 0x002d, 0x0127}, | ||
2921 | {0, 0xfff8, 0x0124}, | ||
2922 | {0, 0xfffd, 0x0124}, | ||
2923 | {0, 0xfffa, 0x0124}, | ||
2924 | {0, 0xfff9, 0x0124}, | ||
2925 | {0, 0x0086, 0x0127}, | ||
2926 | {0, 0xfff8, 0x0124}, | ||
2927 | {0, 0xfffd, 0x0124}, | ||
2928 | {0, 0x0038, 0x0127}, | ||
2929 | {0, 0xfff8, 0x0124}, | ||
2930 | {0, 0xfffd, 0x0124}, | ||
2931 | {0, 0x0000, 0x0127}, | ||
2932 | {0, 0xfff8, 0x0124}, | ||
2933 | {0, 0xfffd, 0x0124}, | ||
2934 | {0, 0x0014, 0x0127}, | ||
2935 | {0, 0xfff8, 0x0124}, | ||
2936 | {0, 0xfffd, 0x0124}, | ||
2937 | {0, 0xfffa, 0x0124}, | ||
2938 | {0, 0xfff9, 0x0124}, | ||
2939 | {0, 0x0086, 0x0127}, | ||
2940 | {0, 0xfff8, 0x0124}, | ||
2941 | {0, 0xfffd, 0x0124}, | ||
2942 | {0, 0x0037, 0x0127}, | ||
2943 | {0, 0xfff8, 0x0124}, | ||
2944 | {0, 0xfffd, 0x0124}, | ||
2945 | {0, 0x0001, 0x0127}, | ||
2946 | {0, 0xfff8, 0x0124}, | ||
2947 | {0, 0xfffd, 0x0124}, | ||
2948 | {0, 0x002e, 0x0127}, | ||
2949 | {0, 0xfff8, 0x0124}, | ||
2950 | {0, 0xfffd, 0x0124}, | ||
2951 | {0, 0xfffa, 0x0124}, | ||
2952 | {0, 0xfff9, 0x0124}, | ||
2953 | {0, 0x0086, 0x0127}, | ||
2954 | {0, 0xfff8, 0x0124}, | ||
2955 | {0, 0xfffd, 0x0124}, | ||
2956 | {0, 0x0038, 0x0127}, | ||
2957 | {0, 0xfff8, 0x0124}, | ||
2958 | {0, 0xfffd, 0x0124}, | ||
2959 | {0, 0x0003, 0x0127}, | ||
2960 | {0, 0xfff8, 0x0124}, | ||
2961 | {0, 0xfffd, 0x0124}, | ||
2962 | {0, 0x0000, 0x0127}, | ||
2963 | {0, 0xfff8, 0x0124}, | ||
2964 | {0, 0xfffd, 0x0124}, | ||
2965 | {0, 0xfffa, 0x0124}, | ||
2966 | {0, 0xfff9, 0x0124}, | ||
2967 | {0, 0x0086, 0x0127}, | ||
2968 | {0, 0xfff8, 0x0124}, | ||
2969 | {0, 0xfffd, 0x0124}, | ||
2970 | {0, 0x0037, 0x0127}, | ||
2971 | {0, 0xfff8, 0x0124}, | ||
2972 | {0, 0xfffd, 0x0124}, | ||
2973 | {0, 0x0001, 0x0127}, | ||
2974 | {0, 0xfff8, 0x0124}, | ||
2975 | {0, 0xfffd, 0x0124}, | ||
2976 | {0, 0x002f, 0x0127}, | ||
2977 | {0, 0xfff8, 0x0124}, | ||
2978 | {0, 0xfffd, 0x0124}, | ||
2979 | {0, 0xfffa, 0x0124}, | ||
2980 | {0, 0xfff9, 0x0124}, | ||
2981 | {0, 0x0086, 0x0127}, | ||
2982 | {0, 0xfff8, 0x0124}, | ||
2983 | {0, 0xfffd, 0x0124}, | ||
2984 | {0, 0x0038, 0x0127}, | ||
2985 | {0, 0xfff8, 0x0124}, | ||
2986 | {0, 0xfffd, 0x0124}, | ||
2987 | {0, 0x0003, 0x0127}, | ||
2988 | {0, 0xfff8, 0x0124}, | ||
2989 | {0, 0xfffd, 0x0124}, | ||
2990 | {0, 0x0014, 0x0127}, | ||
2991 | {0, 0xfff8, 0x0124}, | ||
2992 | {0, 0xfffd, 0x0124}, | ||
2993 | {0, 0xfffa, 0x0124}, | ||
2994 | {0, 0xfff9, 0x0124}, | ||
2995 | {0, 0x0086, 0x0127}, | ||
2996 | {0, 0xfff8, 0x0124}, | ||
2997 | {0, 0xfffd, 0x0124}, | ||
2998 | {0, 0x0037, 0x0127}, | ||
2999 | {0, 0xfff8, 0x0124}, | ||
3000 | {0, 0xfffd, 0x0124}, | ||
3001 | {0, 0x0001, 0x0127}, | ||
3002 | {0, 0xfff8, 0x0124}, | ||
3003 | {0, 0xfffd, 0x0124}, | ||
3004 | {0, 0x0040, 0x0127}, | ||
3005 | {0, 0xfff8, 0x0124}, | ||
3006 | {0, 0xfffd, 0x0124}, | ||
3007 | {0, 0xfffa, 0x0124}, | ||
3008 | {0, 0xfff9, 0x0124}, | ||
3009 | {0, 0x0086, 0x0127}, | ||
3010 | {0, 0xfff8, 0x0124}, | ||
3011 | {0, 0xfffd, 0x0124}, | ||
3012 | {0, 0x0038, 0x0127}, | ||
3013 | {0, 0xfff8, 0x0124}, | ||
3014 | {0, 0xfffd, 0x0124}, | ||
3015 | {0, 0x0000, 0x0127}, | ||
3016 | {0, 0xfff8, 0x0124}, | ||
3017 | {0, 0xfffd, 0x0124}, | ||
3018 | {0, 0x0040, 0x0127}, | ||
3019 | {0, 0xfff8, 0x0124}, | ||
3020 | {0, 0xfffd, 0x0124}, | ||
3021 | {0, 0xfffa, 0x0124}, | ||
3022 | {0, 0xfff9, 0x0124}, | ||
3023 | {0, 0x0086, 0x0127}, | ||
3024 | {0, 0xfff8, 0x0124}, | ||
3025 | {0, 0xfffd, 0x0124}, | ||
3026 | {0, 0x0037, 0x0127}, | ||
3027 | {0, 0xfff8, 0x0124}, | ||
3028 | {0, 0xfffd, 0x0124}, | ||
3029 | {0, 0x0001, 0x0127}, | ||
3030 | {0, 0xfff8, 0x0124}, | ||
3031 | {0, 0xfffd, 0x0124}, | ||
3032 | {0, 0x0053, 0x0127}, | ||
3033 | {0, 0xfff8, 0x0124}, | ||
3034 | {0, 0xfffd, 0x0124}, | ||
3035 | {0, 0xfffa, 0x0124}, | ||
3036 | {0, 0xfff9, 0x0124}, | ||
3037 | {0, 0x0086, 0x0127}, | ||
3038 | {0, 0xfff8, 0x0124}, | ||
3039 | {0, 0xfffd, 0x0124}, | ||
3040 | {0, 0x0038, 0x0127}, | ||
3041 | {0, 0xfff8, 0x0124}, | ||
3042 | {0, 0xfffd, 0x0124}, | ||
3043 | {0, 0x0000, 0x0127}, | ||
3044 | {0, 0xfff8, 0x0124}, | ||
3045 | {0, 0xfffd, 0x0124}, | ||
3046 | {0, 0x0038, 0x0127}, | ||
3047 | {0, 0xfff8, 0x0124}, | ||
3048 | {0, 0xfffd, 0x0124}, | ||
3049 | {0, 0xfffa, 0x0124}, | ||
3050 | {0, 0x0000, 0x0101}, | ||
3051 | {0, 0x00a0, 0x0103}, | ||
3052 | {0, 0x0078, 0x0105}, | ||
3053 | {0, 0x0000, 0x010a}, | ||
3054 | {0, 0x0024, 0x010b}, | ||
3055 | {0, 0x0028, 0x0119}, | ||
3056 | {0, 0x0088, 0x011b}, | ||
3057 | {0, 0x0002, 0x011d}, | ||
3058 | {0, 0x0003, 0x011e}, | ||
3059 | {0, 0x0000, 0x0129}, | ||
3060 | {0, 0x00fc, 0x012b}, | ||
3061 | {0, 0x0008, 0x0102}, | ||
3062 | {0, 0x0000, 0x0104}, | ||
3063 | {0, 0x0008, 0x011a}, | ||
3064 | {0, 0x0028, 0x011c}, | ||
3065 | {0, 0x0021, 0x012a}, | ||
3066 | {0, 0x0000, 0x0118}, | ||
3067 | {0, 0x0000, 0x0132}, | ||
3068 | {0, 0x0000, 0x0109}, | ||
3069 | {0, 0xfff9, 0x0124}, | ||
3070 | {0, 0x0086, 0x0127}, | ||
3071 | {0, 0xfff8, 0x0124}, | ||
3072 | {0, 0xfffd, 0x0124}, | ||
3073 | {0, 0x0037, 0x0127}, | ||
3074 | {0, 0xfff8, 0x0124}, | ||
3075 | {0, 0xfffd, 0x0124}, | ||
3076 | {0, 0x0001, 0x0127}, | ||
3077 | {0, 0xfff8, 0x0124}, | ||
3078 | {0, 0xfffd, 0x0124}, | ||
3079 | {0, 0x0031, 0x0127}, | ||
3080 | {0, 0xfff8, 0x0124}, | ||
3081 | {0, 0xfffd, 0x0124}, | ||
3082 | {0, 0xfffa, 0x0124}, | ||
3083 | {0, 0xfff9, 0x0124}, | ||
3084 | {0, 0x0086, 0x0127}, | ||
3085 | {0, 0xfff8, 0x0124}, | ||
3086 | {0, 0xfffd, 0x0124}, | ||
3087 | {0, 0x0038, 0x0127}, | ||
3088 | {0, 0xfff8, 0x0124}, | ||
3089 | {0, 0xfffd, 0x0124}, | ||
3090 | {0, 0x0000, 0x0127}, | ||
3091 | {0, 0xfff8, 0x0124}, | ||
3092 | {0, 0xfffd, 0x0124}, | ||
3093 | {0, 0x0000, 0x0127}, | ||
3094 | {0, 0xfff8, 0x0124}, | ||
3095 | {0, 0xfffd, 0x0124}, | ||
3096 | {0, 0xfffa, 0x0124}, | ||
3097 | {0, 0xfff9, 0x0124}, | ||
3098 | {0, 0x0086, 0x0127}, | ||
3099 | {0, 0xfff8, 0x0124}, | ||
3100 | {0, 0xfffd, 0x0124}, | ||
3101 | {0, 0x0037, 0x0127}, | ||
3102 | {0, 0xfff8, 0x0124}, | ||
3103 | {0, 0xfffd, 0x0124}, | ||
3104 | {0, 0x0001, 0x0127}, | ||
3105 | {0, 0xfff8, 0x0124}, | ||
3106 | {0, 0xfffd, 0x0124}, | ||
3107 | {0, 0x0040, 0x0127}, | ||
3108 | {0, 0xfff8, 0x0124}, | ||
3109 | {0, 0xfffd, 0x0124}, | ||
3110 | {0, 0xfffa, 0x0124}, | ||
3111 | {0, 0xfff9, 0x0124}, | ||
3112 | {0, 0x0086, 0x0127}, | ||
3113 | {0, 0xfff8, 0x0124}, | ||
3114 | {0, 0xfffd, 0x0124}, | ||
3115 | {0, 0x0038, 0x0127}, | ||
3116 | {0, 0xfff8, 0x0124}, | ||
3117 | {0, 0xfffd, 0x0124}, | ||
3118 | {0, 0x0000, 0x0127}, | ||
3119 | {0, 0xfff8, 0x0124}, | ||
3120 | {0, 0xfffd, 0x0124}, | ||
3121 | {0, 0x0040, 0x0127}, | ||
3122 | {0, 0xfff8, 0x0124}, | ||
3123 | {0, 0xfffd, 0x0124}, | ||
3124 | {0, 0xfffa, 0x0124}, | ||
3125 | {0, 0xfff9, 0x0124}, | ||
3126 | {0, 0x0086, 0x0127}, | ||
3127 | {0, 0xfff8, 0x0124}, | ||
3128 | {0, 0xfffd, 0x0124}, | ||
3129 | {0, 0x0037, 0x0127}, | ||
3130 | {0, 0xfff8, 0x0124}, | ||
3131 | {0, 0xfffd, 0x0124}, | ||
3132 | {0, 0x0000, 0x0127}, | ||
3133 | {0, 0xfff8, 0x0124}, | ||
3134 | {0, 0xfffd, 0x0124}, | ||
3135 | {0, 0x00dc, 0x0127}, | ||
3136 | {0, 0xfff8, 0x0124}, | ||
3137 | {0, 0xfffd, 0x0124}, | ||
3138 | {0, 0xfffa, 0x0124}, | ||
3139 | {0, 0xfff9, 0x0124}, | ||
3140 | {0, 0x0086, 0x0127}, | ||
3141 | {0, 0xfff8, 0x0124}, | ||
3142 | {0, 0xfffd, 0x0124}, | ||
3143 | {0, 0x0038, 0x0127}, | ||
3144 | {0, 0xfff8, 0x0124}, | ||
3145 | {0, 0xfffd, 0x0124}, | ||
3146 | {0, 0x0000, 0x0127}, | ||
3147 | {0, 0xfff8, 0x0124}, | ||
3148 | {0, 0xfffd, 0x0124}, | ||
3149 | {0, 0x0000, 0x0127}, | ||
3150 | {0, 0xfff8, 0x0124}, | ||
3151 | {0, 0xfffd, 0x0124}, | ||
3152 | {0, 0xfffa, 0x0124}, | ||
3153 | {0, 0xfff9, 0x0124}, | ||
3154 | {0, 0x0086, 0x0127}, | ||
3155 | {0, 0xfff8, 0x0124}, | ||
3156 | {0, 0xfffd, 0x0124}, | ||
3157 | {0, 0x0037, 0x0127}, | ||
3158 | {0, 0xfff8, 0x0124}, | ||
3159 | {0, 0xfffd, 0x0124}, | ||
3160 | {0, 0x0001, 0x0127}, | ||
3161 | {0, 0xfff8, 0x0124}, | ||
3162 | {0, 0xfffd, 0x0124}, | ||
3163 | {0, 0x0032, 0x0127}, | ||
3164 | {0, 0xfff8, 0x0124}, | ||
3165 | {0, 0xfffd, 0x0124}, | ||
3166 | {0, 0xfffa, 0x0124}, | ||
3167 | {0, 0xfff9, 0x0124}, | ||
3168 | {0, 0x0086, 0x0127}, | ||
3169 | {0, 0xfff8, 0x0124}, | ||
3170 | {0, 0xfffd, 0x0124}, | ||
3171 | {0, 0x0038, 0x0127}, | ||
3172 | {0, 0xfff8, 0x0124}, | ||
3173 | {0, 0xfffd, 0x0124}, | ||
3174 | {0, 0x0001, 0x0127}, | ||
3175 | {0, 0xfff8, 0x0124}, | ||
3176 | {0, 0xfffd, 0x0124}, | ||
3177 | {0, 0x0020, 0x0127}, | ||
3178 | {0, 0xfff8, 0x0124}, | ||
3179 | {0, 0xfffd, 0x0124}, | ||
3180 | {0, 0xfffa, 0x0124}, | ||
3181 | {0, 0xfff9, 0x0124}, | ||
3182 | {0, 0x0086, 0x0127}, | ||
3183 | {0, 0xfff8, 0x0124}, | ||
3184 | {0, 0xfffd, 0x0124}, | ||
3185 | {0, 0x0037, 0x0127}, | ||
3186 | {0, 0xfff8, 0x0124}, | ||
3187 | {0, 0xfffd, 0x0124}, | ||
3188 | {0, 0x0001, 0x0127}, | ||
3189 | {0, 0xfff8, 0x0124}, | ||
3190 | {0, 0xfffd, 0x0124}, | ||
3191 | {0, 0x0040, 0x0127}, | ||
3192 | {0, 0xfff8, 0x0124}, | ||
3193 | {0, 0xfffd, 0x0124}, | ||
3194 | {0, 0xfffa, 0x0124}, | ||
3195 | {0, 0xfff9, 0x0124}, | ||
3196 | {0, 0x0086, 0x0127}, | ||
3197 | {0, 0xfff8, 0x0124}, | ||
3198 | {0, 0xfffd, 0x0124}, | ||
3199 | {0, 0x0038, 0x0127}, | ||
3200 | {0, 0xfff8, 0x0124}, | ||
3201 | {0, 0xfffd, 0x0124}, | ||
3202 | {0, 0x0000, 0x0127}, | ||
3203 | {0, 0xfff8, 0x0124}, | ||
3204 | {0, 0xfffd, 0x0124}, | ||
3205 | {0, 0x0040, 0x0127}, | ||
3206 | {0, 0xfff8, 0x0124}, | ||
3207 | {0, 0xfffd, 0x0124}, | ||
3208 | {0, 0xfffa, 0x0124}, | ||
3209 | {0, 0xfff9, 0x0124}, | ||
3210 | {0, 0x0086, 0x0127}, | ||
3211 | {0, 0xfff8, 0x0124}, | ||
3212 | {0, 0xfffd, 0x0124}, | ||
3213 | {0, 0x0037, 0x0127}, | ||
3214 | {0, 0xfff8, 0x0124}, | ||
3215 | {0, 0xfffd, 0x0124}, | ||
3216 | {0, 0x0000, 0x0127}, | ||
3217 | {0, 0xfff8, 0x0124}, | ||
3218 | {0, 0xfffd, 0x0124}, | ||
3219 | {0, 0x0030, 0x0127}, | ||
3220 | {0, 0xfff8, 0x0124}, | ||
3221 | {0, 0xfffd, 0x0124}, | ||
3222 | {0, 0xfffa, 0x0124}, | ||
3223 | {0, 0xfff9, 0x0124}, | ||
3224 | {0, 0x0086, 0x0127}, | ||
3225 | {0, 0xfff8, 0x0124}, | ||
3226 | {0, 0xfffd, 0x0124}, | ||
3227 | {0, 0x0038, 0x0127}, | ||
3228 | {0, 0xfff8, 0x0124}, | ||
3229 | {0, 0xfffd, 0x0124}, | ||
3230 | {0, 0x0008, 0x0127}, | ||
3231 | {0, 0xfff8, 0x0124}, | ||
3232 | {0, 0xfffd, 0x0124}, | ||
3233 | {0, 0x0000, 0x0127}, | ||
3234 | {0, 0xfff8, 0x0124}, | ||
3235 | {0, 0xfffd, 0x0124}, | ||
3236 | {0, 0xfffa, 0x0124}, | ||
3237 | {0, 0x0003, 0x0106}, | ||
3238 | {0, 0x0062, 0x0107}, | ||
3239 | {0, 0x0003, 0x0111}, | ||
3240 | }; | ||
3241 | #define NUM_INIT_DATA | ||
3242 | |||
3243 | unsigned short compression = 0; /* 0=none, 7=best frame rate */ | ||
3244 | int f_rate; /* 0=Fastest 7=slowest */ | ||
3245 | |||
3246 | if (IBMCAM_T(uvd)->initialized) | ||
3247 | return; | ||
3248 | |||
3249 | /* Internal frame rate is controlled by f_rate value */ | ||
3250 | f_rate = 7 - framerate; | ||
3251 | RESTRICT_TO_RANGE(f_rate, 0, 7); | ||
3252 | |||
3253 | ibmcam_veio(uvd, 0, 0x0000, 0x0100); | ||
3254 | ibmcam_veio(uvd, 1, 0x0000, 0x0116); | ||
3255 | ibmcam_veio(uvd, 0, 0x0060, 0x0116); | ||
3256 | ibmcam_veio(uvd, 0, 0x0002, 0x0112); | ||
3257 | ibmcam_veio(uvd, 0, 0x0000, 0x0123); | ||
3258 | ibmcam_veio(uvd, 0, 0x0001, 0x0117); | ||
3259 | ibmcam_veio(uvd, 0, 0x0040, 0x0108); | ||
3260 | ibmcam_veio(uvd, 0, 0x0019, 0x012c); | ||
3261 | ibmcam_veio(uvd, 0, 0x0060, 0x0116); | ||
3262 | ibmcam_veio(uvd, 0, 0x0002, 0x0115); | ||
3263 | ibmcam_veio(uvd, 0, 0x0003, 0x0115); | ||
3264 | ibmcam_veio(uvd, 1, 0x0000, 0x0115); | ||
3265 | ibmcam_veio(uvd, 0, 0x000b, 0x0115); | ||
3266 | ibmcam_model3_Packet1(uvd, 0x000a, 0x0040); | ||
3267 | ibmcam_model3_Packet1(uvd, 0x000b, 0x00f6); | ||
3268 | ibmcam_model3_Packet1(uvd, 0x000c, 0x0002); | ||
3269 | ibmcam_model3_Packet1(uvd, 0x000d, 0x0020); | ||
3270 | ibmcam_model3_Packet1(uvd, 0x000e, 0x0033); | ||
3271 | ibmcam_model3_Packet1(uvd, 0x000f, 0x0007); | ||
3272 | ibmcam_model3_Packet1(uvd, 0x0010, 0x0000); | ||
3273 | ibmcam_model3_Packet1(uvd, 0x0011, 0x0070); | ||
3274 | ibmcam_model3_Packet1(uvd, 0x0012, 0x0030); | ||
3275 | ibmcam_model3_Packet1(uvd, 0x0013, 0x0000); | ||
3276 | ibmcam_model3_Packet1(uvd, 0x0014, 0x0001); | ||
3277 | ibmcam_model3_Packet1(uvd, 0x0015, 0x0001); | ||
3278 | ibmcam_model3_Packet1(uvd, 0x0016, 0x0001); | ||
3279 | ibmcam_model3_Packet1(uvd, 0x0017, 0x0001); | ||
3280 | ibmcam_model3_Packet1(uvd, 0x0018, 0x0000); | ||
3281 | ibmcam_model3_Packet1(uvd, 0x001e, 0x00c3); | ||
3282 | ibmcam_model3_Packet1(uvd, 0x0020, 0x0000); | ||
3283 | ibmcam_model3_Packet1(uvd, 0x0028, 0x0010); | ||
3284 | ibmcam_model3_Packet1(uvd, 0x0029, 0x0054); | ||
3285 | ibmcam_model3_Packet1(uvd, 0x002a, 0x0013); | ||
3286 | ibmcam_model3_Packet1(uvd, 0x002b, 0x0007); | ||
3287 | ibmcam_model3_Packet1(uvd, 0x002d, 0x0028); | ||
3288 | ibmcam_model3_Packet1(uvd, 0x002e, 0x0000); | ||
3289 | ibmcam_model3_Packet1(uvd, 0x0031, 0x0000); | ||
3290 | ibmcam_model3_Packet1(uvd, 0x0032, 0x0000); | ||
3291 | ibmcam_model3_Packet1(uvd, 0x0033, 0x0000); | ||
3292 | ibmcam_model3_Packet1(uvd, 0x0034, 0x0000); | ||
3293 | ibmcam_model3_Packet1(uvd, 0x0035, 0x0038); | ||
3294 | ibmcam_model3_Packet1(uvd, 0x003a, 0x0001); | ||
3295 | ibmcam_model3_Packet1(uvd, 0x003c, 0x001e); | ||
3296 | ibmcam_model3_Packet1(uvd, 0x003f, 0x000a); | ||
3297 | ibmcam_model3_Packet1(uvd, 0x0041, 0x0000); | ||
3298 | ibmcam_model3_Packet1(uvd, 0x0046, 0x003f); | ||
3299 | ibmcam_model3_Packet1(uvd, 0x0047, 0x0000); | ||
3300 | ibmcam_model3_Packet1(uvd, 0x0050, 0x0005); | ||
3301 | ibmcam_model3_Packet1(uvd, 0x0052, 0x001a); | ||
3302 | ibmcam_model3_Packet1(uvd, 0x0053, 0x0003); | ||
3303 | ibmcam_model3_Packet1(uvd, 0x005a, 0x006b); | ||
3304 | ibmcam_model3_Packet1(uvd, 0x005d, 0x001e); | ||
3305 | ibmcam_model3_Packet1(uvd, 0x005e, 0x0030); | ||
3306 | ibmcam_model3_Packet1(uvd, 0x005f, 0x0041); | ||
3307 | ibmcam_model3_Packet1(uvd, 0x0064, 0x0008); | ||
3308 | ibmcam_model3_Packet1(uvd, 0x0065, 0x0015); | ||
3309 | ibmcam_model3_Packet1(uvd, 0x0068, 0x000f); | ||
3310 | ibmcam_model3_Packet1(uvd, 0x0079, 0x0000); | ||
3311 | ibmcam_model3_Packet1(uvd, 0x007a, 0x0000); | ||
3312 | ibmcam_model3_Packet1(uvd, 0x007c, 0x003f); | ||
3313 | ibmcam_model3_Packet1(uvd, 0x0082, 0x000f); | ||
3314 | ibmcam_model3_Packet1(uvd, 0x0085, 0x0000); | ||
3315 | ibmcam_model3_Packet1(uvd, 0x0099, 0x0000); | ||
3316 | ibmcam_model3_Packet1(uvd, 0x009b, 0x0023); | ||
3317 | ibmcam_model3_Packet1(uvd, 0x009c, 0x0022); | ||
3318 | ibmcam_model3_Packet1(uvd, 0x009d, 0x0096); | ||
3319 | ibmcam_model3_Packet1(uvd, 0x009e, 0x0096); | ||
3320 | ibmcam_model3_Packet1(uvd, 0x009f, 0x000a); | ||
3321 | |||
3322 | switch (uvd->videosize) { | ||
3323 | case VIDEOSIZE_160x120: | ||
3324 | ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */ | ||
3325 | ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */ | ||
3326 | ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */ | ||
3327 | ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */ | ||
3328 | ibmcam_veio(uvd, 0, 0x0024, 0x010b); /* Differs everywhere */ | ||
3329 | ibmcam_veio(uvd, 0, 0x00a9, 0x0119); | ||
3330 | ibmcam_veio(uvd, 0, 0x0016, 0x011b); | ||
3331 | ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same on 176x144, 320x240 */ | ||
3332 | ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */ | ||
3333 | ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */ | ||
3334 | ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */ | ||
3335 | ibmcam_veio(uvd, 0, 0x0018, 0x0102); | ||
3336 | ibmcam_veio(uvd, 0, 0x0004, 0x0104); | ||
3337 | ibmcam_veio(uvd, 0, 0x0004, 0x011a); | ||
3338 | ibmcam_veio(uvd, 0, 0x0028, 0x011c); | ||
3339 | ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */ | ||
3340 | ibmcam_veio(uvd, 0, 0x0000, 0x0118); | ||
3341 | ibmcam_veio(uvd, 0, 0x0000, 0x0132); | ||
3342 | ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */ | ||
3343 | ibmcam_veio(uvd, 0, compression, 0x0109); | ||
3344 | break; | ||
3345 | case VIDEOSIZE_320x240: | ||
3346 | ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */ | ||
3347 | ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */ | ||
3348 | ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */ | ||
3349 | ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */ | ||
3350 | ibmcam_veio(uvd, 0, 0x0028, 0x010b); /* Differs everywhere */ | ||
3351 | ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same */ | ||
3352 | ibmcam_veio(uvd, 0, 0x0000, 0x011e); | ||
3353 | ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */ | ||
3354 | ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */ | ||
3355 | /* 4 commands from 160x120 skipped */ | ||
3356 | ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */ | ||
3357 | ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */ | ||
3358 | ibmcam_veio(uvd, 0, compression, 0x0109); | ||
3359 | ibmcam_veio(uvd, 0, 0x00d9, 0x0119); | ||
3360 | ibmcam_veio(uvd, 0, 0x0006, 0x011b); | ||
3361 | ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */ | ||
3362 | ibmcam_veio(uvd, 0, 0x0010, 0x0104); | ||
3363 | ibmcam_veio(uvd, 0, 0x0004, 0x011a); | ||
3364 | ibmcam_veio(uvd, 0, 0x003f, 0x011c); | ||
3365 | ibmcam_veio(uvd, 0, 0x001c, 0x0118); | ||
3366 | ibmcam_veio(uvd, 0, 0x0000, 0x0132); | ||
3367 | break; | ||
3368 | case VIDEOSIZE_640x480: | ||
3369 | ibmcam_veio(uvd, 0, 0x00f0, 0x0105); | ||
3370 | ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */ | ||
3371 | ibmcam_veio(uvd, 0, 0x0038, 0x010b); /* Differs everywhere */ | ||
3372 | ibmcam_veio(uvd, 0, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */ | ||
3373 | ibmcam_veio(uvd, 0, 0x0006, 0x011b); /* Same on 320x240, 640x480 */ | ||
3374 | ibmcam_veio(uvd, 0, 0x0004, 0x011d); /* NC */ | ||
3375 | ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */ | ||
3376 | ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */ | ||
3377 | ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */ | ||
3378 | ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */ | ||
3379 | ibmcam_veio(uvd, 0, 0x0016, 0x0104); /* NC */ | ||
3380 | ibmcam_veio(uvd, 0, 0x0004, 0x011a); /* Same on 320x240, 640x480 */ | ||
3381 | ibmcam_veio(uvd, 0, 0x003f, 0x011c); /* Same on 320x240, 640x480 */ | ||
3382 | ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */ | ||
3383 | ibmcam_veio(uvd, 0, 0x001c, 0x0118); /* Same on 320x240, 640x480 */ | ||
3384 | ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */ | ||
3385 | ibmcam_veio(uvd, 0, compression, 0x0109); | ||
3386 | ibmcam_veio(uvd, 0, 0x0040, 0x0101); | ||
3387 | ibmcam_veio(uvd, 0, 0x0040, 0x0103); | ||
3388 | ibmcam_veio(uvd, 0, 0x0000, 0x0132); /* Same on 320x240, 640x480 */ | ||
3389 | break; | ||
3390 | } | ||
3391 | ibmcam_model3_Packet1(uvd, 0x007e, 0x000e); /* Hue */ | ||
3392 | ibmcam_model3_Packet1(uvd, 0x0036, 0x0011); /* Brightness */ | ||
3393 | ibmcam_model3_Packet1(uvd, 0x0060, 0x0002); /* Sharpness */ | ||
3394 | ibmcam_model3_Packet1(uvd, 0x0061, 0x0004); /* Sharpness */ | ||
3395 | ibmcam_model3_Packet1(uvd, 0x0062, 0x0005); /* Sharpness */ | ||
3396 | ibmcam_model3_Packet1(uvd, 0x0063, 0x0014); /* Sharpness */ | ||
3397 | ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0); /* Red gain */ | ||
3398 | ibmcam_model3_Packet1(uvd, 0x0097, 0x0096); /* Blue gain */ | ||
3399 | ibmcam_model3_Packet1(uvd, 0x0067, 0x0001); /* Contrast */ | ||
3400 | ibmcam_model3_Packet1(uvd, 0x005b, 0x000c); /* Contrast */ | ||
3401 | ibmcam_model3_Packet1(uvd, 0x005c, 0x0016); /* Contrast */ | ||
3402 | ibmcam_model3_Packet1(uvd, 0x0098, 0x000b); | ||
3403 | ibmcam_model3_Packet1(uvd, 0x002c, 0x0003); /* Was 1, broke 640x480 */ | ||
3404 | ibmcam_model3_Packet1(uvd, 0x002f, 0x002a); | ||
3405 | ibmcam_model3_Packet1(uvd, 0x0030, 0x0029); | ||
3406 | ibmcam_model3_Packet1(uvd, 0x0037, 0x0002); | ||
3407 | ibmcam_model3_Packet1(uvd, 0x0038, 0x0059); | ||
3408 | ibmcam_model3_Packet1(uvd, 0x003d, 0x002e); | ||
3409 | ibmcam_model3_Packet1(uvd, 0x003e, 0x0028); | ||
3410 | ibmcam_model3_Packet1(uvd, 0x0078, 0x0005); | ||
3411 | ibmcam_model3_Packet1(uvd, 0x007b, 0x0011); | ||
3412 | ibmcam_model3_Packet1(uvd, 0x007d, 0x004b); | ||
3413 | ibmcam_model3_Packet1(uvd, 0x007f, 0x0022); | ||
3414 | ibmcam_model3_Packet1(uvd, 0x0080, 0x000c); | ||
3415 | ibmcam_model3_Packet1(uvd, 0x0081, 0x000b); | ||
3416 | ibmcam_model3_Packet1(uvd, 0x0083, 0x00fd); | ||
3417 | ibmcam_model3_Packet1(uvd, 0x0086, 0x000b); | ||
3418 | ibmcam_model3_Packet1(uvd, 0x0087, 0x000b); | ||
3419 | ibmcam_model3_Packet1(uvd, 0x007e, 0x000e); | ||
3420 | ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0); /* Red gain */ | ||
3421 | ibmcam_model3_Packet1(uvd, 0x0097, 0x0096); /* Blue gain */ | ||
3422 | ibmcam_model3_Packet1(uvd, 0x0098, 0x000b); | ||
3423 | |||
3424 | switch (uvd->videosize) { | ||
3425 | case VIDEOSIZE_160x120: | ||
3426 | ibmcam_veio(uvd, 0, 0x0002, 0x0106); | ||
3427 | ibmcam_veio(uvd, 0, 0x0008, 0x0107); | ||
3428 | ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */ | ||
3429 | ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */ | ||
3430 | ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */ | ||
3431 | ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */ | ||
3432 | ibmcam_model3_Packet1(uvd, 0x0040, 0x000a); | ||
3433 | ibmcam_model3_Packet1(uvd, 0x0051, 0x000a); | ||
3434 | break; | ||
3435 | case VIDEOSIZE_320x240: | ||
3436 | ibmcam_veio(uvd, 0, 0x0003, 0x0106); | ||
3437 | ibmcam_veio(uvd, 0, 0x0062, 0x0107); | ||
3438 | ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */ | ||
3439 | ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */ | ||
3440 | ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */ | ||
3441 | ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */ | ||
3442 | ibmcam_model3_Packet1(uvd, 0x0040, 0x0008); | ||
3443 | ibmcam_model3_Packet1(uvd, 0x0051, 0x000b); | ||
3444 | break; | ||
3445 | case VIDEOSIZE_640x480: | ||
3446 | ibmcam_veio(uvd, 0, 0x0002, 0x0106); /* Adjustments */ | ||
3447 | ibmcam_veio(uvd, 0, 0x00b4, 0x0107); /* Adjustments */ | ||
3448 | ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */ | ||
3449 | ibmcam_model3_Packet1(uvd, 0x001f, 0x0002); /* !Same */ | ||
3450 | ibmcam_model3_Packet1(uvd, 0x0039, 0x003e); /* !Same */ | ||
3451 | ibmcam_model3_Packet1(uvd, 0x0040, 0x0008); | ||
3452 | ibmcam_model3_Packet1(uvd, 0x0051, 0x000a); | ||
3453 | break; | ||
3454 | } | ||
3455 | |||
3456 | /* 01.01.08 - Added for RCA video in support -LO */ | ||
3457 | if(init_model3_input) { | ||
3458 | if (debug > 0) | ||
3459 | info("Setting input to RCA."); | ||
3460 | for (i=0; i < ARRAY_SIZE(initData); i++) { | ||
3461 | ibmcam_veio(uvd, initData[i].req, initData[i].value, initData[i].index); | ||
3462 | } | ||
3463 | } | ||
3464 | |||
3465 | ibmcam_veio(uvd, 0, 0x0001, 0x0114); | ||
3466 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); | ||
3467 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
3468 | } | ||
3469 | |||
3470 | /* | ||
3471 | * ibmcam_video_stop() | ||
3472 | * | ||
3473 | * This code tells camera to stop streaming. The interface remains | ||
3474 | * configured and bandwidth - claimed. | ||
3475 | */ | ||
3476 | static void ibmcam_video_stop(struct uvd *uvd) | ||
3477 | { | ||
3478 | switch (IBMCAM_T(uvd)->camera_model) { | ||
3479 | case IBMCAM_MODEL_1: | ||
3480 | ibmcam_veio(uvd, 0, 0x00, 0x010c); | ||
3481 | ibmcam_veio(uvd, 0, 0x00, 0x010c); | ||
3482 | ibmcam_veio(uvd, 0, 0x01, 0x0114); | ||
3483 | ibmcam_veio(uvd, 0, 0xc0, 0x010c); | ||
3484 | ibmcam_veio(uvd, 0, 0x00, 0x010c); | ||
3485 | ibmcam_send_FF_04_02(uvd); | ||
3486 | ibmcam_veio(uvd, 1, 0x00, 0x0100); | ||
3487 | ibmcam_veio(uvd, 0, 0x81, 0x0100); /* LED Off */ | ||
3488 | break; | ||
3489 | case IBMCAM_MODEL_2: | ||
3490 | case IBMCAM_MODEL_4: | ||
3491 | ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop the camera */ | ||
3492 | |||
3493 | ibmcam_model2_Packet1(uvd, 0x0030, 0x0004); | ||
3494 | |||
3495 | ibmcam_veio(uvd, 0, 0x0080, 0x0100); /* LED Off */ | ||
3496 | ibmcam_veio(uvd, 0, 0x0020, 0x0111); | ||
3497 | ibmcam_veio(uvd, 0, 0x00a0, 0x0111); | ||
3498 | |||
3499 | ibmcam_model2_Packet1(uvd, 0x0030, 0x0002); | ||
3500 | |||
3501 | ibmcam_veio(uvd, 0, 0x0020, 0x0111); | ||
3502 | ibmcam_veio(uvd, 0, 0x0000, 0x0112); | ||
3503 | break; | ||
3504 | case IBMCAM_MODEL_3: | ||
3505 | #if 1 | ||
3506 | ibmcam_veio(uvd, 0, 0x0000, 0x010c); | ||
3507 | |||
3508 | /* Here we are supposed to select video interface alt. setting 0 */ | ||
3509 | ibmcam_veio(uvd, 0, 0x0006, 0x012c); | ||
3510 | |||
3511 | ibmcam_model3_Packet1(uvd, 0x0046, 0x0000); | ||
3512 | |||
3513 | ibmcam_veio(uvd, 1, 0x0000, 0x0116); | ||
3514 | ibmcam_veio(uvd, 0, 0x0064, 0x0116); | ||
3515 | ibmcam_veio(uvd, 1, 0x0000, 0x0115); | ||
3516 | ibmcam_veio(uvd, 0, 0x0003, 0x0115); | ||
3517 | ibmcam_veio(uvd, 0, 0x0008, 0x0123); | ||
3518 | ibmcam_veio(uvd, 0, 0x0000, 0x0117); | ||
3519 | ibmcam_veio(uvd, 0, 0x0000, 0x0112); | ||
3520 | ibmcam_veio(uvd, 0, 0x0080, 0x0100); | ||
3521 | IBMCAM_T(uvd)->initialized = 0; | ||
3522 | #endif | ||
3523 | break; | ||
3524 | } /* switch */ | ||
3525 | } | ||
3526 | |||
3527 | /* | ||
3528 | * ibmcam_reinit_iso() | ||
3529 | * | ||
3530 | * This procedure sends couple of commands to the camera and then | ||
3531 | * resets the video pipe. This sequence was observed to reinit the | ||
3532 | * camera or, at least, to initiate ISO data stream. | ||
3533 | * | ||
3534 | * History: | ||
3535 | * 1/2/00 Created. | ||
3536 | */ | ||
3537 | static void ibmcam_reinit_iso(struct uvd *uvd, int do_stop) | ||
3538 | { | ||
3539 | switch (IBMCAM_T(uvd)->camera_model) { | ||
3540 | case IBMCAM_MODEL_1: | ||
3541 | if (do_stop) | ||
3542 | ibmcam_video_stop(uvd); | ||
3543 | ibmcam_veio(uvd, 0, 0x0001, 0x0114); | ||
3544 | ibmcam_veio(uvd, 0, 0x00c0, 0x010c); | ||
3545 | usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); | ||
3546 | ibmcam_model1_setup_after_video_if(uvd); | ||
3547 | break; | ||
3548 | case IBMCAM_MODEL_2: | ||
3549 | ibmcam_model2_setup_after_video_if(uvd); | ||
3550 | break; | ||
3551 | case IBMCAM_MODEL_3: | ||
3552 | ibmcam_video_stop(uvd); | ||
3553 | ibmcam_model3_setup_after_video_if(uvd); | ||
3554 | break; | ||
3555 | case IBMCAM_MODEL_4: | ||
3556 | ibmcam_model4_setup_after_video_if(uvd); | ||
3557 | break; | ||
3558 | } | ||
3559 | } | ||
3560 | |||
3561 | static void ibmcam_video_start(struct uvd *uvd) | ||
3562 | { | ||
3563 | ibmcam_change_lighting_conditions(uvd); | ||
3564 | ibmcam_set_sharpness(uvd); | ||
3565 | ibmcam_reinit_iso(uvd, 0); | ||
3566 | } | ||
3567 | |||
3568 | /* | ||
3569 | * Return negative code on failure, 0 on success. | ||
3570 | */ | ||
3571 | static int ibmcam_setup_on_open(struct uvd *uvd) | ||
3572 | { | ||
3573 | int setup_ok = 0; /* Success by default */ | ||
3574 | /* Send init sequence only once, it's large! */ | ||
3575 | if (!IBMCAM_T(uvd)->initialized) { /* FIXME rename */ | ||
3576 | switch (IBMCAM_T(uvd)->camera_model) { | ||
3577 | case IBMCAM_MODEL_1: | ||
3578 | setup_ok = ibmcam_model1_setup(uvd); | ||
3579 | break; | ||
3580 | case IBMCAM_MODEL_2: | ||
3581 | setup_ok = ibmcam_model2_setup(uvd); | ||
3582 | break; | ||
3583 | case IBMCAM_MODEL_3: | ||
3584 | case IBMCAM_MODEL_4: | ||
3585 | /* We do all setup when Isoc stream is requested */ | ||
3586 | break; | ||
3587 | } | ||
3588 | IBMCAM_T(uvd)->initialized = (setup_ok != 0); | ||
3589 | } | ||
3590 | return setup_ok; | ||
3591 | } | ||
3592 | |||
3593 | static void ibmcam_configure_video(struct uvd *uvd) | ||
3594 | { | ||
3595 | if (uvd == NULL) | ||
3596 | return; | ||
3597 | |||
3598 | RESTRICT_TO_RANGE(init_brightness, 0, 255); | ||
3599 | RESTRICT_TO_RANGE(init_contrast, 0, 255); | ||
3600 | RESTRICT_TO_RANGE(init_color, 0, 255); | ||
3601 | RESTRICT_TO_RANGE(init_hue, 0, 255); | ||
3602 | RESTRICT_TO_RANGE(hue_correction, 0, 255); | ||
3603 | |||
3604 | memset(&uvd->vpic, 0, sizeof(uvd->vpic)); | ||
3605 | memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); | ||
3606 | |||
3607 | uvd->vpic.colour = init_color << 8; | ||
3608 | uvd->vpic.hue = init_hue << 8; | ||
3609 | uvd->vpic.brightness = init_brightness << 8; | ||
3610 | uvd->vpic.contrast = init_contrast << 8; | ||
3611 | uvd->vpic.whiteness = 105 << 8; /* This one isn't used */ | ||
3612 | uvd->vpic.depth = 24; | ||
3613 | uvd->vpic.palette = VIDEO_PALETTE_RGB24; | ||
3614 | |||
3615 | memset(&uvd->vcap, 0, sizeof(uvd->vcap)); | ||
3616 | strcpy(uvd->vcap.name, "IBM USB Camera"); | ||
3617 | uvd->vcap.type = VID_TYPE_CAPTURE; | ||
3618 | uvd->vcap.channels = 1; | ||
3619 | uvd->vcap.audios = 0; | ||
3620 | uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas); | ||
3621 | uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas); | ||
3622 | uvd->vcap.minwidth = min_canvasWidth; | ||
3623 | uvd->vcap.minheight = min_canvasHeight; | ||
3624 | |||
3625 | memset(&uvd->vchan, 0, sizeof(uvd->vchan)); | ||
3626 | uvd->vchan.flags = 0; | ||
3627 | uvd->vchan.tuners = 0; | ||
3628 | uvd->vchan.channel = 0; | ||
3629 | uvd->vchan.type = VIDEO_TYPE_CAMERA; | ||
3630 | strcpy(uvd->vchan.name, "Camera"); | ||
3631 | } | ||
3632 | |||
3633 | /* | ||
3634 | * ibmcam_probe() | ||
3635 | * | ||
3636 | * This procedure queries device descriptor and accepts the interface | ||
3637 | * if it looks like IBM C-it camera. | ||
3638 | * | ||
3639 | * History: | ||
3640 | * 22-Jan-2000 Moved camera init code to ibmcam_open() | ||
3641 | * 27=Jan-2000 Changed to use static structures, added locking. | ||
3642 | * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). | ||
3643 | * 03-Jul-2000 Fixed endianness bug. | ||
3644 | * 12-Nov-2000 Reworked to comply with new probe() signature. | ||
3645 | * 23-Jan-2001 Added compatibility with 2.2.x kernels. | ||
3646 | */ | ||
3647 | static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *devid) | ||
3648 | { | ||
3649 | struct usb_device *dev = interface_to_usbdev(intf); | ||
3650 | struct uvd *uvd = NULL; | ||
3651 | int ix, i, nas, model=0, canvasX=0, canvasY=0; | ||
3652 | int actInterface=-1, inactInterface=-1, maxPS=0; | ||
3653 | __u8 ifnum = intf->altsetting->desc.bInterfaceNumber; | ||
3654 | unsigned char video_ep = 0; | ||
3655 | |||
3656 | if (debug >= 1) | ||
3657 | info("ibmcam_probe(%p,%u.)", intf, ifnum); | ||
3658 | |||
3659 | /* We don't handle multi-config cameras */ | ||
3660 | if (dev->descriptor.bNumConfigurations != 1) | ||
3661 | return -ENODEV; | ||
3662 | |||
3663 | /* Check the version/revision */ | ||
3664 | switch (le16_to_cpu(dev->descriptor.bcdDevice)) { | ||
3665 | case 0x0002: | ||
3666 | if (ifnum != 2) | ||
3667 | return -ENODEV; | ||
3668 | model = IBMCAM_MODEL_1; | ||
3669 | break; | ||
3670 | case 0x030A: | ||
3671 | if (ifnum != 0) | ||
3672 | return -ENODEV; | ||
3673 | if ((le16_to_cpu(dev->descriptor.idProduct) == NETCAM_PRODUCT_ID) || | ||
3674 | (le16_to_cpu(dev->descriptor.idProduct) == VEO_800D_PRODUCT_ID)) | ||
3675 | model = IBMCAM_MODEL_4; | ||
3676 | else | ||
3677 | model = IBMCAM_MODEL_2; | ||
3678 | break; | ||
3679 | case 0x0301: | ||
3680 | if (ifnum != 0) | ||
3681 | return -ENODEV; | ||
3682 | model = IBMCAM_MODEL_3; | ||
3683 | break; | ||
3684 | default: | ||
3685 | err("IBM camera with revision 0x%04x is not supported.", | ||
3686 | le16_to_cpu(dev->descriptor.bcdDevice)); | ||
3687 | return -ENODEV; | ||
3688 | } | ||
3689 | |||
3690 | /* Print detailed info on what we found so far */ | ||
3691 | do { | ||
3692 | char *brand = NULL; | ||
3693 | switch (le16_to_cpu(dev->descriptor.idProduct)) { | ||
3694 | case NETCAM_PRODUCT_ID: | ||
3695 | brand = "IBM NetCamera"; | ||
3696 | break; | ||
3697 | case VEO_800C_PRODUCT_ID: | ||
3698 | brand = "Veo Stingray [800C]"; | ||
3699 | break; | ||
3700 | case VEO_800D_PRODUCT_ID: | ||
3701 | brand = "Veo Stingray [800D]"; | ||
3702 | break; | ||
3703 | case IBMCAM_PRODUCT_ID: | ||
3704 | default: | ||
3705 | brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */ | ||
3706 | break; | ||
3707 | } | ||
3708 | info("%s USB camera found (model %d, rev. 0x%04x)", | ||
3709 | brand, model, le16_to_cpu(dev->descriptor.bcdDevice)); | ||
3710 | } while (0); | ||
3711 | |||
3712 | /* Validate found interface: must have one ISO endpoint */ | ||
3713 | nas = intf->num_altsetting; | ||
3714 | if (debug > 0) | ||
3715 | info("Number of alternate settings=%d.", nas); | ||
3716 | if (nas < 2) { | ||
3717 | err("Too few alternate settings for this camera!"); | ||
3718 | return -ENODEV; | ||
3719 | } | ||
3720 | /* Validate all alternate settings */ | ||
3721 | for (ix=0; ix < nas; ix++) { | ||
3722 | const struct usb_host_interface *interface; | ||
3723 | const struct usb_endpoint_descriptor *endpoint; | ||
3724 | |||
3725 | interface = &intf->altsetting[ix]; | ||
3726 | i = interface->desc.bAlternateSetting; | ||
3727 | if (interface->desc.bNumEndpoints != 1) { | ||
3728 | err("Interface %d. has %u. endpoints!", | ||
3729 | ifnum, (unsigned)(interface->desc.bNumEndpoints)); | ||
3730 | return -ENODEV; | ||
3731 | } | ||
3732 | endpoint = &interface->endpoint[0].desc; | ||
3733 | if (video_ep == 0) | ||
3734 | video_ep = endpoint->bEndpointAddress; | ||
3735 | else if (video_ep != endpoint->bEndpointAddress) { | ||
3736 | err("Alternate settings have different endpoint addresses!"); | ||
3737 | return -ENODEV; | ||
3738 | } | ||
3739 | if ((endpoint->bmAttributes & 0x03) != 0x01) { | ||
3740 | err("Interface %d. has non-ISO endpoint!", ifnum); | ||
3741 | return -ENODEV; | ||
3742 | } | ||
3743 | if ((endpoint->bEndpointAddress & 0x80) == 0) { | ||
3744 | err("Interface %d. has ISO OUT endpoint!", ifnum); | ||
3745 | return -ENODEV; | ||
3746 | } | ||
3747 | if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) { | ||
3748 | if (inactInterface < 0) | ||
3749 | inactInterface = i; | ||
3750 | else { | ||
3751 | err("More than one inactive alt. setting!"); | ||
3752 | return -ENODEV; | ||
3753 | } | ||
3754 | } else { | ||
3755 | if (actInterface < 0) { | ||
3756 | actInterface = i; | ||
3757 | maxPS = le16_to_cpu(endpoint->wMaxPacketSize); | ||
3758 | if (debug > 0) | ||
3759 | info("Active setting=%d. maxPS=%d.", i, maxPS); | ||
3760 | } else | ||
3761 | err("More than one active alt. setting! Ignoring #%d.", i); | ||
3762 | } | ||
3763 | } | ||
3764 | if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) { | ||
3765 | err("Failed to recognize the camera!"); | ||
3766 | return -ENODEV; | ||
3767 | } | ||
3768 | |||
3769 | /* Validate options */ | ||
3770 | switch (model) { | ||
3771 | case IBMCAM_MODEL_1: | ||
3772 | RESTRICT_TO_RANGE(lighting, 0, 2); | ||
3773 | RESTRICT_TO_RANGE(size, SIZE_128x96, SIZE_352x288); | ||
3774 | if (framerate < 0) | ||
3775 | framerate = 2; | ||
3776 | canvasX = 352; | ||
3777 | canvasY = 288; | ||
3778 | break; | ||
3779 | case IBMCAM_MODEL_2: | ||
3780 | RESTRICT_TO_RANGE(lighting, 0, 15); | ||
3781 | RESTRICT_TO_RANGE(size, SIZE_176x144, SIZE_352x240); | ||
3782 | if (framerate < 0) | ||
3783 | framerate = 2; | ||
3784 | canvasX = 352; | ||
3785 | canvasY = 240; | ||
3786 | break; | ||
3787 | case IBMCAM_MODEL_3: | ||
3788 | RESTRICT_TO_RANGE(lighting, 0, 15); /* FIXME */ | ||
3789 | switch (size) { | ||
3790 | case SIZE_160x120: | ||
3791 | canvasX = 160; | ||
3792 | canvasY = 120; | ||
3793 | if (framerate < 0) | ||
3794 | framerate = 2; | ||
3795 | RESTRICT_TO_RANGE(framerate, 0, 5); | ||
3796 | break; | ||
3797 | default: | ||
3798 | info("IBM camera: using 320x240"); | ||
3799 | size = SIZE_320x240; | ||
3800 | /* No break here */ | ||
3801 | case SIZE_320x240: | ||
3802 | canvasX = 320; | ||
3803 | canvasY = 240; | ||
3804 | if (framerate < 0) | ||
3805 | framerate = 3; | ||
3806 | RESTRICT_TO_RANGE(framerate, 0, 5); | ||
3807 | break; | ||
3808 | case SIZE_640x480: | ||
3809 | canvasX = 640; | ||
3810 | canvasY = 480; | ||
3811 | framerate = 0; /* Slowest, and maybe even that is too fast */ | ||
3812 | break; | ||
3813 | } | ||
3814 | break; | ||
3815 | case IBMCAM_MODEL_4: | ||
3816 | RESTRICT_TO_RANGE(lighting, 0, 2); | ||
3817 | switch (size) { | ||
3818 | case SIZE_128x96: | ||
3819 | canvasX = 128; | ||
3820 | canvasY = 96; | ||
3821 | break; | ||
3822 | case SIZE_160x120: | ||
3823 | canvasX = 160; | ||
3824 | canvasY = 120; | ||
3825 | break; | ||
3826 | default: | ||
3827 | info("IBM NetCamera: using 176x144"); | ||
3828 | size = SIZE_176x144; | ||
3829 | /* No break here */ | ||
3830 | case SIZE_176x144: | ||
3831 | canvasX = 176; | ||
3832 | canvasY = 144; | ||
3833 | break; | ||
3834 | case SIZE_320x240: | ||
3835 | canvasX = 320; | ||
3836 | canvasY = 240; | ||
3837 | break; | ||
3838 | case SIZE_352x288: | ||
3839 | canvasX = 352; | ||
3840 | canvasY = 288; | ||
3841 | break; | ||
3842 | } | ||
3843 | break; | ||
3844 | default: | ||
3845 | err("IBM camera: Model %d. not supported!", model); | ||
3846 | return -ENODEV; | ||
3847 | } | ||
3848 | |||
3849 | uvd = usbvideo_AllocateDevice(cams); | ||
3850 | if (uvd != NULL) { | ||
3851 | /* Here uvd is a fully allocated uvd object */ | ||
3852 | uvd->flags = flags; | ||
3853 | uvd->debug = debug; | ||
3854 | uvd->dev = dev; | ||
3855 | uvd->iface = ifnum; | ||
3856 | uvd->ifaceAltInactive = inactInterface; | ||
3857 | uvd->ifaceAltActive = actInterface; | ||
3858 | uvd->video_endp = video_ep; | ||
3859 | uvd->iso_packet_len = maxPS; | ||
3860 | uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24; | ||
3861 | uvd->defaultPalette = VIDEO_PALETTE_RGB24; | ||
3862 | uvd->canvas = VIDEOSIZE(canvasX, canvasY); | ||
3863 | uvd->videosize = ibmcam_size_to_videosize(size); | ||
3864 | |||
3865 | /* Initialize ibmcam-specific data */ | ||
3866 | assert(IBMCAM_T(uvd) != NULL); | ||
3867 | IBMCAM_T(uvd)->camera_model = model; | ||
3868 | IBMCAM_T(uvd)->initialized = 0; | ||
3869 | |||
3870 | ibmcam_configure_video(uvd); | ||
3871 | |||
3872 | i = usbvideo_RegisterVideoDevice(uvd); | ||
3873 | if (i != 0) { | ||
3874 | err("usbvideo_RegisterVideoDevice() failed."); | ||
3875 | uvd = NULL; | ||
3876 | } | ||
3877 | } | ||
3878 | usb_set_intfdata (intf, uvd); | ||
3879 | return 0; | ||
3880 | } | ||
3881 | |||
3882 | |||
3883 | static struct usb_device_id id_table[] = { | ||
3884 | { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) }, /* Model 1 */ | ||
3885 | { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */ | ||
3886 | { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) }, /* Model 3 */ | ||
3887 | { USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */ | ||
3888 | { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */ | ||
3889 | { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */ | ||
3890 | { } /* Terminating entry */ | ||
3891 | }; | ||
3892 | |||
3893 | /* | ||
3894 | * ibmcam_init() | ||
3895 | * | ||
3896 | * This code is run to initialize the driver. | ||
3897 | * | ||
3898 | * History: | ||
3899 | * 1/27/00 Reworked to use statically allocated ibmcam structures. | ||
3900 | * 21/10/00 Completely redesigned to use usbvideo services. | ||
3901 | */ | ||
3902 | static int __init ibmcam_init(void) | ||
3903 | { | ||
3904 | struct usbvideo_cb cbTbl; | ||
3905 | memset(&cbTbl, 0, sizeof(cbTbl)); | ||
3906 | cbTbl.probe = ibmcam_probe; | ||
3907 | cbTbl.setupOnOpen = ibmcam_setup_on_open; | ||
3908 | cbTbl.videoStart = ibmcam_video_start; | ||
3909 | cbTbl.videoStop = ibmcam_video_stop; | ||
3910 | cbTbl.processData = ibmcam_ProcessIsocData; | ||
3911 | cbTbl.postProcess = usbvideo_DeinterlaceFrame; | ||
3912 | cbTbl.adjustPicture = ibmcam_adjust_picture; | ||
3913 | cbTbl.getFPS = ibmcam_calculate_fps; | ||
3914 | return usbvideo_register( | ||
3915 | &cams, | ||
3916 | MAX_IBMCAM, | ||
3917 | sizeof(ibmcam_t), | ||
3918 | "ibmcam", | ||
3919 | &cbTbl, | ||
3920 | THIS_MODULE, | ||
3921 | id_table); | ||
3922 | } | ||
3923 | |||
3924 | static void __exit ibmcam_cleanup(void) | ||
3925 | { | ||
3926 | usbvideo_Deregister(&cams); | ||
3927 | } | ||
3928 | |||
3929 | MODULE_DEVICE_TABLE(usb, id_table); | ||
3930 | |||
3931 | module_init(ibmcam_init); | ||
3932 | module_exit(ibmcam_cleanup); | ||
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c new file mode 100644 index 000000000000..e2ede583518f --- /dev/null +++ b/drivers/media/video/usbvideo/konicawc.c | |||
@@ -0,0 +1,978 @@ | |||
1 | /* | ||
2 | * konicawc.c - konica webcam driver | ||
3 | * | ||
4 | * Author: Simon Evans <spse@secret.org.uk> | ||
5 | * | ||
6 | * Copyright (C) 2002 Simon Evans | ||
7 | * | ||
8 | * Licence: GPL | ||
9 | * | ||
10 | * Driver for USB webcams based on Konica chipset. This | ||
11 | * chipset is used in Intel YC76 camera. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/input.h> | ||
19 | #include <linux/usb_input.h> | ||
20 | |||
21 | #include "usbvideo.h" | ||
22 | |||
23 | #define MAX_BRIGHTNESS 108 | ||
24 | #define MAX_CONTRAST 108 | ||
25 | #define MAX_SATURATION 108 | ||
26 | #define MAX_SHARPNESS 108 | ||
27 | #define MAX_WHITEBAL 372 | ||
28 | #define MAX_SPEED 6 | ||
29 | |||
30 | |||
31 | #define MAX_CAMERAS 1 | ||
32 | |||
33 | #define DRIVER_VERSION "v1.4" | ||
34 | #define DRIVER_DESC "Konica Webcam driver" | ||
35 | |||
36 | enum ctrl_req { | ||
37 | SetWhitebal = 0x01, | ||
38 | SetBrightness = 0x02, | ||
39 | SetSharpness = 0x03, | ||
40 | SetContrast = 0x04, | ||
41 | SetSaturation = 0x05, | ||
42 | }; | ||
43 | |||
44 | |||
45 | enum frame_sizes { | ||
46 | SIZE_160X120 = 0, | ||
47 | SIZE_160X136 = 1, | ||
48 | SIZE_176X144 = 2, | ||
49 | SIZE_320X240 = 3, | ||
50 | |||
51 | }; | ||
52 | |||
53 | #define MAX_FRAME_SIZE SIZE_320X240 | ||
54 | |||
55 | static struct usbvideo *cams; | ||
56 | |||
57 | #ifdef CONFIG_USB_DEBUG | ||
58 | static int debug; | ||
59 | #define DEBUG(n, format, arg...) \ | ||
60 | if (n <= debug) { \ | ||
61 | printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \ | ||
62 | } | ||
63 | #else | ||
64 | #define DEBUG(n, arg...) | ||
65 | static const int debug = 0; | ||
66 | #endif | ||
67 | |||
68 | |||
69 | /* Some default values for initial camera settings, | ||
70 | can be set by modprobe */ | ||
71 | |||
72 | static int size; | ||
73 | static int speed = 6; /* Speed (fps) 0 (slowest) to 6 (fastest) */ | ||
74 | static int brightness = MAX_BRIGHTNESS/2; | ||
75 | static int contrast = MAX_CONTRAST/2; | ||
76 | static int saturation = MAX_SATURATION/2; | ||
77 | static int sharpness = MAX_SHARPNESS/2; | ||
78 | static int whitebal = 3*(MAX_WHITEBAL/4); | ||
79 | |||
80 | static const int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 }; | ||
81 | |||
82 | /* These FPS speeds are from the windows config box. They are | ||
83 | * indexed on size (0-2) and speed (0-6). Divide by 3 to get the | ||
84 | * real fps. | ||
85 | */ | ||
86 | |||
87 | static const int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 }, | ||
88 | { 24, 40, 48, 60, 72, 80, 100 }, | ||
89 | { 18, 30, 36, 45, 54, 60, 75 }, | ||
90 | { 6, 10, 12, 15, 18, 21, 25 } }; | ||
91 | |||
92 | struct cam_size { | ||
93 | u16 width; | ||
94 | u16 height; | ||
95 | u8 cmd; | ||
96 | }; | ||
97 | |||
98 | static const struct cam_size camera_sizes[] = { { 160, 120, 0x7 }, | ||
99 | { 160, 136, 0xa }, | ||
100 | { 176, 144, 0x4 }, | ||
101 | { 320, 240, 0x5 } }; | ||
102 | |||
103 | struct konicawc { | ||
104 | u8 brightness; /* camera uses 0 - 9, x11 for real value */ | ||
105 | u8 contrast; /* as above */ | ||
106 | u8 saturation; /* as above */ | ||
107 | u8 sharpness; /* as above */ | ||
108 | u8 white_bal; /* 0 - 33, x11 for real value */ | ||
109 | u8 speed; /* Stored as 0 - 6, used as index in spd_to_* (above) */ | ||
110 | u8 size; /* Frame Size */ | ||
111 | int height; | ||
112 | int width; | ||
113 | struct urb *sts_urb[USBVIDEO_NUMSBUF]; | ||
114 | u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC]; | ||
115 | struct urb *last_data_urb; | ||
116 | int lastframe; | ||
117 | int cur_frame_size; /* number of bytes in current frame size */ | ||
118 | int maxline; /* number of lines per frame */ | ||
119 | int yplanesz; /* Number of bytes in the Y plane */ | ||
120 | unsigned int buttonsts:1; | ||
121 | #ifdef CONFIG_INPUT | ||
122 | struct input_dev *input; | ||
123 | char input_physname[64]; | ||
124 | #endif | ||
125 | }; | ||
126 | |||
127 | |||
128 | #define konicawc_set_misc(uvd, req, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, req, value, index, NULL, 0) | ||
129 | #define konicawc_get_misc(uvd, req, value, index, buf, sz) konicawc_ctrl_msg(uvd, USB_DIR_IN, req, value, index, buf, sz) | ||
130 | #define konicawc_set_value(uvd, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0) | ||
131 | |||
132 | |||
133 | static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len) | ||
134 | { | ||
135 | int retval = usb_control_msg(uvd->dev, | ||
136 | dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0), | ||
137 | request, 0x40 | dir, value, index, buf, len, 1000); | ||
138 | return retval < 0 ? retval : 0; | ||
139 | } | ||
140 | |||
141 | |||
142 | static inline void konicawc_camera_on(struct uvd *uvd) | ||
143 | { | ||
144 | DEBUG(0, "camera on"); | ||
145 | konicawc_set_misc(uvd, 0x2, 1, 0x0b); | ||
146 | } | ||
147 | |||
148 | |||
149 | static inline void konicawc_camera_off(struct uvd *uvd) | ||
150 | { | ||
151 | DEBUG(0, "camera off"); | ||
152 | konicawc_set_misc(uvd, 0x2, 0, 0x0b); | ||
153 | } | ||
154 | |||
155 | |||
156 | static void konicawc_set_camera_size(struct uvd *uvd) | ||
157 | { | ||
158 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
159 | |||
160 | konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08); | ||
161 | cam->width = camera_sizes[cam->size].width; | ||
162 | cam->height = camera_sizes[cam->size].height; | ||
163 | cam->yplanesz = cam->height * cam->width; | ||
164 | cam->cur_frame_size = (cam->yplanesz * 3) / 2; | ||
165 | cam->maxline = cam->yplanesz / 256; | ||
166 | uvd->videosize = VIDEOSIZE(cam->width, cam->height); | ||
167 | } | ||
168 | |||
169 | |||
170 | static int konicawc_setup_on_open(struct uvd *uvd) | ||
171 | { | ||
172 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
173 | |||
174 | DEBUG(1, "setting brightness to %d (%d)", cam->brightness, | ||
175 | cam->brightness * 11); | ||
176 | konicawc_set_value(uvd, cam->brightness, SetBrightness); | ||
177 | DEBUG(1, "setting white balance to %d (%d)", cam->white_bal, | ||
178 | cam->white_bal * 11); | ||
179 | konicawc_set_value(uvd, cam->white_bal, SetWhitebal); | ||
180 | DEBUG(1, "setting contrast to %d (%d)", cam->contrast, | ||
181 | cam->contrast * 11); | ||
182 | konicawc_set_value(uvd, cam->contrast, SetContrast); | ||
183 | DEBUG(1, "setting saturation to %d (%d)", cam->saturation, | ||
184 | cam->saturation * 11); | ||
185 | konicawc_set_value(uvd, cam->saturation, SetSaturation); | ||
186 | DEBUG(1, "setting sharpness to %d (%d)", cam->sharpness, | ||
187 | cam->sharpness * 11); | ||
188 | konicawc_set_value(uvd, cam->sharpness, SetSharpness); | ||
189 | konicawc_set_camera_size(uvd); | ||
190 | cam->lastframe = -2; | ||
191 | cam->buttonsts = 0; | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | |||
196 | static void konicawc_adjust_picture(struct uvd *uvd) | ||
197 | { | ||
198 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
199 | |||
200 | konicawc_camera_off(uvd); | ||
201 | DEBUG(1, "new brightness: %d", uvd->vpic.brightness); | ||
202 | uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness; | ||
203 | if(cam->brightness != uvd->vpic.brightness / 11) { | ||
204 | cam->brightness = uvd->vpic.brightness / 11; | ||
205 | DEBUG(1, "setting brightness to %d (%d)", cam->brightness, | ||
206 | cam->brightness * 11); | ||
207 | konicawc_set_value(uvd, cam->brightness, SetBrightness); | ||
208 | } | ||
209 | |||
210 | DEBUG(1, "new contrast: %d", uvd->vpic.contrast); | ||
211 | uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast; | ||
212 | if(cam->contrast != uvd->vpic.contrast / 11) { | ||
213 | cam->contrast = uvd->vpic.contrast / 11; | ||
214 | DEBUG(1, "setting contrast to %d (%d)", cam->contrast, | ||
215 | cam->contrast * 11); | ||
216 | konicawc_set_value(uvd, cam->contrast, SetContrast); | ||
217 | } | ||
218 | konicawc_camera_on(uvd); | ||
219 | } | ||
220 | |||
221 | #ifdef CONFIG_INPUT | ||
222 | |||
223 | static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) | ||
224 | { | ||
225 | struct input_dev *input_dev; | ||
226 | |||
227 | usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname)); | ||
228 | strncat(cam->input_physname, "/input0", sizeof(cam->input_physname)); | ||
229 | |||
230 | cam->input = input_dev = input_allocate_device(); | ||
231 | if (!input_dev) { | ||
232 | warn("Not enough memory for camera's input device\n"); | ||
233 | return; | ||
234 | } | ||
235 | |||
236 | input_dev->name = "Konicawc snapshot button"; | ||
237 | input_dev->phys = cam->input_physname; | ||
238 | usb_to_input_id(dev, &input_dev->id); | ||
239 | input_dev->cdev.dev = &dev->dev; | ||
240 | |||
241 | input_dev->evbit[0] = BIT(EV_KEY); | ||
242 | input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0); | ||
243 | |||
244 | input_dev->private = cam; | ||
245 | |||
246 | input_register_device(cam->input); | ||
247 | } | ||
248 | |||
249 | static void konicawc_unregister_input(struct konicawc *cam) | ||
250 | { | ||
251 | if (cam->input) { | ||
252 | input_unregister_device(cam->input); | ||
253 | cam->input = NULL; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | static void konicawc_report_buttonstat(struct konicawc *cam) | ||
258 | { | ||
259 | if (cam->input) { | ||
260 | input_report_key(cam->input, BTN_0, cam->buttonsts); | ||
261 | input_sync(cam->input); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | #else | ||
266 | |||
267 | static inline void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) { } | ||
268 | static inline void konicawc_unregister_input(struct konicawc *cam) { } | ||
269 | static inline void konicawc_report_buttonstat(struct konicawc *cam) { } | ||
270 | |||
271 | #endif /* CONFIG_INPUT */ | ||
272 | |||
273 | static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb) | ||
274 | { | ||
275 | char *cdata; | ||
276 | int i, totlen = 0; | ||
277 | unsigned char *status = stsurb->transfer_buffer; | ||
278 | int keep = 0, discard = 0, bad = 0; | ||
279 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
280 | |||
281 | for (i = 0; i < dataurb->number_of_packets; i++) { | ||
282 | int button = cam->buttonsts; | ||
283 | unsigned char sts; | ||
284 | int n = dataurb->iso_frame_desc[i].actual_length; | ||
285 | int st = dataurb->iso_frame_desc[i].status; | ||
286 | cdata = dataurb->transfer_buffer + | ||
287 | dataurb->iso_frame_desc[i].offset; | ||
288 | |||
289 | /* Detect and ignore errored packets */ | ||
290 | if (st < 0) { | ||
291 | DEBUG(1, "Data error: packet=%d. len=%d. status=%d.", | ||
292 | i, n, st); | ||
293 | uvd->stats.iso_err_count++; | ||
294 | continue; | ||
295 | } | ||
296 | |||
297 | /* Detect and ignore empty packets */ | ||
298 | if (n <= 0) { | ||
299 | uvd->stats.iso_skip_count++; | ||
300 | continue; | ||
301 | } | ||
302 | |||
303 | /* See what the status data said about the packet */ | ||
304 | sts = *(status+stsurb->iso_frame_desc[i].offset); | ||
305 | |||
306 | /* sts: 0x80-0xff: frame start with frame number (ie 0-7f) | ||
307 | * otherwise: | ||
308 | * bit 0 0: keep packet | ||
309 | * 1: drop packet (padding data) | ||
310 | * | ||
311 | * bit 4 0 button not clicked | ||
312 | * 1 button clicked | ||
313 | * button is used to `take a picture' (in software) | ||
314 | */ | ||
315 | |||
316 | if(sts < 0x80) { | ||
317 | button = !!(sts & 0x40); | ||
318 | sts &= ~0x40; | ||
319 | } | ||
320 | |||
321 | /* work out the button status, but don't do | ||
322 | anything with it for now */ | ||
323 | |||
324 | if(button != cam->buttonsts) { | ||
325 | DEBUG(2, "button: %sclicked", button ? "" : "un"); | ||
326 | cam->buttonsts = button; | ||
327 | konicawc_report_buttonstat(cam); | ||
328 | } | ||
329 | |||
330 | if(sts == 0x01) { /* drop frame */ | ||
331 | discard++; | ||
332 | continue; | ||
333 | } | ||
334 | |||
335 | if((sts > 0x01) && (sts < 0x80)) { | ||
336 | info("unknown status %2.2x", sts); | ||
337 | bad++; | ||
338 | continue; | ||
339 | } | ||
340 | if(!sts && cam->lastframe == -2) { | ||
341 | DEBUG(2, "dropping frame looking for image start"); | ||
342 | continue; | ||
343 | } | ||
344 | |||
345 | keep++; | ||
346 | if(sts & 0x80) { /* frame start */ | ||
347 | unsigned char marker[] = { 0, 0xff, 0, 0x00 }; | ||
348 | |||
349 | if(cam->lastframe == -2) { | ||
350 | DEBUG(2, "found initial image"); | ||
351 | cam->lastframe = -1; | ||
352 | } | ||
353 | |||
354 | marker[3] = sts & 0x7F; | ||
355 | RingQueue_Enqueue(&uvd->dp, marker, 4); | ||
356 | totlen += 4; | ||
357 | } | ||
358 | |||
359 | totlen += n; /* Little local accounting */ | ||
360 | RingQueue_Enqueue(&uvd->dp, cdata, n); | ||
361 | } | ||
362 | DEBUG(8, "finished: keep = %d discard = %d bad = %d added %d bytes", | ||
363 | keep, discard, bad, totlen); | ||
364 | return totlen; | ||
365 | } | ||
366 | |||
367 | |||
368 | static void resubmit_urb(struct uvd *uvd, struct urb *urb) | ||
369 | { | ||
370 | int i, ret; | ||
371 | for (i = 0; i < FRAMES_PER_DESC; i++) { | ||
372 | urb->iso_frame_desc[i].status = 0; | ||
373 | } | ||
374 | urb->dev = uvd->dev; | ||
375 | urb->status = 0; | ||
376 | ret = usb_submit_urb(urb, GFP_ATOMIC); | ||
377 | DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length); | ||
378 | if(ret) | ||
379 | err("usb_submit_urb error (%d)", ret); | ||
380 | |||
381 | } | ||
382 | |||
383 | |||
384 | static void konicawc_isoc_irq(struct urb *urb, struct pt_regs *regs) | ||
385 | { | ||
386 | struct uvd *uvd = urb->context; | ||
387 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
388 | |||
389 | /* We don't want to do anything if we are about to be removed! */ | ||
390 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
391 | return; | ||
392 | |||
393 | if (!uvd->streaming) { | ||
394 | DEBUG(1, "Not streaming, but interrupt!"); | ||
395 | return; | ||
396 | } | ||
397 | |||
398 | DEBUG(3, "got frame %d len = %d buflen =%d", urb->start_frame, urb->actual_length, urb->transfer_buffer_length); | ||
399 | |||
400 | uvd->stats.urb_count++; | ||
401 | |||
402 | if (urb->transfer_buffer_length > 32) { | ||
403 | cam->last_data_urb = urb; | ||
404 | return; | ||
405 | } | ||
406 | /* Copy the data received into ring queue */ | ||
407 | if(cam->last_data_urb) { | ||
408 | int len = 0; | ||
409 | if(urb->start_frame != cam->last_data_urb->start_frame) | ||
410 | err("Lost sync on frames"); | ||
411 | else if (!urb->status && !cam->last_data_urb->status) | ||
412 | len = konicawc_compress_iso(uvd, cam->last_data_urb, urb); | ||
413 | |||
414 | resubmit_urb(uvd, cam->last_data_urb); | ||
415 | resubmit_urb(uvd, urb); | ||
416 | cam->last_data_urb = NULL; | ||
417 | uvd->stats.urb_length = len; | ||
418 | uvd->stats.data_count += len; | ||
419 | if(len) | ||
420 | RingQueue_WakeUpInterruptible(&uvd->dp); | ||
421 | return; | ||
422 | } | ||
423 | return; | ||
424 | } | ||
425 | |||
426 | |||
427 | static int konicawc_start_data(struct uvd *uvd) | ||
428 | { | ||
429 | struct usb_device *dev = uvd->dev; | ||
430 | int i, errFlag; | ||
431 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
432 | int pktsz; | ||
433 | struct usb_interface *intf; | ||
434 | struct usb_host_interface *interface = NULL; | ||
435 | |||
436 | intf = usb_ifnum_to_if(dev, uvd->iface); | ||
437 | if (intf) | ||
438 | interface = usb_altnum_to_altsetting(intf, | ||
439 | spd_to_iface[cam->speed]); | ||
440 | if (!interface) | ||
441 | return -ENXIO; | ||
442 | pktsz = le16_to_cpu(interface->endpoint[1].desc.wMaxPacketSize); | ||
443 | DEBUG(1, "pktsz = %d", pktsz); | ||
444 | if (!CAMERA_IS_OPERATIONAL(uvd)) { | ||
445 | err("Camera is not operational"); | ||
446 | return -EFAULT; | ||
447 | } | ||
448 | uvd->curframe = -1; | ||
449 | konicawc_camera_on(uvd); | ||
450 | /* Alternate interface 1 is is the biggest frame size */ | ||
451 | i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive); | ||
452 | if (i < 0) { | ||
453 | err("usb_set_interface error"); | ||
454 | uvd->last_error = i; | ||
455 | return -EBUSY; | ||
456 | } | ||
457 | |||
458 | /* We double buffer the Iso lists */ | ||
459 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
460 | int j, k; | ||
461 | struct urb *urb = uvd->sbuf[i].urb; | ||
462 | urb->dev = dev; | ||
463 | urb->context = uvd; | ||
464 | urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp); | ||
465 | urb->interval = 1; | ||
466 | urb->transfer_flags = URB_ISO_ASAP; | ||
467 | urb->transfer_buffer = uvd->sbuf[i].data; | ||
468 | urb->complete = konicawc_isoc_irq; | ||
469 | urb->number_of_packets = FRAMES_PER_DESC; | ||
470 | urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC; | ||
471 | for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) { | ||
472 | urb->iso_frame_desc[j].offset = k; | ||
473 | urb->iso_frame_desc[j].length = pktsz; | ||
474 | } | ||
475 | |||
476 | urb = cam->sts_urb[i]; | ||
477 | urb->dev = dev; | ||
478 | urb->context = uvd; | ||
479 | urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1); | ||
480 | urb->interval = 1; | ||
481 | urb->transfer_flags = URB_ISO_ASAP; | ||
482 | urb->transfer_buffer = cam->sts_buf[i]; | ||
483 | urb->complete = konicawc_isoc_irq; | ||
484 | urb->number_of_packets = FRAMES_PER_DESC; | ||
485 | urb->transfer_buffer_length = FRAMES_PER_DESC; | ||
486 | for (j=0; j < FRAMES_PER_DESC; j++) { | ||
487 | urb->iso_frame_desc[j].offset = j; | ||
488 | urb->iso_frame_desc[j].length = 1; | ||
489 | } | ||
490 | } | ||
491 | |||
492 | cam->last_data_urb = NULL; | ||
493 | |||
494 | /* Submit all URBs */ | ||
495 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
496 | errFlag = usb_submit_urb(cam->sts_urb[i], GFP_KERNEL); | ||
497 | if (errFlag) | ||
498 | err("usb_submit_isoc(%d) ret %d", i, errFlag); | ||
499 | |||
500 | errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL); | ||
501 | if (errFlag) | ||
502 | err ("usb_submit_isoc(%d) ret %d", i, errFlag); | ||
503 | } | ||
504 | |||
505 | uvd->streaming = 1; | ||
506 | DEBUG(1, "streaming=1 video_endp=$%02x", uvd->video_endp); | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | |||
511 | static void konicawc_stop_data(struct uvd *uvd) | ||
512 | { | ||
513 | int i, j; | ||
514 | struct konicawc *cam; | ||
515 | |||
516 | if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL)) | ||
517 | return; | ||
518 | |||
519 | konicawc_camera_off(uvd); | ||
520 | uvd->streaming = 0; | ||
521 | cam = (struct konicawc *)uvd->user_data; | ||
522 | cam->last_data_urb = NULL; | ||
523 | |||
524 | /* Unschedule all of the iso td's */ | ||
525 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
526 | usb_kill_urb(uvd->sbuf[i].urb); | ||
527 | usb_kill_urb(cam->sts_urb[i]); | ||
528 | } | ||
529 | |||
530 | if (!uvd->remove_pending) { | ||
531 | /* Set packet size to 0 */ | ||
532 | j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive); | ||
533 | if (j < 0) { | ||
534 | err("usb_set_interface() error %d.", j); | ||
535 | uvd->last_error = j; | ||
536 | } | ||
537 | } | ||
538 | } | ||
539 | |||
540 | |||
541 | static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame) | ||
542 | { | ||
543 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
544 | int maxline = cam->maxline; | ||
545 | int yplanesz = cam->yplanesz; | ||
546 | |||
547 | assert(frame != NULL); | ||
548 | |||
549 | DEBUG(5, "maxline = %d yplanesz = %d", maxline, yplanesz); | ||
550 | DEBUG(3, "Frame state = %d", frame->scanstate); | ||
551 | |||
552 | if(frame->scanstate == ScanState_Scanning) { | ||
553 | int drop = 0; | ||
554 | int curframe; | ||
555 | int fdrops = 0; | ||
556 | DEBUG(3, "Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp)); | ||
557 | while(RingQueue_GetLength(&uvd->dp) >= 4) { | ||
558 | if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && | ||
559 | (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) && | ||
560 | (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) && | ||
561 | (RING_QUEUE_PEEK(&uvd->dp, 3) < 0x80)) { | ||
562 | curframe = RING_QUEUE_PEEK(&uvd->dp, 3); | ||
563 | if(cam->lastframe >= 0) { | ||
564 | fdrops = (0x80 + curframe - cam->lastframe) & 0x7F; | ||
565 | fdrops--; | ||
566 | if(fdrops) { | ||
567 | info("Dropped %d frames (%d -> %d)", fdrops, | ||
568 | cam->lastframe, curframe); | ||
569 | } | ||
570 | } | ||
571 | cam->lastframe = curframe; | ||
572 | frame->curline = 0; | ||
573 | frame->scanstate = ScanState_Lines; | ||
574 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4); | ||
575 | break; | ||
576 | } | ||
577 | RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); | ||
578 | drop++; | ||
579 | } | ||
580 | if(drop) | ||
581 | DEBUG(2, "dropped %d bytes looking for new frame", drop); | ||
582 | } | ||
583 | |||
584 | if(frame->scanstate == ScanState_Scanning) | ||
585 | return; | ||
586 | |||
587 | /* Try to move data from queue into frame buffer | ||
588 | * We get data in blocks of 384 bytes made up of: | ||
589 | * 256 Y, 64 U, 64 V. | ||
590 | * This needs to be written out as a Y plane, a U plane and a V plane. | ||
591 | */ | ||
592 | |||
593 | while ( frame->curline < maxline && (RingQueue_GetLength(&uvd->dp) >= 384)) { | ||
594 | /* Y */ | ||
595 | RingQueue_Dequeue(&uvd->dp, frame->data + (frame->curline * 256), 256); | ||
596 | /* U */ | ||
597 | RingQueue_Dequeue(&uvd->dp, frame->data + yplanesz + (frame->curline * 64), 64); | ||
598 | /* V */ | ||
599 | RingQueue_Dequeue(&uvd->dp, frame->data + (5 * yplanesz)/4 + (frame->curline * 64), 64); | ||
600 | frame->seqRead_Length += 384; | ||
601 | frame->curline++; | ||
602 | } | ||
603 | /* See if we filled the frame */ | ||
604 | if (frame->curline == maxline) { | ||
605 | DEBUG(5, "got whole frame"); | ||
606 | |||
607 | frame->frameState = FrameState_Done_Hold; | ||
608 | frame->curline = 0; | ||
609 | uvd->curframe = -1; | ||
610 | uvd->stats.frame_num++; | ||
611 | } | ||
612 | } | ||
613 | |||
614 | |||
615 | static int konicawc_find_fps(int size, int fps) | ||
616 | { | ||
617 | int i; | ||
618 | |||
619 | fps *= 3; | ||
620 | DEBUG(1, "konica_find_fps: size = %d fps = %d", size, fps); | ||
621 | if(fps <= spd_to_fps[size][0]) | ||
622 | return 0; | ||
623 | |||
624 | if(fps >= spd_to_fps[size][MAX_SPEED]) | ||
625 | return MAX_SPEED; | ||
626 | |||
627 | for(i = 0; i < MAX_SPEED; i++) { | ||
628 | if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) { | ||
629 | DEBUG(2, "fps %d between %d and %d", fps, i, i+1); | ||
630 | if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps)) | ||
631 | return i; | ||
632 | else | ||
633 | return i+1; | ||
634 | } | ||
635 | } | ||
636 | return MAX_SPEED+1; | ||
637 | } | ||
638 | |||
639 | |||
640 | static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw) | ||
641 | { | ||
642 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
643 | int newspeed = cam->speed; | ||
644 | int newsize; | ||
645 | int x = vw->width; | ||
646 | int y = vw->height; | ||
647 | int fps = vw->flags; | ||
648 | |||
649 | if(x > 0 && y > 0) { | ||
650 | DEBUG(2, "trying to find size %d,%d", x, y); | ||
651 | for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) { | ||
652 | if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y)) | ||
653 | break; | ||
654 | } | ||
655 | } else { | ||
656 | newsize = cam->size; | ||
657 | } | ||
658 | |||
659 | if(newsize > MAX_FRAME_SIZE) { | ||
660 | DEBUG(1, "couldn't find size %d,%d", x, y); | ||
661 | return -EINVAL; | ||
662 | } | ||
663 | |||
664 | if(fps > 0) { | ||
665 | DEBUG(1, "trying to set fps to %d", fps); | ||
666 | newspeed = konicawc_find_fps(newsize, fps); | ||
667 | DEBUG(1, "find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]); | ||
668 | } | ||
669 | |||
670 | if(newspeed > MAX_SPEED) | ||
671 | return -EINVAL; | ||
672 | |||
673 | DEBUG(1, "setting size to %d speed to %d", newsize, newspeed); | ||
674 | if((newsize == cam->size) && (newspeed == cam->speed)) { | ||
675 | DEBUG(1, "Nothing to do"); | ||
676 | return 0; | ||
677 | } | ||
678 | DEBUG(0, "setting to %dx%d @ %d fps", camera_sizes[newsize].width, | ||
679 | camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3); | ||
680 | |||
681 | konicawc_stop_data(uvd); | ||
682 | uvd->ifaceAltActive = spd_to_iface[newspeed]; | ||
683 | DEBUG(1, "new interface = %d", uvd->ifaceAltActive); | ||
684 | cam->speed = newspeed; | ||
685 | |||
686 | if(cam->size != newsize) { | ||
687 | cam->size = newsize; | ||
688 | konicawc_set_camera_size(uvd); | ||
689 | } | ||
690 | |||
691 | /* Flush the input queue and clear any current frame in progress */ | ||
692 | |||
693 | RingQueue_Flush(&uvd->dp); | ||
694 | cam->lastframe = -2; | ||
695 | if(uvd->curframe != -1) { | ||
696 | uvd->frame[uvd->curframe].curline = 0; | ||
697 | uvd->frame[uvd->curframe].seqRead_Length = 0; | ||
698 | uvd->frame[uvd->curframe].seqRead_Index = 0; | ||
699 | } | ||
700 | |||
701 | konicawc_start_data(uvd); | ||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | |||
706 | static int konicawc_calculate_fps(struct uvd *uvd) | ||
707 | { | ||
708 | struct konicawc *cam = uvd->user_data; | ||
709 | return spd_to_fps[cam->size][cam->speed]/3; | ||
710 | } | ||
711 | |||
712 | |||
713 | static void konicawc_configure_video(struct uvd *uvd) | ||
714 | { | ||
715 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
716 | u8 buf[2]; | ||
717 | |||
718 | memset(&uvd->vpic, 0, sizeof(uvd->vpic)); | ||
719 | memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); | ||
720 | |||
721 | RESTRICT_TO_RANGE(brightness, 0, MAX_BRIGHTNESS); | ||
722 | RESTRICT_TO_RANGE(contrast, 0, MAX_CONTRAST); | ||
723 | RESTRICT_TO_RANGE(saturation, 0, MAX_SATURATION); | ||
724 | RESTRICT_TO_RANGE(sharpness, 0, MAX_SHARPNESS); | ||
725 | RESTRICT_TO_RANGE(whitebal, 0, MAX_WHITEBAL); | ||
726 | |||
727 | cam->brightness = brightness / 11; | ||
728 | cam->contrast = contrast / 11; | ||
729 | cam->saturation = saturation / 11; | ||
730 | cam->sharpness = sharpness / 11; | ||
731 | cam->white_bal = whitebal / 11; | ||
732 | |||
733 | uvd->vpic.colour = 108; | ||
734 | uvd->vpic.hue = 108; | ||
735 | uvd->vpic.brightness = brightness; | ||
736 | uvd->vpic.contrast = contrast; | ||
737 | uvd->vpic.whiteness = whitebal; | ||
738 | uvd->vpic.depth = 6; | ||
739 | uvd->vpic.palette = VIDEO_PALETTE_YUV420P; | ||
740 | |||
741 | memset(&uvd->vcap, 0, sizeof(uvd->vcap)); | ||
742 | strcpy(uvd->vcap.name, "Konica Webcam"); | ||
743 | uvd->vcap.type = VID_TYPE_CAPTURE; | ||
744 | uvd->vcap.channels = 1; | ||
745 | uvd->vcap.audios = 0; | ||
746 | uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width; | ||
747 | uvd->vcap.minheight = camera_sizes[SIZE_160X120].height; | ||
748 | uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width; | ||
749 | uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height; | ||
750 | |||
751 | memset(&uvd->vchan, 0, sizeof(uvd->vchan)); | ||
752 | uvd->vchan.flags = 0 ; | ||
753 | uvd->vchan.tuners = 0; | ||
754 | uvd->vchan.channel = 0; | ||
755 | uvd->vchan.type = VIDEO_TYPE_CAMERA; | ||
756 | strcpy(uvd->vchan.name, "Camera"); | ||
757 | |||
758 | /* Talk to device */ | ||
759 | DEBUG(1, "device init"); | ||
760 | if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2)) | ||
761 | DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]); | ||
762 | if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2)) | ||
763 | DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]); | ||
764 | if(konicawc_set_misc(uvd, 0x2, 0, 0xd)) | ||
765 | DEBUG(2, "2,0,d failed"); | ||
766 | DEBUG(1, "setting initial values"); | ||
767 | } | ||
768 | |||
769 | static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id *devid) | ||
770 | { | ||
771 | struct usb_device *dev = interface_to_usbdev(intf); | ||
772 | struct uvd *uvd = NULL; | ||
773 | int ix, i, nas; | ||
774 | int actInterface=-1, inactInterface=-1, maxPS=0; | ||
775 | unsigned char video_ep = 0; | ||
776 | |||
777 | DEBUG(1, "konicawc_probe(%p)", intf); | ||
778 | |||
779 | /* We don't handle multi-config cameras */ | ||
780 | if (dev->descriptor.bNumConfigurations != 1) | ||
781 | return -ENODEV; | ||
782 | |||
783 | info("Konica Webcam (rev. 0x%04x)", le16_to_cpu(dev->descriptor.bcdDevice)); | ||
784 | RESTRICT_TO_RANGE(speed, 0, MAX_SPEED); | ||
785 | |||
786 | /* Validate found interface: must have one ISO endpoint */ | ||
787 | nas = intf->num_altsetting; | ||
788 | if (nas != 8) { | ||
789 | err("Incorrect number of alternate settings (%d) for this camera!", nas); | ||
790 | return -ENODEV; | ||
791 | } | ||
792 | /* Validate all alternate settings */ | ||
793 | for (ix=0; ix < nas; ix++) { | ||
794 | const struct usb_host_interface *interface; | ||
795 | const struct usb_endpoint_descriptor *endpoint; | ||
796 | |||
797 | interface = &intf->altsetting[ix]; | ||
798 | i = interface->desc.bAlternateSetting; | ||
799 | if (interface->desc.bNumEndpoints != 2) { | ||
800 | err("Interface %d. has %u. endpoints!", | ||
801 | interface->desc.bInterfaceNumber, | ||
802 | (unsigned)(interface->desc.bNumEndpoints)); | ||
803 | return -ENODEV; | ||
804 | } | ||
805 | endpoint = &interface->endpoint[1].desc; | ||
806 | DEBUG(1, "found endpoint: addr: 0x%2.2x maxps = 0x%4.4x", | ||
807 | endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize)); | ||
808 | if (video_ep == 0) | ||
809 | video_ep = endpoint->bEndpointAddress; | ||
810 | else if (video_ep != endpoint->bEndpointAddress) { | ||
811 | err("Alternate settings have different endpoint addresses!"); | ||
812 | return -ENODEV; | ||
813 | } | ||
814 | if ((endpoint->bmAttributes & 0x03) != 0x01) { | ||
815 | err("Interface %d. has non-ISO endpoint!", | ||
816 | interface->desc.bInterfaceNumber); | ||
817 | return -ENODEV; | ||
818 | } | ||
819 | if ((endpoint->bEndpointAddress & 0x80) == 0) { | ||
820 | err("Interface %d. has ISO OUT endpoint!", | ||
821 | interface->desc.bInterfaceNumber); | ||
822 | return -ENODEV; | ||
823 | } | ||
824 | if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) { | ||
825 | if (inactInterface < 0) | ||
826 | inactInterface = i; | ||
827 | else { | ||
828 | err("More than one inactive alt. setting!"); | ||
829 | return -ENODEV; | ||
830 | } | ||
831 | } else { | ||
832 | if (i == spd_to_iface[speed]) { | ||
833 | /* This one is the requested one */ | ||
834 | actInterface = i; | ||
835 | } | ||
836 | } | ||
837 | if (le16_to_cpu(endpoint->wMaxPacketSize) > maxPS) | ||
838 | maxPS = le16_to_cpu(endpoint->wMaxPacketSize); | ||
839 | } | ||
840 | if(actInterface == -1) { | ||
841 | err("Cant find required endpoint"); | ||
842 | return -ENODEV; | ||
843 | } | ||
844 | |||
845 | DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS); | ||
846 | |||
847 | uvd = usbvideo_AllocateDevice(cams); | ||
848 | if (uvd != NULL) { | ||
849 | struct konicawc *cam = (struct konicawc *)(uvd->user_data); | ||
850 | /* Here uvd is a fully allocated uvd object */ | ||
851 | for(i = 0; i < USBVIDEO_NUMSBUF; i++) { | ||
852 | cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); | ||
853 | if(cam->sts_urb[i] == NULL) { | ||
854 | while(i--) { | ||
855 | usb_free_urb(cam->sts_urb[i]); | ||
856 | } | ||
857 | err("can't allocate urbs"); | ||
858 | return -ENOMEM; | ||
859 | } | ||
860 | } | ||
861 | cam->speed = speed; | ||
862 | RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240); | ||
863 | cam->width = camera_sizes[size].width; | ||
864 | cam->height = camera_sizes[size].height; | ||
865 | cam->size = size; | ||
866 | |||
867 | uvd->flags = 0; | ||
868 | uvd->debug = debug; | ||
869 | uvd->dev = dev; | ||
870 | uvd->iface = intf->altsetting->desc.bInterfaceNumber; | ||
871 | uvd->ifaceAltInactive = inactInterface; | ||
872 | uvd->ifaceAltActive = actInterface; | ||
873 | uvd->video_endp = video_ep; | ||
874 | uvd->iso_packet_len = maxPS; | ||
875 | uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P; | ||
876 | uvd->defaultPalette = VIDEO_PALETTE_YUV420P; | ||
877 | uvd->canvas = VIDEOSIZE(320, 240); | ||
878 | uvd->videosize = VIDEOSIZE(cam->width, cam->height); | ||
879 | |||
880 | /* Initialize konicawc specific data */ | ||
881 | konicawc_configure_video(uvd); | ||
882 | |||
883 | i = usbvideo_RegisterVideoDevice(uvd); | ||
884 | uvd->max_frame_size = (320 * 240 * 3)/2; | ||
885 | if (i != 0) { | ||
886 | err("usbvideo_RegisterVideoDevice() failed."); | ||
887 | uvd = NULL; | ||
888 | } | ||
889 | |||
890 | konicawc_register_input(cam, dev); | ||
891 | } | ||
892 | |||
893 | if (uvd) { | ||
894 | usb_set_intfdata (intf, uvd); | ||
895 | return 0; | ||
896 | } | ||
897 | return -EIO; | ||
898 | } | ||
899 | |||
900 | |||
901 | static void konicawc_free_uvd(struct uvd *uvd) | ||
902 | { | ||
903 | int i; | ||
904 | struct konicawc *cam = (struct konicawc *)uvd->user_data; | ||
905 | |||
906 | konicawc_unregister_input(cam); | ||
907 | |||
908 | for (i = 0; i < USBVIDEO_NUMSBUF; i++) { | ||
909 | usb_free_urb(cam->sts_urb[i]); | ||
910 | cam->sts_urb[i] = NULL; | ||
911 | } | ||
912 | } | ||
913 | |||
914 | |||
915 | static struct usb_device_id id_table[] = { | ||
916 | { USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */ | ||
917 | { } /* Terminating entry */ | ||
918 | }; | ||
919 | |||
920 | |||
921 | static int __init konicawc_init(void) | ||
922 | { | ||
923 | struct usbvideo_cb cbTbl; | ||
924 | info(DRIVER_DESC " " DRIVER_VERSION); | ||
925 | memset(&cbTbl, 0, sizeof(cbTbl)); | ||
926 | cbTbl.probe = konicawc_probe; | ||
927 | cbTbl.setupOnOpen = konicawc_setup_on_open; | ||
928 | cbTbl.processData = konicawc_process_isoc; | ||
929 | cbTbl.getFPS = konicawc_calculate_fps; | ||
930 | cbTbl.setVideoMode = konicawc_set_video_mode; | ||
931 | cbTbl.startDataPump = konicawc_start_data; | ||
932 | cbTbl.stopDataPump = konicawc_stop_data; | ||
933 | cbTbl.adjustPicture = konicawc_adjust_picture; | ||
934 | cbTbl.userFree = konicawc_free_uvd; | ||
935 | return usbvideo_register( | ||
936 | &cams, | ||
937 | MAX_CAMERAS, | ||
938 | sizeof(struct konicawc), | ||
939 | "konicawc", | ||
940 | &cbTbl, | ||
941 | THIS_MODULE, | ||
942 | id_table); | ||
943 | } | ||
944 | |||
945 | |||
946 | static void __exit konicawc_cleanup(void) | ||
947 | { | ||
948 | usbvideo_Deregister(&cams); | ||
949 | } | ||
950 | |||
951 | |||
952 | MODULE_DEVICE_TABLE(usb, id_table); | ||
953 | |||
954 | MODULE_LICENSE("GPL"); | ||
955 | MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>"); | ||
956 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
957 | module_param(speed, int, 0); | ||
958 | MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)"); | ||
959 | module_param(size, int, 0); | ||
960 | MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240"); | ||
961 | module_param(brightness, int, 0); | ||
962 | MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108"); | ||
963 | module_param(contrast, int, 0); | ||
964 | MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108"); | ||
965 | module_param(saturation, int, 0); | ||
966 | MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108"); | ||
967 | module_param(sharpness, int, 0); | ||
968 | MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108"); | ||
969 | module_param(whitebal, int, 0); | ||
970 | MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363"); | ||
971 | |||
972 | #ifdef CONFIG_USB_DEBUG | ||
973 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
974 | MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); | ||
975 | #endif | ||
976 | |||
977 | module_init(konicawc_init); | ||
978 | module_exit(konicawc_cleanup); | ||
diff --git a/drivers/media/video/usbvideo/ultracam.c b/drivers/media/video/usbvideo/ultracam.c new file mode 100644 index 000000000000..75ff755224df --- /dev/null +++ b/drivers/media/video/usbvideo/ultracam.c | |||
@@ -0,0 +1,679 @@ | |||
1 | /* | ||
2 | * USB NB Camera driver | ||
3 | * | ||
4 | * HISTORY: | ||
5 | * 25-Dec-2002 Dmitri Removed lighting, sharpness parameters, methods. | ||
6 | */ | ||
7 | |||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/sched.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/init.h> | ||
12 | |||
13 | #include "usbvideo.h" | ||
14 | |||
15 | #define ULTRACAM_VENDOR_ID 0x0461 | ||
16 | #define ULTRACAM_PRODUCT_ID 0x0813 | ||
17 | |||
18 | #define MAX_CAMERAS 4 /* How many devices we allow to connect */ | ||
19 | |||
20 | /* | ||
21 | * This structure lives in uvd_t->user field. | ||
22 | */ | ||
23 | typedef struct { | ||
24 | int initialized; /* Had we already sent init sequence? */ | ||
25 | int camera_model; /* What type of IBM camera we got? */ | ||
26 | int has_hdr; | ||
27 | } ultracam_t; | ||
28 | #define ULTRACAM_T(uvd) ((ultracam_t *)((uvd)->user_data)) | ||
29 | |||
30 | static struct usbvideo *cams = NULL; | ||
31 | |||
32 | static int debug = 0; | ||
33 | |||
34 | static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */ | ||
35 | |||
36 | static const int min_canvasWidth = 8; | ||
37 | static const int min_canvasHeight = 4; | ||
38 | |||
39 | #define FRAMERATE_MIN 0 | ||
40 | #define FRAMERATE_MAX 6 | ||
41 | static int framerate = -1; | ||
42 | |||
43 | /* | ||
44 | * Here we define several initialization variables. They may | ||
45 | * be used to automatically set color, hue, brightness and | ||
46 | * contrast to desired values. This is particularly useful in | ||
47 | * case of webcams (which have no controls and no on-screen | ||
48 | * output) and also when a client V4L software is used that | ||
49 | * does not have some of those controls. In any case it's | ||
50 | * good to have startup values as options. | ||
51 | * | ||
52 | * These values are all in [0..255] range. This simplifies | ||
53 | * operation. Note that actual values of V4L variables may | ||
54 | * be scaled up (as much as << 8). User can see that only | ||
55 | * on overlay output, however, or through a V4L client. | ||
56 | */ | ||
57 | static int init_brightness = 128; | ||
58 | static int init_contrast = 192; | ||
59 | static int init_color = 128; | ||
60 | static int init_hue = 128; | ||
61 | static int hue_correction = 128; | ||
62 | |||
63 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
64 | MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); | ||
65 | module_param(flags, int, 0); | ||
66 | MODULE_PARM_DESC(flags, | ||
67 | "Bitfield: 0=VIDIOCSYNC, " | ||
68 | "1=B/W, " | ||
69 | "2=show hints, " | ||
70 | "3=show stats, " | ||
71 | "4=test pattern, " | ||
72 | "5=separate frames, " | ||
73 | "6=clean frames"); | ||
74 | module_param(framerate, int, 0); | ||
75 | MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); | ||
76 | |||
77 | module_param(init_brightness, int, 0); | ||
78 | MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); | ||
79 | module_param(init_contrast, int, 0); | ||
80 | MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); | ||
81 | module_param(init_color, int, 0); | ||
82 | MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); | ||
83 | module_param(init_hue, int, 0); | ||
84 | MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); | ||
85 | module_param(hue_correction, int, 0); | ||
86 | MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); | ||
87 | |||
88 | /* | ||
89 | * ultracam_ProcessIsocData() | ||
90 | * | ||
91 | * Generic routine to parse the ring queue data. It employs either | ||
92 | * ultracam_find_header() or ultracam_parse_lines() to do most | ||
93 | * of work. | ||
94 | * | ||
95 | * 02-Nov-2000 First (mostly dummy) version. | ||
96 | * 06-Nov-2000 Rewrote to dump all data into frame. | ||
97 | */ | ||
98 | static void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame) | ||
99 | { | ||
100 | int n; | ||
101 | |||
102 | assert(uvd != NULL); | ||
103 | assert(frame != NULL); | ||
104 | |||
105 | /* Try to move data from queue into frame buffer */ | ||
106 | n = RingQueue_GetLength(&uvd->dp); | ||
107 | if (n > 0) { | ||
108 | int m; | ||
109 | /* See how much spare we have left */ | ||
110 | m = uvd->max_frame_size - frame->seqRead_Length; | ||
111 | if (n > m) | ||
112 | n = m; | ||
113 | /* Now move that much data into frame buffer */ | ||
114 | RingQueue_Dequeue( | ||
115 | &uvd->dp, | ||
116 | frame->data + frame->seqRead_Length, | ||
117 | m); | ||
118 | frame->seqRead_Length += m; | ||
119 | } | ||
120 | /* See if we filled the frame */ | ||
121 | if (frame->seqRead_Length >= uvd->max_frame_size) { | ||
122 | frame->frameState = FrameState_Done; | ||
123 | uvd->curframe = -1; | ||
124 | uvd->stats.frame_num++; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | /* | ||
129 | * ultracam_veio() | ||
130 | * | ||
131 | * History: | ||
132 | * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged. | ||
133 | */ | ||
134 | static int ultracam_veio( | ||
135 | struct uvd *uvd, | ||
136 | unsigned char req, | ||
137 | unsigned short value, | ||
138 | unsigned short index, | ||
139 | int is_out) | ||
140 | { | ||
141 | static const char proc[] = "ultracam_veio"; | ||
142 | unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */; | ||
143 | int i; | ||
144 | |||
145 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
146 | return 0; | ||
147 | |||
148 | if (!is_out) { | ||
149 | i = usb_control_msg( | ||
150 | uvd->dev, | ||
151 | usb_rcvctrlpipe(uvd->dev, 0), | ||
152 | req, | ||
153 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
154 | value, | ||
155 | index, | ||
156 | cp, | ||
157 | sizeof(cp), | ||
158 | 1000); | ||
159 | #if 1 | ||
160 | info("USB => %02x%02x%02x%02x%02x%02x%02x%02x " | ||
161 | "(req=$%02x val=$%04x ind=$%04x)", | ||
162 | cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], | ||
163 | req, value, index); | ||
164 | #endif | ||
165 | } else { | ||
166 | i = usb_control_msg( | ||
167 | uvd->dev, | ||
168 | usb_sndctrlpipe(uvd->dev, 0), | ||
169 | req, | ||
170 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
171 | value, | ||
172 | index, | ||
173 | NULL, | ||
174 | 0, | ||
175 | 1000); | ||
176 | } | ||
177 | if (i < 0) { | ||
178 | err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.", | ||
179 | proc, i); | ||
180 | uvd->last_error = i; | ||
181 | } | ||
182 | return i; | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | * ultracam_calculate_fps() | ||
187 | */ | ||
188 | static int ultracam_calculate_fps(struct uvd *uvd) | ||
189 | { | ||
190 | return 3 + framerate*4 + framerate/2; | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * ultracam_adjust_contrast() | ||
195 | */ | ||
196 | static void ultracam_adjust_contrast(struct uvd *uvd) | ||
197 | { | ||
198 | } | ||
199 | |||
200 | /* | ||
201 | * ultracam_set_brightness() | ||
202 | * | ||
203 | * This procedure changes brightness of the picture. | ||
204 | */ | ||
205 | static void ultracam_set_brightness(struct uvd *uvd) | ||
206 | { | ||
207 | } | ||
208 | |||
209 | static void ultracam_set_hue(struct uvd *uvd) | ||
210 | { | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * ultracam_adjust_picture() | ||
215 | * | ||
216 | * This procedure gets called from V4L interface to update picture settings. | ||
217 | * Here we change brightness and contrast. | ||
218 | */ | ||
219 | static void ultracam_adjust_picture(struct uvd *uvd) | ||
220 | { | ||
221 | ultracam_adjust_contrast(uvd); | ||
222 | ultracam_set_brightness(uvd); | ||
223 | ultracam_set_hue(uvd); | ||
224 | } | ||
225 | |||
226 | /* | ||
227 | * ultracam_video_stop() | ||
228 | * | ||
229 | * This code tells camera to stop streaming. The interface remains | ||
230 | * configured and bandwidth - claimed. | ||
231 | */ | ||
232 | static void ultracam_video_stop(struct uvd *uvd) | ||
233 | { | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * ultracam_reinit_iso() | ||
238 | * | ||
239 | * This procedure sends couple of commands to the camera and then | ||
240 | * resets the video pipe. This sequence was observed to reinit the | ||
241 | * camera or, at least, to initiate ISO data stream. | ||
242 | */ | ||
243 | static void ultracam_reinit_iso(struct uvd *uvd, int do_stop) | ||
244 | { | ||
245 | } | ||
246 | |||
247 | static void ultracam_video_start(struct uvd *uvd) | ||
248 | { | ||
249 | ultracam_reinit_iso(uvd, 0); | ||
250 | } | ||
251 | |||
252 | static int ultracam_resetPipe(struct uvd *uvd) | ||
253 | { | ||
254 | usb_clear_halt(uvd->dev, uvd->video_endp); | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static int ultracam_alternateSetting(struct uvd *uvd, int setting) | ||
259 | { | ||
260 | static const char proc[] = "ultracam_alternateSetting"; | ||
261 | int i; | ||
262 | i = usb_set_interface(uvd->dev, uvd->iface, setting); | ||
263 | if (i < 0) { | ||
264 | err("%s: usb_set_interface error", proc); | ||
265 | uvd->last_error = i; | ||
266 | return -EBUSY; | ||
267 | } | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * Return negative code on failure, 0 on success. | ||
273 | */ | ||
274 | static int ultracam_setup_on_open(struct uvd *uvd) | ||
275 | { | ||
276 | int setup_ok = 0; /* Success by default */ | ||
277 | /* Send init sequence only once, it's large! */ | ||
278 | if (!ULTRACAM_T(uvd)->initialized) { | ||
279 | ultracam_alternateSetting(uvd, 0x04); | ||
280 | ultracam_alternateSetting(uvd, 0x00); | ||
281 | ultracam_veio(uvd, 0x02, 0x0004, 0x000b, 1); | ||
282 | ultracam_veio(uvd, 0x02, 0x0001, 0x0005, 1); | ||
283 | ultracam_veio(uvd, 0x02, 0x8000, 0x0000, 1); | ||
284 | ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1); | ||
285 | ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, 1); | ||
286 | ultracam_veio(uvd, 0x00, 0x0000, 0x0002, 1); | ||
287 | ultracam_veio(uvd, 0x00, 0x000c, 0x0003, 1); | ||
288 | ultracam_veio(uvd, 0x00, 0x000b, 0x0004, 1); | ||
289 | ultracam_veio(uvd, 0x00, 0x0000, 0x0005, 1); | ||
290 | ultracam_veio(uvd, 0x00, 0x0000, 0x0006, 1); | ||
291 | ultracam_veio(uvd, 0x00, 0x0079, 0x0007, 1); | ||
292 | ultracam_veio(uvd, 0x00, 0x003b, 0x0008, 1); | ||
293 | ultracam_veio(uvd, 0x00, 0x0002, 0x000f, 1); | ||
294 | ultracam_veio(uvd, 0x00, 0x0001, 0x0010, 1); | ||
295 | ultracam_veio(uvd, 0x00, 0x0000, 0x0011, 1); | ||
296 | ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, 1); | ||
297 | ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, 1); | ||
298 | ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, 1); | ||
299 | ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, 1); | ||
300 | ultracam_veio(uvd, 0x01, 0x0010, 0x0002, 1); | ||
301 | ultracam_veio(uvd, 0x01, 0x0066, 0x0007, 1); | ||
302 | ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1); | ||
303 | ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1); | ||
304 | ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1); | ||
305 | ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1); | ||
306 | ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1); | ||
307 | ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1); | ||
308 | ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1); | ||
309 | ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1); | ||
310 | ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1); | ||
311 | ultracam_veio(uvd, 0x01, 0x000b, 0x0011, 1); | ||
312 | ultracam_veio(uvd, 0x01, 0x0001, 0x0012, 1); | ||
313 | ultracam_veio(uvd, 0x01, 0x0000, 0x0013, 1); | ||
314 | ultracam_veio(uvd, 0x01, 0x0000, 0x0014, 1); | ||
315 | ultracam_veio(uvd, 0x01, 0x0087, 0x0051, 1); | ||
316 | ultracam_veio(uvd, 0x01, 0x0040, 0x0052, 1); | ||
317 | ultracam_veio(uvd, 0x01, 0x0058, 0x0053, 1); | ||
318 | ultracam_veio(uvd, 0x01, 0x0040, 0x0054, 1); | ||
319 | ultracam_veio(uvd, 0x01, 0x0000, 0x0040, 1); | ||
320 | ultracam_veio(uvd, 0x01, 0x0010, 0x0041, 1); | ||
321 | ultracam_veio(uvd, 0x01, 0x0020, 0x0042, 1); | ||
322 | ultracam_veio(uvd, 0x01, 0x0030, 0x0043, 1); | ||
323 | ultracam_veio(uvd, 0x01, 0x0040, 0x0044, 1); | ||
324 | ultracam_veio(uvd, 0x01, 0x0050, 0x0045, 1); | ||
325 | ultracam_veio(uvd, 0x01, 0x0060, 0x0046, 1); | ||
326 | ultracam_veio(uvd, 0x01, 0x0070, 0x0047, 1); | ||
327 | ultracam_veio(uvd, 0x01, 0x0080, 0x0048, 1); | ||
328 | ultracam_veio(uvd, 0x01, 0x0090, 0x0049, 1); | ||
329 | ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, 1); | ||
330 | ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, 1); | ||
331 | ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, 1); | ||
332 | ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, 1); | ||
333 | ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, 1); | ||
334 | ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, 1); | ||
335 | ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, 1); | ||
336 | ultracam_veio(uvd, 0x01, 0x0000, 0x0056, 1); | ||
337 | ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1); | ||
338 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1); | ||
339 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | ||
340 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
341 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
342 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
343 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
344 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
345 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
346 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
347 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
348 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
349 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
350 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
351 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
352 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
353 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
354 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
355 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
356 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
357 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
358 | ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1); | ||
359 | ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, 1); | ||
360 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | ||
361 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
362 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
363 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
364 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
365 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
366 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
367 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
368 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
369 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
370 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
371 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
372 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
373 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
374 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
375 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
376 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
377 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
378 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
379 | ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, 1); | ||
380 | ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, 1); | ||
381 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | ||
382 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); | ||
383 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); | ||
384 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); | ||
385 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); | ||
386 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); | ||
387 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); | ||
388 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
389 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); | ||
390 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); | ||
391 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); | ||
392 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); | ||
393 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); | ||
394 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); | ||
395 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
396 | ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, 1); | ||
397 | ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, 1); | ||
398 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | ||
399 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); | ||
400 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); | ||
401 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); | ||
402 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); | ||
403 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); | ||
404 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); | ||
405 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
406 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); | ||
407 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); | ||
408 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); | ||
409 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); | ||
410 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); | ||
411 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); | ||
412 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); | ||
413 | ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, 1); | ||
414 | ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1); | ||
415 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | ||
416 | ultracam_veio(uvd, 0x02, 0xc040, 0x0001, 1); | ||
417 | ultracam_veio(uvd, 0x01, 0x0000, 0x0008, 0); | ||
418 | ultracam_veio(uvd, 0x01, 0x0000, 0x0009, 0); | ||
419 | ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 0); | ||
420 | ultracam_veio(uvd, 0x01, 0x0000, 0x000b, 0); | ||
421 | ultracam_veio(uvd, 0x01, 0x0000, 0x000c, 0); | ||
422 | ultracam_veio(uvd, 0x01, 0x0000, 0x000d, 0); | ||
423 | ultracam_veio(uvd, 0x01, 0x0000, 0x000e, 0); | ||
424 | ultracam_veio(uvd, 0x01, 0x0000, 0x000f, 0); | ||
425 | ultracam_veio(uvd, 0x01, 0x0000, 0x0010, 0); | ||
426 | ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1); | ||
427 | ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1); | ||
428 | ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1); | ||
429 | ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1); | ||
430 | ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1); | ||
431 | ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1); | ||
432 | ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1); | ||
433 | ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1); | ||
434 | ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1); | ||
435 | ultracam_veio(uvd, 0x01, 0x0000, 0x0001, 0); | ||
436 | ultracam_veio(uvd, 0x01, 0x0064, 0x0001, 1); | ||
437 | ultracam_veio(uvd, 0x01, 0x0059, 0x0051, 1); | ||
438 | ultracam_veio(uvd, 0x01, 0x003f, 0x0052, 1); | ||
439 | ultracam_veio(uvd, 0x01, 0x0094, 0x0053, 1); | ||
440 | ultracam_veio(uvd, 0x01, 0x00ff, 0x0011, 1); | ||
441 | ultracam_veio(uvd, 0x01, 0x0003, 0x0012, 1); | ||
442 | ultracam_veio(uvd, 0x01, 0x00f7, 0x0013, 1); | ||
443 | ultracam_veio(uvd, 0x00, 0x0009, 0x0011, 1); | ||
444 | ultracam_veio(uvd, 0x00, 0x0000, 0x0001, 1); | ||
445 | ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1); | ||
446 | ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, 1); | ||
447 | ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, 1); | ||
448 | ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); | ||
449 | ultracam_alternateSetting(uvd, 0x04); | ||
450 | ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1); | ||
451 | ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1); | ||
452 | ultracam_veio(uvd, 0x02, 0x0000, 0x0006, 1); | ||
453 | ultracam_veio(uvd, 0x02, 0x9000, 0x0007, 1); | ||
454 | ultracam_veio(uvd, 0x02, 0x0042, 0x0001, 1); | ||
455 | ultracam_veio(uvd, 0x02, 0x0000, 0x000b, 0); | ||
456 | ultracam_resetPipe(uvd); | ||
457 | ULTRACAM_T(uvd)->initialized = (setup_ok != 0); | ||
458 | } | ||
459 | return setup_ok; | ||
460 | } | ||
461 | |||
462 | static void ultracam_configure_video(struct uvd *uvd) | ||
463 | { | ||
464 | if (uvd == NULL) | ||
465 | return; | ||
466 | |||
467 | RESTRICT_TO_RANGE(init_brightness, 0, 255); | ||
468 | RESTRICT_TO_RANGE(init_contrast, 0, 255); | ||
469 | RESTRICT_TO_RANGE(init_color, 0, 255); | ||
470 | RESTRICT_TO_RANGE(init_hue, 0, 255); | ||
471 | RESTRICT_TO_RANGE(hue_correction, 0, 255); | ||
472 | |||
473 | memset(&uvd->vpic, 0, sizeof(uvd->vpic)); | ||
474 | memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); | ||
475 | |||
476 | uvd->vpic.colour = init_color << 8; | ||
477 | uvd->vpic.hue = init_hue << 8; | ||
478 | uvd->vpic.brightness = init_brightness << 8; | ||
479 | uvd->vpic.contrast = init_contrast << 8; | ||
480 | uvd->vpic.whiteness = 105 << 8; /* This one isn't used */ | ||
481 | uvd->vpic.depth = 24; | ||
482 | uvd->vpic.palette = VIDEO_PALETTE_RGB24; | ||
483 | |||
484 | memset(&uvd->vcap, 0, sizeof(uvd->vcap)); | ||
485 | strcpy(uvd->vcap.name, "IBM Ultra Camera"); | ||
486 | uvd->vcap.type = VID_TYPE_CAPTURE; | ||
487 | uvd->vcap.channels = 1; | ||
488 | uvd->vcap.audios = 0; | ||
489 | uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas); | ||
490 | uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas); | ||
491 | uvd->vcap.minwidth = min_canvasWidth; | ||
492 | uvd->vcap.minheight = min_canvasHeight; | ||
493 | |||
494 | memset(&uvd->vchan, 0, sizeof(uvd->vchan)); | ||
495 | uvd->vchan.flags = 0; | ||
496 | uvd->vchan.tuners = 0; | ||
497 | uvd->vchan.channel = 0; | ||
498 | uvd->vchan.type = VIDEO_TYPE_CAMERA; | ||
499 | strcpy(uvd->vchan.name, "Camera"); | ||
500 | } | ||
501 | |||
502 | /* | ||
503 | * ultracam_probe() | ||
504 | * | ||
505 | * This procedure queries device descriptor and accepts the interface | ||
506 | * if it looks like our camera. | ||
507 | * | ||
508 | * History: | ||
509 | * 12-Nov-2000 Reworked to comply with new probe() signature. | ||
510 | * 23-Jan-2001 Added compatibility with 2.2.x kernels. | ||
511 | */ | ||
512 | static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id *devid) | ||
513 | { | ||
514 | struct usb_device *dev = interface_to_usbdev(intf); | ||
515 | struct uvd *uvd = NULL; | ||
516 | int ix, i, nas; | ||
517 | int actInterface=-1, inactInterface=-1, maxPS=0; | ||
518 | unsigned char video_ep = 0; | ||
519 | |||
520 | if (debug >= 1) | ||
521 | info("ultracam_probe(%p)", intf); | ||
522 | |||
523 | /* We don't handle multi-config cameras */ | ||
524 | if (dev->descriptor.bNumConfigurations != 1) | ||
525 | return -ENODEV; | ||
526 | |||
527 | info("IBM Ultra camera found (rev. 0x%04x)", | ||
528 | le16_to_cpu(dev->descriptor.bcdDevice)); | ||
529 | |||
530 | /* Validate found interface: must have one ISO endpoint */ | ||
531 | nas = intf->num_altsetting; | ||
532 | if (debug > 0) | ||
533 | info("Number of alternate settings=%d.", nas); | ||
534 | if (nas < 8) { | ||
535 | err("Too few alternate settings for this camera!"); | ||
536 | return -ENODEV; | ||
537 | } | ||
538 | /* Validate all alternate settings */ | ||
539 | for (ix=0; ix < nas; ix++) { | ||
540 | const struct usb_host_interface *interface; | ||
541 | const struct usb_endpoint_descriptor *endpoint; | ||
542 | |||
543 | interface = &intf->altsetting[ix]; | ||
544 | i = interface->desc.bAlternateSetting; | ||
545 | if (interface->desc.bNumEndpoints != 1) { | ||
546 | err("Interface %d. has %u. endpoints!", | ||
547 | interface->desc.bInterfaceNumber, | ||
548 | (unsigned)(interface->desc.bNumEndpoints)); | ||
549 | return -ENODEV; | ||
550 | } | ||
551 | endpoint = &interface->endpoint[0].desc; | ||
552 | if (video_ep == 0) | ||
553 | video_ep = endpoint->bEndpointAddress; | ||
554 | else if (video_ep != endpoint->bEndpointAddress) { | ||
555 | err("Alternate settings have different endpoint addresses!"); | ||
556 | return -ENODEV; | ||
557 | } | ||
558 | if ((endpoint->bmAttributes & 0x03) != 0x01) { | ||
559 | err("Interface %d. has non-ISO endpoint!", | ||
560 | interface->desc.bInterfaceNumber); | ||
561 | return -ENODEV; | ||
562 | } | ||
563 | if ((endpoint->bEndpointAddress & 0x80) == 0) { | ||
564 | err("Interface %d. has ISO OUT endpoint!", | ||
565 | interface->desc.bInterfaceNumber); | ||
566 | return -ENODEV; | ||
567 | } | ||
568 | if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) { | ||
569 | if (inactInterface < 0) | ||
570 | inactInterface = i; | ||
571 | else { | ||
572 | err("More than one inactive alt. setting!"); | ||
573 | return -ENODEV; | ||
574 | } | ||
575 | } else { | ||
576 | if (actInterface < 0) { | ||
577 | actInterface = i; | ||
578 | maxPS = le16_to_cpu(endpoint->wMaxPacketSize); | ||
579 | if (debug > 0) | ||
580 | info("Active setting=%d. maxPS=%d.", i, maxPS); | ||
581 | } else { | ||
582 | /* Got another active alt. setting */ | ||
583 | if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) { | ||
584 | /* This one is better! */ | ||
585 | actInterface = i; | ||
586 | maxPS = le16_to_cpu(endpoint->wMaxPacketSize); | ||
587 | if (debug > 0) { | ||
588 | info("Even better ctive setting=%d. maxPS=%d.", | ||
589 | i, maxPS); | ||
590 | } | ||
591 | } | ||
592 | } | ||
593 | } | ||
594 | } | ||
595 | if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) { | ||
596 | err("Failed to recognize the camera!"); | ||
597 | return -ENODEV; | ||
598 | } | ||
599 | |||
600 | uvd = usbvideo_AllocateDevice(cams); | ||
601 | if (uvd != NULL) { | ||
602 | /* Here uvd is a fully allocated uvd object */ | ||
603 | uvd->flags = flags; | ||
604 | uvd->debug = debug; | ||
605 | uvd->dev = dev; | ||
606 | uvd->iface = intf->altsetting->desc.bInterfaceNumber; | ||
607 | uvd->ifaceAltInactive = inactInterface; | ||
608 | uvd->ifaceAltActive = actInterface; | ||
609 | uvd->video_endp = video_ep; | ||
610 | uvd->iso_packet_len = maxPS; | ||
611 | uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24; | ||
612 | uvd->defaultPalette = VIDEO_PALETTE_RGB24; | ||
613 | uvd->canvas = VIDEOSIZE(640, 480); /* FIXME */ | ||
614 | uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/ | ||
615 | |||
616 | /* Initialize ibmcam-specific data */ | ||
617 | assert(ULTRACAM_T(uvd) != NULL); | ||
618 | ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */ | ||
619 | ULTRACAM_T(uvd)->initialized = 0; | ||
620 | |||
621 | ultracam_configure_video(uvd); | ||
622 | |||
623 | i = usbvideo_RegisterVideoDevice(uvd); | ||
624 | if (i != 0) { | ||
625 | err("usbvideo_RegisterVideoDevice() failed."); | ||
626 | uvd = NULL; | ||
627 | } | ||
628 | } | ||
629 | |||
630 | if (uvd) { | ||
631 | usb_set_intfdata (intf, uvd); | ||
632 | return 0; | ||
633 | } | ||
634 | return -EIO; | ||
635 | } | ||
636 | |||
637 | |||
638 | static struct usb_device_id id_table[] = { | ||
639 | { USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) }, | ||
640 | { } /* Terminating entry */ | ||
641 | }; | ||
642 | |||
643 | /* | ||
644 | * ultracam_init() | ||
645 | * | ||
646 | * This code is run to initialize the driver. | ||
647 | */ | ||
648 | static int __init ultracam_init(void) | ||
649 | { | ||
650 | struct usbvideo_cb cbTbl; | ||
651 | memset(&cbTbl, 0, sizeof(cbTbl)); | ||
652 | cbTbl.probe = ultracam_probe; | ||
653 | cbTbl.setupOnOpen = ultracam_setup_on_open; | ||
654 | cbTbl.videoStart = ultracam_video_start; | ||
655 | cbTbl.videoStop = ultracam_video_stop; | ||
656 | cbTbl.processData = ultracam_ProcessIsocData; | ||
657 | cbTbl.postProcess = usbvideo_DeinterlaceFrame; | ||
658 | cbTbl.adjustPicture = ultracam_adjust_picture; | ||
659 | cbTbl.getFPS = ultracam_calculate_fps; | ||
660 | return usbvideo_register( | ||
661 | &cams, | ||
662 | MAX_CAMERAS, | ||
663 | sizeof(ultracam_t), | ||
664 | "ultracam", | ||
665 | &cbTbl, | ||
666 | THIS_MODULE, | ||
667 | id_table); | ||
668 | } | ||
669 | |||
670 | static void __exit ultracam_cleanup(void) | ||
671 | { | ||
672 | usbvideo_Deregister(&cams); | ||
673 | } | ||
674 | |||
675 | MODULE_DEVICE_TABLE(usb, id_table); | ||
676 | MODULE_LICENSE("GPL"); | ||
677 | |||
678 | module_init(ultracam_init); | ||
679 | module_exit(ultracam_cleanup); | ||
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c new file mode 100644 index 000000000000..0b51fae720a9 --- /dev/null +++ b/drivers/media/video/usbvideo/usbvideo.c | |||
@@ -0,0 +1,2190 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2, or (at your option) | ||
5 | * any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/list.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/smp_lock.h> | ||
24 | #include <linux/vmalloc.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | |||
28 | #include <asm/io.h> | ||
29 | |||
30 | #include "usbvideo.h" | ||
31 | |||
32 | #if defined(MAP_NR) | ||
33 | #define virt_to_page(v) MAP_NR(v) /* Kernels 2.2.x */ | ||
34 | #endif | ||
35 | |||
36 | static int video_nr = -1; | ||
37 | module_param(video_nr, int, 0); | ||
38 | |||
39 | /* | ||
40 | * Local prototypes. | ||
41 | */ | ||
42 | static void usbvideo_Disconnect(struct usb_interface *intf); | ||
43 | static void usbvideo_CameraRelease(struct uvd *uvd); | ||
44 | |||
45 | static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file, | ||
46 | unsigned int cmd, unsigned long arg); | ||
47 | static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma); | ||
48 | static int usbvideo_v4l_open(struct inode *inode, struct file *file); | ||
49 | static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf, | ||
50 | size_t count, loff_t *ppos); | ||
51 | static int usbvideo_v4l_close(struct inode *inode, struct file *file); | ||
52 | |||
53 | static int usbvideo_StartDataPump(struct uvd *uvd); | ||
54 | static void usbvideo_StopDataPump(struct uvd *uvd); | ||
55 | static int usbvideo_GetFrame(struct uvd *uvd, int frameNum); | ||
56 | static int usbvideo_NewFrame(struct uvd *uvd, int framenum); | ||
57 | static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, | ||
58 | struct usbvideo_frame *frame); | ||
59 | |||
60 | /*******************************/ | ||
61 | /* Memory management functions */ | ||
62 | /*******************************/ | ||
63 | static void *usbvideo_rvmalloc(unsigned long size) | ||
64 | { | ||
65 | void *mem; | ||
66 | unsigned long adr; | ||
67 | |||
68 | size = PAGE_ALIGN(size); | ||
69 | mem = vmalloc_32(size); | ||
70 | if (!mem) | ||
71 | return NULL; | ||
72 | |||
73 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
74 | adr = (unsigned long) mem; | ||
75 | while (size > 0) { | ||
76 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
77 | adr += PAGE_SIZE; | ||
78 | size -= PAGE_SIZE; | ||
79 | } | ||
80 | |||
81 | return mem; | ||
82 | } | ||
83 | |||
84 | static void usbvideo_rvfree(void *mem, unsigned long size) | ||
85 | { | ||
86 | unsigned long adr; | ||
87 | |||
88 | if (!mem) | ||
89 | return; | ||
90 | |||
91 | adr = (unsigned long) mem; | ||
92 | while ((long) size > 0) { | ||
93 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
94 | adr += PAGE_SIZE; | ||
95 | size -= PAGE_SIZE; | ||
96 | } | ||
97 | vfree(mem); | ||
98 | } | ||
99 | |||
100 | static void RingQueue_Initialize(struct RingQueue *rq) | ||
101 | { | ||
102 | assert(rq != NULL); | ||
103 | init_waitqueue_head(&rq->wqh); | ||
104 | } | ||
105 | |||
106 | static void RingQueue_Allocate(struct RingQueue *rq, int rqLen) | ||
107 | { | ||
108 | /* Make sure the requested size is a power of 2 and | ||
109 | round up if necessary. This allows index wrapping | ||
110 | using masks rather than modulo */ | ||
111 | |||
112 | int i = 1; | ||
113 | assert(rq != NULL); | ||
114 | assert(rqLen > 0); | ||
115 | |||
116 | while(rqLen >> i) | ||
117 | i++; | ||
118 | if(rqLen != 1 << (i-1)) | ||
119 | rqLen = 1 << i; | ||
120 | |||
121 | rq->length = rqLen; | ||
122 | rq->ri = rq->wi = 0; | ||
123 | rq->queue = usbvideo_rvmalloc(rq->length); | ||
124 | assert(rq->queue != NULL); | ||
125 | } | ||
126 | |||
127 | static int RingQueue_IsAllocated(const struct RingQueue *rq) | ||
128 | { | ||
129 | if (rq == NULL) | ||
130 | return 0; | ||
131 | return (rq->queue != NULL) && (rq->length > 0); | ||
132 | } | ||
133 | |||
134 | static void RingQueue_Free(struct RingQueue *rq) | ||
135 | { | ||
136 | assert(rq != NULL); | ||
137 | if (RingQueue_IsAllocated(rq)) { | ||
138 | usbvideo_rvfree(rq->queue, rq->length); | ||
139 | rq->queue = NULL; | ||
140 | rq->length = 0; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len) | ||
145 | { | ||
146 | int rql, toread; | ||
147 | |||
148 | assert(rq != NULL); | ||
149 | assert(dst != NULL); | ||
150 | |||
151 | rql = RingQueue_GetLength(rq); | ||
152 | if(!rql) | ||
153 | return 0; | ||
154 | |||
155 | /* Clip requested length to available data */ | ||
156 | if(len > rql) | ||
157 | len = rql; | ||
158 | |||
159 | toread = len; | ||
160 | if(rq->ri > rq->wi) { | ||
161 | /* Read data from tail */ | ||
162 | int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri; | ||
163 | memcpy(dst, rq->queue + rq->ri, read); | ||
164 | toread -= read; | ||
165 | dst += read; | ||
166 | rq->ri = (rq->ri + read) & (rq->length-1); | ||
167 | } | ||
168 | if(toread) { | ||
169 | /* Read data from head */ | ||
170 | memcpy(dst, rq->queue + rq->ri, toread); | ||
171 | rq->ri = (rq->ri + toread) & (rq->length-1); | ||
172 | } | ||
173 | return len; | ||
174 | } | ||
175 | |||
176 | EXPORT_SYMBOL(RingQueue_Dequeue); | ||
177 | |||
178 | int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n) | ||
179 | { | ||
180 | int enqueued = 0; | ||
181 | |||
182 | assert(rq != NULL); | ||
183 | assert(cdata != NULL); | ||
184 | assert(rq->length > 0); | ||
185 | while (n > 0) { | ||
186 | int m, q_avail; | ||
187 | |||
188 | /* Calculate the largest chunk that fits the tail of the ring */ | ||
189 | q_avail = rq->length - rq->wi; | ||
190 | if (q_avail <= 0) { | ||
191 | rq->wi = 0; | ||
192 | q_avail = rq->length; | ||
193 | } | ||
194 | m = n; | ||
195 | assert(q_avail > 0); | ||
196 | if (m > q_avail) | ||
197 | m = q_avail; | ||
198 | |||
199 | memcpy(rq->queue + rq->wi, cdata, m); | ||
200 | RING_QUEUE_ADVANCE_INDEX(rq, wi, m); | ||
201 | cdata += m; | ||
202 | enqueued += m; | ||
203 | n -= m; | ||
204 | } | ||
205 | return enqueued; | ||
206 | } | ||
207 | |||
208 | EXPORT_SYMBOL(RingQueue_Enqueue); | ||
209 | |||
210 | static void RingQueue_InterruptibleSleepOn(struct RingQueue *rq) | ||
211 | { | ||
212 | assert(rq != NULL); | ||
213 | interruptible_sleep_on(&rq->wqh); | ||
214 | } | ||
215 | |||
216 | void RingQueue_WakeUpInterruptible(struct RingQueue *rq) | ||
217 | { | ||
218 | assert(rq != NULL); | ||
219 | if (waitqueue_active(&rq->wqh)) | ||
220 | wake_up_interruptible(&rq->wqh); | ||
221 | } | ||
222 | |||
223 | EXPORT_SYMBOL(RingQueue_WakeUpInterruptible); | ||
224 | |||
225 | void RingQueue_Flush(struct RingQueue *rq) | ||
226 | { | ||
227 | assert(rq != NULL); | ||
228 | rq->ri = 0; | ||
229 | rq->wi = 0; | ||
230 | } | ||
231 | |||
232 | EXPORT_SYMBOL(RingQueue_Flush); | ||
233 | |||
234 | |||
235 | /* | ||
236 | * usbvideo_VideosizeToString() | ||
237 | * | ||
238 | * This procedure converts given videosize value to readable string. | ||
239 | * | ||
240 | * History: | ||
241 | * 07-Aug-2000 Created. | ||
242 | * 19-Oct-2000 Reworked for usbvideo module. | ||
243 | */ | ||
244 | static void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs) | ||
245 | { | ||
246 | char tmp[40]; | ||
247 | int n; | ||
248 | |||
249 | n = 1 + sprintf(tmp, "%ldx%ld", VIDEOSIZE_X(vs), VIDEOSIZE_Y(vs)); | ||
250 | assert(n < sizeof(tmp)); | ||
251 | if ((buf == NULL) || (bufLen < n)) | ||
252 | err("usbvideo_VideosizeToString: buffer is too small."); | ||
253 | else | ||
254 | memmove(buf, tmp, n); | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * usbvideo_OverlayChar() | ||
259 | * | ||
260 | * History: | ||
261 | * 01-Feb-2000 Created. | ||
262 | */ | ||
263 | static void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame, | ||
264 | int x, int y, int ch) | ||
265 | { | ||
266 | static const unsigned short digits[16] = { | ||
267 | 0xF6DE, /* 0 */ | ||
268 | 0x2492, /* 1 */ | ||
269 | 0xE7CE, /* 2 */ | ||
270 | 0xE79E, /* 3 */ | ||
271 | 0xB792, /* 4 */ | ||
272 | 0xF39E, /* 5 */ | ||
273 | 0xF3DE, /* 6 */ | ||
274 | 0xF492, /* 7 */ | ||
275 | 0xF7DE, /* 8 */ | ||
276 | 0xF79E, /* 9 */ | ||
277 | 0x77DA, /* a */ | ||
278 | 0xD75C, /* b */ | ||
279 | 0xF24E, /* c */ | ||
280 | 0xD6DC, /* d */ | ||
281 | 0xF34E, /* e */ | ||
282 | 0xF348 /* f */ | ||
283 | }; | ||
284 | unsigned short digit; | ||
285 | int ix, iy; | ||
286 | |||
287 | if ((uvd == NULL) || (frame == NULL)) | ||
288 | return; | ||
289 | |||
290 | if (ch >= '0' && ch <= '9') | ||
291 | ch -= '0'; | ||
292 | else if (ch >= 'A' && ch <= 'F') | ||
293 | ch = 10 + (ch - 'A'); | ||
294 | else if (ch >= 'a' && ch <= 'f') | ||
295 | ch = 10 + (ch - 'a'); | ||
296 | else | ||
297 | return; | ||
298 | digit = digits[ch]; | ||
299 | |||
300 | for (iy=0; iy < 5; iy++) { | ||
301 | for (ix=0; ix < 3; ix++) { | ||
302 | if (digit & 0x8000) { | ||
303 | if (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24)) { | ||
304 | /* TODO */ RGB24_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF); | ||
305 | } | ||
306 | } | ||
307 | digit = digit << 1; | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * usbvideo_OverlayString() | ||
314 | * | ||
315 | * History: | ||
316 | * 01-Feb-2000 Created. | ||
317 | */ | ||
318 | static void usbvideo_OverlayString(struct uvd *uvd, struct usbvideo_frame *frame, | ||
319 | int x, int y, const char *str) | ||
320 | { | ||
321 | while (*str) { | ||
322 | usbvideo_OverlayChar(uvd, frame, x, y, *str); | ||
323 | str++; | ||
324 | x += 4; /* 3 pixels character + 1 space */ | ||
325 | } | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * usbvideo_OverlayStats() | ||
330 | * | ||
331 | * Overlays important debugging information. | ||
332 | * | ||
333 | * History: | ||
334 | * 01-Feb-2000 Created. | ||
335 | */ | ||
336 | static void usbvideo_OverlayStats(struct uvd *uvd, struct usbvideo_frame *frame) | ||
337 | { | ||
338 | const int y_diff = 8; | ||
339 | char tmp[16]; | ||
340 | int x = 10, y=10; | ||
341 | long i, j, barLength; | ||
342 | const int qi_x1 = 60, qi_y1 = 10; | ||
343 | const int qi_x2 = VIDEOSIZE_X(frame->request) - 10, qi_h = 10; | ||
344 | |||
345 | /* Call the user callback, see if we may proceed after that */ | ||
346 | if (VALID_CALLBACK(uvd, overlayHook)) { | ||
347 | if (GET_CALLBACK(uvd, overlayHook)(uvd, frame) < 0) | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * We draw a (mostly) hollow rectangle with qi_xxx coordinates. | ||
353 | * Left edge symbolizes the queue index 0; right edge symbolizes | ||
354 | * the full capacity of the queue. | ||
355 | */ | ||
356 | barLength = qi_x2 - qi_x1 - 2; | ||
357 | if ((barLength > 10) && (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))) { | ||
358 | /* TODO */ long u_lo, u_hi, q_used; | ||
359 | long m_ri, m_wi, m_lo, m_hi; | ||
360 | |||
361 | /* | ||
362 | * Determine fill zones (used areas of the queue): | ||
363 | * 0 xxxxxxx u_lo ...... uvd->dp.ri xxxxxxxx u_hi ..... uvd->dp.length | ||
364 | * | ||
365 | * if u_lo < 0 then there is no first filler. | ||
366 | */ | ||
367 | |||
368 | q_used = RingQueue_GetLength(&uvd->dp); | ||
369 | if ((uvd->dp.ri + q_used) >= uvd->dp.length) { | ||
370 | u_hi = uvd->dp.length; | ||
371 | u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1); | ||
372 | } else { | ||
373 | u_hi = (q_used + uvd->dp.ri); | ||
374 | u_lo = -1; | ||
375 | } | ||
376 | |||
377 | /* Convert byte indices into screen units */ | ||
378 | m_ri = qi_x1 + ((barLength * uvd->dp.ri) / uvd->dp.length); | ||
379 | m_wi = qi_x1 + ((barLength * uvd->dp.wi) / uvd->dp.length); | ||
380 | m_lo = (u_lo > 0) ? (qi_x1 + ((barLength * u_lo) / uvd->dp.length)) : -1; | ||
381 | m_hi = qi_x1 + ((barLength * u_hi) / uvd->dp.length); | ||
382 | |||
383 | for (j=qi_y1; j < (qi_y1 + qi_h); j++) { | ||
384 | for (i=qi_x1; i < qi_x2; i++) { | ||
385 | /* Draw border lines */ | ||
386 | if ((j == qi_y1) || (j == (qi_y1 + qi_h - 1)) || | ||
387 | (i == qi_x1) || (i == (qi_x2 - 1))) { | ||
388 | RGB24_PUTPIXEL(frame, i, j, 0xFF, 0xFF, 0xFF); | ||
389 | continue; | ||
390 | } | ||
391 | /* For all other points the Y coordinate does not matter */ | ||
392 | if ((i >= m_ri) && (i <= (m_ri + 3))) { | ||
393 | RGB24_PUTPIXEL(frame, i, j, 0x00, 0xFF, 0x00); | ||
394 | } else if ((i >= m_wi) && (i <= (m_wi + 3))) { | ||
395 | RGB24_PUTPIXEL(frame, i, j, 0xFF, 0x00, 0x00); | ||
396 | } else if ((i < m_lo) || ((i > m_ri) && (i < m_hi))) | ||
397 | RGB24_PUTPIXEL(frame, i, j, 0x00, 0x00, 0xFF); | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | |||
402 | sprintf(tmp, "%8lx", uvd->stats.frame_num); | ||
403 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
404 | y += y_diff; | ||
405 | |||
406 | sprintf(tmp, "%8lx", uvd->stats.urb_count); | ||
407 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
408 | y += y_diff; | ||
409 | |||
410 | sprintf(tmp, "%8lx", uvd->stats.urb_length); | ||
411 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
412 | y += y_diff; | ||
413 | |||
414 | sprintf(tmp, "%8lx", uvd->stats.data_count); | ||
415 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
416 | y += y_diff; | ||
417 | |||
418 | sprintf(tmp, "%8lx", uvd->stats.header_count); | ||
419 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
420 | y += y_diff; | ||
421 | |||
422 | sprintf(tmp, "%8lx", uvd->stats.iso_skip_count); | ||
423 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
424 | y += y_diff; | ||
425 | |||
426 | sprintf(tmp, "%8lx", uvd->stats.iso_err_count); | ||
427 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
428 | y += y_diff; | ||
429 | |||
430 | sprintf(tmp, "%8x", uvd->vpic.colour); | ||
431 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
432 | y += y_diff; | ||
433 | |||
434 | sprintf(tmp, "%8x", uvd->vpic.hue); | ||
435 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
436 | y += y_diff; | ||
437 | |||
438 | sprintf(tmp, "%8x", uvd->vpic.brightness >> 8); | ||
439 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
440 | y += y_diff; | ||
441 | |||
442 | sprintf(tmp, "%8x", uvd->vpic.contrast >> 12); | ||
443 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
444 | y += y_diff; | ||
445 | |||
446 | sprintf(tmp, "%8d", uvd->vpic.whiteness >> 8); | ||
447 | usbvideo_OverlayString(uvd, frame, x, y, tmp); | ||
448 | y += y_diff; | ||
449 | } | ||
450 | |||
451 | /* | ||
452 | * usbvideo_ReportStatistics() | ||
453 | * | ||
454 | * This procedure prints packet and transfer statistics. | ||
455 | * | ||
456 | * History: | ||
457 | * 14-Jan-2000 Corrected default multiplier. | ||
458 | */ | ||
459 | static void usbvideo_ReportStatistics(const struct uvd *uvd) | ||
460 | { | ||
461 | if ((uvd != NULL) && (uvd->stats.urb_count > 0)) { | ||
462 | unsigned long allPackets, badPackets, goodPackets, percent; | ||
463 | allPackets = uvd->stats.urb_count * CAMERA_URB_FRAMES; | ||
464 | badPackets = uvd->stats.iso_skip_count + uvd->stats.iso_err_count; | ||
465 | goodPackets = allPackets - badPackets; | ||
466 | /* Calculate percentage wisely, remember integer limits */ | ||
467 | assert(allPackets != 0); | ||
468 | if (goodPackets < (((unsigned long)-1)/100)) | ||
469 | percent = (100 * goodPackets) / allPackets; | ||
470 | else | ||
471 | percent = goodPackets / (allPackets / 100); | ||
472 | info("Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%", | ||
473 | allPackets, badPackets, percent); | ||
474 | if (uvd->iso_packet_len > 0) { | ||
475 | unsigned long allBytes, xferBytes; | ||
476 | char multiplier = ' '; | ||
477 | allBytes = allPackets * uvd->iso_packet_len; | ||
478 | xferBytes = uvd->stats.data_count; | ||
479 | assert(allBytes != 0); | ||
480 | if (xferBytes < (((unsigned long)-1)/100)) | ||
481 | percent = (100 * xferBytes) / allBytes; | ||
482 | else | ||
483 | percent = xferBytes / (allBytes / 100); | ||
484 | /* Scale xferBytes for easy reading */ | ||
485 | if (xferBytes > 10*1024) { | ||
486 | xferBytes /= 1024; | ||
487 | multiplier = 'K'; | ||
488 | if (xferBytes > 10*1024) { | ||
489 | xferBytes /= 1024; | ||
490 | multiplier = 'M'; | ||
491 | if (xferBytes > 10*1024) { | ||
492 | xferBytes /= 1024; | ||
493 | multiplier = 'G'; | ||
494 | if (xferBytes > 10*1024) { | ||
495 | xferBytes /= 1024; | ||
496 | multiplier = 'T'; | ||
497 | } | ||
498 | } | ||
499 | } | ||
500 | } | ||
501 | info("Transfer Statistics: Transferred=%lu%cB Usage=%lu%%", | ||
502 | xferBytes, multiplier, percent); | ||
503 | } | ||
504 | } | ||
505 | } | ||
506 | |||
507 | /* | ||
508 | * usbvideo_TestPattern() | ||
509 | * | ||
510 | * Procedure forms a test pattern (yellow grid on blue background). | ||
511 | * | ||
512 | * Parameters: | ||
513 | * fullframe: if TRUE then entire frame is filled, otherwise the procedure | ||
514 | * continues from the current scanline. | ||
515 | * pmode 0: fill the frame with solid blue color (like on VCR or TV) | ||
516 | * 1: Draw a colored grid | ||
517 | * | ||
518 | * History: | ||
519 | * 01-Feb-2000 Created. | ||
520 | */ | ||
521 | void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode) | ||
522 | { | ||
523 | struct usbvideo_frame *frame; | ||
524 | int num_cell = 0; | ||
525 | int scan_length = 0; | ||
526 | static int num_pass = 0; | ||
527 | |||
528 | if (uvd == NULL) { | ||
529 | err("%s: uvd == NULL", __FUNCTION__); | ||
530 | return; | ||
531 | } | ||
532 | if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) { | ||
533 | err("%s: uvd->curframe=%d.", __FUNCTION__, uvd->curframe); | ||
534 | return; | ||
535 | } | ||
536 | |||
537 | /* Grab the current frame */ | ||
538 | frame = &uvd->frame[uvd->curframe]; | ||
539 | |||
540 | /* Optionally start at the beginning */ | ||
541 | if (fullframe) { | ||
542 | frame->curline = 0; | ||
543 | frame->seqRead_Length = 0; | ||
544 | } | ||
545 | #if 0 | ||
546 | { /* For debugging purposes only */ | ||
547 | char tmp[20]; | ||
548 | usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request); | ||
549 | info("testpattern: frame=%s", tmp); | ||
550 | } | ||
551 | #endif | ||
552 | /* Form every scan line */ | ||
553 | for (; frame->curline < VIDEOSIZE_Y(frame->request); frame->curline++) { | ||
554 | int i; | ||
555 | unsigned char *f = frame->data + | ||
556 | (VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL * frame->curline); | ||
557 | for (i=0; i < VIDEOSIZE_X(frame->request); i++) { | ||
558 | unsigned char cb=0x80; | ||
559 | unsigned char cg = 0; | ||
560 | unsigned char cr = 0; | ||
561 | |||
562 | if (pmode == 1) { | ||
563 | if (frame->curline % 32 == 0) | ||
564 | cb = 0, cg = cr = 0xFF; | ||
565 | else if (i % 32 == 0) { | ||
566 | if (frame->curline % 32 == 1) | ||
567 | num_cell++; | ||
568 | cb = 0, cg = cr = 0xFF; | ||
569 | } else { | ||
570 | cb = ((num_cell*7) + num_pass) & 0xFF; | ||
571 | cg = ((num_cell*5) + num_pass*2) & 0xFF; | ||
572 | cr = ((num_cell*3) + num_pass*3) & 0xFF; | ||
573 | } | ||
574 | } else { | ||
575 | /* Just the blue screen */ | ||
576 | } | ||
577 | |||
578 | *f++ = cb; | ||
579 | *f++ = cg; | ||
580 | *f++ = cr; | ||
581 | scan_length += 3; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | frame->frameState = FrameState_Done; | ||
586 | frame->seqRead_Length += scan_length; | ||
587 | ++num_pass; | ||
588 | |||
589 | /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */ | ||
590 | usbvideo_OverlayStats(uvd, frame); | ||
591 | } | ||
592 | |||
593 | EXPORT_SYMBOL(usbvideo_TestPattern); | ||
594 | |||
595 | |||
596 | #ifdef DEBUG | ||
597 | /* | ||
598 | * usbvideo_HexDump() | ||
599 | * | ||
600 | * A debugging tool. Prints hex dumps. | ||
601 | * | ||
602 | * History: | ||
603 | * 29-Jul-2000 Added printing of offsets. | ||
604 | */ | ||
605 | void usbvideo_HexDump(const unsigned char *data, int len) | ||
606 | { | ||
607 | const int bytes_per_line = 32; | ||
608 | char tmp[128]; /* 32*3 + 5 */ | ||
609 | int i, k; | ||
610 | |||
611 | for (i=k=0; len > 0; i++, len--) { | ||
612 | if (i > 0 && ((i % bytes_per_line) == 0)) { | ||
613 | printk("%s\n", tmp); | ||
614 | k=0; | ||
615 | } | ||
616 | if ((i % bytes_per_line) == 0) | ||
617 | k += sprintf(&tmp[k], "%04x: ", i); | ||
618 | k += sprintf(&tmp[k], "%02x ", data[i]); | ||
619 | } | ||
620 | if (k > 0) | ||
621 | printk("%s\n", tmp); | ||
622 | } | ||
623 | |||
624 | EXPORT_SYMBOL(usbvideo_HexDump); | ||
625 | |||
626 | #endif | ||
627 | |||
628 | /* ******************************************************************** */ | ||
629 | |||
630 | /* XXX: this piece of crap really wants some error handling.. */ | ||
631 | static void usbvideo_ClientIncModCount(struct uvd *uvd) | ||
632 | { | ||
633 | if (uvd == NULL) { | ||
634 | err("%s: uvd == NULL", __FUNCTION__); | ||
635 | return; | ||
636 | } | ||
637 | if (uvd->handle == NULL) { | ||
638 | err("%s: uvd->handle == NULL", __FUNCTION__); | ||
639 | return; | ||
640 | } | ||
641 | if (uvd->handle->md_module == NULL) { | ||
642 | err("%s: uvd->handle->md_module == NULL", __FUNCTION__); | ||
643 | return; | ||
644 | } | ||
645 | if (!try_module_get(uvd->handle->md_module)) { | ||
646 | err("%s: try_module_get() == 0", __FUNCTION__); | ||
647 | return; | ||
648 | } | ||
649 | } | ||
650 | |||
651 | static void usbvideo_ClientDecModCount(struct uvd *uvd) | ||
652 | { | ||
653 | if (uvd == NULL) { | ||
654 | err("%s: uvd == NULL", __FUNCTION__); | ||
655 | return; | ||
656 | } | ||
657 | if (uvd->handle == NULL) { | ||
658 | err("%s: uvd->handle == NULL", __FUNCTION__); | ||
659 | return; | ||
660 | } | ||
661 | if (uvd->handle->md_module == NULL) { | ||
662 | err("%s: uvd->handle->md_module == NULL", __FUNCTION__); | ||
663 | return; | ||
664 | } | ||
665 | module_put(uvd->handle->md_module); | ||
666 | } | ||
667 | |||
668 | int usbvideo_register( | ||
669 | struct usbvideo **pCams, | ||
670 | const int num_cams, | ||
671 | const int num_extra, | ||
672 | const char *driverName, | ||
673 | const struct usbvideo_cb *cbTbl, | ||
674 | struct module *md, | ||
675 | const struct usb_device_id *id_table) | ||
676 | { | ||
677 | struct usbvideo *cams; | ||
678 | int i, base_size, result; | ||
679 | |||
680 | /* Check parameters for sanity */ | ||
681 | if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) { | ||
682 | err("%s: Illegal call", __FUNCTION__); | ||
683 | return -EINVAL; | ||
684 | } | ||
685 | |||
686 | /* Check registration callback - must be set! */ | ||
687 | if (cbTbl->probe == NULL) { | ||
688 | err("%s: probe() is required!", __FUNCTION__); | ||
689 | return -EINVAL; | ||
690 | } | ||
691 | |||
692 | base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo); | ||
693 | cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL); | ||
694 | if (cams == NULL) { | ||
695 | err("Failed to allocate %d. bytes for usbvideo struct", base_size); | ||
696 | return -ENOMEM; | ||
697 | } | ||
698 | dbg("%s: Allocated $%p (%d. bytes) for %d. cameras", | ||
699 | __FUNCTION__, cams, base_size, num_cams); | ||
700 | |||
701 | /* Copy callbacks, apply defaults for those that are not set */ | ||
702 | memmove(&cams->cb, cbTbl, sizeof(cams->cb)); | ||
703 | if (cams->cb.getFrame == NULL) | ||
704 | cams->cb.getFrame = usbvideo_GetFrame; | ||
705 | if (cams->cb.disconnect == NULL) | ||
706 | cams->cb.disconnect = usbvideo_Disconnect; | ||
707 | if (cams->cb.startDataPump == NULL) | ||
708 | cams->cb.startDataPump = usbvideo_StartDataPump; | ||
709 | if (cams->cb.stopDataPump == NULL) | ||
710 | cams->cb.stopDataPump = usbvideo_StopDataPump; | ||
711 | |||
712 | cams->num_cameras = num_cams; | ||
713 | cams->cam = (struct uvd *) &cams[1]; | ||
714 | cams->md_module = md; | ||
715 | if (cams->md_module == NULL) | ||
716 | warn("%s: module == NULL!", __FUNCTION__); | ||
717 | mutex_init(&cams->lock); /* to 1 == available */ | ||
718 | |||
719 | for (i = 0; i < num_cams; i++) { | ||
720 | struct uvd *up = &cams->cam[i]; | ||
721 | |||
722 | up->handle = cams; | ||
723 | |||
724 | /* Allocate user_data separately because of kmalloc's limits */ | ||
725 | if (num_extra > 0) { | ||
726 | up->user_size = num_cams * num_extra; | ||
727 | up->user_data = kmalloc(up->user_size, GFP_KERNEL); | ||
728 | if (up->user_data == NULL) { | ||
729 | err("%s: Failed to allocate user_data (%d. bytes)", | ||
730 | __FUNCTION__, up->user_size); | ||
731 | while (i) { | ||
732 | up = &cams->cam[--i]; | ||
733 | kfree(up->user_data); | ||
734 | } | ||
735 | kfree(cams); | ||
736 | return -ENOMEM; | ||
737 | } | ||
738 | dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)", | ||
739 | __FUNCTION__, i, up->user_data, up->user_size); | ||
740 | } | ||
741 | } | ||
742 | |||
743 | /* | ||
744 | * Register ourselves with USB stack. | ||
745 | */ | ||
746 | strcpy(cams->drvName, (driverName != NULL) ? driverName : "Unknown"); | ||
747 | cams->usbdrv.name = cams->drvName; | ||
748 | cams->usbdrv.probe = cams->cb.probe; | ||
749 | cams->usbdrv.disconnect = cams->cb.disconnect; | ||
750 | cams->usbdrv.id_table = id_table; | ||
751 | |||
752 | /* | ||
753 | * Update global handle to usbvideo. This is very important | ||
754 | * because probe() can be called before usb_register() returns. | ||
755 | * If the handle is not yet updated then the probe() will fail. | ||
756 | */ | ||
757 | *pCams = cams; | ||
758 | result = usb_register(&cams->usbdrv); | ||
759 | if (result) { | ||
760 | for (i = 0; i < num_cams; i++) { | ||
761 | struct uvd *up = &cams->cam[i]; | ||
762 | kfree(up->user_data); | ||
763 | } | ||
764 | kfree(cams); | ||
765 | } | ||
766 | |||
767 | return result; | ||
768 | } | ||
769 | |||
770 | EXPORT_SYMBOL(usbvideo_register); | ||
771 | |||
772 | /* | ||
773 | * usbvideo_Deregister() | ||
774 | * | ||
775 | * Procedure frees all usbvideo and user data structures. Be warned that | ||
776 | * if you had some dynamically allocated components in ->user field then | ||
777 | * you should free them before calling here. | ||
778 | */ | ||
779 | void usbvideo_Deregister(struct usbvideo **pCams) | ||
780 | { | ||
781 | struct usbvideo *cams; | ||
782 | int i; | ||
783 | |||
784 | if (pCams == NULL) { | ||
785 | err("%s: pCams == NULL", __FUNCTION__); | ||
786 | return; | ||
787 | } | ||
788 | cams = *pCams; | ||
789 | if (cams == NULL) { | ||
790 | err("%s: cams == NULL", __FUNCTION__); | ||
791 | return; | ||
792 | } | ||
793 | |||
794 | dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName); | ||
795 | usb_deregister(&cams->usbdrv); | ||
796 | |||
797 | dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras); | ||
798 | for (i=0; i < cams->num_cameras; i++) { | ||
799 | struct uvd *up = &cams->cam[i]; | ||
800 | int warning = 0; | ||
801 | |||
802 | if (up->user_data != NULL) { | ||
803 | if (up->user_size <= 0) | ||
804 | ++warning; | ||
805 | } else { | ||
806 | if (up->user_size > 0) | ||
807 | ++warning; | ||
808 | } | ||
809 | if (warning) { | ||
810 | err("%s: Warning: user_data=$%p user_size=%d.", | ||
811 | __FUNCTION__, up->user_data, up->user_size); | ||
812 | } else { | ||
813 | dbg("%s: Freeing %d. $%p->user_data=$%p", | ||
814 | __FUNCTION__, i, up, up->user_data); | ||
815 | kfree(up->user_data); | ||
816 | } | ||
817 | } | ||
818 | /* Whole array was allocated in one chunk */ | ||
819 | dbg("%s: Freed %d uvd structures", | ||
820 | __FUNCTION__, cams->num_cameras); | ||
821 | kfree(cams); | ||
822 | *pCams = NULL; | ||
823 | } | ||
824 | |||
825 | EXPORT_SYMBOL(usbvideo_Deregister); | ||
826 | |||
827 | /* | ||
828 | * usbvideo_Disconnect() | ||
829 | * | ||
830 | * This procedure stops all driver activity. Deallocation of | ||
831 | * the interface-private structure (pointed by 'ptr') is done now | ||
832 | * (if we don't have any open files) or later, when those files | ||
833 | * are closed. After that driver should be removable. | ||
834 | * | ||
835 | * This code handles surprise removal. The uvd->user is a counter which | ||
836 | * increments on open() and decrements on close(). If we see here that | ||
837 | * this counter is not 0 then we have a client who still has us opened. | ||
838 | * We set uvd->remove_pending flag as early as possible, and after that | ||
839 | * all access to the camera will gracefully fail. These failures should | ||
840 | * prompt client to (eventually) close the video device, and then - in | ||
841 | * usbvideo_v4l_close() - we decrement uvd->uvd_used and usage counter. | ||
842 | * | ||
843 | * History: | ||
844 | * 22-Jan-2000 Added polling of MOD_IN_USE to delay removal until all users gone. | ||
845 | * 27-Jan-2000 Reworked to allow pending disconnects; see xxx_close() | ||
846 | * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). | ||
847 | * 19-Oct-2000 Moved to usbvideo module. | ||
848 | */ | ||
849 | static void usbvideo_Disconnect(struct usb_interface *intf) | ||
850 | { | ||
851 | struct uvd *uvd = usb_get_intfdata (intf); | ||
852 | int i; | ||
853 | |||
854 | if (uvd == NULL) { | ||
855 | err("%s($%p): Illegal call.", __FUNCTION__, intf); | ||
856 | return; | ||
857 | } | ||
858 | |||
859 | usb_set_intfdata (intf, NULL); | ||
860 | |||
861 | usbvideo_ClientIncModCount(uvd); | ||
862 | if (uvd->debug > 0) | ||
863 | info("%s(%p.)", __FUNCTION__, intf); | ||
864 | |||
865 | mutex_lock(&uvd->lock); | ||
866 | uvd->remove_pending = 1; /* Now all ISO data will be ignored */ | ||
867 | |||
868 | /* At this time we ask to cancel outstanding URBs */ | ||
869 | GET_CALLBACK(uvd, stopDataPump)(uvd); | ||
870 | |||
871 | for (i=0; i < USBVIDEO_NUMSBUF; i++) | ||
872 | usb_free_urb(uvd->sbuf[i].urb); | ||
873 | |||
874 | usb_put_dev(uvd->dev); | ||
875 | uvd->dev = NULL; /* USB device is no more */ | ||
876 | |||
877 | video_unregister_device(&uvd->vdev); | ||
878 | if (uvd->debug > 0) | ||
879 | info("%s: Video unregistered.", __FUNCTION__); | ||
880 | |||
881 | if (uvd->user) | ||
882 | info("%s: In use, disconnect pending.", __FUNCTION__); | ||
883 | else | ||
884 | usbvideo_CameraRelease(uvd); | ||
885 | mutex_unlock(&uvd->lock); | ||
886 | info("USB camera disconnected."); | ||
887 | |||
888 | usbvideo_ClientDecModCount(uvd); | ||
889 | } | ||
890 | |||
891 | /* | ||
892 | * usbvideo_CameraRelease() | ||
893 | * | ||
894 | * This code does final release of uvd. This happens | ||
895 | * after the device is disconnected -and- all clients | ||
896 | * closed their files. | ||
897 | * | ||
898 | * History: | ||
899 | * 27-Jan-2000 Created. | ||
900 | */ | ||
901 | static void usbvideo_CameraRelease(struct uvd *uvd) | ||
902 | { | ||
903 | if (uvd == NULL) { | ||
904 | err("%s: Illegal call", __FUNCTION__); | ||
905 | return; | ||
906 | } | ||
907 | |||
908 | RingQueue_Free(&uvd->dp); | ||
909 | if (VALID_CALLBACK(uvd, userFree)) | ||
910 | GET_CALLBACK(uvd, userFree)(uvd); | ||
911 | uvd->uvd_used = 0; /* This is atomic, no need to take mutex */ | ||
912 | } | ||
913 | |||
914 | /* | ||
915 | * usbvideo_find_struct() | ||
916 | * | ||
917 | * This code searches the array of preallocated (static) structures | ||
918 | * and returns index of the first one that isn't in use. Returns -1 | ||
919 | * if there are no free structures. | ||
920 | * | ||
921 | * History: | ||
922 | * 27-Jan-2000 Created. | ||
923 | */ | ||
924 | static int usbvideo_find_struct(struct usbvideo *cams) | ||
925 | { | ||
926 | int u, rv = -1; | ||
927 | |||
928 | if (cams == NULL) { | ||
929 | err("No usbvideo handle?"); | ||
930 | return -1; | ||
931 | } | ||
932 | mutex_lock(&cams->lock); | ||
933 | for (u = 0; u < cams->num_cameras; u++) { | ||
934 | struct uvd *uvd = &cams->cam[u]; | ||
935 | if (!uvd->uvd_used) /* This one is free */ | ||
936 | { | ||
937 | uvd->uvd_used = 1; /* In use now */ | ||
938 | mutex_init(&uvd->lock); /* to 1 == available */ | ||
939 | uvd->dev = NULL; | ||
940 | rv = u; | ||
941 | break; | ||
942 | } | ||
943 | } | ||
944 | mutex_unlock(&cams->lock); | ||
945 | return rv; | ||
946 | } | ||
947 | |||
948 | static struct file_operations usbvideo_fops = { | ||
949 | .owner = THIS_MODULE, | ||
950 | .open = usbvideo_v4l_open, | ||
951 | .release =usbvideo_v4l_close, | ||
952 | .read = usbvideo_v4l_read, | ||
953 | .mmap = usbvideo_v4l_mmap, | ||
954 | .ioctl = usbvideo_v4l_ioctl, | ||
955 | .compat_ioctl = v4l_compat_ioctl32, | ||
956 | .llseek = no_llseek, | ||
957 | }; | ||
958 | static const struct video_device usbvideo_template = { | ||
959 | .owner = THIS_MODULE, | ||
960 | .type = VID_TYPE_CAPTURE, | ||
961 | .hardware = VID_HARDWARE_CPIA, | ||
962 | .fops = &usbvideo_fops, | ||
963 | }; | ||
964 | |||
965 | struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams) | ||
966 | { | ||
967 | int i, devnum; | ||
968 | struct uvd *uvd = NULL; | ||
969 | |||
970 | if (cams == NULL) { | ||
971 | err("No usbvideo handle?"); | ||
972 | return NULL; | ||
973 | } | ||
974 | |||
975 | devnum = usbvideo_find_struct(cams); | ||
976 | if (devnum == -1) { | ||
977 | err("IBM USB camera driver: Too many devices!"); | ||
978 | return NULL; | ||
979 | } | ||
980 | uvd = &cams->cam[devnum]; | ||
981 | dbg("Device entry #%d. at $%p", devnum, uvd); | ||
982 | |||
983 | /* Not relying upon caller we increase module counter ourselves */ | ||
984 | usbvideo_ClientIncModCount(uvd); | ||
985 | |||
986 | mutex_lock(&uvd->lock); | ||
987 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
988 | uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); | ||
989 | if (uvd->sbuf[i].urb == NULL) { | ||
990 | err("usb_alloc_urb(%d.) failed.", FRAMES_PER_DESC); | ||
991 | uvd->uvd_used = 0; | ||
992 | uvd = NULL; | ||
993 | goto allocate_done; | ||
994 | } | ||
995 | } | ||
996 | uvd->user=0; | ||
997 | uvd->remove_pending = 0; | ||
998 | uvd->last_error = 0; | ||
999 | RingQueue_Initialize(&uvd->dp); | ||
1000 | |||
1001 | /* Initialize video device structure */ | ||
1002 | uvd->vdev = usbvideo_template; | ||
1003 | sprintf(uvd->vdev.name, "%.20s USB Camera", cams->drvName); | ||
1004 | /* | ||
1005 | * The client is free to overwrite those because we | ||
1006 | * return control to the client's probe function right now. | ||
1007 | */ | ||
1008 | allocate_done: | ||
1009 | mutex_unlock(&uvd->lock); | ||
1010 | usbvideo_ClientDecModCount(uvd); | ||
1011 | return uvd; | ||
1012 | } | ||
1013 | |||
1014 | EXPORT_SYMBOL(usbvideo_AllocateDevice); | ||
1015 | |||
1016 | int usbvideo_RegisterVideoDevice(struct uvd *uvd) | ||
1017 | { | ||
1018 | char tmp1[20], tmp2[20]; /* Buffers for printing */ | ||
1019 | |||
1020 | if (uvd == NULL) { | ||
1021 | err("%s: Illegal call.", __FUNCTION__); | ||
1022 | return -EINVAL; | ||
1023 | } | ||
1024 | if (uvd->video_endp == 0) { | ||
1025 | info("%s: No video endpoint specified; data pump disabled.", __FUNCTION__); | ||
1026 | } | ||
1027 | if (uvd->paletteBits == 0) { | ||
1028 | err("%s: No palettes specified!", __FUNCTION__); | ||
1029 | return -EINVAL; | ||
1030 | } | ||
1031 | if (uvd->defaultPalette == 0) { | ||
1032 | info("%s: No default palette!", __FUNCTION__); | ||
1033 | } | ||
1034 | |||
1035 | uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) * | ||
1036 | VIDEOSIZE_Y(uvd->canvas) * V4L_BYTES_PER_PIXEL; | ||
1037 | usbvideo_VideosizeToString(tmp1, sizeof(tmp1), uvd->videosize); | ||
1038 | usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas); | ||
1039 | |||
1040 | if (uvd->debug > 0) { | ||
1041 | info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx", | ||
1042 | __FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits); | ||
1043 | } | ||
1044 | if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { | ||
1045 | err("%s: video_register_device failed", __FUNCTION__); | ||
1046 | return -EPIPE; | ||
1047 | } | ||
1048 | if (uvd->debug > 1) { | ||
1049 | info("%s: video_register_device() successful", __FUNCTION__); | ||
1050 | } | ||
1051 | if (uvd->dev == NULL) { | ||
1052 | err("%s: uvd->dev == NULL", __FUNCTION__); | ||
1053 | return -EINVAL; | ||
1054 | } | ||
1055 | |||
1056 | info("%s on /dev/video%d: canvas=%s videosize=%s", | ||
1057 | (uvd->handle != NULL) ? uvd->handle->drvName : "???", | ||
1058 | uvd->vdev.minor, tmp2, tmp1); | ||
1059 | |||
1060 | usb_get_dev(uvd->dev); | ||
1061 | return 0; | ||
1062 | } | ||
1063 | |||
1064 | EXPORT_SYMBOL(usbvideo_RegisterVideoDevice); | ||
1065 | |||
1066 | /* ******************************************************************** */ | ||
1067 | |||
1068 | static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma) | ||
1069 | { | ||
1070 | struct uvd *uvd = file->private_data; | ||
1071 | unsigned long start = vma->vm_start; | ||
1072 | unsigned long size = vma->vm_end-vma->vm_start; | ||
1073 | unsigned long page, pos; | ||
1074 | |||
1075 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
1076 | return -EFAULT; | ||
1077 | |||
1078 | if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) | ||
1079 | return -EINVAL; | ||
1080 | |||
1081 | pos = (unsigned long) uvd->fbuf; | ||
1082 | while (size > 0) { | ||
1083 | page = vmalloc_to_pfn((void *)pos); | ||
1084 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) | ||
1085 | return -EAGAIN; | ||
1086 | |||
1087 | start += PAGE_SIZE; | ||
1088 | pos += PAGE_SIZE; | ||
1089 | if (size > PAGE_SIZE) | ||
1090 | size -= PAGE_SIZE; | ||
1091 | else | ||
1092 | size = 0; | ||
1093 | } | ||
1094 | |||
1095 | return 0; | ||
1096 | } | ||
1097 | |||
1098 | /* | ||
1099 | * usbvideo_v4l_open() | ||
1100 | * | ||
1101 | * This is part of Video 4 Linux API. The driver can be opened by one | ||
1102 | * client only (checks internal counter 'uvdser'). The procedure | ||
1103 | * then allocates buffers needed for video processing. | ||
1104 | * | ||
1105 | * History: | ||
1106 | * 22-Jan-2000 Rewrote, moved scratch buffer allocation here. Now the | ||
1107 | * camera is also initialized here (once per connect), at | ||
1108 | * expense of V4L client (it waits on open() call). | ||
1109 | * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. | ||
1110 | * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). | ||
1111 | */ | ||
1112 | static int usbvideo_v4l_open(struct inode *inode, struct file *file) | ||
1113 | { | ||
1114 | struct video_device *dev = video_devdata(file); | ||
1115 | struct uvd *uvd = (struct uvd *) dev; | ||
1116 | const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len; | ||
1117 | int i, errCode = 0; | ||
1118 | |||
1119 | if (uvd->debug > 1) | ||
1120 | info("%s($%p)", __FUNCTION__, dev); | ||
1121 | |||
1122 | usbvideo_ClientIncModCount(uvd); | ||
1123 | mutex_lock(&uvd->lock); | ||
1124 | |||
1125 | if (uvd->user) { | ||
1126 | err("%s: Someone tried to open an already opened device!", __FUNCTION__); | ||
1127 | errCode = -EBUSY; | ||
1128 | } else { | ||
1129 | /* Clear statistics */ | ||
1130 | memset(&uvd->stats, 0, sizeof(uvd->stats)); | ||
1131 | |||
1132 | /* Clean pointers so we know if we allocated something */ | ||
1133 | for (i=0; i < USBVIDEO_NUMSBUF; i++) | ||
1134 | uvd->sbuf[i].data = NULL; | ||
1135 | |||
1136 | /* Allocate memory for the frame buffers */ | ||
1137 | uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size; | ||
1138 | uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size); | ||
1139 | RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE); | ||
1140 | if ((uvd->fbuf == NULL) || | ||
1141 | (!RingQueue_IsAllocated(&uvd->dp))) { | ||
1142 | err("%s: Failed to allocate fbuf or dp", __FUNCTION__); | ||
1143 | errCode = -ENOMEM; | ||
1144 | } else { | ||
1145 | /* Allocate all buffers */ | ||
1146 | for (i=0; i < USBVIDEO_NUMFRAMES; i++) { | ||
1147 | uvd->frame[i].frameState = FrameState_Unused; | ||
1148 | uvd->frame[i].data = uvd->fbuf + i*(uvd->max_frame_size); | ||
1149 | /* | ||
1150 | * Set default sizes in case IOCTL (VIDIOCMCAPTURE) | ||
1151 | * is not used (using read() instead). | ||
1152 | */ | ||
1153 | uvd->frame[i].canvas = uvd->canvas; | ||
1154 | uvd->frame[i].seqRead_Index = 0; | ||
1155 | } | ||
1156 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
1157 | uvd->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL); | ||
1158 | if (uvd->sbuf[i].data == NULL) { | ||
1159 | errCode = -ENOMEM; | ||
1160 | break; | ||
1161 | } | ||
1162 | } | ||
1163 | } | ||
1164 | if (errCode != 0) { | ||
1165 | /* Have to free all that memory */ | ||
1166 | if (uvd->fbuf != NULL) { | ||
1167 | usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); | ||
1168 | uvd->fbuf = NULL; | ||
1169 | } | ||
1170 | RingQueue_Free(&uvd->dp); | ||
1171 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
1172 | kfree(uvd->sbuf[i].data); | ||
1173 | uvd->sbuf[i].data = NULL; | ||
1174 | } | ||
1175 | } | ||
1176 | } | ||
1177 | |||
1178 | /* If so far no errors then we shall start the camera */ | ||
1179 | if (errCode == 0) { | ||
1180 | /* Start data pump if we have valid endpoint */ | ||
1181 | if (uvd->video_endp != 0) | ||
1182 | errCode = GET_CALLBACK(uvd, startDataPump)(uvd); | ||
1183 | if (errCode == 0) { | ||
1184 | if (VALID_CALLBACK(uvd, setupOnOpen)) { | ||
1185 | if (uvd->debug > 1) | ||
1186 | info("%s: setupOnOpen callback", __FUNCTION__); | ||
1187 | errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd); | ||
1188 | if (errCode < 0) { | ||
1189 | err("%s: setupOnOpen callback failed (%d.).", | ||
1190 | __FUNCTION__, errCode); | ||
1191 | } else if (uvd->debug > 1) { | ||
1192 | info("%s: setupOnOpen callback successful", __FUNCTION__); | ||
1193 | } | ||
1194 | } | ||
1195 | if (errCode == 0) { | ||
1196 | uvd->settingsAdjusted = 0; | ||
1197 | if (uvd->debug > 1) | ||
1198 | info("%s: Open succeeded.", __FUNCTION__); | ||
1199 | uvd->user++; | ||
1200 | file->private_data = uvd; | ||
1201 | } | ||
1202 | } | ||
1203 | } | ||
1204 | mutex_unlock(&uvd->lock); | ||
1205 | if (errCode != 0) | ||
1206 | usbvideo_ClientDecModCount(uvd); | ||
1207 | if (uvd->debug > 0) | ||
1208 | info("%s: Returning %d.", __FUNCTION__, errCode); | ||
1209 | return errCode; | ||
1210 | } | ||
1211 | |||
1212 | /* | ||
1213 | * usbvideo_v4l_close() | ||
1214 | * | ||
1215 | * This is part of Video 4 Linux API. The procedure | ||
1216 | * stops streaming and deallocates all buffers that were earlier | ||
1217 | * allocated in usbvideo_v4l_open(). | ||
1218 | * | ||
1219 | * History: | ||
1220 | * 22-Jan-2000 Moved scratch buffer deallocation here. | ||
1221 | * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. | ||
1222 | * 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep. | ||
1223 | */ | ||
1224 | static int usbvideo_v4l_close(struct inode *inode, struct file *file) | ||
1225 | { | ||
1226 | struct video_device *dev = file->private_data; | ||
1227 | struct uvd *uvd = (struct uvd *) dev; | ||
1228 | int i; | ||
1229 | |||
1230 | if (uvd->debug > 1) | ||
1231 | info("%s($%p)", __FUNCTION__, dev); | ||
1232 | |||
1233 | mutex_lock(&uvd->lock); | ||
1234 | GET_CALLBACK(uvd, stopDataPump)(uvd); | ||
1235 | usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); | ||
1236 | uvd->fbuf = NULL; | ||
1237 | RingQueue_Free(&uvd->dp); | ||
1238 | |||
1239 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
1240 | kfree(uvd->sbuf[i].data); | ||
1241 | uvd->sbuf[i].data = NULL; | ||
1242 | } | ||
1243 | |||
1244 | #if USBVIDEO_REPORT_STATS | ||
1245 | usbvideo_ReportStatistics(uvd); | ||
1246 | #endif | ||
1247 | |||
1248 | uvd->user--; | ||
1249 | if (uvd->remove_pending) { | ||
1250 | if (uvd->debug > 0) | ||
1251 | info("usbvideo_v4l_close: Final disconnect."); | ||
1252 | usbvideo_CameraRelease(uvd); | ||
1253 | } | ||
1254 | mutex_unlock(&uvd->lock); | ||
1255 | usbvideo_ClientDecModCount(uvd); | ||
1256 | |||
1257 | if (uvd->debug > 1) | ||
1258 | info("%s: Completed.", __FUNCTION__); | ||
1259 | file->private_data = NULL; | ||
1260 | return 0; | ||
1261 | } | ||
1262 | |||
1263 | /* | ||
1264 | * usbvideo_v4l_ioctl() | ||
1265 | * | ||
1266 | * This is part of Video 4 Linux API. The procedure handles ioctl() calls. | ||
1267 | * | ||
1268 | * History: | ||
1269 | * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings. | ||
1270 | */ | ||
1271 | static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file, | ||
1272 | unsigned int cmd, void *arg) | ||
1273 | { | ||
1274 | struct uvd *uvd = file->private_data; | ||
1275 | |||
1276 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
1277 | return -EIO; | ||
1278 | |||
1279 | switch (cmd) { | ||
1280 | case VIDIOCGCAP: | ||
1281 | { | ||
1282 | struct video_capability *b = arg; | ||
1283 | *b = uvd->vcap; | ||
1284 | return 0; | ||
1285 | } | ||
1286 | case VIDIOCGCHAN: | ||
1287 | { | ||
1288 | struct video_channel *v = arg; | ||
1289 | *v = uvd->vchan; | ||
1290 | return 0; | ||
1291 | } | ||
1292 | case VIDIOCSCHAN: | ||
1293 | { | ||
1294 | struct video_channel *v = arg; | ||
1295 | if (v->channel != 0) | ||
1296 | return -EINVAL; | ||
1297 | return 0; | ||
1298 | } | ||
1299 | case VIDIOCGPICT: | ||
1300 | { | ||
1301 | struct video_picture *pic = arg; | ||
1302 | *pic = uvd->vpic; | ||
1303 | return 0; | ||
1304 | } | ||
1305 | case VIDIOCSPICT: | ||
1306 | { | ||
1307 | struct video_picture *pic = arg; | ||
1308 | /* | ||
1309 | * Use temporary 'video_picture' structure to preserve our | ||
1310 | * own settings (such as color depth, palette) that we | ||
1311 | * aren't allowing everyone (V4L client) to change. | ||
1312 | */ | ||
1313 | uvd->vpic.brightness = pic->brightness; | ||
1314 | uvd->vpic.hue = pic->hue; | ||
1315 | uvd->vpic.colour = pic->colour; | ||
1316 | uvd->vpic.contrast = pic->contrast; | ||
1317 | uvd->settingsAdjusted = 0; /* Will force new settings */ | ||
1318 | return 0; | ||
1319 | } | ||
1320 | case VIDIOCSWIN: | ||
1321 | { | ||
1322 | struct video_window *vw = arg; | ||
1323 | |||
1324 | if(VALID_CALLBACK(uvd, setVideoMode)) { | ||
1325 | return GET_CALLBACK(uvd, setVideoMode)(uvd, vw); | ||
1326 | } | ||
1327 | |||
1328 | if (vw->flags) | ||
1329 | return -EINVAL; | ||
1330 | if (vw->clipcount) | ||
1331 | return -EINVAL; | ||
1332 | if (vw->width != VIDEOSIZE_X(uvd->canvas)) | ||
1333 | return -EINVAL; | ||
1334 | if (vw->height != VIDEOSIZE_Y(uvd->canvas)) | ||
1335 | return -EINVAL; | ||
1336 | |||
1337 | return 0; | ||
1338 | } | ||
1339 | case VIDIOCGWIN: | ||
1340 | { | ||
1341 | struct video_window *vw = arg; | ||
1342 | |||
1343 | vw->x = 0; | ||
1344 | vw->y = 0; | ||
1345 | vw->width = VIDEOSIZE_X(uvd->videosize); | ||
1346 | vw->height = VIDEOSIZE_Y(uvd->videosize); | ||
1347 | vw->chromakey = 0; | ||
1348 | if (VALID_CALLBACK(uvd, getFPS)) | ||
1349 | vw->flags = GET_CALLBACK(uvd, getFPS)(uvd); | ||
1350 | else | ||
1351 | vw->flags = 10; /* FIXME: do better! */ | ||
1352 | return 0; | ||
1353 | } | ||
1354 | case VIDIOCGMBUF: | ||
1355 | { | ||
1356 | struct video_mbuf *vm = arg; | ||
1357 | int i; | ||
1358 | |||
1359 | memset(vm, 0, sizeof(*vm)); | ||
1360 | vm->size = uvd->max_frame_size * USBVIDEO_NUMFRAMES; | ||
1361 | vm->frames = USBVIDEO_NUMFRAMES; | ||
1362 | for(i = 0; i < USBVIDEO_NUMFRAMES; i++) | ||
1363 | vm->offsets[i] = i * uvd->max_frame_size; | ||
1364 | |||
1365 | return 0; | ||
1366 | } | ||
1367 | case VIDIOCMCAPTURE: | ||
1368 | { | ||
1369 | struct video_mmap *vm = arg; | ||
1370 | |||
1371 | if (uvd->debug >= 1) { | ||
1372 | info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.", | ||
1373 | vm->frame, vm->width, vm->height, vm->format); | ||
1374 | } | ||
1375 | /* | ||
1376 | * Check if the requested size is supported. If the requestor | ||
1377 | * requests too big a frame then we may be tricked into accessing | ||
1378 | * outside of own preallocated frame buffer (in uvd->frame). | ||
1379 | * This will cause oops or a security hole. Theoretically, we | ||
1380 | * could only clamp the size down to acceptable bounds, but then | ||
1381 | * we'd need to figure out how to insert our smaller buffer into | ||
1382 | * larger caller's buffer... this is not an easy question. So we | ||
1383 | * here just flatly reject too large requests, assuming that the | ||
1384 | * caller will resubmit with smaller size. Callers should know | ||
1385 | * what size we support (returned by VIDIOCGCAP). However vidcat, | ||
1386 | * for one, does not care and allows to ask for any size. | ||
1387 | */ | ||
1388 | if ((vm->width > VIDEOSIZE_X(uvd->canvas)) || | ||
1389 | (vm->height > VIDEOSIZE_Y(uvd->canvas))) { | ||
1390 | if (uvd->debug > 0) { | ||
1391 | info("VIDIOCMCAPTURE: Size=%dx%d too large; " | ||
1392 | "allowed only up to %ldx%ld", vm->width, vm->height, | ||
1393 | VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas)); | ||
1394 | } | ||
1395 | return -EINVAL; | ||
1396 | } | ||
1397 | /* Check if the palette is supported */ | ||
1398 | if (((1L << vm->format) & uvd->paletteBits) == 0) { | ||
1399 | if (uvd->debug > 0) { | ||
1400 | info("VIDIOCMCAPTURE: format=%d. not supported" | ||
1401 | " (paletteBits=$%08lx)", | ||
1402 | vm->format, uvd->paletteBits); | ||
1403 | } | ||
1404 | return -EINVAL; | ||
1405 | } | ||
1406 | if ((vm->frame < 0) || (vm->frame >= USBVIDEO_NUMFRAMES)) { | ||
1407 | err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm->frame, USBVIDEO_NUMFRAMES-1); | ||
1408 | return -EINVAL; | ||
1409 | } | ||
1410 | if (uvd->frame[vm->frame].frameState == FrameState_Grabbing) { | ||
1411 | /* Not an error - can happen */ | ||
1412 | } | ||
1413 | uvd->frame[vm->frame].request = VIDEOSIZE(vm->width, vm->height); | ||
1414 | uvd->frame[vm->frame].palette = vm->format; | ||
1415 | |||
1416 | /* Mark it as ready */ | ||
1417 | uvd->frame[vm->frame].frameState = FrameState_Ready; | ||
1418 | |||
1419 | return usbvideo_NewFrame(uvd, vm->frame); | ||
1420 | } | ||
1421 | case VIDIOCSYNC: | ||
1422 | { | ||
1423 | int *frameNum = arg; | ||
1424 | int ret; | ||
1425 | |||
1426 | if (*frameNum < 0 || *frameNum >= USBVIDEO_NUMFRAMES) | ||
1427 | return -EINVAL; | ||
1428 | |||
1429 | if (uvd->debug >= 1) | ||
1430 | info("VIDIOCSYNC: syncing to frame %d.", *frameNum); | ||
1431 | if (uvd->flags & FLAGS_NO_DECODING) | ||
1432 | ret = usbvideo_GetFrame(uvd, *frameNum); | ||
1433 | else if (VALID_CALLBACK(uvd, getFrame)) { | ||
1434 | ret = GET_CALLBACK(uvd, getFrame)(uvd, *frameNum); | ||
1435 | if ((ret < 0) && (uvd->debug >= 1)) { | ||
1436 | err("VIDIOCSYNC: getFrame() returned %d.", ret); | ||
1437 | } | ||
1438 | } else { | ||
1439 | err("VIDIOCSYNC: getFrame is not set"); | ||
1440 | ret = -EFAULT; | ||
1441 | } | ||
1442 | |||
1443 | /* | ||
1444 | * The frame is in FrameState_Done_Hold state. Release it | ||
1445 | * right now because its data is already mapped into | ||
1446 | * the user space and it's up to the application to | ||
1447 | * make use of it until it asks for another frame. | ||
1448 | */ | ||
1449 | uvd->frame[*frameNum].frameState = FrameState_Unused; | ||
1450 | return ret; | ||
1451 | } | ||
1452 | case VIDIOCGFBUF: | ||
1453 | { | ||
1454 | struct video_buffer *vb = arg; | ||
1455 | |||
1456 | memset(vb, 0, sizeof(*vb)); | ||
1457 | return 0; | ||
1458 | } | ||
1459 | case VIDIOCKEY: | ||
1460 | return 0; | ||
1461 | |||
1462 | case VIDIOCCAPTURE: | ||
1463 | return -EINVAL; | ||
1464 | |||
1465 | case VIDIOCSFBUF: | ||
1466 | |||
1467 | case VIDIOCGTUNER: | ||
1468 | case VIDIOCSTUNER: | ||
1469 | |||
1470 | case VIDIOCGFREQ: | ||
1471 | case VIDIOCSFREQ: | ||
1472 | |||
1473 | case VIDIOCGAUDIO: | ||
1474 | case VIDIOCSAUDIO: | ||
1475 | return -EINVAL; | ||
1476 | |||
1477 | default: | ||
1478 | return -ENOIOCTLCMD; | ||
1479 | } | ||
1480 | return 0; | ||
1481 | } | ||
1482 | |||
1483 | static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file, | ||
1484 | unsigned int cmd, unsigned long arg) | ||
1485 | { | ||
1486 | return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl); | ||
1487 | } | ||
1488 | |||
1489 | /* | ||
1490 | * usbvideo_v4l_read() | ||
1491 | * | ||
1492 | * This is mostly boring stuff. We simply ask for a frame and when it | ||
1493 | * arrives copy all the video data from it into user space. There is | ||
1494 | * no obvious need to override this method. | ||
1495 | * | ||
1496 | * History: | ||
1497 | * 20-Oct-2000 Created. | ||
1498 | * 01-Nov-2000 Added mutex (uvd->lock). | ||
1499 | */ | ||
1500 | static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf, | ||
1501 | size_t count, loff_t *ppos) | ||
1502 | { | ||
1503 | struct uvd *uvd = file->private_data; | ||
1504 | int noblock = file->f_flags & O_NONBLOCK; | ||
1505 | int frmx = -1, i; | ||
1506 | struct usbvideo_frame *frame; | ||
1507 | |||
1508 | if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL)) | ||
1509 | return -EFAULT; | ||
1510 | |||
1511 | if (uvd->debug >= 1) | ||
1512 | info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock); | ||
1513 | |||
1514 | mutex_lock(&uvd->lock); | ||
1515 | |||
1516 | /* See if a frame is completed, then use it. */ | ||
1517 | for(i = 0; i < USBVIDEO_NUMFRAMES; i++) { | ||
1518 | if ((uvd->frame[i].frameState == FrameState_Done) || | ||
1519 | (uvd->frame[i].frameState == FrameState_Done_Hold) || | ||
1520 | (uvd->frame[i].frameState == FrameState_Error)) { | ||
1521 | frmx = i; | ||
1522 | break; | ||
1523 | } | ||
1524 | } | ||
1525 | |||
1526 | /* FIXME: If we don't start a frame here then who ever does? */ | ||
1527 | if (noblock && (frmx == -1)) { | ||
1528 | count = -EAGAIN; | ||
1529 | goto read_done; | ||
1530 | } | ||
1531 | |||
1532 | /* | ||
1533 | * If no FrameState_Done, look for a FrameState_Grabbing state. | ||
1534 | * See if a frame is in process (grabbing), then use it. | ||
1535 | * We will need to wait until it becomes cooked, of course. | ||
1536 | */ | ||
1537 | if (frmx == -1) { | ||
1538 | for(i = 0; i < USBVIDEO_NUMFRAMES; i++) { | ||
1539 | if (uvd->frame[i].frameState == FrameState_Grabbing) { | ||
1540 | frmx = i; | ||
1541 | break; | ||
1542 | } | ||
1543 | } | ||
1544 | } | ||
1545 | |||
1546 | /* | ||
1547 | * If no frame is active, start one. We don't care which one | ||
1548 | * it will be, so #0 is as good as any. | ||
1549 | * In read access mode we don't have convenience of VIDIOCMCAPTURE | ||
1550 | * to specify the requested palette (video format) on per-frame | ||
1551 | * basis. This means that we have to return data in -some- format | ||
1552 | * and just hope that the client knows what to do with it. | ||
1553 | * The default format is configured in uvd->defaultPalette field | ||
1554 | * as one of VIDEO_PALETTE_xxx values. We stuff it into the new | ||
1555 | * frame and initiate the frame filling process. | ||
1556 | */ | ||
1557 | if (frmx == -1) { | ||
1558 | if (uvd->defaultPalette == 0) { | ||
1559 | err("%s: No default palette; don't know what to do!", __FUNCTION__); | ||
1560 | count = -EFAULT; | ||
1561 | goto read_done; | ||
1562 | } | ||
1563 | frmx = 0; | ||
1564 | /* | ||
1565 | * We have no per-frame control over video size. | ||
1566 | * Therefore we only can use whatever size was | ||
1567 | * specified as default. | ||
1568 | */ | ||
1569 | uvd->frame[frmx].request = uvd->videosize; | ||
1570 | uvd->frame[frmx].palette = uvd->defaultPalette; | ||
1571 | uvd->frame[frmx].frameState = FrameState_Ready; | ||
1572 | usbvideo_NewFrame(uvd, frmx); | ||
1573 | /* Now frame 0 is supposed to start filling... */ | ||
1574 | } | ||
1575 | |||
1576 | /* | ||
1577 | * Get a pointer to the active frame. It is either previously | ||
1578 | * completed frame or frame in progress but not completed yet. | ||
1579 | */ | ||
1580 | frame = &uvd->frame[frmx]; | ||
1581 | |||
1582 | /* | ||
1583 | * Sit back & wait until the frame gets filled and postprocessed. | ||
1584 | * If we fail to get the picture [in time] then return the error. | ||
1585 | * In this call we specify that we want the frame to be waited for, | ||
1586 | * postprocessed and switched into FrameState_Done_Hold state. This | ||
1587 | * state is used to hold the frame as "fully completed" between | ||
1588 | * subsequent partial reads of the same frame. | ||
1589 | */ | ||
1590 | if (frame->frameState != FrameState_Done_Hold) { | ||
1591 | long rv = -EFAULT; | ||
1592 | if (uvd->flags & FLAGS_NO_DECODING) | ||
1593 | rv = usbvideo_GetFrame(uvd, frmx); | ||
1594 | else if (VALID_CALLBACK(uvd, getFrame)) | ||
1595 | rv = GET_CALLBACK(uvd, getFrame)(uvd, frmx); | ||
1596 | else | ||
1597 | err("getFrame is not set"); | ||
1598 | if ((rv != 0) || (frame->frameState != FrameState_Done_Hold)) { | ||
1599 | count = rv; | ||
1600 | goto read_done; | ||
1601 | } | ||
1602 | } | ||
1603 | |||
1604 | /* | ||
1605 | * Copy bytes to user space. We allow for partial reads, which | ||
1606 | * means that the user application can request read less than | ||
1607 | * the full frame size. It is up to the application to issue | ||
1608 | * subsequent calls until entire frame is read. | ||
1609 | * | ||
1610 | * First things first, make sure we don't copy more than we | ||
1611 | * have - even if the application wants more. That would be | ||
1612 | * a big security embarassment! | ||
1613 | */ | ||
1614 | if ((count + frame->seqRead_Index) > frame->seqRead_Length) | ||
1615 | count = frame->seqRead_Length - frame->seqRead_Index; | ||
1616 | |||
1617 | /* | ||
1618 | * Copy requested amount of data to user space. We start | ||
1619 | * copying from the position where we last left it, which | ||
1620 | * will be zero for a new frame (not read before). | ||
1621 | */ | ||
1622 | if (copy_to_user(buf, frame->data + frame->seqRead_Index, count)) { | ||
1623 | count = -EFAULT; | ||
1624 | goto read_done; | ||
1625 | } | ||
1626 | |||
1627 | /* Update last read position */ | ||
1628 | frame->seqRead_Index += count; | ||
1629 | if (uvd->debug >= 1) { | ||
1630 | err("%s: {copy} count used=%Zd, new seqRead_Index=%ld", | ||
1631 | __FUNCTION__, count, frame->seqRead_Index); | ||
1632 | } | ||
1633 | |||
1634 | /* Finally check if the frame is done with and "release" it */ | ||
1635 | if (frame->seqRead_Index >= frame->seqRead_Length) { | ||
1636 | /* All data has been read */ | ||
1637 | frame->seqRead_Index = 0; | ||
1638 | |||
1639 | /* Mark it as available to be used again. */ | ||
1640 | uvd->frame[frmx].frameState = FrameState_Unused; | ||
1641 | if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) { | ||
1642 | err("%s: usbvideo_NewFrame failed.", __FUNCTION__); | ||
1643 | } | ||
1644 | } | ||
1645 | read_done: | ||
1646 | mutex_unlock(&uvd->lock); | ||
1647 | return count; | ||
1648 | } | ||
1649 | |||
1650 | /* | ||
1651 | * Make all of the blocks of data contiguous | ||
1652 | */ | ||
1653 | static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb) | ||
1654 | { | ||
1655 | char *cdata; | ||
1656 | int i, totlen = 0; | ||
1657 | |||
1658 | for (i = 0; i < urb->number_of_packets; i++) { | ||
1659 | int n = urb->iso_frame_desc[i].actual_length; | ||
1660 | int st = urb->iso_frame_desc[i].status; | ||
1661 | |||
1662 | cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; | ||
1663 | |||
1664 | /* Detect and ignore errored packets */ | ||
1665 | if (st < 0) { | ||
1666 | if (uvd->debug >= 1) | ||
1667 | err("Data error: packet=%d. len=%d. status=%d.", i, n, st); | ||
1668 | uvd->stats.iso_err_count++; | ||
1669 | continue; | ||
1670 | } | ||
1671 | |||
1672 | /* Detect and ignore empty packets */ | ||
1673 | if (n <= 0) { | ||
1674 | uvd->stats.iso_skip_count++; | ||
1675 | continue; | ||
1676 | } | ||
1677 | totlen += n; /* Little local accounting */ | ||
1678 | RingQueue_Enqueue(&uvd->dp, cdata, n); | ||
1679 | } | ||
1680 | return totlen; | ||
1681 | } | ||
1682 | |||
1683 | static void usbvideo_IsocIrq(struct urb *urb, struct pt_regs *regs) | ||
1684 | { | ||
1685 | int i, ret, len; | ||
1686 | struct uvd *uvd = urb->context; | ||
1687 | |||
1688 | /* We don't want to do anything if we are about to be removed! */ | ||
1689 | if (!CAMERA_IS_OPERATIONAL(uvd)) | ||
1690 | return; | ||
1691 | #if 0 | ||
1692 | if (urb->actual_length > 0) { | ||
1693 | info("urb=$%p status=%d. errcount=%d. length=%d.", | ||
1694 | urb, urb->status, urb->error_count, urb->actual_length); | ||
1695 | } else { | ||
1696 | static int c = 0; | ||
1697 | if (c++ % 100 == 0) | ||
1698 | info("No Isoc data"); | ||
1699 | } | ||
1700 | #endif | ||
1701 | |||
1702 | if (!uvd->streaming) { | ||
1703 | if (uvd->debug >= 1) | ||
1704 | info("Not streaming, but interrupt!"); | ||
1705 | return; | ||
1706 | } | ||
1707 | |||
1708 | uvd->stats.urb_count++; | ||
1709 | if (urb->actual_length <= 0) | ||
1710 | goto urb_done_with; | ||
1711 | |||
1712 | /* Copy the data received into ring queue */ | ||
1713 | len = usbvideo_CompressIsochronous(uvd, urb); | ||
1714 | uvd->stats.urb_length = len; | ||
1715 | if (len <= 0) | ||
1716 | goto urb_done_with; | ||
1717 | |||
1718 | /* Here we got some data */ | ||
1719 | uvd->stats.data_count += len; | ||
1720 | RingQueue_WakeUpInterruptible(&uvd->dp); | ||
1721 | |||
1722 | urb_done_with: | ||
1723 | for (i = 0; i < FRAMES_PER_DESC; i++) { | ||
1724 | urb->iso_frame_desc[i].status = 0; | ||
1725 | urb->iso_frame_desc[i].actual_length = 0; | ||
1726 | } | ||
1727 | urb->status = 0; | ||
1728 | urb->dev = uvd->dev; | ||
1729 | ret = usb_submit_urb (urb, GFP_KERNEL); | ||
1730 | if(ret) | ||
1731 | err("usb_submit_urb error (%d)", ret); | ||
1732 | return; | ||
1733 | } | ||
1734 | |||
1735 | /* | ||
1736 | * usbvideo_StartDataPump() | ||
1737 | * | ||
1738 | * History: | ||
1739 | * 27-Jan-2000 Used ibmcam->iface, ibmcam->ifaceAltActive instead | ||
1740 | * of hardcoded values. Simplified by using for loop, | ||
1741 | * allowed any number of URBs. | ||
1742 | */ | ||
1743 | static int usbvideo_StartDataPump(struct uvd *uvd) | ||
1744 | { | ||
1745 | struct usb_device *dev = uvd->dev; | ||
1746 | int i, errFlag; | ||
1747 | |||
1748 | if (uvd->debug > 1) | ||
1749 | info("%s($%p)", __FUNCTION__, uvd); | ||
1750 | |||
1751 | if (!CAMERA_IS_OPERATIONAL(uvd)) { | ||
1752 | err("%s: Camera is not operational", __FUNCTION__); | ||
1753 | return -EFAULT; | ||
1754 | } | ||
1755 | uvd->curframe = -1; | ||
1756 | |||
1757 | /* Alternate interface 1 is is the biggest frame size */ | ||
1758 | i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive); | ||
1759 | if (i < 0) { | ||
1760 | err("%s: usb_set_interface error", __FUNCTION__); | ||
1761 | uvd->last_error = i; | ||
1762 | return -EBUSY; | ||
1763 | } | ||
1764 | if (VALID_CALLBACK(uvd, videoStart)) | ||
1765 | GET_CALLBACK(uvd, videoStart)(uvd); | ||
1766 | else | ||
1767 | err("%s: videoStart not set", __FUNCTION__); | ||
1768 | |||
1769 | /* We double buffer the Iso lists */ | ||
1770 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
1771 | int j, k; | ||
1772 | struct urb *urb = uvd->sbuf[i].urb; | ||
1773 | urb->dev = dev; | ||
1774 | urb->context = uvd; | ||
1775 | urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp); | ||
1776 | urb->interval = 1; | ||
1777 | urb->transfer_flags = URB_ISO_ASAP; | ||
1778 | urb->transfer_buffer = uvd->sbuf[i].data; | ||
1779 | urb->complete = usbvideo_IsocIrq; | ||
1780 | urb->number_of_packets = FRAMES_PER_DESC; | ||
1781 | urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC; | ||
1782 | for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) { | ||
1783 | urb->iso_frame_desc[j].offset = k; | ||
1784 | urb->iso_frame_desc[j].length = uvd->iso_packet_len; | ||
1785 | } | ||
1786 | } | ||
1787 | |||
1788 | /* Submit all URBs */ | ||
1789 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
1790 | errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL); | ||
1791 | if (errFlag) | ||
1792 | err("%s: usb_submit_isoc(%d) ret %d", __FUNCTION__, i, errFlag); | ||
1793 | } | ||
1794 | |||
1795 | uvd->streaming = 1; | ||
1796 | if (uvd->debug > 1) | ||
1797 | info("%s: streaming=1 video_endp=$%02x", __FUNCTION__, uvd->video_endp); | ||
1798 | return 0; | ||
1799 | } | ||
1800 | |||
1801 | /* | ||
1802 | * usbvideo_StopDataPump() | ||
1803 | * | ||
1804 | * This procedure stops streaming and deallocates URBs. Then it | ||
1805 | * activates zero-bandwidth alt. setting of the video interface. | ||
1806 | * | ||
1807 | * History: | ||
1808 | * 22-Jan-2000 Corrected order of actions to work after surprise removal. | ||
1809 | * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values. | ||
1810 | */ | ||
1811 | static void usbvideo_StopDataPump(struct uvd *uvd) | ||
1812 | { | ||
1813 | int i, j; | ||
1814 | |||
1815 | if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL)) | ||
1816 | return; | ||
1817 | |||
1818 | if (uvd->debug > 1) | ||
1819 | info("%s($%p)", __FUNCTION__, uvd); | ||
1820 | |||
1821 | /* Unschedule all of the iso td's */ | ||
1822 | for (i=0; i < USBVIDEO_NUMSBUF; i++) { | ||
1823 | usb_kill_urb(uvd->sbuf[i].urb); | ||
1824 | } | ||
1825 | if (uvd->debug > 1) | ||
1826 | info("%s: streaming=0", __FUNCTION__); | ||
1827 | uvd->streaming = 0; | ||
1828 | |||
1829 | if (!uvd->remove_pending) { | ||
1830 | /* Invoke minidriver's magic to stop the camera */ | ||
1831 | if (VALID_CALLBACK(uvd, videoStop)) | ||
1832 | GET_CALLBACK(uvd, videoStop)(uvd); | ||
1833 | else | ||
1834 | err("%s: videoStop not set", __FUNCTION__); | ||
1835 | |||
1836 | /* Set packet size to 0 */ | ||
1837 | j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive); | ||
1838 | if (j < 0) { | ||
1839 | err("%s: usb_set_interface() error %d.", __FUNCTION__, j); | ||
1840 | uvd->last_error = j; | ||
1841 | } | ||
1842 | } | ||
1843 | } | ||
1844 | |||
1845 | /* | ||
1846 | * usbvideo_NewFrame() | ||
1847 | * | ||
1848 | * History: | ||
1849 | * 29-Mar-00 Added copying of previous frame into the current one. | ||
1850 | * 6-Aug-00 Added model 3 video sizes, removed redundant width, height. | ||
1851 | */ | ||
1852 | static int usbvideo_NewFrame(struct uvd *uvd, int framenum) | ||
1853 | { | ||
1854 | struct usbvideo_frame *frame; | ||
1855 | int n; | ||
1856 | |||
1857 | if (uvd->debug > 1) | ||
1858 | info("usbvideo_NewFrame($%p,%d.)", uvd, framenum); | ||
1859 | |||
1860 | /* If we're not grabbing a frame right now and the other frame is */ | ||
1861 | /* ready to be grabbed into, then use it instead */ | ||
1862 | if (uvd->curframe != -1) | ||
1863 | return 0; | ||
1864 | |||
1865 | /* If necessary we adjust picture settings between frames */ | ||
1866 | if (!uvd->settingsAdjusted) { | ||
1867 | if (VALID_CALLBACK(uvd, adjustPicture)) | ||
1868 | GET_CALLBACK(uvd, adjustPicture)(uvd); | ||
1869 | uvd->settingsAdjusted = 1; | ||
1870 | } | ||
1871 | |||
1872 | n = (framenum + 1) % USBVIDEO_NUMFRAMES; | ||
1873 | if (uvd->frame[n].frameState == FrameState_Ready) | ||
1874 | framenum = n; | ||
1875 | |||
1876 | frame = &uvd->frame[framenum]; | ||
1877 | |||
1878 | frame->frameState = FrameState_Grabbing; | ||
1879 | frame->scanstate = ScanState_Scanning; | ||
1880 | frame->seqRead_Length = 0; /* Accumulated in xxx_parse_data() */ | ||
1881 | frame->deinterlace = Deinterlace_None; | ||
1882 | frame->flags = 0; /* No flags yet, up to minidriver (or us) to set them */ | ||
1883 | uvd->curframe = framenum; | ||
1884 | |||
1885 | /* | ||
1886 | * Normally we would want to copy previous frame into the current one | ||
1887 | * before we even start filling it with data; this allows us to stop | ||
1888 | * filling at any moment; top portion of the frame will be new and | ||
1889 | * bottom portion will stay as it was in previous frame. If we don't | ||
1890 | * do that then missing chunks of video stream will result in flickering | ||
1891 | * portions of old data whatever it was before. | ||
1892 | * | ||
1893 | * If we choose not to copy previous frame (to, for example, save few | ||
1894 | * bus cycles - the frame can be pretty large!) then we have an option | ||
1895 | * to clear the frame before using. If we experience losses in this | ||
1896 | * mode then missing picture will be black (no flickering). | ||
1897 | * | ||
1898 | * Finally, if user chooses not to clean the current frame before | ||
1899 | * filling it with data then the old data will be visible if we fail | ||
1900 | * to refill entire frame with new data. | ||
1901 | */ | ||
1902 | if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) { | ||
1903 | /* This copies previous frame into this one to mask losses */ | ||
1904 | int prev = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES; | ||
1905 | memmove(frame->data, uvd->frame[prev].data, uvd->max_frame_size); | ||
1906 | } else { | ||
1907 | if (uvd->flags & FLAGS_CLEAN_FRAMES) { | ||
1908 | /* This provides a "clean" frame but slows things down */ | ||
1909 | memset(frame->data, 0, uvd->max_frame_size); | ||
1910 | } | ||
1911 | } | ||
1912 | return 0; | ||
1913 | } | ||
1914 | |||
1915 | /* | ||
1916 | * usbvideo_CollectRawData() | ||
1917 | * | ||
1918 | * This procedure can be used instead of 'processData' callback if you | ||
1919 | * only want to dump the raw data from the camera into the output | ||
1920 | * device (frame buffer). You can look at it with V4L client, but the | ||
1921 | * image will be unwatchable. The main purpose of this code and of the | ||
1922 | * mode FLAGS_NO_DECODING is debugging and capturing of datastreams from | ||
1923 | * new, unknown cameras. This procedure will be automatically invoked | ||
1924 | * instead of the specified callback handler when uvd->flags has bit | ||
1925 | * FLAGS_NO_DECODING set. Therefore, any regular build of any driver | ||
1926 | * based on usbvideo can use this feature at any time. | ||
1927 | */ | ||
1928 | static void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame) | ||
1929 | { | ||
1930 | int n; | ||
1931 | |||
1932 | assert(uvd != NULL); | ||
1933 | assert(frame != NULL); | ||
1934 | |||
1935 | /* Try to move data from queue into frame buffer */ | ||
1936 | n = RingQueue_GetLength(&uvd->dp); | ||
1937 | if (n > 0) { | ||
1938 | int m; | ||
1939 | /* See how much space we have left */ | ||
1940 | m = uvd->max_frame_size - frame->seqRead_Length; | ||
1941 | if (n > m) | ||
1942 | n = m; | ||
1943 | /* Now move that much data into frame buffer */ | ||
1944 | RingQueue_Dequeue( | ||
1945 | &uvd->dp, | ||
1946 | frame->data + frame->seqRead_Length, | ||
1947 | m); | ||
1948 | frame->seqRead_Length += m; | ||
1949 | } | ||
1950 | /* See if we filled the frame */ | ||
1951 | if (frame->seqRead_Length >= uvd->max_frame_size) { | ||
1952 | frame->frameState = FrameState_Done; | ||
1953 | uvd->curframe = -1; | ||
1954 | uvd->stats.frame_num++; | ||
1955 | } | ||
1956 | } | ||
1957 | |||
1958 | static int usbvideo_GetFrame(struct uvd *uvd, int frameNum) | ||
1959 | { | ||
1960 | struct usbvideo_frame *frame = &uvd->frame[frameNum]; | ||
1961 | |||
1962 | if (uvd->debug >= 2) | ||
1963 | info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum); | ||
1964 | |||
1965 | switch (frame->frameState) { | ||
1966 | case FrameState_Unused: | ||
1967 | if (uvd->debug >= 2) | ||
1968 | info("%s: FrameState_Unused", __FUNCTION__); | ||
1969 | return -EINVAL; | ||
1970 | case FrameState_Ready: | ||
1971 | case FrameState_Grabbing: | ||
1972 | case FrameState_Error: | ||
1973 | { | ||
1974 | int ntries, signalPending; | ||
1975 | redo: | ||
1976 | if (!CAMERA_IS_OPERATIONAL(uvd)) { | ||
1977 | if (uvd->debug >= 2) | ||
1978 | info("%s: Camera is not operational (1)", __FUNCTION__); | ||
1979 | return -EIO; | ||
1980 | } | ||
1981 | ntries = 0; | ||
1982 | do { | ||
1983 | RingQueue_InterruptibleSleepOn(&uvd->dp); | ||
1984 | signalPending = signal_pending(current); | ||
1985 | if (!CAMERA_IS_OPERATIONAL(uvd)) { | ||
1986 | if (uvd->debug >= 2) | ||
1987 | info("%s: Camera is not operational (2)", __FUNCTION__); | ||
1988 | return -EIO; | ||
1989 | } | ||
1990 | assert(uvd->fbuf != NULL); | ||
1991 | if (signalPending) { | ||
1992 | if (uvd->debug >= 2) | ||
1993 | info("%s: Signal=$%08x", __FUNCTION__, signalPending); | ||
1994 | if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) { | ||
1995 | usbvideo_TestPattern(uvd, 1, 0); | ||
1996 | uvd->curframe = -1; | ||
1997 | uvd->stats.frame_num++; | ||
1998 | if (uvd->debug >= 2) | ||
1999 | info("%s: Forced test pattern screen", __FUNCTION__); | ||
2000 | return 0; | ||
2001 | } else { | ||
2002 | /* Standard answer: Interrupted! */ | ||
2003 | if (uvd->debug >= 2) | ||
2004 | info("%s: Interrupted!", __FUNCTION__); | ||
2005 | return -EINTR; | ||
2006 | } | ||
2007 | } else { | ||
2008 | /* No signals - we just got new data in dp queue */ | ||
2009 | if (uvd->flags & FLAGS_NO_DECODING) | ||
2010 | usbvideo_CollectRawData(uvd, frame); | ||
2011 | else if (VALID_CALLBACK(uvd, processData)) | ||
2012 | GET_CALLBACK(uvd, processData)(uvd, frame); | ||
2013 | else | ||
2014 | err("%s: processData not set", __FUNCTION__); | ||
2015 | } | ||
2016 | } while (frame->frameState == FrameState_Grabbing); | ||
2017 | if (uvd->debug >= 2) { | ||
2018 | info("%s: Grabbing done; state=%d. (%lu. bytes)", | ||
2019 | __FUNCTION__, frame->frameState, frame->seqRead_Length); | ||
2020 | } | ||
2021 | if (frame->frameState == FrameState_Error) { | ||
2022 | int ret = usbvideo_NewFrame(uvd, frameNum); | ||
2023 | if (ret < 0) { | ||
2024 | err("%s: usbvideo_NewFrame() failed (%d.)", __FUNCTION__, ret); | ||
2025 | return ret; | ||
2026 | } | ||
2027 | goto redo; | ||
2028 | } | ||
2029 | /* Note that we fall through to meet our destiny below */ | ||
2030 | } | ||
2031 | case FrameState_Done: | ||
2032 | /* | ||
2033 | * Do all necessary postprocessing of data prepared in | ||
2034 | * "interrupt" code and the collecting code above. The | ||
2035 | * frame gets marked as FrameState_Done by queue parsing code. | ||
2036 | * This status means that we collected enough data and | ||
2037 | * most likely processed it as we went through. However | ||
2038 | * the data may need postprocessing, such as deinterlacing | ||
2039 | * or picture adjustments implemented in software (horror!) | ||
2040 | * | ||
2041 | * As soon as the frame becomes "final" it gets promoted to | ||
2042 | * FrameState_Done_Hold status where it will remain until the | ||
2043 | * caller consumed all the video data from the frame. Then | ||
2044 | * the empty shell of ex-frame is thrown out for dogs to eat. | ||
2045 | * But we, worried about pets, will recycle the frame! | ||
2046 | */ | ||
2047 | uvd->stats.frame_num++; | ||
2048 | if ((uvd->flags & FLAGS_NO_DECODING) == 0) { | ||
2049 | if (VALID_CALLBACK(uvd, postProcess)) | ||
2050 | GET_CALLBACK(uvd, postProcess)(uvd, frame); | ||
2051 | if (frame->flags & USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST) | ||
2052 | usbvideo_SoftwareContrastAdjustment(uvd, frame); | ||
2053 | } | ||
2054 | frame->frameState = FrameState_Done_Hold; | ||
2055 | if (uvd->debug >= 2) | ||
2056 | info("%s: Entered FrameState_Done_Hold state.", __FUNCTION__); | ||
2057 | return 0; | ||
2058 | |||
2059 | case FrameState_Done_Hold: | ||
2060 | /* | ||
2061 | * We stay in this state indefinitely until someone external, | ||
2062 | * like ioctl() or read() call finishes digesting the frame | ||
2063 | * data. Then it will mark the frame as FrameState_Unused and | ||
2064 | * it will be released back into the wild to roam freely. | ||
2065 | */ | ||
2066 | if (uvd->debug >= 2) | ||
2067 | info("%s: FrameState_Done_Hold state.", __FUNCTION__); | ||
2068 | return 0; | ||
2069 | } | ||
2070 | |||
2071 | /* Catch-all for other cases. We shall not be here. */ | ||
2072 | err("%s: Invalid state %d.", __FUNCTION__, frame->frameState); | ||
2073 | frame->frameState = FrameState_Unused; | ||
2074 | return 0; | ||
2075 | } | ||
2076 | |||
2077 | /* | ||
2078 | * usbvideo_DeinterlaceFrame() | ||
2079 | * | ||
2080 | * This procedure deinterlaces the given frame. Some cameras produce | ||
2081 | * only half of scanlines - sometimes only even lines, sometimes only | ||
2082 | * odd lines. The deinterlacing method is stored in frame->deinterlace | ||
2083 | * variable. | ||
2084 | * | ||
2085 | * Here we scan the frame vertically and replace missing scanlines with | ||
2086 | * average between surrounding ones - before and after. If we have no | ||
2087 | * line above then we just copy next line. Similarly, if we need to | ||
2088 | * create a last line then preceding line is used. | ||
2089 | */ | ||
2090 | void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame) | ||
2091 | { | ||
2092 | if ((uvd == NULL) || (frame == NULL)) | ||
2093 | return; | ||
2094 | |||
2095 | if ((frame->deinterlace == Deinterlace_FillEvenLines) || | ||
2096 | (frame->deinterlace == Deinterlace_FillOddLines)) | ||
2097 | { | ||
2098 | const int v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; | ||
2099 | int i = (frame->deinterlace == Deinterlace_FillEvenLines) ? 0 : 1; | ||
2100 | |||
2101 | for (; i < VIDEOSIZE_Y(frame->request); i += 2) { | ||
2102 | const unsigned char *fs1, *fs2; | ||
2103 | unsigned char *fd; | ||
2104 | int ip, in, j; /* Previous and next lines */ | ||
2105 | |||
2106 | /* | ||
2107 | * Need to average lines before and after 'i'. | ||
2108 | * If we go out of bounds seeking those lines then | ||
2109 | * we point back to existing line. | ||
2110 | */ | ||
2111 | ip = i - 1; /* First, get rough numbers */ | ||
2112 | in = i + 1; | ||
2113 | |||
2114 | /* Now validate */ | ||
2115 | if (ip < 0) | ||
2116 | ip = in; | ||
2117 | if (in >= VIDEOSIZE_Y(frame->request)) | ||
2118 | in = ip; | ||
2119 | |||
2120 | /* Sanity check */ | ||
2121 | if ((ip < 0) || (in < 0) || | ||
2122 | (ip >= VIDEOSIZE_Y(frame->request)) || | ||
2123 | (in >= VIDEOSIZE_Y(frame->request))) | ||
2124 | { | ||
2125 | err("Error: ip=%d. in=%d. req.height=%ld.", | ||
2126 | ip, in, VIDEOSIZE_Y(frame->request)); | ||
2127 | break; | ||
2128 | } | ||
2129 | |||
2130 | /* Now we need to average lines 'ip' and 'in' to produce line 'i' */ | ||
2131 | fs1 = frame->data + (v4l_linesize * ip); | ||
2132 | fs2 = frame->data + (v4l_linesize * in); | ||
2133 | fd = frame->data + (v4l_linesize * i); | ||
2134 | |||
2135 | /* Average lines around destination */ | ||
2136 | for (j=0; j < v4l_linesize; j++) { | ||
2137 | fd[j] = (unsigned char)((((unsigned) fs1[j]) + | ||
2138 | ((unsigned)fs2[j])) >> 1); | ||
2139 | } | ||
2140 | } | ||
2141 | } | ||
2142 | |||
2143 | /* Optionally display statistics on the screen */ | ||
2144 | if (uvd->flags & FLAGS_OVERLAY_STATS) | ||
2145 | usbvideo_OverlayStats(uvd, frame); | ||
2146 | } | ||
2147 | |||
2148 | EXPORT_SYMBOL(usbvideo_DeinterlaceFrame); | ||
2149 | |||
2150 | /* | ||
2151 | * usbvideo_SoftwareContrastAdjustment() | ||
2152 | * | ||
2153 | * This code adjusts the contrast of the frame, assuming RGB24 format. | ||
2154 | * As most software image processing, this job is CPU-intensive. | ||
2155 | * Get a camera that supports hardware adjustment! | ||
2156 | * | ||
2157 | * History: | ||
2158 | * 09-Feb-2001 Created. | ||
2159 | */ | ||
2160 | static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, | ||
2161 | struct usbvideo_frame *frame) | ||
2162 | { | ||
2163 | int i, j, v4l_linesize; | ||
2164 | signed long adj; | ||
2165 | const int ccm = 128; /* Color correction median - see below */ | ||
2166 | |||
2167 | if ((uvd == NULL) || (frame == NULL)) { | ||
2168 | err("%s: Illegal call.", __FUNCTION__); | ||
2169 | return; | ||
2170 | } | ||
2171 | adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ | ||
2172 | RESTRICT_TO_RANGE(adj, -ccm, ccm+1); | ||
2173 | if (adj == 0) { | ||
2174 | /* In rare case of no adjustment */ | ||
2175 | return; | ||
2176 | } | ||
2177 | v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; | ||
2178 | for (i=0; i < VIDEOSIZE_Y(frame->request); i++) { | ||
2179 | unsigned char *fd = frame->data + (v4l_linesize * i); | ||
2180 | for (j=0; j < v4l_linesize; j++) { | ||
2181 | signed long v = (signed long) fd[j]; | ||
2182 | /* Magnify up to 2 times, reduce down to zero */ | ||
2183 | v = 128 + ((ccm + adj) * (v - 128)) / ccm; | ||
2184 | RESTRICT_TO_RANGE(v, 0, 0xFF); /* Must flatten tails */ | ||
2185 | fd[j] = (unsigned char) v; | ||
2186 | } | ||
2187 | } | ||
2188 | } | ||
2189 | |||
2190 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/video/usbvideo/usbvideo.h b/drivers/media/video/usbvideo/usbvideo.h new file mode 100644 index 000000000000..135433c2680a --- /dev/null +++ b/drivers/media/video/usbvideo/usbvideo.h | |||
@@ -0,0 +1,394 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2, or (at your option) | ||
5 | * any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
15 | */ | ||
16 | #ifndef usbvideo_h | ||
17 | #define usbvideo_h | ||
18 | |||
19 | #include <linux/config.h> | ||
20 | #include <linux/videodev.h> | ||
21 | #include <linux/usb.h> | ||
22 | #include <linux/mutex.h> | ||
23 | |||
24 | /* Most helpful debugging aid */ | ||
25 | #define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__)))) | ||
26 | |||
27 | #define USBVIDEO_REPORT_STATS 1 /* Set to 0 to block statistics on close */ | ||
28 | |||
29 | /* Bit flags (options) */ | ||
30 | #define FLAGS_RETRY_VIDIOCSYNC (1 << 0) | ||
31 | #define FLAGS_MONOCHROME (1 << 1) | ||
32 | #define FLAGS_DISPLAY_HINTS (1 << 2) | ||
33 | #define FLAGS_OVERLAY_STATS (1 << 3) | ||
34 | #define FLAGS_FORCE_TESTPATTERN (1 << 4) | ||
35 | #define FLAGS_SEPARATE_FRAMES (1 << 5) | ||
36 | #define FLAGS_CLEAN_FRAMES (1 << 6) | ||
37 | #define FLAGS_NO_DECODING (1 << 7) | ||
38 | |||
39 | /* Bit flags for frames (apply to the frame where they are specified) */ | ||
40 | #define USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST (1 << 0) | ||
41 | |||
42 | /* Camera capabilities (maximum) */ | ||
43 | #define CAMERA_URB_FRAMES 32 | ||
44 | #define CAMERA_MAX_ISO_PACKET 1023 /* 1022 actually sent by camera */ | ||
45 | #define FRAMES_PER_DESC (CAMERA_URB_FRAMES) | ||
46 | #define FRAME_SIZE_PER_DESC (CAMERA_MAX_ISO_PACKET) | ||
47 | |||
48 | /* This macro restricts an int variable to an inclusive range */ | ||
49 | #define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); } | ||
50 | |||
51 | #define V4L_BYTES_PER_PIXEL 3 /* Because we produce RGB24 */ | ||
52 | |||
53 | /* | ||
54 | * Use this macro to construct constants for different video sizes. | ||
55 | * We have to deal with different video sizes that have to be | ||
56 | * configured in the device or compared against when we receive | ||
57 | * a data. Normally one would define a bunch of VIDEOSIZE_x_by_y | ||
58 | * #defines and that's the end of story. However this solution | ||
59 | * does not allow to convert between real pixel sizes and the | ||
60 | * constant (integer) value that may be used to tag a frame or | ||
61 | * whatever. The set of macros below constructs videosize constants | ||
62 | * from the pixel size and allows to reconstruct the pixel size | ||
63 | * from the combined value later. | ||
64 | */ | ||
65 | #define VIDEOSIZE(x,y) (((x) & 0xFFFFL) | (((y) & 0xFFFFL) << 16)) | ||
66 | #define VIDEOSIZE_X(vs) ((vs) & 0xFFFFL) | ||
67 | #define VIDEOSIZE_Y(vs) (((vs) >> 16) & 0xFFFFL) | ||
68 | typedef unsigned long videosize_t; | ||
69 | |||
70 | /* | ||
71 | * This macro checks if the camera is still operational. The 'uvd' | ||
72 | * pointer must be valid, uvd->dev must be valid, we are not | ||
73 | * removing the device and the device has not erred on us. | ||
74 | */ | ||
75 | #define CAMERA_IS_OPERATIONAL(uvd) (\ | ||
76 | (uvd != NULL) && \ | ||
77 | ((uvd)->dev != NULL) && \ | ||
78 | ((uvd)->last_error == 0) && \ | ||
79 | (!(uvd)->remove_pending)) | ||
80 | |||
81 | /* | ||
82 | * We use macros to do YUV -> RGB conversion because this is | ||
83 | * very important for speed and totally unimportant for size. | ||
84 | * | ||
85 | * YUV -> RGB Conversion | ||
86 | * --------------------- | ||
87 | * | ||
88 | * B = 1.164*(Y-16) + 2.018*(V-128) | ||
89 | * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128) | ||
90 | * R = 1.164*(Y-16) + 1.596*(U-128) | ||
91 | * | ||
92 | * If you fancy integer arithmetics (as you should), hear this: | ||
93 | * | ||
94 | * 65536*B = 76284*(Y-16) + 132252*(V-128) | ||
95 | * 65536*G = 76284*(Y-16) - 53281*(U-128) - 25625*(V-128) | ||
96 | * 65536*R = 76284*(Y-16) + 104595*(U-128) | ||
97 | * | ||
98 | * Make sure the output values are within [0..255] range. | ||
99 | */ | ||
100 | #define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x))) | ||
101 | #define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \ | ||
102 | int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \ | ||
103 | mm_y = (my) - 16; \ | ||
104 | mm_u = (mu) - 128; \ | ||
105 | mm_v = (mv) - 128; \ | ||
106 | mm_yc= mm_y * 76284; \ | ||
107 | mm_b = (mm_yc + 132252*mm_v ) >> 16; \ | ||
108 | mm_g = (mm_yc - 53281*mm_u - 25625*mm_v ) >> 16; \ | ||
109 | mm_r = (mm_yc + 104595*mm_u ) >> 16; \ | ||
110 | mb = LIMIT_RGB(mm_b); \ | ||
111 | mg = LIMIT_RGB(mm_g); \ | ||
112 | mr = LIMIT_RGB(mm_r); \ | ||
113 | } | ||
114 | |||
115 | #define RING_QUEUE_SIZE (128*1024) /* Must be a power of 2 */ | ||
116 | #define RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1) | ||
117 | #define RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n) | ||
118 | #define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)]) | ||
119 | |||
120 | struct RingQueue { | ||
121 | unsigned char *queue; /* Data from the Isoc data pump */ | ||
122 | int length; /* How many bytes allocated for the queue */ | ||
123 | int wi; /* That's where we write */ | ||
124 | int ri; /* Read from here until you hit write index */ | ||
125 | wait_queue_head_t wqh; /* Processes waiting */ | ||
126 | }; | ||
127 | |||
128 | enum ScanState { | ||
129 | ScanState_Scanning, /* Scanning for header */ | ||
130 | ScanState_Lines /* Parsing lines */ | ||
131 | }; | ||
132 | |||
133 | /* Completion states of the data parser */ | ||
134 | enum ParseState { | ||
135 | scan_Continue, /* Just parse next item */ | ||
136 | scan_NextFrame, /* Frame done, send it to V4L */ | ||
137 | scan_Out, /* Not enough data for frame */ | ||
138 | scan_EndParse /* End parsing */ | ||
139 | }; | ||
140 | |||
141 | enum FrameState { | ||
142 | FrameState_Unused, /* Unused (no MCAPTURE) */ | ||
143 | FrameState_Ready, /* Ready to start grabbing */ | ||
144 | FrameState_Grabbing, /* In the process of being grabbed into */ | ||
145 | FrameState_Done, /* Finished grabbing, but not been synced yet */ | ||
146 | FrameState_Done_Hold, /* Are syncing or reading */ | ||
147 | FrameState_Error, /* Something bad happened while processing */ | ||
148 | }; | ||
149 | |||
150 | /* | ||
151 | * Some frames may contain only even or odd lines. This type | ||
152 | * specifies what type of deinterlacing is required. | ||
153 | */ | ||
154 | enum Deinterlace { | ||
155 | Deinterlace_None=0, | ||
156 | Deinterlace_FillOddLines, | ||
157 | Deinterlace_FillEvenLines | ||
158 | }; | ||
159 | |||
160 | #define USBVIDEO_NUMFRAMES 2 /* How many frames we work with */ | ||
161 | #define USBVIDEO_NUMSBUF 2 /* How many URBs linked in a ring */ | ||
162 | |||
163 | /* This structure represents one Isoc request - URB and buffer */ | ||
164 | struct usbvideo_sbuf { | ||
165 | char *data; | ||
166 | struct urb *urb; | ||
167 | }; | ||
168 | |||
169 | struct usbvideo_frame { | ||
170 | char *data; /* Frame buffer */ | ||
171 | unsigned long header; /* Significant bits from the header */ | ||
172 | |||
173 | videosize_t canvas; /* The canvas (max. image) allocated */ | ||
174 | videosize_t request; /* That's what the application asked for */ | ||
175 | unsigned short palette; /* The desired format */ | ||
176 | |||
177 | enum FrameState frameState;/* State of grabbing */ | ||
178 | enum ScanState scanstate; /* State of scanning */ | ||
179 | enum Deinterlace deinterlace; | ||
180 | int flags; /* USBVIDEO_FRAME_FLAG_xxx bit flags */ | ||
181 | |||
182 | int curline; /* Line of frame we're working on */ | ||
183 | |||
184 | long seqRead_Length; /* Raw data length of frame */ | ||
185 | long seqRead_Index; /* Amount of data that has been already read */ | ||
186 | |||
187 | void *user; /* Additional data that user may need */ | ||
188 | }; | ||
189 | |||
190 | /* Statistics that can be overlaid on screen */ | ||
191 | struct usbvideo_statistics { | ||
192 | unsigned long frame_num; /* Sequential number of the frame */ | ||
193 | unsigned long urb_count; /* How many URBs we received so far */ | ||
194 | unsigned long urb_length; /* Length of last URB */ | ||
195 | unsigned long data_count; /* How many bytes we received */ | ||
196 | unsigned long header_count; /* How many frame headers we found */ | ||
197 | unsigned long iso_skip_count; /* How many empty ISO packets received */ | ||
198 | unsigned long iso_err_count; /* How many bad ISO packets received */ | ||
199 | }; | ||
200 | |||
201 | struct usbvideo; | ||
202 | |||
203 | struct uvd { | ||
204 | struct video_device vdev; /* Must be the first field! */ | ||
205 | struct usb_device *dev; | ||
206 | struct usbvideo *handle; /* Points back to the struct usbvideo */ | ||
207 | void *user_data; /* Camera-dependent data */ | ||
208 | int user_size; /* Size of that camera-dependent data */ | ||
209 | int debug; /* Debug level for usbvideo */ | ||
210 | unsigned char iface; /* Video interface number */ | ||
211 | unsigned char video_endp; | ||
212 | unsigned char ifaceAltActive; | ||
213 | unsigned char ifaceAltInactive; /* Alt settings */ | ||
214 | unsigned long flags; /* FLAGS_USBVIDEO_xxx */ | ||
215 | unsigned long paletteBits; /* Which palettes we accept? */ | ||
216 | unsigned short defaultPalette; /* What palette to use for read() */ | ||
217 | struct mutex lock; | ||
218 | int user; /* user count for exclusive use */ | ||
219 | |||
220 | videosize_t videosize; /* Current setting */ | ||
221 | videosize_t canvas; /* This is the width,height of the V4L canvas */ | ||
222 | int max_frame_size; /* Bytes in one video frame */ | ||
223 | |||
224 | int uvd_used; /* Is this structure in use? */ | ||
225 | int streaming; /* Are we streaming Isochronous? */ | ||
226 | int grabbing; /* Are we grabbing? */ | ||
227 | int settingsAdjusted; /* Have we adjusted contrast etc.? */ | ||
228 | int last_error; /* What calamity struck us? */ | ||
229 | |||
230 | char *fbuf; /* Videodev buffer area */ | ||
231 | int fbuf_size; /* Videodev buffer size */ | ||
232 | |||
233 | int curframe; | ||
234 | int iso_packet_len; /* Videomode-dependent, saves bus bandwidth */ | ||
235 | |||
236 | struct RingQueue dp; /* Isoc data pump */ | ||
237 | struct usbvideo_frame frame[USBVIDEO_NUMFRAMES]; | ||
238 | struct usbvideo_sbuf sbuf[USBVIDEO_NUMSBUF]; | ||
239 | |||
240 | volatile int remove_pending; /* If set then about to exit */ | ||
241 | |||
242 | struct video_picture vpic, vpic_old; /* Picture settings */ | ||
243 | struct video_capability vcap; /* Video capabilities */ | ||
244 | struct video_channel vchan; /* May be used for tuner support */ | ||
245 | struct usbvideo_statistics stats; | ||
246 | char videoName[32]; /* Holds name like "video7" */ | ||
247 | }; | ||
248 | |||
249 | /* | ||
250 | * usbvideo callbacks (virtual methods). They are set when usbvideo | ||
251 | * services are registered. All of these default to NULL, except those | ||
252 | * that default to usbvideo-provided methods. | ||
253 | */ | ||
254 | struct usbvideo_cb { | ||
255 | int (*probe)(struct usb_interface *, const struct usb_device_id *); | ||
256 | void (*userFree)(struct uvd *); | ||
257 | void (*disconnect)(struct usb_interface *); | ||
258 | int (*setupOnOpen)(struct uvd *); | ||
259 | void (*videoStart)(struct uvd *); | ||
260 | void (*videoStop)(struct uvd *); | ||
261 | void (*processData)(struct uvd *, struct usbvideo_frame *); | ||
262 | void (*postProcess)(struct uvd *, struct usbvideo_frame *); | ||
263 | void (*adjustPicture)(struct uvd *); | ||
264 | int (*getFPS)(struct uvd *); | ||
265 | int (*overlayHook)(struct uvd *, struct usbvideo_frame *); | ||
266 | int (*getFrame)(struct uvd *, int); | ||
267 | int (*startDataPump)(struct uvd *uvd); | ||
268 | void (*stopDataPump)(struct uvd *uvd); | ||
269 | int (*setVideoMode)(struct uvd *uvd, struct video_window *vw); | ||
270 | }; | ||
271 | |||
272 | struct usbvideo { | ||
273 | int num_cameras; /* As allocated */ | ||
274 | struct usb_driver usbdrv; /* Interface to the USB stack */ | ||
275 | char drvName[80]; /* Driver name */ | ||
276 | struct mutex lock; /* Mutex protecting camera structures */ | ||
277 | struct usbvideo_cb cb; /* Table of callbacks (virtual methods) */ | ||
278 | struct video_device vdt; /* Video device template */ | ||
279 | struct uvd *cam; /* Array of camera structures */ | ||
280 | struct module *md_module; /* Minidriver module */ | ||
281 | }; | ||
282 | |||
283 | |||
284 | /* | ||
285 | * This macro retrieves callback address from the struct uvd object. | ||
286 | * No validity checks are done here, so be sure to check the | ||
287 | * callback beforehand with VALID_CALLBACK. | ||
288 | */ | ||
289 | #define GET_CALLBACK(uvd,cbName) ((uvd)->handle->cb.cbName) | ||
290 | |||
291 | /* | ||
292 | * This macro returns either callback pointer or NULL. This is safe | ||
293 | * macro, meaning that most of components of data structures involved | ||
294 | * may be NULL - this only results in NULL being returned. You may | ||
295 | * wish to use this macro to make sure that the callback is callable. | ||
296 | * However keep in mind that those checks take time. | ||
297 | */ | ||
298 | #define VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \ | ||
299 | ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL) | ||
300 | |||
301 | int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len); | ||
302 | int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n); | ||
303 | void RingQueue_WakeUpInterruptible(struct RingQueue *rq); | ||
304 | void RingQueue_Flush(struct RingQueue *rq); | ||
305 | |||
306 | static inline int RingQueue_GetLength(const struct RingQueue *rq) | ||
307 | { | ||
308 | return (rq->wi - rq->ri + rq->length) & (rq->length-1); | ||
309 | } | ||
310 | |||
311 | static inline int RingQueue_GetFreeSpace(const struct RingQueue *rq) | ||
312 | { | ||
313 | return rq->length - RingQueue_GetLength(rq); | ||
314 | } | ||
315 | |||
316 | void usbvideo_DrawLine( | ||
317 | struct usbvideo_frame *frame, | ||
318 | int x1, int y1, | ||
319 | int x2, int y2, | ||
320 | unsigned char cr, unsigned char cg, unsigned char cb); | ||
321 | void usbvideo_HexDump(const unsigned char *data, int len); | ||
322 | void usbvideo_SayAndWait(const char *what); | ||
323 | void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode); | ||
324 | |||
325 | /* Memory allocation routines */ | ||
326 | unsigned long usbvideo_kvirt_to_pa(unsigned long adr); | ||
327 | |||
328 | int usbvideo_register( | ||
329 | struct usbvideo **pCams, | ||
330 | const int num_cams, | ||
331 | const int num_extra, | ||
332 | const char *driverName, | ||
333 | const struct usbvideo_cb *cbTable, | ||
334 | struct module *md, | ||
335 | const struct usb_device_id *id_table); | ||
336 | struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams); | ||
337 | int usbvideo_RegisterVideoDevice(struct uvd *uvd); | ||
338 | void usbvideo_Deregister(struct usbvideo **uvt); | ||
339 | |||
340 | int usbvideo_v4l_initialize(struct video_device *dev); | ||
341 | |||
342 | void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame); | ||
343 | |||
344 | /* | ||
345 | * This code performs bounds checking - use it when working with | ||
346 | * new formats, or else you may get oopses all over the place. | ||
347 | * If pixel falls out of bounds then it gets shoved back (as close | ||
348 | * to place of offence as possible) and is painted bright red. | ||
349 | * | ||
350 | * There are two important concepts: frame width, height and | ||
351 | * V4L canvas width, height. The former is the area requested by | ||
352 | * the application -for this very frame-. The latter is the largest | ||
353 | * possible frame that we can serve (we advertise that via V4L ioctl). | ||
354 | * The frame data is expected to be formatted as lines of length | ||
355 | * VIDEOSIZE_X(fr->request), total VIDEOSIZE_Y(frame->request) lines. | ||
356 | */ | ||
357 | static inline void RGB24_PUTPIXEL( | ||
358 | struct usbvideo_frame *fr, | ||
359 | int ix, int iy, | ||
360 | unsigned char vr, | ||
361 | unsigned char vg, | ||
362 | unsigned char vb) | ||
363 | { | ||
364 | register unsigned char *pf; | ||
365 | int limiter = 0, mx, my; | ||
366 | mx = ix; | ||
367 | my = iy; | ||
368 | if (mx < 0) { | ||
369 | mx=0; | ||
370 | limiter++; | ||
371 | } else if (mx >= VIDEOSIZE_X((fr)->request)) { | ||
372 | mx= VIDEOSIZE_X((fr)->request) - 1; | ||
373 | limiter++; | ||
374 | } | ||
375 | if (my < 0) { | ||
376 | my = 0; | ||
377 | limiter++; | ||
378 | } else if (my >= VIDEOSIZE_Y((fr)->request)) { | ||
379 | my = VIDEOSIZE_Y((fr)->request) - 1; | ||
380 | limiter++; | ||
381 | } | ||
382 | pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*VIDEOSIZE_X((fr)->request) + (ix)); | ||
383 | if (limiter) { | ||
384 | *pf++ = 0; | ||
385 | *pf++ = 0; | ||
386 | *pf++ = 0xFF; | ||
387 | } else { | ||
388 | *pf++ = (vb); | ||
389 | *pf++ = (vg); | ||
390 | *pf++ = (vr); | ||
391 | } | ||
392 | } | ||
393 | |||
394 | #endif /* usbvideo_h */ | ||
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c new file mode 100644 index 000000000000..1d06e53ec7c5 --- /dev/null +++ b/drivers/media/video/usbvideo/vicam.c | |||
@@ -0,0 +1,1411 @@ | |||
1 | /* | ||
2 | * USB ViCam WebCam driver | ||
3 | * Copyright (c) 2002 Joe Burks (jburks@wavicle.org), | ||
4 | * Christopher L Cheney (ccheney@cheney.cx), | ||
5 | * Pavel Machek (pavel@suse.cz), | ||
6 | * John Tyner (jtyner@cs.ucr.edu), | ||
7 | * Monroe Williams (monroe@pobox.com) | ||
8 | * | ||
9 | * Supports 3COM HomeConnect PC Digital WebCam | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | * | ||
25 | * This source code is based heavily on the CPiA webcam driver which was | ||
26 | * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt | ||
27 | * | ||
28 | * Portions of this code were also copied from usbvideo.c | ||
29 | * | ||
30 | * Special thanks to the the whole team at Sourceforge for help making | ||
31 | * this driver become a reality. Notably: | ||
32 | * Andy Armstrong who reverse engineered the color encoding and | ||
33 | * Pavel Machek and Chris Cheney who worked on reverse engineering the | ||
34 | * camera controls and wrote the first generation driver. | ||
35 | */ | ||
36 | |||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <linux/init.h> | ||
40 | #include <linux/videodev.h> | ||
41 | #include <linux/usb.h> | ||
42 | #include <linux/vmalloc.h> | ||
43 | #include <linux/slab.h> | ||
44 | #include <linux/proc_fs.h> | ||
45 | #include <linux/mutex.h> | ||
46 | #include "usbvideo.h" | ||
47 | |||
48 | // #define VICAM_DEBUG | ||
49 | |||
50 | #ifdef VICAM_DEBUG | ||
51 | #define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args) | ||
52 | #define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args) | ||
53 | #else | ||
54 | #define DBG(fmn,args...) do {} while(0) | ||
55 | #endif | ||
56 | |||
57 | #define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org" | ||
58 | #define DRIVER_DESC "ViCam WebCam Driver" | ||
59 | |||
60 | /* Define these values to match your device */ | ||
61 | #define USB_VICAM_VENDOR_ID 0x04c1 | ||
62 | #define USB_VICAM_PRODUCT_ID 0x009d | ||
63 | |||
64 | #define VICAM_BYTES_PER_PIXEL 3 | ||
65 | #define VICAM_MAX_READ_SIZE (512*242+128) | ||
66 | #define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240) | ||
67 | #define VICAM_FRAMES 2 | ||
68 | |||
69 | #define VICAM_HEADER_SIZE 64 | ||
70 | |||
71 | #define clamp( x, l, h ) max_t( __typeof__( x ), \ | ||
72 | ( l ), \ | ||
73 | min_t( __typeof__( x ), \ | ||
74 | ( h ), \ | ||
75 | ( x ) ) ) | ||
76 | |||
77 | /* Not sure what all the bytes in these char | ||
78 | * arrays do, but they're necessary to make | ||
79 | * the camera work. | ||
80 | */ | ||
81 | |||
82 | static unsigned char setup1[] = { | ||
83 | 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67, | ||
84 | 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00, | ||
85 | 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17, | ||
86 | 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00, | ||
87 | 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00 | ||
88 | }; | ||
89 | |||
90 | static unsigned char setup2[] = { | ||
91 | 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00, | ||
92 | 0x00, 0x00 | ||
93 | }; | ||
94 | |||
95 | static unsigned char setup3[] = { | ||
96 | 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00 | ||
97 | }; | ||
98 | |||
99 | static unsigned char setup4[] = { | ||
100 | 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07, | ||
101 | 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00, | ||
102 | 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00, | ||
103 | 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07, | ||
104 | 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00, | ||
105 | 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00, | ||
106 | 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07, | ||
107 | 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, | ||
108 | 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0, | ||
109 | 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07, | ||
110 | 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00, | ||
111 | 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0, | ||
112 | 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1, | ||
113 | 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09, | ||
114 | 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, | ||
115 | 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF, | ||
116 | 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02, | ||
117 | 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, | ||
118 | 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF, | ||
119 | 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00, | ||
120 | 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00, | ||
121 | 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05, | ||
122 | 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA, | ||
123 | 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06, | ||
124 | 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF, | ||
125 | 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05, | ||
126 | 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01, | ||
127 | 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09, | ||
128 | 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06, | ||
129 | 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05, | ||
130 | 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA, | ||
131 | 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05, | ||
132 | 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, | ||
133 | 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00, | ||
134 | 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF, | ||
135 | 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00, | ||
136 | 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0, | ||
137 | 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06, | ||
138 | 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00, | ||
139 | 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07, | ||
140 | 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF, | ||
141 | 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00, | ||
142 | 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06, | ||
143 | 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57, | ||
144 | 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57, | ||
145 | 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00, | ||
146 | 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0, | ||
147 | 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B, | ||
148 | 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06, | ||
149 | 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, | ||
150 | 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E, | ||
151 | 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, | ||
152 | 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, | ||
153 | 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00, | ||
154 | 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06, | ||
155 | 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF, | ||
156 | 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0, | ||
157 | 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, | ||
158 | 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05, | ||
159 | 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF, | ||
160 | 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0, | ||
161 | 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07, | ||
162 | 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07, | ||
163 | 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF, | ||
164 | 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF, | ||
165 | 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, | ||
166 | 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01, | ||
167 | 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1, | ||
168 | 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67, | ||
169 | 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00, | ||
170 | 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07, | ||
171 | 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07, | ||
172 | 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07, | ||
173 | 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00, | ||
174 | 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06, | ||
175 | 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67, | ||
176 | 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8, | ||
177 | 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, | ||
178 | 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF, | ||
179 | 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02, | ||
180 | 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07, | ||
181 | 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06, | ||
182 | 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05, | ||
183 | 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80, | ||
184 | 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00, | ||
185 | 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06, | ||
186 | 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07, | ||
187 | 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05, | ||
188 | 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05, | ||
189 | 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80, | ||
190 | 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04, | ||
191 | 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF, | ||
192 | 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06, | ||
193 | 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, | ||
194 | 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00, | ||
195 | 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05, | ||
196 | 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07, | ||
197 | 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07, | ||
198 | 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07, | ||
199 | 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF, | ||
200 | 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07, | ||
201 | 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06, | ||
202 | 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05, | ||
203 | 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07, | ||
204 | 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00, | ||
205 | 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00, | ||
206 | 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77, | ||
207 | 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04, | ||
208 | 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0, | ||
209 | 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1, | ||
210 | 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07, | ||
211 | 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF, | ||
212 | 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, | ||
213 | 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, | ||
214 | 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, | ||
215 | 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77, | ||
216 | 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1, | ||
217 | 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07, | ||
218 | 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, | ||
219 | 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06, | ||
220 | 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, | ||
221 | 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, | ||
222 | 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07, | ||
223 | 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00, | ||
224 | 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00, | ||
225 | 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, | ||
226 | 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, | ||
227 | 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F, | ||
228 | 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00, | ||
229 | 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00, | ||
230 | 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA, | ||
231 | 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, | ||
232 | 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06, | ||
233 | 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF, | ||
234 | 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B, | ||
235 | 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, | ||
236 | 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09, | ||
237 | 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05, | ||
238 | 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07, | ||
239 | 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00, | ||
240 | 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF, | ||
241 | 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05, | ||
242 | 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00, | ||
243 | 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00, | ||
244 | 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05, | ||
245 | 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05, | ||
246 | 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00, | ||
247 | 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF, | ||
248 | 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09, | ||
249 | 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, | ||
250 | 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1, | ||
251 | 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00, | ||
252 | 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05, | ||
253 | 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00, | ||
254 | 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00, | ||
255 | 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05, | ||
256 | 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0, | ||
257 | 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67, | ||
258 | 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87, | ||
259 | 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9, | ||
260 | 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1, | ||
261 | 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF, | ||
262 | 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00, | ||
263 | 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0, | ||
264 | 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87, | ||
265 | 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, | ||
266 | 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67, | ||
267 | 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, | ||
268 | 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, | ||
269 | 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67, | ||
270 | 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, | ||
271 | 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, | ||
272 | 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01, | ||
273 | 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00, | ||
274 | 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF, | ||
275 | 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, | ||
276 | 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67, | ||
277 | 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09, | ||
278 | 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, | ||
279 | 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA, | ||
280 | 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87, | ||
281 | 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07, | ||
282 | 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80, | ||
283 | 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07, | ||
284 | 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80, | ||
285 | 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02, | ||
286 | 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09, | ||
287 | 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, | ||
288 | 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00, | ||
289 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
290 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
291 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
292 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
293 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
294 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
295 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
296 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
297 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
298 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
299 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
300 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
301 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
302 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
303 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
304 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
305 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
306 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
307 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
308 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
309 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
310 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
311 | }; | ||
312 | |||
313 | static unsigned char setup5[] = { | ||
314 | 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00, | ||
315 | 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, | ||
316 | 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00, | ||
317 | 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00, | ||
318 | 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00, | ||
319 | 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00, | ||
320 | 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00, | ||
321 | 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01, | ||
322 | 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01, | ||
323 | 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01, | ||
324 | 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01, | ||
325 | 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01, | ||
326 | 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01, | ||
327 | 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01, | ||
328 | 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01, | ||
329 | 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02, | ||
330 | 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02, | ||
331 | 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02, | ||
332 | 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02, | ||
333 | 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02, | ||
334 | 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02, | ||
335 | 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02, | ||
336 | 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02, | ||
337 | 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03, | ||
338 | 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03, | ||
339 | 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03, | ||
340 | 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03, | ||
341 | 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03, | ||
342 | 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03, | ||
343 | 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03, | ||
344 | 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04, | ||
345 | 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04, | ||
346 | 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04, | ||
347 | 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04, | ||
348 | 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04, | ||
349 | 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04, | ||
350 | 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04, | ||
351 | 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05, | ||
352 | 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00 | ||
353 | }; | ||
354 | |||
355 | /* rvmalloc / rvfree copied from usbvideo.c | ||
356 | * | ||
357 | * Not sure why these are not yet non-statics which I can reference through | ||
358 | * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime | ||
359 | * in the future. | ||
360 | * | ||
361 | */ | ||
362 | static void *rvmalloc(unsigned long size) | ||
363 | { | ||
364 | void *mem; | ||
365 | unsigned long adr; | ||
366 | |||
367 | size = PAGE_ALIGN(size); | ||
368 | mem = vmalloc_32(size); | ||
369 | if (!mem) | ||
370 | return NULL; | ||
371 | |||
372 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
373 | adr = (unsigned long) mem; | ||
374 | while (size > 0) { | ||
375 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
376 | adr += PAGE_SIZE; | ||
377 | size -= PAGE_SIZE; | ||
378 | } | ||
379 | |||
380 | return mem; | ||
381 | } | ||
382 | |||
383 | static void rvfree(void *mem, unsigned long size) | ||
384 | { | ||
385 | unsigned long adr; | ||
386 | |||
387 | if (!mem) | ||
388 | return; | ||
389 | |||
390 | adr = (unsigned long) mem; | ||
391 | while ((long) size > 0) { | ||
392 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
393 | adr += PAGE_SIZE; | ||
394 | size -= PAGE_SIZE; | ||
395 | } | ||
396 | vfree(mem); | ||
397 | } | ||
398 | |||
399 | struct vicam_camera { | ||
400 | u16 shutter_speed; // capture shutter speed | ||
401 | u16 gain; // capture gain | ||
402 | |||
403 | u8 *raw_image; // raw data captured from the camera | ||
404 | u8 *framebuf; // processed data in RGB24 format | ||
405 | u8 *cntrlbuf; // area used to send control msgs | ||
406 | |||
407 | struct video_device vdev; // v4l video device | ||
408 | struct usb_device *udev; // usb device | ||
409 | |||
410 | /* guard against simultaneous accesses to the camera */ | ||
411 | struct mutex cam_lock; | ||
412 | |||
413 | int is_initialized; | ||
414 | u8 open_count; | ||
415 | u8 bulkEndpoint; | ||
416 | int needsDummyRead; | ||
417 | |||
418 | #if defined(CONFIG_VIDEO_PROC_FS) | ||
419 | struct proc_dir_entry *proc_dir; | ||
420 | #endif | ||
421 | |||
422 | }; | ||
423 | |||
424 | static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id); | ||
425 | static void vicam_disconnect(struct usb_interface *intf); | ||
426 | static void read_frame(struct vicam_camera *cam, int framenum); | ||
427 | static void vicam_decode_color(const u8 *, u8 *); | ||
428 | |||
429 | static int __send_control_msg(struct vicam_camera *cam, | ||
430 | u8 request, | ||
431 | u16 value, | ||
432 | u16 index, | ||
433 | unsigned char *cp, | ||
434 | u16 size) | ||
435 | { | ||
436 | int status; | ||
437 | |||
438 | /* cp must be memory that has been allocated by kmalloc */ | ||
439 | |||
440 | status = usb_control_msg(cam->udev, | ||
441 | usb_sndctrlpipe(cam->udev, 0), | ||
442 | request, | ||
443 | USB_DIR_OUT | USB_TYPE_VENDOR | | ||
444 | USB_RECIP_DEVICE, value, index, | ||
445 | cp, size, 1000); | ||
446 | |||
447 | status = min(status, 0); | ||
448 | |||
449 | if (status < 0) { | ||
450 | printk(KERN_INFO "Failed sending control message, error %d.\n", | ||
451 | status); | ||
452 | } | ||
453 | |||
454 | return status; | ||
455 | } | ||
456 | |||
457 | static int send_control_msg(struct vicam_camera *cam, | ||
458 | u8 request, | ||
459 | u16 value, | ||
460 | u16 index, | ||
461 | unsigned char *cp, | ||
462 | u16 size) | ||
463 | { | ||
464 | int status = -ENODEV; | ||
465 | mutex_lock(&cam->cam_lock); | ||
466 | if (cam->udev) { | ||
467 | status = __send_control_msg(cam, request, value, | ||
468 | index, cp, size); | ||
469 | } | ||
470 | mutex_unlock(&cam->cam_lock); | ||
471 | return status; | ||
472 | } | ||
473 | static int | ||
474 | initialize_camera(struct vicam_camera *cam) | ||
475 | { | ||
476 | const struct { | ||
477 | u8 *data; | ||
478 | u32 size; | ||
479 | } firmware[] = { | ||
480 | { .data = setup1, .size = sizeof(setup1) }, | ||
481 | { .data = setup2, .size = sizeof(setup2) }, | ||
482 | { .data = setup3, .size = sizeof(setup3) }, | ||
483 | { .data = setup4, .size = sizeof(setup4) }, | ||
484 | { .data = setup5, .size = sizeof(setup5) }, | ||
485 | { .data = setup3, .size = sizeof(setup3) }, | ||
486 | { .data = NULL, .size = 0 } | ||
487 | }; | ||
488 | |||
489 | int err, i; | ||
490 | |||
491 | for (i = 0, err = 0; firmware[i].data && !err; i++) { | ||
492 | memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size); | ||
493 | |||
494 | err = send_control_msg(cam, 0xff, 0, 0, | ||
495 | cam->cntrlbuf, firmware[i].size); | ||
496 | } | ||
497 | |||
498 | return err; | ||
499 | } | ||
500 | |||
501 | static int | ||
502 | set_camera_power(struct vicam_camera *cam, int state) | ||
503 | { | ||
504 | int status; | ||
505 | |||
506 | if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0) | ||
507 | return status; | ||
508 | |||
509 | if (state) { | ||
510 | send_control_msg(cam, 0x55, 1, 0, NULL, 0); | ||
511 | } | ||
512 | |||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static int | ||
517 | vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg) | ||
518 | { | ||
519 | void __user *user_arg = (void __user *)arg; | ||
520 | struct vicam_camera *cam = file->private_data; | ||
521 | int retval = 0; | ||
522 | |||
523 | if (!cam) | ||
524 | return -ENODEV; | ||
525 | |||
526 | switch (ioctlnr) { | ||
527 | /* query capabilities */ | ||
528 | case VIDIOCGCAP: | ||
529 | { | ||
530 | struct video_capability b; | ||
531 | |||
532 | DBG("VIDIOCGCAP\n"); | ||
533 | memset(&b, 0, sizeof(b)); | ||
534 | strcpy(b.name, "ViCam-based Camera"); | ||
535 | b.type = VID_TYPE_CAPTURE; | ||
536 | b.channels = 1; | ||
537 | b.audios = 0; | ||
538 | b.maxwidth = 320; /* VIDEOSIZE_CIF */ | ||
539 | b.maxheight = 240; | ||
540 | b.minwidth = 320; /* VIDEOSIZE_48_48 */ | ||
541 | b.minheight = 240; | ||
542 | |||
543 | if (copy_to_user(user_arg, &b, sizeof(b))) | ||
544 | retval = -EFAULT; | ||
545 | |||
546 | break; | ||
547 | } | ||
548 | /* get/set video source - we are a camera and nothing else */ | ||
549 | case VIDIOCGCHAN: | ||
550 | { | ||
551 | struct video_channel v; | ||
552 | |||
553 | DBG("VIDIOCGCHAN\n"); | ||
554 | if (copy_from_user(&v, user_arg, sizeof(v))) { | ||
555 | retval = -EFAULT; | ||
556 | break; | ||
557 | } | ||
558 | if (v.channel != 0) { | ||
559 | retval = -EINVAL; | ||
560 | break; | ||
561 | } | ||
562 | |||
563 | v.channel = 0; | ||
564 | strcpy(v.name, "Camera"); | ||
565 | v.tuners = 0; | ||
566 | v.flags = 0; | ||
567 | v.type = VIDEO_TYPE_CAMERA; | ||
568 | v.norm = 0; | ||
569 | |||
570 | if (copy_to_user(user_arg, &v, sizeof(v))) | ||
571 | retval = -EFAULT; | ||
572 | break; | ||
573 | } | ||
574 | |||
575 | case VIDIOCSCHAN: | ||
576 | { | ||
577 | int v; | ||
578 | |||
579 | if (copy_from_user(&v, user_arg, sizeof(v))) | ||
580 | retval = -EFAULT; | ||
581 | DBG("VIDIOCSCHAN %d\n", v); | ||
582 | |||
583 | if (retval == 0 && v != 0) | ||
584 | retval = -EINVAL; | ||
585 | |||
586 | break; | ||
587 | } | ||
588 | |||
589 | /* image properties */ | ||
590 | case VIDIOCGPICT: | ||
591 | { | ||
592 | struct video_picture vp; | ||
593 | DBG("VIDIOCGPICT\n"); | ||
594 | memset(&vp, 0, sizeof (struct video_picture)); | ||
595 | vp.brightness = cam->gain << 8; | ||
596 | vp.depth = 24; | ||
597 | vp.palette = VIDEO_PALETTE_RGB24; | ||
598 | if (copy_to_user(user_arg, &vp, sizeof (struct video_picture))) | ||
599 | retval = -EFAULT; | ||
600 | break; | ||
601 | } | ||
602 | |||
603 | case VIDIOCSPICT: | ||
604 | { | ||
605 | struct video_picture vp; | ||
606 | |||
607 | if (copy_from_user(&vp, user_arg, sizeof(vp))) { | ||
608 | retval = -EFAULT; | ||
609 | break; | ||
610 | } | ||
611 | |||
612 | DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth, | ||
613 | vp.palette); | ||
614 | |||
615 | cam->gain = vp.brightness >> 8; | ||
616 | |||
617 | if (vp.depth != 24 | ||
618 | || vp.palette != VIDEO_PALETTE_RGB24) | ||
619 | retval = -EINVAL; | ||
620 | |||
621 | break; | ||
622 | } | ||
623 | |||
624 | /* get/set capture window */ | ||
625 | case VIDIOCGWIN: | ||
626 | { | ||
627 | struct video_window vw; | ||
628 | vw.x = 0; | ||
629 | vw.y = 0; | ||
630 | vw.width = 320; | ||
631 | vw.height = 240; | ||
632 | vw.chromakey = 0; | ||
633 | vw.flags = 0; | ||
634 | vw.clips = NULL; | ||
635 | vw.clipcount = 0; | ||
636 | |||
637 | DBG("VIDIOCGWIN\n"); | ||
638 | |||
639 | if (copy_to_user(user_arg, (void *)&vw, sizeof(vw))) | ||
640 | retval = -EFAULT; | ||
641 | |||
642 | // I'm not sure what the deal with a capture window is, it is very poorly described | ||
643 | // in the doc. So I won't support it now. | ||
644 | break; | ||
645 | } | ||
646 | |||
647 | case VIDIOCSWIN: | ||
648 | { | ||
649 | |||
650 | struct video_window vw; | ||
651 | |||
652 | if (copy_from_user(&vw, user_arg, sizeof(vw))) { | ||
653 | retval = -EFAULT; | ||
654 | break; | ||
655 | } | ||
656 | |||
657 | DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height); | ||
658 | |||
659 | if ( vw.width != 320 || vw.height != 240 ) | ||
660 | retval = -EFAULT; | ||
661 | |||
662 | break; | ||
663 | } | ||
664 | |||
665 | /* mmap interface */ | ||
666 | case VIDIOCGMBUF: | ||
667 | { | ||
668 | struct video_mbuf vm; | ||
669 | int i; | ||
670 | |||
671 | DBG("VIDIOCGMBUF\n"); | ||
672 | memset(&vm, 0, sizeof (vm)); | ||
673 | vm.size = | ||
674 | VICAM_MAX_FRAME_SIZE * VICAM_FRAMES; | ||
675 | vm.frames = VICAM_FRAMES; | ||
676 | for (i = 0; i < VICAM_FRAMES; i++) | ||
677 | vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i; | ||
678 | |||
679 | if (copy_to_user(user_arg, (void *)&vm, sizeof(vm))) | ||
680 | retval = -EFAULT; | ||
681 | |||
682 | break; | ||
683 | } | ||
684 | |||
685 | case VIDIOCMCAPTURE: | ||
686 | { | ||
687 | struct video_mmap vm; | ||
688 | // int video_size; | ||
689 | |||
690 | if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) { | ||
691 | retval = -EFAULT; | ||
692 | break; | ||
693 | } | ||
694 | |||
695 | DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format); | ||
696 | |||
697 | if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 ) | ||
698 | retval = -EINVAL; | ||
699 | |||
700 | // in theory right here we'd start the image capturing | ||
701 | // (fill in a bulk urb and submit it asynchronously) | ||
702 | // | ||
703 | // Instead we're going to do a total hack job for now and | ||
704 | // retrieve the frame in VIDIOCSYNC | ||
705 | |||
706 | break; | ||
707 | } | ||
708 | |||
709 | case VIDIOCSYNC: | ||
710 | { | ||
711 | int frame; | ||
712 | |||
713 | if (copy_from_user((void *)&frame, user_arg, sizeof(int))) { | ||
714 | retval = -EFAULT; | ||
715 | break; | ||
716 | } | ||
717 | DBG("VIDIOCSYNC: %d\n", frame); | ||
718 | |||
719 | read_frame(cam, frame); | ||
720 | vicam_decode_color(cam->raw_image, | ||
721 | cam->framebuf + | ||
722 | frame * VICAM_MAX_FRAME_SIZE ); | ||
723 | |||
724 | break; | ||
725 | } | ||
726 | |||
727 | /* pointless to implement overlay with this camera */ | ||
728 | case VIDIOCCAPTURE: | ||
729 | case VIDIOCGFBUF: | ||
730 | case VIDIOCSFBUF: | ||
731 | case VIDIOCKEY: | ||
732 | retval = -EINVAL; | ||
733 | break; | ||
734 | |||
735 | /* tuner interface - we have none */ | ||
736 | case VIDIOCGTUNER: | ||
737 | case VIDIOCSTUNER: | ||
738 | case VIDIOCGFREQ: | ||
739 | case VIDIOCSFREQ: | ||
740 | retval = -EINVAL; | ||
741 | break; | ||
742 | |||
743 | /* audio interface - we have none */ | ||
744 | case VIDIOCGAUDIO: | ||
745 | case VIDIOCSAUDIO: | ||
746 | retval = -EINVAL; | ||
747 | break; | ||
748 | default: | ||
749 | retval = -ENOIOCTLCMD; | ||
750 | break; | ||
751 | } | ||
752 | |||
753 | return retval; | ||
754 | } | ||
755 | |||
756 | static int | ||
757 | vicam_open(struct inode *inode, struct file *file) | ||
758 | { | ||
759 | struct video_device *dev = video_devdata(file); | ||
760 | struct vicam_camera *cam = | ||
761 | (struct vicam_camera *) dev->priv; | ||
762 | DBG("open\n"); | ||
763 | |||
764 | if (!cam) { | ||
765 | printk(KERN_ERR | ||
766 | "vicam video_device improperly initialized"); | ||
767 | return -EINVAL; | ||
768 | } | ||
769 | |||
770 | /* the videodev_lock held above us protects us from | ||
771 | * simultaneous opens...for now. we probably shouldn't | ||
772 | * rely on this fact forever. | ||
773 | */ | ||
774 | |||
775 | if (cam->open_count > 0) { | ||
776 | printk(KERN_INFO | ||
777 | "vicam_open called on already opened camera"); | ||
778 | return -EBUSY; | ||
779 | } | ||
780 | |||
781 | cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL); | ||
782 | if (!cam->raw_image) { | ||
783 | return -ENOMEM; | ||
784 | } | ||
785 | |||
786 | cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); | ||
787 | if (!cam->framebuf) { | ||
788 | kfree(cam->raw_image); | ||
789 | return -ENOMEM; | ||
790 | } | ||
791 | |||
792 | cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
793 | if (!cam->cntrlbuf) { | ||
794 | kfree(cam->raw_image); | ||
795 | rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); | ||
796 | return -ENOMEM; | ||
797 | } | ||
798 | |||
799 | // First upload firmware, then turn the camera on | ||
800 | |||
801 | if (!cam->is_initialized) { | ||
802 | initialize_camera(cam); | ||
803 | |||
804 | cam->is_initialized = 1; | ||
805 | } | ||
806 | |||
807 | set_camera_power(cam, 1); | ||
808 | |||
809 | cam->needsDummyRead = 1; | ||
810 | cam->open_count++; | ||
811 | |||
812 | file->private_data = cam; | ||
813 | |||
814 | return 0; | ||
815 | } | ||
816 | |||
817 | static int | ||
818 | vicam_close(struct inode *inode, struct file *file) | ||
819 | { | ||
820 | struct vicam_camera *cam = file->private_data; | ||
821 | int open_count; | ||
822 | struct usb_device *udev; | ||
823 | |||
824 | DBG("close\n"); | ||
825 | |||
826 | /* it's not the end of the world if | ||
827 | * we fail to turn the camera off. | ||
828 | */ | ||
829 | |||
830 | set_camera_power(cam, 0); | ||
831 | |||
832 | kfree(cam->raw_image); | ||
833 | rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); | ||
834 | kfree(cam->cntrlbuf); | ||
835 | |||
836 | mutex_lock(&cam->cam_lock); | ||
837 | |||
838 | cam->open_count--; | ||
839 | open_count = cam->open_count; | ||
840 | udev = cam->udev; | ||
841 | |||
842 | mutex_unlock(&cam->cam_lock); | ||
843 | |||
844 | if (!open_count && !udev) { | ||
845 | kfree(cam); | ||
846 | } | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | static void vicam_decode_color(const u8 *data, u8 *rgb) | ||
852 | { | ||
853 | /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB | ||
854 | * Copyright (C) 2002 Monroe Williams (monroe@pobox.com) | ||
855 | */ | ||
856 | |||
857 | int i, prevY, nextY; | ||
858 | |||
859 | prevY = 512; | ||
860 | nextY = 512; | ||
861 | |||
862 | data += VICAM_HEADER_SIZE; | ||
863 | |||
864 | for( i = 0; i < 240; i++, data += 512 ) { | ||
865 | const int y = ( i * 242 ) / 240; | ||
866 | |||
867 | int j, prevX, nextX; | ||
868 | int Y, Cr, Cb; | ||
869 | |||
870 | if ( y == 242 - 1 ) { | ||
871 | nextY = -512; | ||
872 | } | ||
873 | |||
874 | prevX = 1; | ||
875 | nextX = 1; | ||
876 | |||
877 | for ( j = 0; j < 320; j++, rgb += 3 ) { | ||
878 | const int x = ( j * 512 ) / 320; | ||
879 | const u8 * const src = &data[x]; | ||
880 | |||
881 | if ( x == 512 - 1 ) { | ||
882 | nextX = -1; | ||
883 | } | ||
884 | |||
885 | Cr = ( src[prevX] - src[0] ) + | ||
886 | ( src[nextX] - src[0] ); | ||
887 | Cr /= 2; | ||
888 | |||
889 | Cb = ( src[prevY] - src[prevX + prevY] ) + | ||
890 | ( src[prevY] - src[nextX + prevY] ) + | ||
891 | ( src[nextY] - src[prevX + nextY] ) + | ||
892 | ( src[nextY] - src[nextX + nextY] ); | ||
893 | Cb /= 4; | ||
894 | |||
895 | Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 ); | ||
896 | |||
897 | if ( i & 1 ) { | ||
898 | int Ct = Cr; | ||
899 | Cr = Cb; | ||
900 | Cb = Ct; | ||
901 | } | ||
902 | |||
903 | if ( ( x ^ i ) & 1 ) { | ||
904 | Cr = -Cr; | ||
905 | Cb = -Cb; | ||
906 | } | ||
907 | |||
908 | rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) + | ||
909 | 500 ) / 900, 0, 255 ); | ||
910 | rgb[1] = clamp( ( ( Y - ( 392 * Cb ) - | ||
911 | ( 813 * Cr ) ) + | ||
912 | 500 ) / 1000, 0, 255 ); | ||
913 | rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) + | ||
914 | 500 ) / 1300, 0, 255 ); | ||
915 | |||
916 | prevX = -1; | ||
917 | } | ||
918 | |||
919 | prevY = -512; | ||
920 | } | ||
921 | } | ||
922 | |||
923 | static void | ||
924 | read_frame(struct vicam_camera *cam, int framenum) | ||
925 | { | ||
926 | unsigned char *request = cam->cntrlbuf; | ||
927 | int realShutter; | ||
928 | int n; | ||
929 | int actual_length; | ||
930 | |||
931 | if (cam->needsDummyRead) { | ||
932 | cam->needsDummyRead = 0; | ||
933 | read_frame(cam, framenum); | ||
934 | } | ||
935 | |||
936 | memset(request, 0, 16); | ||
937 | request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain | ||
938 | |||
939 | request[1] = 0; // 512x242 capture | ||
940 | |||
941 | request[2] = 0x90; // the function of these two bytes | ||
942 | request[3] = 0x07; // is not yet understood | ||
943 | |||
944 | if (cam->shutter_speed > 60) { | ||
945 | // Short exposure | ||
946 | realShutter = | ||
947 | ((-15631900 / cam->shutter_speed) + 260533) / 1000; | ||
948 | request[4] = realShutter & 0xFF; | ||
949 | request[5] = (realShutter >> 8) & 0xFF; | ||
950 | request[6] = 0x03; | ||
951 | request[7] = 0x01; | ||
952 | } else { | ||
953 | // Long exposure | ||
954 | realShutter = 15600 / cam->shutter_speed - 1; | ||
955 | request[4] = 0; | ||
956 | request[5] = 0; | ||
957 | request[6] = realShutter & 0xFF; | ||
958 | request[7] = realShutter >> 8; | ||
959 | } | ||
960 | |||
961 | // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0 | ||
962 | request[8] = 0; | ||
963 | // bytes 9-15 do not seem to affect exposure or image quality | ||
964 | |||
965 | mutex_lock(&cam->cam_lock); | ||
966 | |||
967 | if (!cam->udev) { | ||
968 | goto done; | ||
969 | } | ||
970 | |||
971 | n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16); | ||
972 | |||
973 | if (n < 0) { | ||
974 | printk(KERN_ERR | ||
975 | " Problem sending frame capture control message"); | ||
976 | goto done; | ||
977 | } | ||
978 | |||
979 | n = usb_bulk_msg(cam->udev, | ||
980 | usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint), | ||
981 | cam->raw_image, | ||
982 | 512 * 242 + 128, &actual_length, 10000); | ||
983 | |||
984 | if (n < 0) { | ||
985 | printk(KERN_ERR "Problem during bulk read of frame data: %d\n", | ||
986 | n); | ||
987 | } | ||
988 | |||
989 | done: | ||
990 | mutex_unlock(&cam->cam_lock); | ||
991 | } | ||
992 | |||
993 | static ssize_t | ||
994 | vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos ) | ||
995 | { | ||
996 | struct vicam_camera *cam = file->private_data; | ||
997 | |||
998 | DBG("read %d bytes.\n", (int) count); | ||
999 | |||
1000 | if (*ppos >= VICAM_MAX_FRAME_SIZE) { | ||
1001 | *ppos = 0; | ||
1002 | return 0; | ||
1003 | } | ||
1004 | |||
1005 | if (*ppos == 0) { | ||
1006 | read_frame(cam, 0); | ||
1007 | vicam_decode_color(cam->raw_image, | ||
1008 | cam->framebuf + | ||
1009 | 0 * VICAM_MAX_FRAME_SIZE); | ||
1010 | } | ||
1011 | |||
1012 | count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos); | ||
1013 | |||
1014 | if (copy_to_user(buf, &cam->framebuf[*ppos], count)) { | ||
1015 | count = -EFAULT; | ||
1016 | } else { | ||
1017 | *ppos += count; | ||
1018 | } | ||
1019 | |||
1020 | if (count == VICAM_MAX_FRAME_SIZE) { | ||
1021 | *ppos = 0; | ||
1022 | } | ||
1023 | |||
1024 | return count; | ||
1025 | } | ||
1026 | |||
1027 | |||
1028 | static int | ||
1029 | vicam_mmap(struct file *file, struct vm_area_struct *vma) | ||
1030 | { | ||
1031 | // TODO: allocate the raw frame buffer if necessary | ||
1032 | unsigned long page, pos; | ||
1033 | unsigned long start = vma->vm_start; | ||
1034 | unsigned long size = vma->vm_end-vma->vm_start; | ||
1035 | struct vicam_camera *cam = file->private_data; | ||
1036 | |||
1037 | if (!cam) | ||
1038 | return -ENODEV; | ||
1039 | |||
1040 | DBG("vicam_mmap: %ld\n", size); | ||
1041 | |||
1042 | /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes | ||
1043 | * to the size the application requested for mmap and it was screwing apps up. | ||
1044 | if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE) | ||
1045 | return -EINVAL; | ||
1046 | */ | ||
1047 | |||
1048 | pos = (unsigned long)cam->framebuf; | ||
1049 | while (size > 0) { | ||
1050 | page = vmalloc_to_pfn((void *)pos); | ||
1051 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) | ||
1052 | return -EAGAIN; | ||
1053 | |||
1054 | start += PAGE_SIZE; | ||
1055 | pos += PAGE_SIZE; | ||
1056 | if (size > PAGE_SIZE) | ||
1057 | size -= PAGE_SIZE; | ||
1058 | else | ||
1059 | size = 0; | ||
1060 | } | ||
1061 | |||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1065 | #if defined(CONFIG_VIDEO_PROC_FS) | ||
1066 | |||
1067 | static struct proc_dir_entry *vicam_proc_root = NULL; | ||
1068 | |||
1069 | static int vicam_read_helper(char *page, char **start, off_t off, | ||
1070 | int count, int *eof, int value) | ||
1071 | { | ||
1072 | char *out = page; | ||
1073 | int len; | ||
1074 | |||
1075 | out += sprintf(out, "%d",value); | ||
1076 | |||
1077 | len = out - page; | ||
1078 | len -= off; | ||
1079 | if (len < count) { | ||
1080 | *eof = 1; | ||
1081 | if (len <= 0) | ||
1082 | return 0; | ||
1083 | } else | ||
1084 | len = count; | ||
1085 | |||
1086 | *start = page + off; | ||
1087 | return len; | ||
1088 | } | ||
1089 | |||
1090 | static int vicam_read_proc_shutter(char *page, char **start, off_t off, | ||
1091 | int count, int *eof, void *data) | ||
1092 | { | ||
1093 | return vicam_read_helper(page,start,off,count,eof, | ||
1094 | ((struct vicam_camera *)data)->shutter_speed); | ||
1095 | } | ||
1096 | |||
1097 | static int vicam_read_proc_gain(char *page, char **start, off_t off, | ||
1098 | int count, int *eof, void *data) | ||
1099 | { | ||
1100 | return vicam_read_helper(page,start,off,count,eof, | ||
1101 | ((struct vicam_camera *)data)->gain); | ||
1102 | } | ||
1103 | |||
1104 | static int | ||
1105 | vicam_write_proc_shutter(struct file *file, const char *buffer, | ||
1106 | unsigned long count, void *data) | ||
1107 | { | ||
1108 | u16 stmp; | ||
1109 | char kbuf[8]; | ||
1110 | struct vicam_camera *cam = (struct vicam_camera *) data; | ||
1111 | |||
1112 | if (count > 6) | ||
1113 | return -EINVAL; | ||
1114 | |||
1115 | if (copy_from_user(kbuf, buffer, count)) | ||
1116 | return -EFAULT; | ||
1117 | |||
1118 | stmp = (u16) simple_strtoul(kbuf, NULL, 10); | ||
1119 | if (stmp < 4 || stmp > 32000) | ||
1120 | return -EINVAL; | ||
1121 | |||
1122 | cam->shutter_speed = stmp; | ||
1123 | |||
1124 | return count; | ||
1125 | } | ||
1126 | |||
1127 | static int | ||
1128 | vicam_write_proc_gain(struct file *file, const char *buffer, | ||
1129 | unsigned long count, void *data) | ||
1130 | { | ||
1131 | u16 gtmp; | ||
1132 | char kbuf[8]; | ||
1133 | |||
1134 | struct vicam_camera *cam = (struct vicam_camera *) data; | ||
1135 | |||
1136 | if (count > 4) | ||
1137 | return -EINVAL; | ||
1138 | |||
1139 | if (copy_from_user(kbuf, buffer, count)) | ||
1140 | return -EFAULT; | ||
1141 | |||
1142 | gtmp = (u16) simple_strtoul(kbuf, NULL, 10); | ||
1143 | if (gtmp > 255) | ||
1144 | return -EINVAL; | ||
1145 | cam->gain = gtmp; | ||
1146 | |||
1147 | return count; | ||
1148 | } | ||
1149 | |||
1150 | static void | ||
1151 | vicam_create_proc_root(void) | ||
1152 | { | ||
1153 | vicam_proc_root = proc_mkdir("video/vicam", NULL); | ||
1154 | |||
1155 | if (vicam_proc_root) | ||
1156 | vicam_proc_root->owner = THIS_MODULE; | ||
1157 | else | ||
1158 | printk(KERN_ERR | ||
1159 | "could not create /proc entry for vicam!"); | ||
1160 | } | ||
1161 | |||
1162 | static void | ||
1163 | vicam_destroy_proc_root(void) | ||
1164 | { | ||
1165 | if (vicam_proc_root) | ||
1166 | remove_proc_entry("video/vicam", 0); | ||
1167 | } | ||
1168 | |||
1169 | static void | ||
1170 | vicam_create_proc_entry(struct vicam_camera *cam) | ||
1171 | { | ||
1172 | char name[64]; | ||
1173 | struct proc_dir_entry *ent; | ||
1174 | |||
1175 | DBG(KERN_INFO "vicam: creating proc entry\n"); | ||
1176 | |||
1177 | if (!vicam_proc_root || !cam) { | ||
1178 | printk(KERN_INFO | ||
1179 | "vicam: could not create proc entry, %s pointer is null.\n", | ||
1180 | (!cam ? "camera" : "root")); | ||
1181 | return; | ||
1182 | } | ||
1183 | |||
1184 | sprintf(name, "video%d", cam->vdev.minor); | ||
1185 | |||
1186 | cam->proc_dir = proc_mkdir(name, vicam_proc_root); | ||
1187 | |||
1188 | if ( !cam->proc_dir ) | ||
1189 | return; // FIXME: We should probably return an error here | ||
1190 | |||
1191 | ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR, | ||
1192 | cam->proc_dir); | ||
1193 | if (ent) { | ||
1194 | ent->data = cam; | ||
1195 | ent->read_proc = vicam_read_proc_shutter; | ||
1196 | ent->write_proc = vicam_write_proc_shutter; | ||
1197 | ent->size = 64; | ||
1198 | } | ||
1199 | |||
1200 | ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR, | ||
1201 | cam->proc_dir); | ||
1202 | if (ent) { | ||
1203 | ent->data = cam; | ||
1204 | ent->read_proc = vicam_read_proc_gain; | ||
1205 | ent->write_proc = vicam_write_proc_gain; | ||
1206 | ent->size = 64; | ||
1207 | } | ||
1208 | } | ||
1209 | |||
1210 | static void | ||
1211 | vicam_destroy_proc_entry(void *ptr) | ||
1212 | { | ||
1213 | struct vicam_camera *cam = (struct vicam_camera *) ptr; | ||
1214 | char name[16]; | ||
1215 | |||
1216 | if ( !cam->proc_dir ) | ||
1217 | return; | ||
1218 | |||
1219 | sprintf(name, "video%d", cam->vdev.minor); | ||
1220 | remove_proc_entry("shutter", cam->proc_dir); | ||
1221 | remove_proc_entry("gain", cam->proc_dir); | ||
1222 | remove_proc_entry(name,vicam_proc_root); | ||
1223 | cam->proc_dir = NULL; | ||
1224 | |||
1225 | } | ||
1226 | |||
1227 | #else | ||
1228 | static inline void vicam_create_proc_root(void) { } | ||
1229 | static inline void vicam_destroy_proc_root(void) { } | ||
1230 | static inline void vicam_create_proc_entry(struct vicam_camera *cam) { } | ||
1231 | static inline void vicam_destroy_proc_entry(void *ptr) { } | ||
1232 | #endif | ||
1233 | |||
1234 | static struct file_operations vicam_fops = { | ||
1235 | .owner = THIS_MODULE, | ||
1236 | .open = vicam_open, | ||
1237 | .release = vicam_close, | ||
1238 | .read = vicam_read, | ||
1239 | .mmap = vicam_mmap, | ||
1240 | .ioctl = vicam_ioctl, | ||
1241 | .compat_ioctl = v4l_compat_ioctl32, | ||
1242 | .llseek = no_llseek, | ||
1243 | }; | ||
1244 | |||
1245 | static struct video_device vicam_template = { | ||
1246 | .owner = THIS_MODULE, | ||
1247 | .name = "ViCam-based USB Camera", | ||
1248 | .type = VID_TYPE_CAPTURE, | ||
1249 | .hardware = VID_HARDWARE_VICAM, | ||
1250 | .fops = &vicam_fops, | ||
1251 | .minor = -1, | ||
1252 | }; | ||
1253 | |||
1254 | /* table of devices that work with this driver */ | ||
1255 | static struct usb_device_id vicam_table[] = { | ||
1256 | {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)}, | ||
1257 | {} /* Terminating entry */ | ||
1258 | }; | ||
1259 | |||
1260 | MODULE_DEVICE_TABLE(usb, vicam_table); | ||
1261 | |||
1262 | static struct usb_driver vicam_driver = { | ||
1263 | .name = "vicam", | ||
1264 | .probe = vicam_probe, | ||
1265 | .disconnect = vicam_disconnect, | ||
1266 | .id_table = vicam_table | ||
1267 | }; | ||
1268 | |||
1269 | /** | ||
1270 | * vicam_probe | ||
1271 | * @intf: the interface | ||
1272 | * @id: the device id | ||
1273 | * | ||
1274 | * Called by the usb core when a new device is connected that it thinks | ||
1275 | * this driver might be interested in. | ||
1276 | */ | ||
1277 | static int | ||
1278 | vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) | ||
1279 | { | ||
1280 | struct usb_device *dev = interface_to_usbdev(intf); | ||
1281 | int bulkEndpoint = 0; | ||
1282 | const struct usb_host_interface *interface; | ||
1283 | const struct usb_endpoint_descriptor *endpoint; | ||
1284 | struct vicam_camera *cam; | ||
1285 | |||
1286 | printk(KERN_INFO "ViCam based webcam connected\n"); | ||
1287 | |||
1288 | interface = intf->cur_altsetting; | ||
1289 | |||
1290 | DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n", | ||
1291 | interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints)); | ||
1292 | endpoint = &interface->endpoint[0].desc; | ||
1293 | |||
1294 | if ((endpoint->bEndpointAddress & 0x80) && | ||
1295 | ((endpoint->bmAttributes & 3) == 0x02)) { | ||
1296 | /* we found a bulk in endpoint */ | ||
1297 | bulkEndpoint = endpoint->bEndpointAddress; | ||
1298 | } else { | ||
1299 | printk(KERN_ERR | ||
1300 | "No bulk in endpoint was found ?! (this is bad)\n"); | ||
1301 | } | ||
1302 | |||
1303 | if ((cam = | ||
1304 | kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) { | ||
1305 | printk(KERN_WARNING | ||
1306 | "could not allocate kernel memory for vicam_camera struct\n"); | ||
1307 | return -ENOMEM; | ||
1308 | } | ||
1309 | |||
1310 | memset(cam, 0, sizeof (struct vicam_camera)); | ||
1311 | |||
1312 | cam->shutter_speed = 15; | ||
1313 | |||
1314 | mutex_init(&cam->cam_lock); | ||
1315 | |||
1316 | memcpy(&cam->vdev, &vicam_template, | ||
1317 | sizeof (vicam_template)); | ||
1318 | cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only | ||
1319 | |||
1320 | cam->udev = dev; | ||
1321 | cam->bulkEndpoint = bulkEndpoint; | ||
1322 | |||
1323 | if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) { | ||
1324 | kfree(cam); | ||
1325 | printk(KERN_WARNING "video_register_device failed\n"); | ||
1326 | return -EIO; | ||
1327 | } | ||
1328 | |||
1329 | vicam_create_proc_entry(cam); | ||
1330 | |||
1331 | printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor); | ||
1332 | |||
1333 | usb_set_intfdata (intf, cam); | ||
1334 | |||
1335 | return 0; | ||
1336 | } | ||
1337 | |||
1338 | static void | ||
1339 | vicam_disconnect(struct usb_interface *intf) | ||
1340 | { | ||
1341 | int open_count; | ||
1342 | struct vicam_camera *cam = usb_get_intfdata (intf); | ||
1343 | usb_set_intfdata (intf, NULL); | ||
1344 | |||
1345 | /* we must unregister the device before taking its | ||
1346 | * cam_lock. This is because the video open call | ||
1347 | * holds the same lock as video unregister. if we | ||
1348 | * unregister inside of the cam_lock and open also | ||
1349 | * uses the cam_lock, we get deadlock. | ||
1350 | */ | ||
1351 | |||
1352 | video_unregister_device(&cam->vdev); | ||
1353 | |||
1354 | /* stop the camera from being used */ | ||
1355 | |||
1356 | mutex_lock(&cam->cam_lock); | ||
1357 | |||
1358 | /* mark the camera as gone */ | ||
1359 | |||
1360 | cam->udev = NULL; | ||
1361 | |||
1362 | vicam_destroy_proc_entry(cam); | ||
1363 | |||
1364 | /* the only thing left to do is synchronize with | ||
1365 | * our close/release function on who should release | ||
1366 | * the camera memory. if there are any users using the | ||
1367 | * camera, it's their job. if there are no users, | ||
1368 | * it's ours. | ||
1369 | */ | ||
1370 | |||
1371 | open_count = cam->open_count; | ||
1372 | |||
1373 | mutex_unlock(&cam->cam_lock); | ||
1374 | |||
1375 | if (!open_count) { | ||
1376 | kfree(cam); | ||
1377 | } | ||
1378 | |||
1379 | printk(KERN_DEBUG "ViCam-based WebCam disconnected\n"); | ||
1380 | } | ||
1381 | |||
1382 | /* | ||
1383 | */ | ||
1384 | static int __init | ||
1385 | usb_vicam_init(void) | ||
1386 | { | ||
1387 | int retval; | ||
1388 | DBG(KERN_INFO "ViCam-based WebCam driver startup\n"); | ||
1389 | vicam_create_proc_root(); | ||
1390 | retval = usb_register(&vicam_driver); | ||
1391 | if (retval) | ||
1392 | printk(KERN_WARNING "usb_register failed!\n"); | ||
1393 | return retval; | ||
1394 | } | ||
1395 | |||
1396 | static void __exit | ||
1397 | usb_vicam_exit(void) | ||
1398 | { | ||
1399 | DBG(KERN_INFO | ||
1400 | "ViCam-based WebCam driver shutdown\n"); | ||
1401 | |||
1402 | usb_deregister(&vicam_driver); | ||
1403 | vicam_destroy_proc_root(); | ||
1404 | } | ||
1405 | |||
1406 | module_init(usb_vicam_init); | ||
1407 | module_exit(usb_vicam_exit); | ||
1408 | |||
1409 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
1410 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
1411 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c new file mode 100644 index 000000000000..b57dec3782e0 --- /dev/null +++ b/drivers/media/video/w9968cf.c | |||
@@ -0,0 +1,3691 @@ | |||
1 | /*************************************************************************** | ||
2 | * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. * | ||
3 | * * | ||
4 | * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * - Memory management code from bttv driver by Ralph Metzler, * | ||
7 | * Marcus Metzler and Gerd Knorr. * | ||
8 | * - I2C interface to kernel, high-level image sensor control routines and * | ||
9 | * some symbolic names from OV511 driver by Mark W. McClelland. * | ||
10 | * - Low-level I2C fast write function by Piotr Czerczak. * | ||
11 | * - Low-level I2C read function by Frederic Jouault. * | ||
12 | * * | ||
13 | * This program is free software; you can redistribute it and/or modify * | ||
14 | * it under the terms of the GNU General Public License as published by * | ||
15 | * the Free Software Foundation; either version 2 of the License, or * | ||
16 | * (at your option) any later version. * | ||
17 | * * | ||
18 | * This program is distributed in the hope that it will be useful, * | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
21 | * GNU General Public License for more details. * | ||
22 | * * | ||
23 | * You should have received a copy of the GNU General Public License * | ||
24 | * along with this program; if not, write to the Free Software * | ||
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
26 | ***************************************************************************/ | ||
27 | |||
28 | #include <linux/module.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/kmod.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/fs.h> | ||
33 | #include <linux/vmalloc.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/mm.h> | ||
36 | #include <linux/string.h> | ||
37 | #include <linux/errno.h> | ||
38 | #include <linux/sched.h> | ||
39 | #include <linux/ioctl.h> | ||
40 | #include <linux/delay.h> | ||
41 | #include <linux/stddef.h> | ||
42 | #include <asm/page.h> | ||
43 | #include <asm/uaccess.h> | ||
44 | #include <linux/page-flags.h> | ||
45 | #include <linux/moduleparam.h> | ||
46 | |||
47 | #include "w9968cf.h" | ||
48 | #include "w9968cf_decoder.h" | ||
49 | |||
50 | static struct w9968cf_vpp_t* w9968cf_vpp; | ||
51 | static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait); | ||
52 | |||
53 | static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */ | ||
54 | static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */ | ||
55 | |||
56 | static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */ | ||
57 | |||
58 | |||
59 | /**************************************************************************** | ||
60 | * Module macros and parameters * | ||
61 | ****************************************************************************/ | ||
62 | |||
63 | MODULE_DEVICE_TABLE(usb, winbond_id_table); | ||
64 | |||
65 | MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL); | ||
66 | MODULE_DESCRIPTION(W9968CF_MODULE_NAME); | ||
67 | MODULE_VERSION(W9968CF_MODULE_VERSION); | ||
68 | MODULE_LICENSE(W9968CF_MODULE_LICENSE); | ||
69 | MODULE_SUPPORTED_DEVICE("Video"); | ||
70 | |||
71 | static int ovmod_load = W9968CF_OVMOD_LOAD; | ||
72 | static unsigned short simcams = W9968CF_SIMCAMS; | ||
73 | static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/ | ||
74 | static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
75 | W9968CF_PACKET_SIZE}; | ||
76 | static unsigned short max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
77 | W9968CF_BUFFERS}; | ||
78 | static int double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
79 | W9968CF_DOUBLE_BUFFER}; | ||
80 | static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING}; | ||
81 | static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] = | ||
82 | W9968CF_FILTER_TYPE}; | ||
83 | static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW}; | ||
84 | static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
85 | W9968CF_DECOMPRESSION}; | ||
86 | static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING}; | ||
87 | static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0}; | ||
88 | static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB}; | ||
89 | static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT}; | ||
90 | static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP}; | ||
91 | static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
92 | W9968CF_LIGHTFREQ}; | ||
93 | static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]= | ||
94 | W9968CF_BANDINGFILTER}; | ||
95 | static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV}; | ||
96 | static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT}; | ||
97 | static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR}; | ||
98 | static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME}; | ||
99 | static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
100 | W9968CF_BRIGHTNESS}; | ||
101 | static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE}; | ||
102 | static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR}; | ||
103 | static unsigned int contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
104 | W9968CF_CONTRAST}; | ||
105 | static unsigned int whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] = | ||
106 | W9968CF_WHITENESS}; | ||
107 | #ifdef W9968CF_DEBUG | ||
108 | static unsigned short debug = W9968CF_DEBUG_LEVEL; | ||
109 | static int specific_debug = W9968CF_SPECIFIC_DEBUG; | ||
110 | #endif | ||
111 | |||
112 | static unsigned int param_nv[24]; /* number of values per parameter */ | ||
113 | |||
114 | #ifdef CONFIG_KMOD | ||
115 | module_param(ovmod_load, bool, 0644); | ||
116 | #endif | ||
117 | module_param(simcams, ushort, 0644); | ||
118 | module_param_array(video_nr, short, ¶m_nv[0], 0444); | ||
119 | module_param_array(packet_size, uint, ¶m_nv[1], 0444); | ||
120 | module_param_array(max_buffers, ushort, ¶m_nv[2], 0444); | ||
121 | module_param_array(double_buffer, bool, ¶m_nv[3], 0444); | ||
122 | module_param_array(clamping, bool, ¶m_nv[4], 0444); | ||
123 | module_param_array(filter_type, ushort, ¶m_nv[5], 0444); | ||
124 | module_param_array(largeview, bool, ¶m_nv[6], 0444); | ||
125 | module_param_array(decompression, ushort, ¶m_nv[7], 0444); | ||
126 | module_param_array(upscaling, bool, ¶m_nv[8], 0444); | ||
127 | module_param_array(force_palette, ushort, ¶m_nv[9], 0444); | ||
128 | module_param_array(force_rgb, ushort, ¶m_nv[10], 0444); | ||
129 | module_param_array(autobright, bool, ¶m_nv[11], 0444); | ||
130 | module_param_array(autoexp, bool, ¶m_nv[12], 0444); | ||
131 | module_param_array(lightfreq, ushort, ¶m_nv[13], 0444); | ||
132 | module_param_array(bandingfilter, bool, ¶m_nv[14], 0444); | ||
133 | module_param_array(clockdiv, short, ¶m_nv[15], 0444); | ||
134 | module_param_array(backlight, bool, ¶m_nv[16], 0444); | ||
135 | module_param_array(mirror, bool, ¶m_nv[17], 0444); | ||
136 | module_param_array(monochrome, bool, ¶m_nv[18], 0444); | ||
137 | module_param_array(brightness, uint, ¶m_nv[19], 0444); | ||
138 | module_param_array(hue, uint, ¶m_nv[20], 0444); | ||
139 | module_param_array(colour, uint, ¶m_nv[21], 0444); | ||
140 | module_param_array(contrast, uint, ¶m_nv[22], 0444); | ||
141 | module_param_array(whiteness, uint, ¶m_nv[23], 0444); | ||
142 | #ifdef W9968CF_DEBUG | ||
143 | module_param(debug, ushort, 0644); | ||
144 | module_param(specific_debug, bool, 0644); | ||
145 | #endif | ||
146 | |||
147 | #ifdef CONFIG_KMOD | ||
148 | MODULE_PARM_DESC(ovmod_load, | ||
149 | "\n<0|1> Automatic 'ovcamchip' module loading." | ||
150 | "\n0 disabled, 1 enabled." | ||
151 | "\nIf enabled,'insmod' searches for the required 'ovcamchip'" | ||
152 | "\nmodule in the system, according to its configuration, and" | ||
153 | "\nattempts to load that module automatically. This action is" | ||
154 | "\nperformed once as soon as the 'w9968cf' module is loaded" | ||
155 | "\ninto memory." | ||
156 | "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"." | ||
157 | "\n"); | ||
158 | #endif | ||
159 | MODULE_PARM_DESC(simcams, | ||
160 | "\n<n> Number of cameras allowed to stream simultaneously." | ||
161 | "\nn may vary from 0 to " | ||
162 | __MODULE_STRING(W9968CF_MAX_DEVICES)"." | ||
163 | "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"." | ||
164 | "\n"); | ||
165 | MODULE_PARM_DESC(video_nr, | ||
166 | "\n<-1|n[,...]> Specify V4L minor mode number." | ||
167 | "\n -1 = use next available (default)" | ||
168 | "\n n = use minor number n (integer >= 0)" | ||
169 | "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES) | ||
170 | " cameras this way." | ||
171 | "\nFor example:" | ||
172 | "\nvideo_nr=-1,2,-1 would assign minor number 2 to" | ||
173 | "\nthe second camera and use auto for the first" | ||
174 | "\none and for every other camera." | ||
175 | "\n"); | ||
176 | MODULE_PARM_DESC(packet_size, | ||
177 | "\n<n[,...]> Specify the maximum data payload" | ||
178 | "\nsize in bytes for alternate settings, for each device." | ||
179 | "\nn is scaled between 63 and 1023 " | ||
180 | "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")." | ||
181 | "\n"); | ||
182 | MODULE_PARM_DESC(max_buffers, | ||
183 | "\n<n[,...]> For advanced users." | ||
184 | "\nSpecify the maximum number of video frame buffers" | ||
185 | "\nto allocate for each device, from 2 to " | ||
186 | __MODULE_STRING(W9968CF_MAX_BUFFERS) | ||
187 | ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")." | ||
188 | "\n"); | ||
189 | MODULE_PARM_DESC(double_buffer, | ||
190 | "\n<0|1[,...]> " | ||
191 | "Hardware double buffering: 0 disabled, 1 enabled." | ||
192 | "\nIt should be enabled if you want smooth video output: if" | ||
193 | "\nyou obtain out of sync. video, disable it, or try to" | ||
194 | "\ndecrease the 'clockdiv' module parameter value." | ||
195 | "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER) | ||
196 | " for every device." | ||
197 | "\n"); | ||
198 | MODULE_PARM_DESC(clamping, | ||
199 | "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled." | ||
200 | "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING) | ||
201 | " for every device." | ||
202 | "\n"); | ||
203 | MODULE_PARM_DESC(filter_type, | ||
204 | "\n<0|1|2[,...]> Video filter type." | ||
205 | "\n0 none, 1 (1-2-1) 3-tap filter, " | ||
206 | "2 (2-3-6-3-2) 5-tap filter." | ||
207 | "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE) | ||
208 | " for every device." | ||
209 | "\nThe filter is used to reduce noise and aliasing artifacts" | ||
210 | "\nproduced by the CCD or CMOS image sensor, and the scaling" | ||
211 | " process." | ||
212 | "\n"); | ||
213 | MODULE_PARM_DESC(largeview, | ||
214 | "\n<0|1[,...]> Large view: 0 disabled, 1 enabled." | ||
215 | "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW) | ||
216 | " for every device." | ||
217 | "\n"); | ||
218 | MODULE_PARM_DESC(upscaling, | ||
219 | "\n<0|1[,...]> Software scaling (for non-compressed video):" | ||
220 | "\n0 disabled, 1 enabled." | ||
221 | "\nDisable it if you have a slow CPU or you don't have" | ||
222 | " enough memory." | ||
223 | "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING) | ||
224 | " for every device." | ||
225 | "\nIf 'w9968cf-vpp' is not present, this parameter is" | ||
226 | " set to 0." | ||
227 | "\n"); | ||
228 | MODULE_PARM_DESC(decompression, | ||
229 | "\n<0|1|2[,...]> Software video decompression:" | ||
230 | "\n- 0 disables decompression (doesn't allow formats needing" | ||
231 | " decompression)" | ||
232 | "\n- 1 forces decompression (allows formats needing" | ||
233 | " decompression only);" | ||
234 | "\n- 2 allows any permitted formats." | ||
235 | "\nFormats supporting compressed video are YUV422P and" | ||
236 | " YUV420P/YUV420 " | ||
237 | "\nin any resolutions where both width and height are " | ||
238 | "a multiple of 16." | ||
239 | "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION) | ||
240 | " for every device." | ||
241 | "\nIf 'w9968cf-vpp' is not present, forcing decompression is " | ||
242 | "\nnot allowed; in this case this parameter is set to 2." | ||
243 | "\n"); | ||
244 | MODULE_PARM_DESC(force_palette, | ||
245 | "\n<0" | ||
246 | "|" __MODULE_STRING(VIDEO_PALETTE_UYVY) | ||
247 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV420) | ||
248 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P) | ||
249 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P) | ||
250 | "|" __MODULE_STRING(VIDEO_PALETTE_YUYV) | ||
251 | "|" __MODULE_STRING(VIDEO_PALETTE_YUV422) | ||
252 | "|" __MODULE_STRING(VIDEO_PALETTE_GREY) | ||
253 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB555) | ||
254 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB565) | ||
255 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB24) | ||
256 | "|" __MODULE_STRING(VIDEO_PALETTE_RGB32) | ||
257 | "[,...]>" | ||
258 | " Force picture palette." | ||
259 | "\nIn order:" | ||
260 | "\n- 0 allows any of the following formats:" | ||
261 | "\n- UYVY 16 bpp - Original video, compression disabled" | ||
262 | "\n- YUV420 12 bpp - Original video, compression enabled" | ||
263 | "\n- YUV422P 16 bpp - Original video, compression enabled" | ||
264 | "\n- YUV420P 12 bpp - Original video, compression enabled" | ||
265 | "\n- YUVY 16 bpp - Software conversion from UYVY" | ||
266 | "\n- YUV422 16 bpp - Software conversion from UYVY" | ||
267 | "\n- GREY 8 bpp - Software conversion from UYVY" | ||
268 | "\n- RGB555 16 bpp - Software conversion from UYVY" | ||
269 | "\n- RGB565 16 bpp - Software conversion from UYVY" | ||
270 | "\n- RGB24 24 bpp - Software conversion from UYVY" | ||
271 | "\n- RGB32 32 bpp - Software conversion from UYVY" | ||
272 | "\nWhen not 0, this parameter will override 'decompression'." | ||
273 | "\nDefault value is 0 for every device." | ||
274 | "\nInitial palette is " | ||
275 | __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"." | ||
276 | "\nIf 'w9968cf-vpp' is not present, this parameter is" | ||
277 | " set to 9 (UYVY)." | ||
278 | "\n"); | ||
279 | MODULE_PARM_DESC(force_rgb, | ||
280 | "\n<0|1[,...]> Read RGB video data instead of BGR:" | ||
281 | "\n 1 = use RGB component ordering." | ||
282 | "\n 0 = use BGR component ordering." | ||
283 | "\nThis parameter has effect when using RGBX palettes only." | ||
284 | "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB) | ||
285 | " for every device." | ||
286 | "\n"); | ||
287 | MODULE_PARM_DESC(autobright, | ||
288 | "\n<0|1[,...]> Image sensor automatically changes brightness:" | ||
289 | "\n 0 = no, 1 = yes" | ||
290 | "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT) | ||
291 | " for every device." | ||
292 | "\n"); | ||
293 | MODULE_PARM_DESC(autoexp, | ||
294 | "\n<0|1[,...]> Image sensor automatically changes exposure:" | ||
295 | "\n 0 = no, 1 = yes" | ||
296 | "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP) | ||
297 | " for every device." | ||
298 | "\n"); | ||
299 | MODULE_PARM_DESC(lightfreq, | ||
300 | "\n<50|60[,...]> Light frequency in Hz:" | ||
301 | "\n 50 for European and Asian lighting," | ||
302 | " 60 for American lighting." | ||
303 | "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ) | ||
304 | " for every device." | ||
305 | "\n"); | ||
306 | MODULE_PARM_DESC(bandingfilter, | ||
307 | "\n<0|1[,...]> Banding filter to reduce effects of" | ||
308 | " fluorescent lighting:" | ||
309 | "\n 0 disabled, 1 enabled." | ||
310 | "\nThis filter tries to reduce the pattern of horizontal" | ||
311 | "\nlight/dark bands caused by some (usually fluorescent)" | ||
312 | " lighting." | ||
313 | "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER) | ||
314 | " for every device." | ||
315 | "\n"); | ||
316 | MODULE_PARM_DESC(clockdiv, | ||
317 | "\n<-1|n[,...]> " | ||
318 | "Force pixel clock divisor to a specific value (for experts):" | ||
319 | "\n n may vary from 0 to 127." | ||
320 | "\n -1 for automatic value." | ||
321 | "\nSee also the 'double_buffer' module parameter." | ||
322 | "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV) | ||
323 | " for every device." | ||
324 | "\n"); | ||
325 | MODULE_PARM_DESC(backlight, | ||
326 | "\n<0|1[,...]> Objects are lit from behind:" | ||
327 | "\n 0 = no, 1 = yes" | ||
328 | "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT) | ||
329 | " for every device." | ||
330 | "\n"); | ||
331 | MODULE_PARM_DESC(mirror, | ||
332 | "\n<0|1[,...]> Reverse image horizontally:" | ||
333 | "\n 0 = no, 1 = yes" | ||
334 | "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR) | ||
335 | " for every device." | ||
336 | "\n"); | ||
337 | MODULE_PARM_DESC(monochrome, | ||
338 | "\n<0|1[,...]> Use image sensor as monochrome sensor:" | ||
339 | "\n 0 = no, 1 = yes" | ||
340 | "\nNot all the sensors support monochrome color." | ||
341 | "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME) | ||
342 | " for every device." | ||
343 | "\n"); | ||
344 | MODULE_PARM_DESC(brightness, | ||
345 | "\n<n[,...]> Set picture brightness (0-65535)." | ||
346 | "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS) | ||
347 | " for every device." | ||
348 | "\nThis parameter has no effect if 'autobright' is enabled." | ||
349 | "\n"); | ||
350 | MODULE_PARM_DESC(hue, | ||
351 | "\n<n[,...]> Set picture hue (0-65535)." | ||
352 | "\nDefault value is "__MODULE_STRING(W9968CF_HUE) | ||
353 | " for every device." | ||
354 | "\n"); | ||
355 | MODULE_PARM_DESC(colour, | ||
356 | "\n<n[,...]> Set picture saturation (0-65535)." | ||
357 | "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR) | ||
358 | " for every device." | ||
359 | "\n"); | ||
360 | MODULE_PARM_DESC(contrast, | ||
361 | "\n<n[,...]> Set picture contrast (0-65535)." | ||
362 | "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST) | ||
363 | " for every device." | ||
364 | "\n"); | ||
365 | MODULE_PARM_DESC(whiteness, | ||
366 | "\n<n[,...]> Set picture whiteness (0-65535)." | ||
367 | "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS) | ||
368 | " for every device." | ||
369 | "\n"); | ||
370 | #ifdef W9968CF_DEBUG | ||
371 | MODULE_PARM_DESC(debug, | ||
372 | "\n<n> Debugging information level, from 0 to 6:" | ||
373 | "\n0 = none (use carefully)" | ||
374 | "\n1 = critical errors" | ||
375 | "\n2 = significant informations" | ||
376 | "\n3 = configuration or general messages" | ||
377 | "\n4 = warnings" | ||
378 | "\n5 = called functions" | ||
379 | "\n6 = function internals" | ||
380 | "\nLevel 5 and 6 are useful for testing only, when only " | ||
381 | "one device is used." | ||
382 | "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"." | ||
383 | "\n"); | ||
384 | MODULE_PARM_DESC(specific_debug, | ||
385 | "\n<0|1> Enable or disable specific debugging messages:" | ||
386 | "\n0 = print messages concerning every level" | ||
387 | " <= 'debug' level." | ||
388 | "\n1 = print messages concerning the level" | ||
389 | " indicated by 'debug'." | ||
390 | "\nDefault value is " | ||
391 | __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"." | ||
392 | "\n"); | ||
393 | #endif /* W9968CF_DEBUG */ | ||
394 | |||
395 | |||
396 | |||
397 | /**************************************************************************** | ||
398 | * Some prototypes * | ||
399 | ****************************************************************************/ | ||
400 | |||
401 | /* Video4linux interface */ | ||
402 | static struct file_operations w9968cf_fops; | ||
403 | static int w9968cf_open(struct inode*, struct file*); | ||
404 | static int w9968cf_release(struct inode*, struct file*); | ||
405 | static int w9968cf_mmap(struct file*, struct vm_area_struct*); | ||
406 | static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long); | ||
407 | static ssize_t w9968cf_read(struct file*, char __user *, size_t, loff_t*); | ||
408 | static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int, | ||
409 | void __user *); | ||
410 | |||
411 | /* USB-specific */ | ||
412 | static int w9968cf_start_transfer(struct w9968cf_device*); | ||
413 | static int w9968cf_stop_transfer(struct w9968cf_device*); | ||
414 | static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index); | ||
415 | static int w9968cf_read_reg(struct w9968cf_device*, u16 index); | ||
416 | static int w9968cf_write_fsb(struct w9968cf_device*, u16* data); | ||
417 | static int w9968cf_write_sb(struct w9968cf_device*, u16 value); | ||
418 | static int w9968cf_read_sb(struct w9968cf_device*); | ||
419 | static int w9968cf_upload_quantizationtables(struct w9968cf_device*); | ||
420 | static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs); | ||
421 | |||
422 | /* Low-level I2C (SMBus) I/O */ | ||
423 | static int w9968cf_smbus_start(struct w9968cf_device*); | ||
424 | static int w9968cf_smbus_stop(struct w9968cf_device*); | ||
425 | static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v); | ||
426 | static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v); | ||
427 | static int w9968cf_smbus_write_ack(struct w9968cf_device*); | ||
428 | static int w9968cf_smbus_read_ack(struct w9968cf_device*); | ||
429 | static int w9968cf_smbus_refresh_bus(struct w9968cf_device*); | ||
430 | static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, | ||
431 | u16 address, u8* value); | ||
432 | static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address, | ||
433 | u8 subaddress, u8* value); | ||
434 | static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*, | ||
435 | u16 address, u8 subaddress); | ||
436 | static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*, | ||
437 | u16 address, u8 subaddress, | ||
438 | u8 value); | ||
439 | |||
440 | /* I2C interface to kernel */ | ||
441 | static int w9968cf_i2c_init(struct w9968cf_device*); | ||
442 | static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr, | ||
443 | unsigned short flags, char read_write, | ||
444 | u8 command, int size, union i2c_smbus_data*); | ||
445 | static u32 w9968cf_i2c_func(struct i2c_adapter*); | ||
446 | static int w9968cf_i2c_attach_inform(struct i2c_client*); | ||
447 | static int w9968cf_i2c_detach_inform(struct i2c_client*); | ||
448 | static int w9968cf_i2c_control(struct i2c_adapter*, unsigned int cmd, | ||
449 | unsigned long arg); | ||
450 | |||
451 | /* Memory management */ | ||
452 | static void* rvmalloc(unsigned long size); | ||
453 | static void rvfree(void *mem, unsigned long size); | ||
454 | static void w9968cf_deallocate_memory(struct w9968cf_device*); | ||
455 | static int w9968cf_allocate_memory(struct w9968cf_device*); | ||
456 | |||
457 | /* High-level image sensor control functions */ | ||
458 | static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val); | ||
459 | static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val); | ||
460 | static int w9968cf_sensor_cmd(struct w9968cf_device*, | ||
461 | unsigned int cmd, void *arg); | ||
462 | static int w9968cf_sensor_init(struct w9968cf_device*); | ||
463 | static int w9968cf_sensor_update_settings(struct w9968cf_device*); | ||
464 | static int w9968cf_sensor_get_picture(struct w9968cf_device*); | ||
465 | static int w9968cf_sensor_update_picture(struct w9968cf_device*, | ||
466 | struct video_picture pict); | ||
467 | |||
468 | /* Other helper functions */ | ||
469 | static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*, | ||
470 | enum w9968cf_model_id, | ||
471 | const unsigned short dev_nr); | ||
472 | static void w9968cf_adjust_configuration(struct w9968cf_device*); | ||
473 | static int w9968cf_turn_on_led(struct w9968cf_device*); | ||
474 | static int w9968cf_init_chip(struct w9968cf_device*); | ||
475 | static inline u16 w9968cf_valid_palette(u16 palette); | ||
476 | static inline u16 w9968cf_valid_depth(u16 palette); | ||
477 | static inline u8 w9968cf_need_decompression(u16 palette); | ||
478 | static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture); | ||
479 | static int w9968cf_set_window(struct w9968cf_device*, struct video_window); | ||
480 | static int w9968cf_postprocess_frame(struct w9968cf_device*, | ||
481 | struct w9968cf_frame_t*); | ||
482 | static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h); | ||
483 | static void w9968cf_init_framelist(struct w9968cf_device*); | ||
484 | static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num); | ||
485 | static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**); | ||
486 | static void w9968cf_release_resources(struct w9968cf_device*); | ||
487 | |||
488 | |||
489 | |||
490 | /**************************************************************************** | ||
491 | * Symbolic names * | ||
492 | ****************************************************************************/ | ||
493 | |||
494 | /* Used to represent a list of values and their respective symbolic names */ | ||
495 | struct w9968cf_symbolic_list { | ||
496 | const int num; | ||
497 | const char *name; | ||
498 | }; | ||
499 | |||
500 | /*-------------------------------------------------------------------------- | ||
501 | Returns the name of the matching element in the symbolic_list array. The | ||
502 | end of the list must be marked with an element that has a NULL name. | ||
503 | --------------------------------------------------------------------------*/ | ||
504 | static inline const char * | ||
505 | symbolic(struct w9968cf_symbolic_list list[], const int num) | ||
506 | { | ||
507 | int i; | ||
508 | |||
509 | for (i = 0; list[i].name != NULL; i++) | ||
510 | if (list[i].num == num) | ||
511 | return (list[i].name); | ||
512 | |||
513 | return "Unknown"; | ||
514 | } | ||
515 | |||
516 | static struct w9968cf_symbolic_list camlist[] = { | ||
517 | { W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" }, | ||
518 | { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" }, | ||
519 | |||
520 | /* Other cameras (having the same descriptors as Generic W996[87]CF) */ | ||
521 | { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" }, | ||
522 | { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" }, | ||
523 | { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" }, | ||
524 | { W9968CF_MOD_LL, "Lebon LDC-035A" }, | ||
525 | { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" }, | ||
526 | { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" }, | ||
527 | { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" }, | ||
528 | { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" }, | ||
529 | { W9968CF_MOD_PDP480, "Pretec DigiPen-480" }, | ||
530 | |||
531 | { -1, NULL } | ||
532 | }; | ||
533 | |||
534 | static struct w9968cf_symbolic_list senlist[] = { | ||
535 | { CC_OV76BE, "OV76BE" }, | ||
536 | { CC_OV7610, "OV7610" }, | ||
537 | { CC_OV7620, "OV7620" }, | ||
538 | { CC_OV7620AE, "OV7620AE" }, | ||
539 | { CC_OV6620, "OV6620" }, | ||
540 | { CC_OV6630, "OV6630" }, | ||
541 | { CC_OV6630AE, "OV6630AE" }, | ||
542 | { CC_OV6630AF, "OV6630AF" }, | ||
543 | { -1, NULL } | ||
544 | }; | ||
545 | |||
546 | /* Video4Linux1 palettes */ | ||
547 | static struct w9968cf_symbolic_list v4l1_plist[] = { | ||
548 | { VIDEO_PALETTE_GREY, "GREY" }, | ||
549 | { VIDEO_PALETTE_HI240, "HI240" }, | ||
550 | { VIDEO_PALETTE_RGB565, "RGB565" }, | ||
551 | { VIDEO_PALETTE_RGB24, "RGB24" }, | ||
552 | { VIDEO_PALETTE_RGB32, "RGB32" }, | ||
553 | { VIDEO_PALETTE_RGB555, "RGB555" }, | ||
554 | { VIDEO_PALETTE_YUV422, "YUV422" }, | ||
555 | { VIDEO_PALETTE_YUYV, "YUYV" }, | ||
556 | { VIDEO_PALETTE_UYVY, "UYVY" }, | ||
557 | { VIDEO_PALETTE_YUV420, "YUV420" }, | ||
558 | { VIDEO_PALETTE_YUV411, "YUV411" }, | ||
559 | { VIDEO_PALETTE_RAW, "RAW" }, | ||
560 | { VIDEO_PALETTE_YUV422P, "YUV422P" }, | ||
561 | { VIDEO_PALETTE_YUV411P, "YUV411P" }, | ||
562 | { VIDEO_PALETTE_YUV420P, "YUV420P" }, | ||
563 | { VIDEO_PALETTE_YUV410P, "YUV410P" }, | ||
564 | { -1, NULL } | ||
565 | }; | ||
566 | |||
567 | /* Decoder error codes: */ | ||
568 | static struct w9968cf_symbolic_list decoder_errlist[] = { | ||
569 | { W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" }, | ||
570 | { W9968CF_DEC_ERR_BUF_OVERFLOW, "Buffer overflow" }, | ||
571 | { W9968CF_DEC_ERR_NO_SOI, "SOI marker not found" }, | ||
572 | { W9968CF_DEC_ERR_NO_SOF0, "SOF0 marker not found" }, | ||
573 | { W9968CF_DEC_ERR_NO_SOS, "SOS marker not found" }, | ||
574 | { W9968CF_DEC_ERR_NO_EOI, "EOI marker not found" }, | ||
575 | { -1, NULL } | ||
576 | }; | ||
577 | |||
578 | /* URB error codes: */ | ||
579 | static struct w9968cf_symbolic_list urb_errlist[] = { | ||
580 | { -ENOMEM, "No memory for allocation of internal structures" }, | ||
581 | { -ENOSPC, "The host controller's bandwidth is already consumed" }, | ||
582 | { -ENOENT, "URB was canceled by unlink_urb" }, | ||
583 | { -EXDEV, "ISO transfer only partially completed" }, | ||
584 | { -EAGAIN, "Too match scheduled for the future" }, | ||
585 | { -ENXIO, "URB already queued" }, | ||
586 | { -EFBIG, "Too much ISO frames requested" }, | ||
587 | { -ENOSR, "Buffer error (overrun)" }, | ||
588 | { -EPIPE, "Specified endpoint is stalled (device not responding)"}, | ||
589 | { -EOVERFLOW, "Babble (bad cable?)" }, | ||
590 | { -EPROTO, "Bit-stuff error (bad cable?)" }, | ||
591 | { -EILSEQ, "CRC/Timeout" }, | ||
592 | { -ETIMEDOUT, "NAK (device does not respond)" }, | ||
593 | { -1, NULL } | ||
594 | }; | ||
595 | |||
596 | |||
597 | |||
598 | /**************************************************************************** | ||
599 | * Memory management functions * | ||
600 | ****************************************************************************/ | ||
601 | static void* rvmalloc(unsigned long size) | ||
602 | { | ||
603 | void* mem; | ||
604 | unsigned long adr; | ||
605 | |||
606 | size = PAGE_ALIGN(size); | ||
607 | mem = vmalloc_32(size); | ||
608 | if (!mem) | ||
609 | return NULL; | ||
610 | |||
611 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
612 | adr = (unsigned long) mem; | ||
613 | while (size > 0) { | ||
614 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
615 | adr += PAGE_SIZE; | ||
616 | size -= PAGE_SIZE; | ||
617 | } | ||
618 | |||
619 | return mem; | ||
620 | } | ||
621 | |||
622 | |||
623 | static void rvfree(void* mem, unsigned long size) | ||
624 | { | ||
625 | unsigned long adr; | ||
626 | |||
627 | if (!mem) | ||
628 | return; | ||
629 | |||
630 | adr = (unsigned long) mem; | ||
631 | while ((long) size > 0) { | ||
632 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
633 | adr += PAGE_SIZE; | ||
634 | size -= PAGE_SIZE; | ||
635 | } | ||
636 | vfree(mem); | ||
637 | } | ||
638 | |||
639 | |||
640 | /*-------------------------------------------------------------------------- | ||
641 | Deallocate previously allocated memory. | ||
642 | --------------------------------------------------------------------------*/ | ||
643 | static void w9968cf_deallocate_memory(struct w9968cf_device* cam) | ||
644 | { | ||
645 | u8 i; | ||
646 | |||
647 | /* Free the isochronous transfer buffers */ | ||
648 | for (i = 0; i < W9968CF_URBS; i++) { | ||
649 | kfree(cam->transfer_buffer[i]); | ||
650 | cam->transfer_buffer[i] = NULL; | ||
651 | } | ||
652 | |||
653 | /* Free temporary frame buffer */ | ||
654 | if (cam->frame_tmp.buffer) { | ||
655 | rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size); | ||
656 | cam->frame_tmp.buffer = NULL; | ||
657 | } | ||
658 | |||
659 | /* Free helper buffer */ | ||
660 | if (cam->frame_vpp.buffer) { | ||
661 | rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size); | ||
662 | cam->frame_vpp.buffer = NULL; | ||
663 | } | ||
664 | |||
665 | /* Free video frame buffers */ | ||
666 | if (cam->frame[0].buffer) { | ||
667 | rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size); | ||
668 | cam->frame[0].buffer = NULL; | ||
669 | } | ||
670 | |||
671 | cam->nbuffers = 0; | ||
672 | |||
673 | DBG(5, "Memory successfully deallocated") | ||
674 | } | ||
675 | |||
676 | |||
677 | /*-------------------------------------------------------------------------- | ||
678 | Allocate memory buffers for USB transfers and video frames. | ||
679 | This function is called by open() only. | ||
680 | Return 0 on success, a negative number otherwise. | ||
681 | --------------------------------------------------------------------------*/ | ||
682 | static int w9968cf_allocate_memory(struct w9968cf_device* cam) | ||
683 | { | ||
684 | const u16 p_size = wMaxPacketSize[cam->altsetting-1]; | ||
685 | void* buff = NULL; | ||
686 | unsigned long hw_bufsize, vpp_bufsize; | ||
687 | u8 i, bpp; | ||
688 | |||
689 | /* NOTE: Deallocation is done elsewhere in case of error */ | ||
690 | |||
691 | /* Calculate the max amount of raw data per frame from the device */ | ||
692 | hw_bufsize = cam->maxwidth*cam->maxheight*2; | ||
693 | |||
694 | /* Calculate the max buf. size needed for post-processing routines */ | ||
695 | bpp = (w9968cf_vpp) ? 4 : 2; | ||
696 | if (cam->upscaling) | ||
697 | vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp, | ||
698 | cam->maxwidth*cam->maxheight*bpp); | ||
699 | else | ||
700 | vpp_bufsize = cam->maxwidth*cam->maxheight*bpp; | ||
701 | |||
702 | /* Allocate memory for the isochronous transfer buffers */ | ||
703 | for (i = 0; i < W9968CF_URBS; i++) { | ||
704 | if (!(cam->transfer_buffer[i] = | ||
705 | kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) { | ||
706 | DBG(1, "Couldn't allocate memory for the isochronous " | ||
707 | "transfer buffers (%u bytes)", | ||
708 | p_size * W9968CF_ISO_PACKETS) | ||
709 | return -ENOMEM; | ||
710 | } | ||
711 | } | ||
712 | |||
713 | /* Allocate memory for the temporary frame buffer */ | ||
714 | if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) { | ||
715 | DBG(1, "Couldn't allocate memory for the temporary " | ||
716 | "video frame buffer (%lu bytes)", hw_bufsize) | ||
717 | return -ENOMEM; | ||
718 | } | ||
719 | cam->frame_tmp.size = hw_bufsize; | ||
720 | cam->frame_tmp.number = -1; | ||
721 | |||
722 | /* Allocate memory for the helper buffer */ | ||
723 | if (w9968cf_vpp) { | ||
724 | if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) { | ||
725 | DBG(1, "Couldn't allocate memory for the helper buffer" | ||
726 | " (%lu bytes)", vpp_bufsize) | ||
727 | return -ENOMEM; | ||
728 | } | ||
729 | cam->frame_vpp.size = vpp_bufsize; | ||
730 | } else | ||
731 | cam->frame_vpp.buffer = NULL; | ||
732 | |||
733 | /* Allocate memory for video frame buffers */ | ||
734 | cam->nbuffers = cam->max_buffers; | ||
735 | while (cam->nbuffers >= 2) { | ||
736 | if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize))) | ||
737 | break; | ||
738 | else | ||
739 | cam->nbuffers--; | ||
740 | } | ||
741 | |||
742 | if (!buff) { | ||
743 | DBG(1, "Couldn't allocate memory for the video frame buffers") | ||
744 | cam->nbuffers = 0; | ||
745 | return -ENOMEM; | ||
746 | } | ||
747 | |||
748 | if (cam->nbuffers != cam->max_buffers) | ||
749 | DBG(2, "Couldn't allocate memory for %u video frame buffers. " | ||
750 | "Only memory for %u buffers has been allocated", | ||
751 | cam->max_buffers, cam->nbuffers) | ||
752 | |||
753 | for (i = 0; i < cam->nbuffers; i++) { | ||
754 | cam->frame[i].buffer = buff + i*vpp_bufsize; | ||
755 | cam->frame[i].size = vpp_bufsize; | ||
756 | cam->frame[i].number = i; | ||
757 | /* Circular list */ | ||
758 | if (i != cam->nbuffers-1) | ||
759 | cam->frame[i].next = &cam->frame[i+1]; | ||
760 | else | ||
761 | cam->frame[i].next = &cam->frame[0]; | ||
762 | cam->frame[i].status = F_UNUSED; | ||
763 | } | ||
764 | |||
765 | DBG(5, "Memory successfully allocated") | ||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | |||
770 | |||
771 | /**************************************************************************** | ||
772 | * USB-specific functions * | ||
773 | ****************************************************************************/ | ||
774 | |||
775 | /*-------------------------------------------------------------------------- | ||
776 | This is an handler function which is called after the URBs are completed. | ||
777 | It collects multiple data packets coming from the camera by putting them | ||
778 | into frame buffers: one or more zero data length data packets are used to | ||
779 | mark the end of a video frame; the first non-zero data packet is the start | ||
780 | of the next video frame; if an error is encountered in a packet, the entire | ||
781 | video frame is discarded and grabbed again. | ||
782 | If there are no requested frames in the FIFO list, packets are collected into | ||
783 | a temporary buffer. | ||
784 | --------------------------------------------------------------------------*/ | ||
785 | static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs) | ||
786 | { | ||
787 | struct w9968cf_device* cam = (struct w9968cf_device*)urb->context; | ||
788 | struct w9968cf_frame_t** f; | ||
789 | unsigned int len, status; | ||
790 | void* pos; | ||
791 | u8 i; | ||
792 | int err = 0; | ||
793 | |||
794 | if ((!cam->streaming) || cam->disconnected) { | ||
795 | DBG(4, "Got interrupt, but not streaming") | ||
796 | return; | ||
797 | } | ||
798 | |||
799 | /* "(*f)" will be used instead of "cam->frame_current" */ | ||
800 | f = &cam->frame_current; | ||
801 | |||
802 | /* If a frame has been requested and we are grabbing into | ||
803 | the temporary frame, we'll switch to that requested frame */ | ||
804 | if ((*f) == &cam->frame_tmp && *cam->requested_frame) { | ||
805 | if (cam->frame_tmp.status == F_GRABBING) { | ||
806 | w9968cf_pop_frame(cam, &cam->frame_current); | ||
807 | (*f)->status = F_GRABBING; | ||
808 | (*f)->length = cam->frame_tmp.length; | ||
809 | memcpy((*f)->buffer, cam->frame_tmp.buffer, | ||
810 | (*f)->length); | ||
811 | DBG(6, "Switched from temp. frame to frame #%d", | ||
812 | (*f)->number) | ||
813 | } | ||
814 | } | ||
815 | |||
816 | for (i = 0; i < urb->number_of_packets; i++) { | ||
817 | len = urb->iso_frame_desc[i].actual_length; | ||
818 | status = urb->iso_frame_desc[i].status; | ||
819 | pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; | ||
820 | |||
821 | if (status && len != 0) { | ||
822 | DBG(4, "URB failed, error in data packet " | ||
823 | "(error #%u, %s)", | ||
824 | status, symbolic(urb_errlist, status)) | ||
825 | (*f)->status = F_ERROR; | ||
826 | continue; | ||
827 | } | ||
828 | |||
829 | if (len) { /* start of frame */ | ||
830 | |||
831 | if ((*f)->status == F_UNUSED) { | ||
832 | (*f)->status = F_GRABBING; | ||
833 | (*f)->length = 0; | ||
834 | } | ||
835 | |||
836 | /* Buffer overflows shouldn't happen, however...*/ | ||
837 | if ((*f)->length + len > (*f)->size) { | ||
838 | DBG(4, "Buffer overflow: bad data packets") | ||
839 | (*f)->status = F_ERROR; | ||
840 | } | ||
841 | |||
842 | if ((*f)->status == F_GRABBING) { | ||
843 | memcpy((*f)->buffer + (*f)->length, pos, len); | ||
844 | (*f)->length += len; | ||
845 | } | ||
846 | |||
847 | } else if ((*f)->status == F_GRABBING) { /* end of frame */ | ||
848 | |||
849 | DBG(6, "Frame #%d successfully grabbed", (*f)->number) | ||
850 | |||
851 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | ||
852 | err = w9968cf_vpp->check_headers((*f)->buffer, | ||
853 | (*f)->length); | ||
854 | if (err) { | ||
855 | DBG(4, "Skip corrupted frame: %s", | ||
856 | symbolic(decoder_errlist, err)) | ||
857 | (*f)->status = F_UNUSED; | ||
858 | continue; /* grab this frame again */ | ||
859 | } | ||
860 | } | ||
861 | |||
862 | (*f)->status = F_READY; | ||
863 | (*f)->queued = 0; | ||
864 | |||
865 | /* Take a pointer to the new frame from the FIFO list. | ||
866 | If the list is empty,we'll use the temporary frame*/ | ||
867 | if (*cam->requested_frame) | ||
868 | w9968cf_pop_frame(cam, &cam->frame_current); | ||
869 | else { | ||
870 | cam->frame_current = &cam->frame_tmp; | ||
871 | (*f)->status = F_UNUSED; | ||
872 | } | ||
873 | |||
874 | } else if ((*f)->status == F_ERROR) | ||
875 | (*f)->status = F_UNUSED; /* grab it again */ | ||
876 | |||
877 | PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d", | ||
878 | (unsigned long)(*f)->length, i, len, (*f)->status) | ||
879 | |||
880 | } /* end for */ | ||
881 | |||
882 | /* Resubmit this URB */ | ||
883 | urb->dev = cam->usbdev; | ||
884 | urb->status = 0; | ||
885 | spin_lock(&cam->urb_lock); | ||
886 | if (cam->streaming) | ||
887 | if ((err = usb_submit_urb(urb, GFP_ATOMIC))) { | ||
888 | cam->misconfigured = 1; | ||
889 | DBG(1, "Couldn't resubmit the URB: error %d, %s", | ||
890 | err, symbolic(urb_errlist, err)) | ||
891 | } | ||
892 | spin_unlock(&cam->urb_lock); | ||
893 | |||
894 | /* Wake up the user process */ | ||
895 | wake_up_interruptible(&cam->wait_queue); | ||
896 | } | ||
897 | |||
898 | |||
899 | /*--------------------------------------------------------------------------- | ||
900 | Setup the URB structures for the isochronous transfer. | ||
901 | Submit the URBs so that the data transfer begins. | ||
902 | Return 0 on success, a negative number otherwise. | ||
903 | ---------------------------------------------------------------------------*/ | ||
904 | static int w9968cf_start_transfer(struct w9968cf_device* cam) | ||
905 | { | ||
906 | struct usb_device *udev = cam->usbdev; | ||
907 | struct urb* urb; | ||
908 | const u16 p_size = wMaxPacketSize[cam->altsetting-1]; | ||
909 | u16 w, h, d; | ||
910 | int vidcapt; | ||
911 | u32 t_size; | ||
912 | int err = 0; | ||
913 | s8 i, j; | ||
914 | |||
915 | for (i = 0; i < W9968CF_URBS; i++) { | ||
916 | urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL); | ||
917 | cam->urb[i] = urb; | ||
918 | if (!urb) { | ||
919 | for (j = 0; j < i; j++) | ||
920 | usb_free_urb(cam->urb[j]); | ||
921 | DBG(1, "Couldn't allocate the URB structures") | ||
922 | return -ENOMEM; | ||
923 | } | ||
924 | |||
925 | urb->dev = udev; | ||
926 | urb->context = (void*)cam; | ||
927 | urb->pipe = usb_rcvisocpipe(udev, 1); | ||
928 | urb->transfer_flags = URB_ISO_ASAP; | ||
929 | urb->number_of_packets = W9968CF_ISO_PACKETS; | ||
930 | urb->complete = w9968cf_urb_complete; | ||
931 | urb->transfer_buffer = cam->transfer_buffer[i]; | ||
932 | urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS; | ||
933 | urb->interval = 1; | ||
934 | for (j = 0; j < W9968CF_ISO_PACKETS; j++) { | ||
935 | urb->iso_frame_desc[j].offset = p_size*j; | ||
936 | urb->iso_frame_desc[j].length = p_size; | ||
937 | } | ||
938 | } | ||
939 | |||
940 | /* Transfer size per frame, in WORD ! */ | ||
941 | d = cam->hw_depth; | ||
942 | w = cam->hw_width; | ||
943 | h = cam->hw_height; | ||
944 | |||
945 | t_size = (w*h*d)/16; | ||
946 | |||
947 | err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ | ||
948 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ | ||
949 | |||
950 | /* Transfer size */ | ||
951 | err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */ | ||
952 | err += w9968cf_write_reg(cam, t_size >> 16, 0x3e); /* high bits */ | ||
953 | |||
954 | if (cam->vpp_flag & VPP_DECOMPRESSION) | ||
955 | err += w9968cf_upload_quantizationtables(cam); | ||
956 | |||
957 | vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */ | ||
958 | err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */ | ||
959 | |||
960 | err += usb_set_interface(udev, 0, cam->altsetting); | ||
961 | err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */ | ||
962 | |||
963 | if (err || (vidcapt < 0)) { | ||
964 | for (i = 0; i < W9968CF_URBS; i++) | ||
965 | usb_free_urb(cam->urb[i]); | ||
966 | DBG(1, "Couldn't tell the camera to start the data transfer") | ||
967 | return err; | ||
968 | } | ||
969 | |||
970 | w9968cf_init_framelist(cam); | ||
971 | |||
972 | /* Begin to grab into the temporary buffer */ | ||
973 | cam->frame_tmp.status = F_UNUSED; | ||
974 | cam->frame_tmp.queued = 0; | ||
975 | cam->frame_current = &cam->frame_tmp; | ||
976 | |||
977 | if (!(cam->vpp_flag & VPP_DECOMPRESSION)) | ||
978 | DBG(5, "Isochronous transfer size: %lu bytes/frame", | ||
979 | (unsigned long)t_size*2) | ||
980 | |||
981 | DBG(5, "Starting the isochronous transfer...") | ||
982 | |||
983 | cam->streaming = 1; | ||
984 | |||
985 | /* Submit the URBs */ | ||
986 | for (i = 0; i < W9968CF_URBS; i++) { | ||
987 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); | ||
988 | if (err) { | ||
989 | cam->streaming = 0; | ||
990 | for (j = i-1; j >= 0; j--) { | ||
991 | usb_kill_urb(cam->urb[j]); | ||
992 | usb_free_urb(cam->urb[j]); | ||
993 | } | ||
994 | DBG(1, "Couldn't send a transfer request to the " | ||
995 | "USB core (error #%d, %s)", err, | ||
996 | symbolic(urb_errlist, err)) | ||
997 | return err; | ||
998 | } | ||
999 | } | ||
1000 | |||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
1004 | |||
1005 | /*-------------------------------------------------------------------------- | ||
1006 | Stop the isochronous transfer and set alternate setting to 0 (0Mb/s). | ||
1007 | Return 0 on success, a negative number otherwise. | ||
1008 | --------------------------------------------------------------------------*/ | ||
1009 | static int w9968cf_stop_transfer(struct w9968cf_device* cam) | ||
1010 | { | ||
1011 | struct usb_device *udev = cam->usbdev; | ||
1012 | unsigned long lock_flags; | ||
1013 | int err = 0; | ||
1014 | s8 i; | ||
1015 | |||
1016 | if (!cam->streaming) | ||
1017 | return 0; | ||
1018 | |||
1019 | /* This avoids race conditions with usb_submit_urb() | ||
1020 | in the URB completition handler */ | ||
1021 | spin_lock_irqsave(&cam->urb_lock, lock_flags); | ||
1022 | cam->streaming = 0; | ||
1023 | spin_unlock_irqrestore(&cam->urb_lock, lock_flags); | ||
1024 | |||
1025 | for (i = W9968CF_URBS-1; i >= 0; i--) | ||
1026 | if (cam->urb[i]) { | ||
1027 | usb_kill_urb(cam->urb[i]); | ||
1028 | usb_free_urb(cam->urb[i]); | ||
1029 | cam->urb[i] = NULL; | ||
1030 | } | ||
1031 | |||
1032 | if (cam->disconnected) | ||
1033 | goto exit; | ||
1034 | |||
1035 | err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */ | ||
1036 | err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */ | ||
1037 | err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */ | ||
1038 | err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */ | ||
1039 | |||
1040 | if (err) { | ||
1041 | DBG(2, "Failed to tell the camera to stop the isochronous " | ||
1042 | "transfer. However this is not a critical error.") | ||
1043 | return -EIO; | ||
1044 | } | ||
1045 | |||
1046 | exit: | ||
1047 | DBG(5, "Isochronous transfer stopped") | ||
1048 | return 0; | ||
1049 | } | ||
1050 | |||
1051 | |||
1052 | /*-------------------------------------------------------------------------- | ||
1053 | Write a W9968CF register. | ||
1054 | Return 0 on success, -1 otherwise. | ||
1055 | --------------------------------------------------------------------------*/ | ||
1056 | static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index) | ||
1057 | { | ||
1058 | struct usb_device* udev = cam->usbdev; | ||
1059 | int res; | ||
1060 | |||
1061 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, | ||
1062 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | ||
1063 | value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT); | ||
1064 | |||
1065 | if (res < 0) | ||
1066 | DBG(4, "Failed to write a register " | ||
1067 | "(value 0x%04X, index 0x%02X, error #%d, %s)", | ||
1068 | value, index, res, symbolic(urb_errlist, res)) | ||
1069 | |||
1070 | return (res >= 0) ? 0 : -1; | ||
1071 | } | ||
1072 | |||
1073 | |||
1074 | /*-------------------------------------------------------------------------- | ||
1075 | Read a W9968CF register. | ||
1076 | Return the register value on success, -1 otherwise. | ||
1077 | --------------------------------------------------------------------------*/ | ||
1078 | static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index) | ||
1079 | { | ||
1080 | struct usb_device* udev = cam->usbdev; | ||
1081 | u16* buff = cam->control_buffer; | ||
1082 | int res; | ||
1083 | |||
1084 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1, | ||
1085 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
1086 | 0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT); | ||
1087 | |||
1088 | if (res < 0) | ||
1089 | DBG(4, "Failed to read a register " | ||
1090 | "(index 0x%02X, error #%d, %s)", | ||
1091 | index, res, symbolic(urb_errlist, res)) | ||
1092 | |||
1093 | return (res >= 0) ? (int)(*buff) : -1; | ||
1094 | } | ||
1095 | |||
1096 | |||
1097 | /*-------------------------------------------------------------------------- | ||
1098 | Write 64-bit data to the fast serial bus registers. | ||
1099 | Return 0 on success, -1 otherwise. | ||
1100 | --------------------------------------------------------------------------*/ | ||
1101 | static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data) | ||
1102 | { | ||
1103 | struct usb_device* udev = cam->usbdev; | ||
1104 | u16 value; | ||
1105 | int res; | ||
1106 | |||
1107 | value = *data++; | ||
1108 | |||
1109 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, | ||
1110 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | ||
1111 | value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT); | ||
1112 | |||
1113 | if (res < 0) | ||
1114 | DBG(4, "Failed to write the FSB registers " | ||
1115 | "(error #%d, %s)", res, symbolic(urb_errlist, res)) | ||
1116 | |||
1117 | return (res >= 0) ? 0 : -1; | ||
1118 | } | ||
1119 | |||
1120 | |||
1121 | /*-------------------------------------------------------------------------- | ||
1122 | Write data to the serial bus control register. | ||
1123 | Return 0 on success, a negative number otherwise. | ||
1124 | --------------------------------------------------------------------------*/ | ||
1125 | static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value) | ||
1126 | { | ||
1127 | int err = 0; | ||
1128 | |||
1129 | err = w9968cf_write_reg(cam, value, 0x01); | ||
1130 | udelay(W9968CF_I2C_BUS_DELAY); | ||
1131 | |||
1132 | return err; | ||
1133 | } | ||
1134 | |||
1135 | |||
1136 | /*-------------------------------------------------------------------------- | ||
1137 | Read data from the serial bus control register. | ||
1138 | Return 0 on success, a negative number otherwise. | ||
1139 | --------------------------------------------------------------------------*/ | ||
1140 | static int w9968cf_read_sb(struct w9968cf_device* cam) | ||
1141 | { | ||
1142 | int v = 0; | ||
1143 | |||
1144 | v = w9968cf_read_reg(cam, 0x01); | ||
1145 | udelay(W9968CF_I2C_BUS_DELAY); | ||
1146 | |||
1147 | return v; | ||
1148 | } | ||
1149 | |||
1150 | |||
1151 | /*-------------------------------------------------------------------------- | ||
1152 | Upload quantization tables for the JPEG compression. | ||
1153 | This function is called by w9968cf_start_transfer(). | ||
1154 | Return 0 on success, a negative number otherwise. | ||
1155 | --------------------------------------------------------------------------*/ | ||
1156 | static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam) | ||
1157 | { | ||
1158 | u16 a, b; | ||
1159 | int err = 0, i, j; | ||
1160 | |||
1161 | err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */ | ||
1162 | |||
1163 | for (i = 0, j = 0; i < 32; i++, j += 2) { | ||
1164 | a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8); | ||
1165 | b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8); | ||
1166 | err += w9968cf_write_reg(cam, a, 0x40+i); | ||
1167 | err += w9968cf_write_reg(cam, b, 0x60+i); | ||
1168 | } | ||
1169 | err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */ | ||
1170 | |||
1171 | return err; | ||
1172 | } | ||
1173 | |||
1174 | |||
1175 | |||
1176 | /**************************************************************************** | ||
1177 | * Low-level I2C I/O functions. * | ||
1178 | * The adapter supports the following I2C transfer functions: * | ||
1179 | * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only) * | ||
1180 | * i2c_adap_read_byte_data() * | ||
1181 | * i2c_adap_read_byte() * | ||
1182 | ****************************************************************************/ | ||
1183 | |||
1184 | static int w9968cf_smbus_start(struct w9968cf_device* cam) | ||
1185 | { | ||
1186 | int err = 0; | ||
1187 | |||
1188 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ | ||
1189 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ | ||
1190 | |||
1191 | return err; | ||
1192 | } | ||
1193 | |||
1194 | |||
1195 | static int w9968cf_smbus_stop(struct w9968cf_device* cam) | ||
1196 | { | ||
1197 | int err = 0; | ||
1198 | |||
1199 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ | ||
1200 | err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */ | ||
1201 | |||
1202 | return err; | ||
1203 | } | ||
1204 | |||
1205 | |||
1206 | static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v) | ||
1207 | { | ||
1208 | u8 bit; | ||
1209 | int err = 0, sda; | ||
1210 | |||
1211 | for (bit = 0 ; bit < 8 ; bit++) { | ||
1212 | sda = (v & 0x80) ? 2 : 0; | ||
1213 | v <<= 1; | ||
1214 | /* SDE=1, SDA=sda, SCL=0 */ | ||
1215 | err += w9968cf_write_sb(cam, 0x10 | sda); | ||
1216 | /* SDE=1, SDA=sda, SCL=1 */ | ||
1217 | err += w9968cf_write_sb(cam, 0x11 | sda); | ||
1218 | /* SDE=1, SDA=sda, SCL=0 */ | ||
1219 | err += w9968cf_write_sb(cam, 0x10 | sda); | ||
1220 | } | ||
1221 | |||
1222 | return err; | ||
1223 | } | ||
1224 | |||
1225 | |||
1226 | static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v) | ||
1227 | { | ||
1228 | u8 bit; | ||
1229 | int err = 0; | ||
1230 | |||
1231 | *v = 0; | ||
1232 | for (bit = 0 ; bit < 8 ; bit++) { | ||
1233 | *v <<= 1; | ||
1234 | err += w9968cf_write_sb(cam, 0x0013); | ||
1235 | *v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0; | ||
1236 | err += w9968cf_write_sb(cam, 0x0012); | ||
1237 | } | ||
1238 | |||
1239 | return err; | ||
1240 | } | ||
1241 | |||
1242 | |||
1243 | static int w9968cf_smbus_write_ack(struct w9968cf_device* cam) | ||
1244 | { | ||
1245 | int err = 0; | ||
1246 | |||
1247 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ | ||
1248 | err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ | ||
1249 | err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ | ||
1250 | |||
1251 | return err; | ||
1252 | } | ||
1253 | |||
1254 | |||
1255 | static int w9968cf_smbus_read_ack(struct w9968cf_device* cam) | ||
1256 | { | ||
1257 | int err = 0, sda; | ||
1258 | |||
1259 | err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */ | ||
1260 | sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */ | ||
1261 | err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */ | ||
1262 | if (sda < 0) | ||
1263 | err += sda; | ||
1264 | if (sda == 1) { | ||
1265 | DBG(6, "Couldn't receive the ACK") | ||
1266 | err += -1; | ||
1267 | } | ||
1268 | |||
1269 | return err; | ||
1270 | } | ||
1271 | |||
1272 | |||
1273 | /* This seems to refresh the communication through the serial bus */ | ||
1274 | static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam) | ||
1275 | { | ||
1276 | int err = 0, j; | ||
1277 | |||
1278 | for (j = 1; j <= 10; j++) { | ||
1279 | err = w9968cf_write_reg(cam, 0x0020, 0x01); | ||
1280 | err += w9968cf_write_reg(cam, 0x0000, 0x01); | ||
1281 | if (err) | ||
1282 | break; | ||
1283 | } | ||
1284 | |||
1285 | return err; | ||
1286 | } | ||
1287 | |||
1288 | |||
1289 | /* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */ | ||
1290 | static int | ||
1291 | w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, | ||
1292 | u16 address, u8 subaddress,u8 value) | ||
1293 | { | ||
1294 | u16* data = cam->data_buffer; | ||
1295 | int err = 0; | ||
1296 | |||
1297 | err += w9968cf_smbus_refresh_bus(cam); | ||
1298 | |||
1299 | /* Enable SBUS outputs */ | ||
1300 | err += w9968cf_write_sb(cam, 0x0020); | ||
1301 | |||
1302 | data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0); | ||
1303 | data[0] |= (address & 0x40) ? 0x4000 : 0x0; | ||
1304 | data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0); | ||
1305 | data[1] |= (address & 0x20) ? 0x0150 : 0x0; | ||
1306 | data[1] |= (address & 0x10) ? 0x5400 : 0x0; | ||
1307 | data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0); | ||
1308 | data[2] |= (address & 0x04) ? 0x0540 : 0x0; | ||
1309 | data[2] |= (address & 0x02) ? 0x5000 : 0x0; | ||
1310 | data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0); | ||
1311 | data[3] |= (address & 0x01) ? 0x0054 : 0x0; | ||
1312 | |||
1313 | err += w9968cf_write_fsb(cam, data); | ||
1314 | |||
1315 | data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0); | ||
1316 | data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0; | ||
1317 | data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0; | ||
1318 | data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0); | ||
1319 | data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0; | ||
1320 | data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0; | ||
1321 | data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0; | ||
1322 | data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0); | ||
1323 | data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0; | ||
1324 | data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0; | ||
1325 | data[3] = 0x001d; | ||
1326 | |||
1327 | err += w9968cf_write_fsb(cam, data); | ||
1328 | |||
1329 | data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0); | ||
1330 | data[0] |= (value & 0x40) ? 0x0540 : 0x0; | ||
1331 | data[0] |= (value & 0x20) ? 0x5000 : 0x0; | ||
1332 | data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0); | ||
1333 | data[1] |= (value & 0x10) ? 0x0054 : 0x0; | ||
1334 | data[1] |= (value & 0x08) ? 0x1500 : 0x0; | ||
1335 | data[1] |= (value & 0x04) ? 0x4000 : 0x0; | ||
1336 | data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0); | ||
1337 | data[2] |= (value & 0x02) ? 0x0150 : 0x0; | ||
1338 | data[2] |= (value & 0x01) ? 0x5400 : 0x0; | ||
1339 | data[3] = 0xfe1d; | ||
1340 | |||
1341 | err += w9968cf_write_fsb(cam, data); | ||
1342 | |||
1343 | /* Disable SBUS outputs */ | ||
1344 | err += w9968cf_write_sb(cam, 0x0000); | ||
1345 | |||
1346 | if (!err) | ||
1347 | DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X " | ||
1348 | "value 0x%02X", address, subaddress, value) | ||
1349 | else | ||
1350 | DBG(5, "I2C write byte data failed, addr.0x%04X, " | ||
1351 | "subaddr.0x%02X, value 0x%02X", | ||
1352 | address, subaddress, value) | ||
1353 | |||
1354 | return err; | ||
1355 | } | ||
1356 | |||
1357 | |||
1358 | /* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */ | ||
1359 | static int | ||
1360 | w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam, | ||
1361 | u16 address, u8 subaddress, | ||
1362 | u8* value) | ||
1363 | { | ||
1364 | int err = 0; | ||
1365 | |||
1366 | /* Serial data enable */ | ||
1367 | err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */ | ||
1368 | |||
1369 | err += w9968cf_smbus_start(cam); | ||
1370 | err += w9968cf_smbus_write_byte(cam, address); | ||
1371 | err += w9968cf_smbus_read_ack(cam); | ||
1372 | err += w9968cf_smbus_write_byte(cam, subaddress); | ||
1373 | err += w9968cf_smbus_read_ack(cam); | ||
1374 | err += w9968cf_smbus_stop(cam); | ||
1375 | err += w9968cf_smbus_start(cam); | ||
1376 | err += w9968cf_smbus_write_byte(cam, address + 1); | ||
1377 | err += w9968cf_smbus_read_ack(cam); | ||
1378 | err += w9968cf_smbus_read_byte(cam, value); | ||
1379 | err += w9968cf_smbus_write_ack(cam); | ||
1380 | err += w9968cf_smbus_stop(cam); | ||
1381 | |||
1382 | /* Serial data disable */ | ||
1383 | err += w9968cf_write_sb(cam, 0x0000); | ||
1384 | |||
1385 | if (!err) | ||
1386 | DBG(5, "I2C read byte data done, addr.0x%04X, " | ||
1387 | "subaddr.0x%02X, value 0x%02X", | ||
1388 | address, subaddress, *value) | ||
1389 | else | ||
1390 | DBG(5, "I2C read byte data failed, addr.0x%04X, " | ||
1391 | "subaddr.0x%02X, wrong value 0x%02X", | ||
1392 | address, subaddress, *value) | ||
1393 | |||
1394 | return err; | ||
1395 | } | ||
1396 | |||
1397 | |||
1398 | /* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */ | ||
1399 | static int | ||
1400 | w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, | ||
1401 | u16 address, u8* value) | ||
1402 | { | ||
1403 | int err = 0; | ||
1404 | |||
1405 | /* Serial data enable */ | ||
1406 | err += w9968cf_write_sb(cam, 0x0013); | ||
1407 | |||
1408 | err += w9968cf_smbus_start(cam); | ||
1409 | err += w9968cf_smbus_write_byte(cam, address + 1); | ||
1410 | err += w9968cf_smbus_read_ack(cam); | ||
1411 | err += w9968cf_smbus_read_byte(cam, value); | ||
1412 | err += w9968cf_smbus_write_ack(cam); | ||
1413 | err += w9968cf_smbus_stop(cam); | ||
1414 | |||
1415 | /* Serial data disable */ | ||
1416 | err += w9968cf_write_sb(cam, 0x0000); | ||
1417 | |||
1418 | if (!err) | ||
1419 | DBG(5, "I2C read byte done, addr.0x%04X, " | ||
1420 | "value 0x%02X", address, *value) | ||
1421 | else | ||
1422 | DBG(5, "I2C read byte failed, addr.0x%04X, " | ||
1423 | "wrong value 0x%02X", address, *value) | ||
1424 | |||
1425 | return err; | ||
1426 | } | ||
1427 | |||
1428 | |||
1429 | /* SMBus protocol: S Addr Wr [A] Value [A] P */ | ||
1430 | static int | ||
1431 | w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam, | ||
1432 | u16 address, u8 value) | ||
1433 | { | ||
1434 | DBG(4, "i2c_write_byte() is an unsupported transfer mode") | ||
1435 | return -EINVAL; | ||
1436 | } | ||
1437 | |||
1438 | |||
1439 | |||
1440 | /**************************************************************************** | ||
1441 | * I2C interface to kernel * | ||
1442 | ****************************************************************************/ | ||
1443 | |||
1444 | static int | ||
1445 | w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, | ||
1446 | unsigned short flags, char read_write, u8 command, | ||
1447 | int size, union i2c_smbus_data *data) | ||
1448 | { | ||
1449 | struct w9968cf_device* cam = i2c_get_adapdata(adapter); | ||
1450 | u8 i; | ||
1451 | int err = 0; | ||
1452 | |||
1453 | switch (addr) { | ||
1454 | case OV6xx0_SID: | ||
1455 | case OV7xx0_SID: | ||
1456 | break; | ||
1457 | default: | ||
1458 | DBG(4, "Rejected slave ID 0x%04X", addr) | ||
1459 | return -EINVAL; | ||
1460 | } | ||
1461 | |||
1462 | if (size == I2C_SMBUS_BYTE) { | ||
1463 | /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */ | ||
1464 | addr <<= 1; | ||
1465 | |||
1466 | if (read_write == I2C_SMBUS_WRITE) | ||
1467 | err = w9968cf_i2c_adap_write_byte(cam, addr, command); | ||
1468 | else if (read_write == I2C_SMBUS_READ) | ||
1469 | err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte); | ||
1470 | |||
1471 | } else if (size == I2C_SMBUS_BYTE_DATA) { | ||
1472 | addr <<= 1; | ||
1473 | |||
1474 | if (read_write == I2C_SMBUS_WRITE) | ||
1475 | err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr, | ||
1476 | command, data->byte); | ||
1477 | else if (read_write == I2C_SMBUS_READ) { | ||
1478 | for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) { | ||
1479 | err = w9968cf_i2c_adap_read_byte_data(cam,addr, | ||
1480 | command, &data->byte); | ||
1481 | if (err) { | ||
1482 | if (w9968cf_smbus_refresh_bus(cam)) { | ||
1483 | err = -EIO; | ||
1484 | break; | ||
1485 | } | ||
1486 | } else | ||
1487 | break; | ||
1488 | } | ||
1489 | |||
1490 | } else | ||
1491 | return -EINVAL; | ||
1492 | |||
1493 | } else { | ||
1494 | DBG(4, "Unsupported I2C transfer mode (%d)", size) | ||
1495 | return -EINVAL; | ||
1496 | } | ||
1497 | |||
1498 | return err; | ||
1499 | } | ||
1500 | |||
1501 | |||
1502 | static u32 w9968cf_i2c_func(struct i2c_adapter* adap) | ||
1503 | { | ||
1504 | return I2C_FUNC_SMBUS_READ_BYTE | | ||
1505 | I2C_FUNC_SMBUS_READ_BYTE_DATA | | ||
1506 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA; | ||
1507 | } | ||
1508 | |||
1509 | |||
1510 | static int w9968cf_i2c_attach_inform(struct i2c_client* client) | ||
1511 | { | ||
1512 | struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); | ||
1513 | int id = client->driver->id, err = 0; | ||
1514 | |||
1515 | if (id == I2C_DRIVERID_OVCAMCHIP) { | ||
1516 | cam->sensor_client = client; | ||
1517 | err = w9968cf_sensor_init(cam); | ||
1518 | if (err) { | ||
1519 | cam->sensor_client = NULL; | ||
1520 | return err; | ||
1521 | } | ||
1522 | } else { | ||
1523 | DBG(4, "Rejected client [%s] with driver [%s]", | ||
1524 | client->name, client->driver->driver.name) | ||
1525 | return -EINVAL; | ||
1526 | } | ||
1527 | |||
1528 | DBG(5, "I2C attach client [%s] with driver [%s]", | ||
1529 | client->name, client->driver->driver.name) | ||
1530 | |||
1531 | return 0; | ||
1532 | } | ||
1533 | |||
1534 | |||
1535 | static int w9968cf_i2c_detach_inform(struct i2c_client* client) | ||
1536 | { | ||
1537 | struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); | ||
1538 | |||
1539 | if (cam->sensor_client == client) | ||
1540 | cam->sensor_client = NULL; | ||
1541 | |||
1542 | DBG(5, "I2C detach client [%s]", client->name) | ||
1543 | |||
1544 | return 0; | ||
1545 | } | ||
1546 | |||
1547 | |||
1548 | static int | ||
1549 | w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd, | ||
1550 | unsigned long arg) | ||
1551 | { | ||
1552 | return 0; | ||
1553 | } | ||
1554 | |||
1555 | |||
1556 | static int w9968cf_i2c_init(struct w9968cf_device* cam) | ||
1557 | { | ||
1558 | int err = 0; | ||
1559 | |||
1560 | static struct i2c_algorithm algo = { | ||
1561 | .smbus_xfer = w9968cf_i2c_smbus_xfer, | ||
1562 | .algo_control = w9968cf_i2c_control, | ||
1563 | .functionality = w9968cf_i2c_func, | ||
1564 | }; | ||
1565 | |||
1566 | static struct i2c_adapter adap = { | ||
1567 | .id = I2C_HW_SMBUS_W9968CF, | ||
1568 | .class = I2C_CLASS_CAM_DIGITAL, | ||
1569 | .owner = THIS_MODULE, | ||
1570 | .client_register = w9968cf_i2c_attach_inform, | ||
1571 | .client_unregister = w9968cf_i2c_detach_inform, | ||
1572 | .algo = &algo, | ||
1573 | }; | ||
1574 | |||
1575 | memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter)); | ||
1576 | strcpy(cam->i2c_adapter.name, "w9968cf"); | ||
1577 | i2c_set_adapdata(&cam->i2c_adapter, cam); | ||
1578 | |||
1579 | DBG(6, "Registering I2C adapter with kernel...") | ||
1580 | |||
1581 | err = i2c_add_adapter(&cam->i2c_adapter); | ||
1582 | if (err) | ||
1583 | DBG(1, "Failed to register the I2C adapter") | ||
1584 | else | ||
1585 | DBG(5, "I2C adapter registered") | ||
1586 | |||
1587 | return err; | ||
1588 | } | ||
1589 | |||
1590 | |||
1591 | |||
1592 | /**************************************************************************** | ||
1593 | * Helper functions * | ||
1594 | ****************************************************************************/ | ||
1595 | |||
1596 | /*-------------------------------------------------------------------------- | ||
1597 | Turn on the LED on some webcams. A beep should be heard too. | ||
1598 | Return 0 on success, a negative number otherwise. | ||
1599 | --------------------------------------------------------------------------*/ | ||
1600 | static int w9968cf_turn_on_led(struct w9968cf_device* cam) | ||
1601 | { | ||
1602 | int err = 0; | ||
1603 | |||
1604 | err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */ | ||
1605 | err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ | ||
1606 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ | ||
1607 | err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */ | ||
1608 | err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */ | ||
1609 | err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */ | ||
1610 | |||
1611 | if (err) | ||
1612 | DBG(2, "Couldn't turn on the LED") | ||
1613 | |||
1614 | DBG(5, "LED turned on") | ||
1615 | |||
1616 | return err; | ||
1617 | } | ||
1618 | |||
1619 | |||
1620 | /*-------------------------------------------------------------------------- | ||
1621 | Write some registers for the device initialization. | ||
1622 | This function is called once on open(). | ||
1623 | Return 0 on success, a negative number otherwise. | ||
1624 | --------------------------------------------------------------------------*/ | ||
1625 | static int w9968cf_init_chip(struct w9968cf_device* cam) | ||
1626 | { | ||
1627 | unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2, | ||
1628 | y0 = 0x0000, | ||
1629 | u0 = y0 + hw_bufsize/2, | ||
1630 | v0 = u0 + hw_bufsize/4, | ||
1631 | y1 = v0 + hw_bufsize/4, | ||
1632 | u1 = y1 + hw_bufsize/2, | ||
1633 | v1 = u1 + hw_bufsize/4; | ||
1634 | int err = 0; | ||
1635 | |||
1636 | err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */ | ||
1637 | err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */ | ||
1638 | |||
1639 | err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */ | ||
1640 | err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */ | ||
1641 | |||
1642 | err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */ | ||
1643 | err += w9968cf_write_reg(cam, y0 >> 16, 0x21); /* Y buf.0, high */ | ||
1644 | err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */ | ||
1645 | err += w9968cf_write_reg(cam, u0 >> 16, 0x25); /* U buf.0, high */ | ||
1646 | err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */ | ||
1647 | err += w9968cf_write_reg(cam, v0 >> 16, 0x29); /* V buf.0, high */ | ||
1648 | |||
1649 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */ | ||
1650 | err += w9968cf_write_reg(cam, y1 >> 16, 0x23); /* Y buf.1, high */ | ||
1651 | err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */ | ||
1652 | err += w9968cf_write_reg(cam, u1 >> 16, 0x27); /* U buf.1, high */ | ||
1653 | err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */ | ||
1654 | err += w9968cf_write_reg(cam, v1 >> 16, 0x2b); /* V buf.1, high */ | ||
1655 | |||
1656 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */ | ||
1657 | err += w9968cf_write_reg(cam, y1 >> 16, 0x33); /* JPEG buf 0 high */ | ||
1658 | |||
1659 | err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */ | ||
1660 | err += w9968cf_write_reg(cam, y1 >> 16, 0x35); /* JPEG bug 1 high */ | ||
1661 | |||
1662 | err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */ | ||
1663 | err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/ | ||
1664 | err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */ | ||
1665 | err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */ | ||
1666 | |||
1667 | err += w9968cf_set_picture(cam, cam->picture); /* this before */ | ||
1668 | err += w9968cf_set_window(cam, cam->window); | ||
1669 | |||
1670 | if (err) | ||
1671 | DBG(1, "Chip initialization failed") | ||
1672 | else | ||
1673 | DBG(5, "Chip successfully initialized") | ||
1674 | |||
1675 | return err; | ||
1676 | } | ||
1677 | |||
1678 | |||
1679 | /*-------------------------------------------------------------------------- | ||
1680 | Return non-zero if the palette is supported, 0 otherwise. | ||
1681 | --------------------------------------------------------------------------*/ | ||
1682 | static inline u16 w9968cf_valid_palette(u16 palette) | ||
1683 | { | ||
1684 | u8 i = 0; | ||
1685 | while (w9968cf_formatlist[i].palette != 0) { | ||
1686 | if (palette == w9968cf_formatlist[i].palette) | ||
1687 | return palette; | ||
1688 | i++; | ||
1689 | } | ||
1690 | return 0; | ||
1691 | } | ||
1692 | |||
1693 | |||
1694 | /*-------------------------------------------------------------------------- | ||
1695 | Return the depth corresponding to the given palette. | ||
1696 | Palette _must_ be supported ! | ||
1697 | --------------------------------------------------------------------------*/ | ||
1698 | static inline u16 w9968cf_valid_depth(u16 palette) | ||
1699 | { | ||
1700 | u8 i=0; | ||
1701 | while (w9968cf_formatlist[i].palette != palette) | ||
1702 | i++; | ||
1703 | |||
1704 | return w9968cf_formatlist[i].depth; | ||
1705 | } | ||
1706 | |||
1707 | |||
1708 | /*-------------------------------------------------------------------------- | ||
1709 | Return non-zero if the format requires decompression, 0 otherwise. | ||
1710 | --------------------------------------------------------------------------*/ | ||
1711 | static inline u8 w9968cf_need_decompression(u16 palette) | ||
1712 | { | ||
1713 | u8 i = 0; | ||
1714 | while (w9968cf_formatlist[i].palette != 0) { | ||
1715 | if (palette == w9968cf_formatlist[i].palette) | ||
1716 | return w9968cf_formatlist[i].compression; | ||
1717 | i++; | ||
1718 | } | ||
1719 | return 0; | ||
1720 | } | ||
1721 | |||
1722 | |||
1723 | /*-------------------------------------------------------------------------- | ||
1724 | Change the picture settings of the camera. | ||
1725 | Return 0 on success, a negative number otherwise. | ||
1726 | --------------------------------------------------------------------------*/ | ||
1727 | static int | ||
1728 | w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict) | ||
1729 | { | ||
1730 | u16 fmt, hw_depth, hw_palette, reg_v = 0x0000; | ||
1731 | int err = 0; | ||
1732 | |||
1733 | /* Make sure we are using a valid depth */ | ||
1734 | pict.depth = w9968cf_valid_depth(pict.palette); | ||
1735 | |||
1736 | fmt = pict.palette; | ||
1737 | |||
1738 | hw_depth = pict.depth; /* depth used by the winbond chip */ | ||
1739 | hw_palette = pict.palette; /* palette used by the winbond chip */ | ||
1740 | |||
1741 | /* VS & HS polarities */ | ||
1742 | reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11); | ||
1743 | |||
1744 | switch (fmt) | ||
1745 | { | ||
1746 | case VIDEO_PALETTE_UYVY: | ||
1747 | reg_v |= 0x0000; | ||
1748 | cam->vpp_flag = VPP_NONE; | ||
1749 | break; | ||
1750 | case VIDEO_PALETTE_YUV422P: | ||
1751 | reg_v |= 0x0002; | ||
1752 | cam->vpp_flag = VPP_DECOMPRESSION; | ||
1753 | break; | ||
1754 | case VIDEO_PALETTE_YUV420: | ||
1755 | case VIDEO_PALETTE_YUV420P: | ||
1756 | reg_v |= 0x0003; | ||
1757 | cam->vpp_flag = VPP_DECOMPRESSION; | ||
1758 | break; | ||
1759 | case VIDEO_PALETTE_YUYV: | ||
1760 | case VIDEO_PALETTE_YUV422: | ||
1761 | reg_v |= 0x0000; | ||
1762 | cam->vpp_flag = VPP_SWAP_YUV_BYTES; | ||
1763 | hw_palette = VIDEO_PALETTE_UYVY; | ||
1764 | break; | ||
1765 | /* Original video is used instead of RGBX palettes. | ||
1766 | Software conversion later. */ | ||
1767 | case VIDEO_PALETTE_GREY: | ||
1768 | case VIDEO_PALETTE_RGB555: | ||
1769 | case VIDEO_PALETTE_RGB565: | ||
1770 | case VIDEO_PALETTE_RGB24: | ||
1771 | case VIDEO_PALETTE_RGB32: | ||
1772 | reg_v |= 0x0000; /* UYVY 16 bit is used */ | ||
1773 | hw_depth = 16; | ||
1774 | hw_palette = VIDEO_PALETTE_UYVY; | ||
1775 | cam->vpp_flag = VPP_UYVY_TO_RGBX; | ||
1776 | break; | ||
1777 | } | ||
1778 | |||
1779 | /* NOTE: due to memory issues, it is better to disable the hardware | ||
1780 | double buffering during compression */ | ||
1781 | if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION)) | ||
1782 | reg_v |= 0x0080; | ||
1783 | |||
1784 | if (cam->clamping) | ||
1785 | reg_v |= 0x0020; | ||
1786 | |||
1787 | if (cam->filter_type == 1) | ||
1788 | reg_v |= 0x0008; | ||
1789 | else if (cam->filter_type == 2) | ||
1790 | reg_v |= 0x000c; | ||
1791 | |||
1792 | if ((err = w9968cf_write_reg(cam, reg_v, 0x16))) | ||
1793 | goto error; | ||
1794 | |||
1795 | if ((err = w9968cf_sensor_update_picture(cam, pict))) | ||
1796 | goto error; | ||
1797 | |||
1798 | /* If all went well, update the device data structure */ | ||
1799 | memcpy(&cam->picture, &pict, sizeof(pict)); | ||
1800 | cam->hw_depth = hw_depth; | ||
1801 | cam->hw_palette = hw_palette; | ||
1802 | |||
1803 | /* Settings changed, so we clear the frame buffers */ | ||
1804 | memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); | ||
1805 | |||
1806 | DBG(4, "Palette is %s, depth is %u bpp", | ||
1807 | symbolic(v4l1_plist, pict.palette), pict.depth) | ||
1808 | |||
1809 | return 0; | ||
1810 | |||
1811 | error: | ||
1812 | DBG(1, "Failed to change picture settings") | ||
1813 | return err; | ||
1814 | } | ||
1815 | |||
1816 | |||
1817 | /*-------------------------------------------------------------------------- | ||
1818 | Change the capture area size of the camera. | ||
1819 | This function _must_ be called _after_ w9968cf_set_picture(). | ||
1820 | Return 0 on success, a negative number otherwise. | ||
1821 | --------------------------------------------------------------------------*/ | ||
1822 | static int | ||
1823 | w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) | ||
1824 | { | ||
1825 | u16 x, y, w, h, scx, scy, cw, ch, ax, ay; | ||
1826 | unsigned long fw, fh; | ||
1827 | struct ovcamchip_window s_win; | ||
1828 | int err = 0; | ||
1829 | |||
1830 | /* Work around to avoid FP arithmetics */ | ||
1831 | #define __SC(x) ((x) << 10) | ||
1832 | #define __UNSC(x) ((x) >> 10) | ||
1833 | |||
1834 | /* Make sure we are using a supported resolution */ | ||
1835 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, | ||
1836 | (u16*)&win.height))) | ||
1837 | goto error; | ||
1838 | |||
1839 | /* Scaling factors */ | ||
1840 | fw = __SC(win.width) / cam->maxwidth; | ||
1841 | fh = __SC(win.height) / cam->maxheight; | ||
1842 | |||
1843 | /* Set up the width and height values used by the chip */ | ||
1844 | if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) { | ||
1845 | cam->vpp_flag |= VPP_UPSCALE; | ||
1846 | /* Calculate largest w,h mantaining the same w/h ratio */ | ||
1847 | w = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh; | ||
1848 | h = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight; | ||
1849 | if (w < cam->minwidth) /* just in case */ | ||
1850 | w = cam->minwidth; | ||
1851 | if (h < cam->minheight) /* just in case */ | ||
1852 | h = cam->minheight; | ||
1853 | } else { | ||
1854 | cam->vpp_flag &= ~VPP_UPSCALE; | ||
1855 | w = win.width; | ||
1856 | h = win.height; | ||
1857 | } | ||
1858 | |||
1859 | /* x,y offsets of the cropped area */ | ||
1860 | scx = cam->start_cropx; | ||
1861 | scy = cam->start_cropy; | ||
1862 | |||
1863 | /* Calculate cropped area manteining the right w/h ratio */ | ||
1864 | if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) { | ||
1865 | cw = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh; | ||
1866 | ch = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight; | ||
1867 | } else { | ||
1868 | cw = w; | ||
1869 | ch = h; | ||
1870 | } | ||
1871 | |||
1872 | /* Setup the window of the sensor */ | ||
1873 | s_win.format = VIDEO_PALETTE_UYVY; | ||
1874 | s_win.width = cam->maxwidth; | ||
1875 | s_win.height = cam->maxheight; | ||
1876 | s_win.quarter = 0; /* full progressive video */ | ||
1877 | |||
1878 | /* Center it */ | ||
1879 | s_win.x = (s_win.width - cw) / 2; | ||
1880 | s_win.y = (s_win.height - ch) / 2; | ||
1881 | |||
1882 | /* Clock divisor */ | ||
1883 | if (cam->clockdiv >= 0) | ||
1884 | s_win.clockdiv = cam->clockdiv; /* manual override */ | ||
1885 | else | ||
1886 | switch (cam->sensor) { | ||
1887 | case CC_OV6620: | ||
1888 | s_win.clockdiv = 0; | ||
1889 | break; | ||
1890 | case CC_OV6630: | ||
1891 | s_win.clockdiv = 0; | ||
1892 | break; | ||
1893 | case CC_OV76BE: | ||
1894 | case CC_OV7610: | ||
1895 | case CC_OV7620: | ||
1896 | s_win.clockdiv = 0; | ||
1897 | break; | ||
1898 | default: | ||
1899 | s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR; | ||
1900 | } | ||
1901 | |||
1902 | /* We have to scale win.x and win.y offsets */ | ||
1903 | if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) | ||
1904 | || (cam->vpp_flag & VPP_UPSCALE) ) { | ||
1905 | ax = __SC(win.x)/fw; | ||
1906 | ay = __SC(win.y)/fh; | ||
1907 | } else { | ||
1908 | ax = win.x; | ||
1909 | ay = win.y; | ||
1910 | } | ||
1911 | |||
1912 | if ((ax + cw) > cam->maxwidth) | ||
1913 | ax = cam->maxwidth - cw; | ||
1914 | |||
1915 | if ((ay + ch) > cam->maxheight) | ||
1916 | ay = cam->maxheight - ch; | ||
1917 | |||
1918 | /* Adjust win.x, win.y */ | ||
1919 | if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) | ||
1920 | || (cam->vpp_flag & VPP_UPSCALE) ) { | ||
1921 | win.x = __UNSC(ax*fw); | ||
1922 | win.y = __UNSC(ay*fh); | ||
1923 | } else { | ||
1924 | win.x = ax; | ||
1925 | win.y = ay; | ||
1926 | } | ||
1927 | |||
1928 | /* Offsets used by the chip */ | ||
1929 | x = ax + s_win.x; | ||
1930 | y = ay + s_win.y; | ||
1931 | |||
1932 | /* Go ! */ | ||
1933 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win))) | ||
1934 | goto error; | ||
1935 | |||
1936 | err += w9968cf_write_reg(cam, scx + x, 0x10); | ||
1937 | err += w9968cf_write_reg(cam, scy + y, 0x11); | ||
1938 | err += w9968cf_write_reg(cam, scx + x + cw, 0x12); | ||
1939 | err += w9968cf_write_reg(cam, scy + y + ch, 0x13); | ||
1940 | err += w9968cf_write_reg(cam, w, 0x14); | ||
1941 | err += w9968cf_write_reg(cam, h, 0x15); | ||
1942 | |||
1943 | /* JPEG width & height */ | ||
1944 | err += w9968cf_write_reg(cam, w, 0x30); | ||
1945 | err += w9968cf_write_reg(cam, h, 0x31); | ||
1946 | |||
1947 | /* Y & UV frame buffer strides (in WORD) */ | ||
1948 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | ||
1949 | err += w9968cf_write_reg(cam, w/2, 0x2c); | ||
1950 | err += w9968cf_write_reg(cam, w/4, 0x2d); | ||
1951 | } else | ||
1952 | err += w9968cf_write_reg(cam, w, 0x2c); | ||
1953 | |||
1954 | if (err) | ||
1955 | goto error; | ||
1956 | |||
1957 | /* If all went well, update the device data structure */ | ||
1958 | memcpy(&cam->window, &win, sizeof(win)); | ||
1959 | cam->hw_width = w; | ||
1960 | cam->hw_height = h; | ||
1961 | |||
1962 | /* Settings changed, so we clear the frame buffers */ | ||
1963 | memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); | ||
1964 | |||
1965 | DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)", | ||
1966 | win.width, win.height, win.x, win.y) | ||
1967 | |||
1968 | PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, " | ||
1969 | "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u", | ||
1970 | x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y, | ||
1971 | win.width, win.height) | ||
1972 | |||
1973 | return 0; | ||
1974 | |||
1975 | error: | ||
1976 | DBG(1, "Failed to change the capture area size") | ||
1977 | return err; | ||
1978 | } | ||
1979 | |||
1980 | |||
1981 | /*-------------------------------------------------------------------------- | ||
1982 | Adjust the asked values for window width and height. | ||
1983 | Return 0 on success, -1 otherwise. | ||
1984 | --------------------------------------------------------------------------*/ | ||
1985 | static int | ||
1986 | w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height) | ||
1987 | { | ||
1988 | u16 maxw, maxh; | ||
1989 | |||
1990 | if ((*width < cam->minwidth) || (*height < cam->minheight)) | ||
1991 | return -ERANGE; | ||
1992 | |||
1993 | maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && | ||
1994 | w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) | ||
1995 | : cam->maxwidth; | ||
1996 | maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && | ||
1997 | w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) | ||
1998 | : cam->maxheight; | ||
1999 | |||
2000 | if (*width > maxw) | ||
2001 | *width = maxw; | ||
2002 | if (*height > maxh) | ||
2003 | *height = maxh; | ||
2004 | |||
2005 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | ||
2006 | *width &= ~15L; /* multiple of 16 */ | ||
2007 | *height &= ~15L; | ||
2008 | } | ||
2009 | |||
2010 | PDBGG("Window size adjusted w=%u, h=%u ", *width, *height) | ||
2011 | |||
2012 | return 0; | ||
2013 | } | ||
2014 | |||
2015 | |||
2016 | /*-------------------------------------------------------------------------- | ||
2017 | Initialize the FIFO list of requested frames. | ||
2018 | --------------------------------------------------------------------------*/ | ||
2019 | static void w9968cf_init_framelist(struct w9968cf_device* cam) | ||
2020 | { | ||
2021 | u8 i; | ||
2022 | |||
2023 | for (i = 0; i < cam->nbuffers; i++) { | ||
2024 | cam->requested_frame[i] = NULL; | ||
2025 | cam->frame[i].queued = 0; | ||
2026 | cam->frame[i].status = F_UNUSED; | ||
2027 | } | ||
2028 | } | ||
2029 | |||
2030 | |||
2031 | /*-------------------------------------------------------------------------- | ||
2032 | Add a frame in the FIFO list of requested frames. | ||
2033 | This function is called in process context. | ||
2034 | --------------------------------------------------------------------------*/ | ||
2035 | static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num) | ||
2036 | { | ||
2037 | u8 f; | ||
2038 | unsigned long lock_flags; | ||
2039 | |||
2040 | spin_lock_irqsave(&cam->flist_lock, lock_flags); | ||
2041 | |||
2042 | for (f=0; cam->requested_frame[f] != NULL; f++); | ||
2043 | cam->requested_frame[f] = &cam->frame[f_num]; | ||
2044 | cam->frame[f_num].queued = 1; | ||
2045 | cam->frame[f_num].status = F_UNUSED; /* clear the status */ | ||
2046 | |||
2047 | spin_unlock_irqrestore(&cam->flist_lock, lock_flags); | ||
2048 | |||
2049 | DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f) | ||
2050 | } | ||
2051 | |||
2052 | |||
2053 | /*-------------------------------------------------------------------------- | ||
2054 | Read, store and remove the first pointer in the FIFO list of requested | ||
2055 | frames. This function is called in interrupt context. | ||
2056 | --------------------------------------------------------------------------*/ | ||
2057 | static void | ||
2058 | w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep) | ||
2059 | { | ||
2060 | u8 i; | ||
2061 | |||
2062 | spin_lock(&cam->flist_lock); | ||
2063 | |||
2064 | *framep = cam->requested_frame[0]; | ||
2065 | |||
2066 | /* Shift the list of pointers */ | ||
2067 | for (i = 0; i < cam->nbuffers-1; i++) | ||
2068 | cam->requested_frame[i] = cam->requested_frame[i+1]; | ||
2069 | cam->requested_frame[i] = NULL; | ||
2070 | |||
2071 | spin_unlock(&cam->flist_lock); | ||
2072 | |||
2073 | DBG(6,"Popped frame #%d from the list", (*framep)->number) | ||
2074 | } | ||
2075 | |||
2076 | |||
2077 | /*-------------------------------------------------------------------------- | ||
2078 | High-level video post-processing routine on grabbed frames. | ||
2079 | Return 0 on success, a negative number otherwise. | ||
2080 | --------------------------------------------------------------------------*/ | ||
2081 | static int | ||
2082 | w9968cf_postprocess_frame(struct w9968cf_device* cam, | ||
2083 | struct w9968cf_frame_t* fr) | ||
2084 | { | ||
2085 | void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp; | ||
2086 | u16 w = cam->window.width, | ||
2087 | h = cam->window.height, | ||
2088 | d = cam->picture.depth, | ||
2089 | fmt = cam->picture.palette, | ||
2090 | rgb = cam->force_rgb, | ||
2091 | hw_w = cam->hw_width, | ||
2092 | hw_h = cam->hw_height, | ||
2093 | hw_d = cam->hw_depth; | ||
2094 | int err = 0; | ||
2095 | |||
2096 | #define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;} | ||
2097 | |||
2098 | if (cam->vpp_flag & VPP_DECOMPRESSION) { | ||
2099 | memcpy(pOut, pIn, fr->length); | ||
2100 | _PSWAP(pIn, pOut) | ||
2101 | err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut); | ||
2102 | PDBGG("Compressed frame length: %lu",(unsigned long)fr->length) | ||
2103 | fr->length = (hw_w*hw_h*hw_d)/8; | ||
2104 | _PSWAP(pIn, pOut) | ||
2105 | if (err) { | ||
2106 | DBG(4, "An error occurred while decoding the frame: " | ||
2107 | "%s", symbolic(decoder_errlist, err)) | ||
2108 | return err; | ||
2109 | } else | ||
2110 | DBG(6, "Frame decoded") | ||
2111 | } | ||
2112 | |||
2113 | if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) { | ||
2114 | w9968cf_vpp->swap_yuvbytes(pIn, fr->length); | ||
2115 | DBG(6, "Original UYVY component ordering changed") | ||
2116 | } | ||
2117 | |||
2118 | if (cam->vpp_flag & VPP_UPSCALE) { | ||
2119 | w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h); | ||
2120 | fr->length = (w*h*hw_d)/8; | ||
2121 | _PSWAP(pIn, pOut) | ||
2122 | DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u", | ||
2123 | hw_w, hw_h, hw_d, w, h) | ||
2124 | } | ||
2125 | |||
2126 | if (cam->vpp_flag & VPP_UYVY_TO_RGBX) { | ||
2127 | w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb); | ||
2128 | fr->length = (w*h*d)/8; | ||
2129 | _PSWAP(pIn, pOut) | ||
2130 | DBG(6, "UYVY-16bit to %s conversion done", | ||
2131 | symbolic(v4l1_plist, fmt)) | ||
2132 | } | ||
2133 | |||
2134 | if (pOut == fr->buffer) | ||
2135 | memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length); | ||
2136 | |||
2137 | return 0; | ||
2138 | } | ||
2139 | |||
2140 | |||
2141 | |||
2142 | /**************************************************************************** | ||
2143 | * Image sensor control routines * | ||
2144 | ****************************************************************************/ | ||
2145 | |||
2146 | static int | ||
2147 | w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val) | ||
2148 | { | ||
2149 | struct ovcamchip_control ctl; | ||
2150 | int err; | ||
2151 | |||
2152 | ctl.id = cid; | ||
2153 | ctl.value = val; | ||
2154 | |||
2155 | err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl); | ||
2156 | |||
2157 | return err; | ||
2158 | } | ||
2159 | |||
2160 | |||
2161 | static int | ||
2162 | w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val) | ||
2163 | { | ||
2164 | struct ovcamchip_control ctl; | ||
2165 | int err; | ||
2166 | |||
2167 | ctl.id = cid; | ||
2168 | |||
2169 | err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl); | ||
2170 | if (!err) | ||
2171 | *val = ctl.value; | ||
2172 | |||
2173 | return err; | ||
2174 | } | ||
2175 | |||
2176 | |||
2177 | static int | ||
2178 | w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg) | ||
2179 | { | ||
2180 | struct i2c_client* c = cam->sensor_client; | ||
2181 | int rc = 0; | ||
2182 | |||
2183 | if (!c || !c->driver || !c->driver->command) | ||
2184 | return -EINVAL; | ||
2185 | |||
2186 | rc = c->driver->command(c, cmd, arg); | ||
2187 | /* The I2C driver returns -EPERM on non-supported controls */ | ||
2188 | return (rc < 0 && rc != -EPERM) ? rc : 0; | ||
2189 | } | ||
2190 | |||
2191 | |||
2192 | /*-------------------------------------------------------------------------- | ||
2193 | Update some settings of the image sensor. | ||
2194 | Returns: 0 on success, a negative number otherwise. | ||
2195 | --------------------------------------------------------------------------*/ | ||
2196 | static int w9968cf_sensor_update_settings(struct w9968cf_device* cam) | ||
2197 | { | ||
2198 | int err = 0; | ||
2199 | |||
2200 | /* Auto brightness */ | ||
2201 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, | ||
2202 | cam->auto_brt); | ||
2203 | if (err) | ||
2204 | return err; | ||
2205 | |||
2206 | /* Auto exposure */ | ||
2207 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, | ||
2208 | cam->auto_exp); | ||
2209 | if (err) | ||
2210 | return err; | ||
2211 | |||
2212 | /* Banding filter */ | ||
2213 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, | ||
2214 | cam->bandfilt); | ||
2215 | if (err) | ||
2216 | return err; | ||
2217 | |||
2218 | /* Light frequency */ | ||
2219 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ, | ||
2220 | cam->lightfreq); | ||
2221 | if (err) | ||
2222 | return err; | ||
2223 | |||
2224 | /* Back light */ | ||
2225 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT, | ||
2226 | cam->backlight); | ||
2227 | if (err) | ||
2228 | return err; | ||
2229 | |||
2230 | /* Mirror */ | ||
2231 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR, | ||
2232 | cam->mirror); | ||
2233 | if (err) | ||
2234 | return err; | ||
2235 | |||
2236 | return 0; | ||
2237 | } | ||
2238 | |||
2239 | |||
2240 | /*-------------------------------------------------------------------------- | ||
2241 | Get some current picture settings from the image sensor and update the | ||
2242 | internal 'picture' structure of the camera. | ||
2243 | Returns: 0 on success, a negative number otherwise. | ||
2244 | --------------------------------------------------------------------------*/ | ||
2245 | static int w9968cf_sensor_get_picture(struct w9968cf_device* cam) | ||
2246 | { | ||
2247 | int err, v; | ||
2248 | |||
2249 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v); | ||
2250 | if (err) | ||
2251 | return err; | ||
2252 | cam->picture.contrast = v; | ||
2253 | |||
2254 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v); | ||
2255 | if (err) | ||
2256 | return err; | ||
2257 | cam->picture.brightness = v; | ||
2258 | |||
2259 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v); | ||
2260 | if (err) | ||
2261 | return err; | ||
2262 | cam->picture.colour = v; | ||
2263 | |||
2264 | err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v); | ||
2265 | if (err) | ||
2266 | return err; | ||
2267 | cam->picture.hue = v; | ||
2268 | |||
2269 | DBG(5, "Got picture settings from the image sensor") | ||
2270 | |||
2271 | PDBGG("Brightness, contrast, hue, colour, whiteness are " | ||
2272 | "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast, | ||
2273 | cam->picture.hue, cam->picture.colour, cam->picture.whiteness) | ||
2274 | |||
2275 | return 0; | ||
2276 | } | ||
2277 | |||
2278 | |||
2279 | /*-------------------------------------------------------------------------- | ||
2280 | Update picture settings of the image sensor. | ||
2281 | Returns: 0 on success, a negative number otherwise. | ||
2282 | --------------------------------------------------------------------------*/ | ||
2283 | static int | ||
2284 | w9968cf_sensor_update_picture(struct w9968cf_device* cam, | ||
2285 | struct video_picture pict) | ||
2286 | { | ||
2287 | int err = 0; | ||
2288 | |||
2289 | if ((!cam->sensor_initialized) | ||
2290 | || pict.contrast != cam->picture.contrast) { | ||
2291 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT, | ||
2292 | pict.contrast); | ||
2293 | if (err) | ||
2294 | goto fail; | ||
2295 | DBG(4, "Contrast changed from %u to %u", | ||
2296 | cam->picture.contrast, pict.contrast) | ||
2297 | cam->picture.contrast = pict.contrast; | ||
2298 | } | ||
2299 | |||
2300 | if (((!cam->sensor_initialized) || | ||
2301 | pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) { | ||
2302 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, | ||
2303 | pict.brightness); | ||
2304 | if (err) | ||
2305 | goto fail; | ||
2306 | DBG(4, "Brightness changed from %u to %u", | ||
2307 | cam->picture.brightness, pict.brightness) | ||
2308 | cam->picture.brightness = pict.brightness; | ||
2309 | } | ||
2310 | |||
2311 | if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) { | ||
2312 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT, | ||
2313 | pict.colour); | ||
2314 | if (err) | ||
2315 | goto fail; | ||
2316 | DBG(4, "Colour changed from %u to %u", | ||
2317 | cam->picture.colour, pict.colour) | ||
2318 | cam->picture.colour = pict.colour; | ||
2319 | } | ||
2320 | |||
2321 | if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) { | ||
2322 | err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, | ||
2323 | pict.hue); | ||
2324 | if (err) | ||
2325 | goto fail; | ||
2326 | DBG(4, "Hue changed from %u to %u", | ||
2327 | cam->picture.hue, pict.hue) | ||
2328 | cam->picture.hue = pict.hue; | ||
2329 | } | ||
2330 | |||
2331 | return 0; | ||
2332 | |||
2333 | fail: | ||
2334 | DBG(4, "Failed to change sensor picture setting") | ||
2335 | return err; | ||
2336 | } | ||
2337 | |||
2338 | |||
2339 | |||
2340 | /**************************************************************************** | ||
2341 | * Camera configuration * | ||
2342 | ****************************************************************************/ | ||
2343 | |||
2344 | /*-------------------------------------------------------------------------- | ||
2345 | This function is called when a supported image sensor is detected. | ||
2346 | Return 0 if the initialization succeeds, a negative number otherwise. | ||
2347 | --------------------------------------------------------------------------*/ | ||
2348 | static int w9968cf_sensor_init(struct w9968cf_device* cam) | ||
2349 | { | ||
2350 | int err = 0; | ||
2351 | |||
2352 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, | ||
2353 | &cam->monochrome))) | ||
2354 | goto error; | ||
2355 | |||
2356 | if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE, | ||
2357 | &cam->sensor))) | ||
2358 | goto error; | ||
2359 | |||
2360 | /* NOTE: Make sure width and height are a multiple of 16 */ | ||
2361 | switch (cam->sensor_client->addr) { | ||
2362 | case OV6xx0_SID: | ||
2363 | cam->maxwidth = 352; | ||
2364 | cam->maxheight = 288; | ||
2365 | cam->minwidth = 64; | ||
2366 | cam->minheight = 48; | ||
2367 | break; | ||
2368 | case OV7xx0_SID: | ||
2369 | cam->maxwidth = 640; | ||
2370 | cam->maxheight = 480; | ||
2371 | cam->minwidth = 64; | ||
2372 | cam->minheight = 48; | ||
2373 | break; | ||
2374 | default: | ||
2375 | DBG(1, "Not supported image sensor detected for %s", | ||
2376 | symbolic(camlist, cam->id)) | ||
2377 | return -EINVAL; | ||
2378 | } | ||
2379 | |||
2380 | /* These values depend on the ones in the ovxxx0.c sources */ | ||
2381 | switch (cam->sensor) { | ||
2382 | case CC_OV7620: | ||
2383 | cam->start_cropx = 287; | ||
2384 | cam->start_cropy = 35; | ||
2385 | /* Seems to work around a bug in the image sensor */ | ||
2386 | cam->vs_polarity = 1; | ||
2387 | cam->hs_polarity = 1; | ||
2388 | break; | ||
2389 | default: | ||
2390 | cam->start_cropx = 320; | ||
2391 | cam->start_cropy = 35; | ||
2392 | cam->vs_polarity = 1; | ||
2393 | cam->hs_polarity = 0; | ||
2394 | } | ||
2395 | |||
2396 | if ((err = w9968cf_sensor_update_settings(cam))) | ||
2397 | goto error; | ||
2398 | |||
2399 | if ((err = w9968cf_sensor_update_picture(cam, cam->picture))) | ||
2400 | goto error; | ||
2401 | |||
2402 | cam->sensor_initialized = 1; | ||
2403 | |||
2404 | DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor)) | ||
2405 | return 0; | ||
2406 | |||
2407 | error: | ||
2408 | cam->sensor_initialized = 0; | ||
2409 | cam->sensor = CC_UNKNOWN; | ||
2410 | DBG(1, "Image sensor initialization failed for %s (/dev/video%d). " | ||
2411 | "Try to detach and attach this device again", | ||
2412 | symbolic(camlist, cam->id), cam->v4ldev->minor) | ||
2413 | return err; | ||
2414 | } | ||
2415 | |||
2416 | |||
2417 | /*-------------------------------------------------------------------------- | ||
2418 | Fill some basic fields in the main device data structure. | ||
2419 | This function is called once on w9968cf_usb_probe() for each recognized | ||
2420 | camera. | ||
2421 | --------------------------------------------------------------------------*/ | ||
2422 | static void | ||
2423 | w9968cf_configure_camera(struct w9968cf_device* cam, | ||
2424 | struct usb_device* udev, | ||
2425 | enum w9968cf_model_id mod_id, | ||
2426 | const unsigned short dev_nr) | ||
2427 | { | ||
2428 | mutex_init(&cam->fileop_mutex); | ||
2429 | init_waitqueue_head(&cam->open); | ||
2430 | spin_lock_init(&cam->urb_lock); | ||
2431 | spin_lock_init(&cam->flist_lock); | ||
2432 | |||
2433 | cam->users = 0; | ||
2434 | cam->disconnected = 0; | ||
2435 | cam->id = mod_id; | ||
2436 | cam->sensor = CC_UNKNOWN; | ||
2437 | cam->sensor_initialized = 0; | ||
2438 | |||
2439 | /* Calculate the alternate setting number (from 1 to 16) | ||
2440 | according to the 'packet_size' module parameter */ | ||
2441 | if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE) | ||
2442 | packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE; | ||
2443 | for (cam->altsetting = 1; | ||
2444 | packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1]; | ||
2445 | cam->altsetting++); | ||
2446 | |||
2447 | cam->max_buffers = (max_buffers[dev_nr] < 2 || | ||
2448 | max_buffers[dev_nr] > W9968CF_MAX_BUFFERS) | ||
2449 | ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr]; | ||
2450 | |||
2451 | cam->double_buffer = (double_buffer[dev_nr] == 0 || | ||
2452 | double_buffer[dev_nr] == 1) | ||
2453 | ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER; | ||
2454 | |||
2455 | cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1) | ||
2456 | ? (u8)clamping[dev_nr] : W9968CF_CLAMPING; | ||
2457 | |||
2458 | cam->filter_type = (filter_type[dev_nr] == 0 || | ||
2459 | filter_type[dev_nr] == 1 || | ||
2460 | filter_type[dev_nr] == 2) | ||
2461 | ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE; | ||
2462 | |||
2463 | cam->capture = 1; | ||
2464 | |||
2465 | cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1) | ||
2466 | ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW; | ||
2467 | |||
2468 | cam->decompression = (decompression[dev_nr] == 0 || | ||
2469 | decompression[dev_nr] == 1 || | ||
2470 | decompression[dev_nr] == 2) | ||
2471 | ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION; | ||
2472 | |||
2473 | cam->upscaling = (upscaling[dev_nr] == 0 || | ||
2474 | upscaling[dev_nr] == 1) | ||
2475 | ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING; | ||
2476 | |||
2477 | cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1) | ||
2478 | ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT; | ||
2479 | |||
2480 | cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1) | ||
2481 | ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP; | ||
2482 | |||
2483 | cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60) | ||
2484 | ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ; | ||
2485 | |||
2486 | cam->bandfilt = (bandingfilter[dev_nr] == 0 || | ||
2487 | bandingfilter[dev_nr] == 1) | ||
2488 | ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER; | ||
2489 | |||
2490 | cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1) | ||
2491 | ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT; | ||
2492 | |||
2493 | cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0) | ||
2494 | ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV; | ||
2495 | |||
2496 | cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1) | ||
2497 | ? (u8)mirror[dev_nr] : W9968CF_MIRROR; | ||
2498 | |||
2499 | cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1) | ||
2500 | ? monochrome[dev_nr] : W9968CF_MONOCHROME; | ||
2501 | |||
2502 | cam->picture.brightness = (u16)brightness[dev_nr]; | ||
2503 | cam->picture.hue = (u16)hue[dev_nr]; | ||
2504 | cam->picture.colour = (u16)colour[dev_nr]; | ||
2505 | cam->picture.contrast = (u16)contrast[dev_nr]; | ||
2506 | cam->picture.whiteness = (u16)whiteness[dev_nr]; | ||
2507 | if (w9968cf_valid_palette((u16)force_palette[dev_nr])) { | ||
2508 | cam->picture.palette = (u16)force_palette[dev_nr]; | ||
2509 | cam->force_palette = 1; | ||
2510 | } else { | ||
2511 | cam->force_palette = 0; | ||
2512 | if (cam->decompression == 0) | ||
2513 | cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF; | ||
2514 | else if (cam->decompression == 1) | ||
2515 | cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE; | ||
2516 | else | ||
2517 | cam->picture.palette = W9968CF_PALETTE_DECOMP_ON; | ||
2518 | } | ||
2519 | cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); | ||
2520 | |||
2521 | cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1) | ||
2522 | ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB; | ||
2523 | |||
2524 | cam->window.x = 0; | ||
2525 | cam->window.y = 0; | ||
2526 | cam->window.width = W9968CF_WIDTH; | ||
2527 | cam->window.height = W9968CF_HEIGHT; | ||
2528 | cam->window.chromakey = 0; | ||
2529 | cam->window.clipcount = 0; | ||
2530 | cam->window.flags = 0; | ||
2531 | |||
2532 | DBG(3, "%s configured with settings #%u:", | ||
2533 | symbolic(camlist, cam->id), dev_nr) | ||
2534 | |||
2535 | DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes", | ||
2536 | wMaxPacketSize[cam->altsetting-1]) | ||
2537 | |||
2538 | DBG(3, "- Number of requested video frame buffers: %u", | ||
2539 | cam->max_buffers) | ||
2540 | |||
2541 | if (cam->double_buffer) | ||
2542 | DBG(3, "- Hardware double buffering enabled") | ||
2543 | else | ||
2544 | DBG(3, "- Hardware double buffering disabled") | ||
2545 | |||
2546 | if (cam->filter_type == 0) | ||
2547 | DBG(3, "- Video filtering disabled") | ||
2548 | else if (cam->filter_type == 1) | ||
2549 | DBG(3, "- Video filtering enabled: type 1-2-1") | ||
2550 | else if (cam->filter_type == 2) | ||
2551 | DBG(3, "- Video filtering enabled: type 2-3-6-3-2") | ||
2552 | |||
2553 | if (cam->clamping) | ||
2554 | DBG(3, "- Video data clamping (CCIR-601 format) enabled") | ||
2555 | else | ||
2556 | DBG(3, "- Video data clamping (CCIR-601 format) disabled") | ||
2557 | |||
2558 | if (cam->largeview) | ||
2559 | DBG(3, "- Large view enabled") | ||
2560 | else | ||
2561 | DBG(3, "- Large view disabled") | ||
2562 | |||
2563 | if ((cam->decompression) == 0 && (!cam->force_palette)) | ||
2564 | DBG(3, "- Decompression disabled") | ||
2565 | else if ((cam->decompression) == 1 && (!cam->force_palette)) | ||
2566 | DBG(3, "- Decompression forced") | ||
2567 | else if ((cam->decompression) == 2 && (!cam->force_palette)) | ||
2568 | DBG(3, "- Decompression allowed") | ||
2569 | |||
2570 | if (cam->upscaling) | ||
2571 | DBG(3, "- Software image scaling enabled") | ||
2572 | else | ||
2573 | DBG(3, "- Software image scaling disabled") | ||
2574 | |||
2575 | if (cam->force_palette) | ||
2576 | DBG(3, "- Image palette forced to %s", | ||
2577 | symbolic(v4l1_plist, cam->picture.palette)) | ||
2578 | |||
2579 | if (cam->force_rgb) | ||
2580 | DBG(3, "- RGB component ordering will be used instead of BGR") | ||
2581 | |||
2582 | if (cam->auto_brt) | ||
2583 | DBG(3, "- Auto brightness enabled") | ||
2584 | else | ||
2585 | DBG(3, "- Auto brightness disabled") | ||
2586 | |||
2587 | if (cam->auto_exp) | ||
2588 | DBG(3, "- Auto exposure enabled") | ||
2589 | else | ||
2590 | DBG(3, "- Auto exposure disabled") | ||
2591 | |||
2592 | if (cam->backlight) | ||
2593 | DBG(3, "- Backlight exposure algorithm enabled") | ||
2594 | else | ||
2595 | DBG(3, "- Backlight exposure algorithm disabled") | ||
2596 | |||
2597 | if (cam->mirror) | ||
2598 | DBG(3, "- Mirror enabled") | ||
2599 | else | ||
2600 | DBG(3, "- Mirror disabled") | ||
2601 | |||
2602 | if (cam->bandfilt) | ||
2603 | DBG(3, "- Banding filter enabled") | ||
2604 | else | ||
2605 | DBG(3, "- Banding filter disabled") | ||
2606 | |||
2607 | DBG(3, "- Power lighting frequency: %u", cam->lightfreq) | ||
2608 | |||
2609 | if (cam->clockdiv == -1) | ||
2610 | DBG(3, "- Automatic clock divisor enabled") | ||
2611 | else | ||
2612 | DBG(3, "- Clock divisor: %d", cam->clockdiv) | ||
2613 | |||
2614 | if (cam->monochrome) | ||
2615 | DBG(3, "- Image sensor used as monochrome") | ||
2616 | else | ||
2617 | DBG(3, "- Image sensor not used as monochrome") | ||
2618 | } | ||
2619 | |||
2620 | |||
2621 | /*-------------------------------------------------------------------------- | ||
2622 | If the video post-processing module is not loaded, some parameters | ||
2623 | must be overridden. | ||
2624 | --------------------------------------------------------------------------*/ | ||
2625 | static void w9968cf_adjust_configuration(struct w9968cf_device* cam) | ||
2626 | { | ||
2627 | if (!w9968cf_vpp) { | ||
2628 | if (cam->decompression == 1) { | ||
2629 | cam->decompression = 2; | ||
2630 | DBG(2, "Video post-processing module not found: " | ||
2631 | "'decompression' parameter forced to 2") | ||
2632 | } | ||
2633 | if (cam->upscaling) { | ||
2634 | cam->upscaling = 0; | ||
2635 | DBG(2, "Video post-processing module not found: " | ||
2636 | "'upscaling' parameter forced to 0") | ||
2637 | } | ||
2638 | if (cam->picture.palette != VIDEO_PALETTE_UYVY) { | ||
2639 | cam->force_palette = 0; | ||
2640 | DBG(2, "Video post-processing module not found: " | ||
2641 | "'force_palette' parameter forced to 0") | ||
2642 | } | ||
2643 | cam->picture.palette = VIDEO_PALETTE_UYVY; | ||
2644 | cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); | ||
2645 | } | ||
2646 | } | ||
2647 | |||
2648 | |||
2649 | /*-------------------------------------------------------------------------- | ||
2650 | Release the resources used by the driver. | ||
2651 | This function is called on disconnect | ||
2652 | (or on close if deallocation has been deferred) | ||
2653 | --------------------------------------------------------------------------*/ | ||
2654 | static void w9968cf_release_resources(struct w9968cf_device* cam) | ||
2655 | { | ||
2656 | mutex_lock(&w9968cf_devlist_mutex); | ||
2657 | |||
2658 | DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor) | ||
2659 | |||
2660 | video_unregister_device(cam->v4ldev); | ||
2661 | list_del(&cam->v4llist); | ||
2662 | i2c_del_adapter(&cam->i2c_adapter); | ||
2663 | w9968cf_deallocate_memory(cam); | ||
2664 | kfree(cam->control_buffer); | ||
2665 | kfree(cam->data_buffer); | ||
2666 | |||
2667 | mutex_unlock(&w9968cf_devlist_mutex); | ||
2668 | } | ||
2669 | |||
2670 | |||
2671 | |||
2672 | /**************************************************************************** | ||
2673 | * Video4Linux interface * | ||
2674 | ****************************************************************************/ | ||
2675 | |||
2676 | static int w9968cf_open(struct inode* inode, struct file* filp) | ||
2677 | { | ||
2678 | struct w9968cf_device* cam; | ||
2679 | int err; | ||
2680 | |||
2681 | /* This the only safe way to prevent race conditions with disconnect */ | ||
2682 | if (!down_read_trylock(&w9968cf_disconnect)) | ||
2683 | return -ERESTARTSYS; | ||
2684 | |||
2685 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
2686 | |||
2687 | mutex_lock(&cam->dev_mutex); | ||
2688 | |||
2689 | if (cam->sensor == CC_UNKNOWN) { | ||
2690 | DBG(2, "No supported image sensor has been detected by the " | ||
2691 | "'ovcamchip' module for the %s (/dev/video%d). Make " | ||
2692 | "sure it is loaded *before* (re)connecting the camera.", | ||
2693 | symbolic(camlist, cam->id), cam->v4ldev->minor) | ||
2694 | mutex_unlock(&cam->dev_mutex); | ||
2695 | up_read(&w9968cf_disconnect); | ||
2696 | return -ENODEV; | ||
2697 | } | ||
2698 | |||
2699 | if (cam->users) { | ||
2700 | DBG(2, "%s (/dev/video%d) has been already occupied by '%s'", | ||
2701 | symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command) | ||
2702 | if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { | ||
2703 | mutex_unlock(&cam->dev_mutex); | ||
2704 | up_read(&w9968cf_disconnect); | ||
2705 | return -EWOULDBLOCK; | ||
2706 | } | ||
2707 | mutex_unlock(&cam->dev_mutex); | ||
2708 | err = wait_event_interruptible_exclusive(cam->open, | ||
2709 | cam->disconnected || | ||
2710 | !cam->users); | ||
2711 | if (err) { | ||
2712 | up_read(&w9968cf_disconnect); | ||
2713 | return err; | ||
2714 | } | ||
2715 | if (cam->disconnected) { | ||
2716 | up_read(&w9968cf_disconnect); | ||
2717 | return -ENODEV; | ||
2718 | } | ||
2719 | mutex_lock(&cam->dev_mutex); | ||
2720 | } | ||
2721 | |||
2722 | DBG(5, "Opening '%s', /dev/video%d ...", | ||
2723 | symbolic(camlist, cam->id), cam->v4ldev->minor) | ||
2724 | |||
2725 | cam->streaming = 0; | ||
2726 | cam->misconfigured = 0; | ||
2727 | |||
2728 | w9968cf_adjust_configuration(cam); | ||
2729 | |||
2730 | if ((err = w9968cf_allocate_memory(cam))) | ||
2731 | goto deallocate_memory; | ||
2732 | |||
2733 | if ((err = w9968cf_init_chip(cam))) | ||
2734 | goto deallocate_memory; | ||
2735 | |||
2736 | if ((err = w9968cf_start_transfer(cam))) | ||
2737 | goto deallocate_memory; | ||
2738 | |||
2739 | filp->private_data = cam; | ||
2740 | |||
2741 | cam->users++; | ||
2742 | strcpy(cam->command, current->comm); | ||
2743 | |||
2744 | init_waitqueue_head(&cam->wait_queue); | ||
2745 | |||
2746 | DBG(5, "Video device is open") | ||
2747 | |||
2748 | mutex_unlock(&cam->dev_mutex); | ||
2749 | up_read(&w9968cf_disconnect); | ||
2750 | |||
2751 | return 0; | ||
2752 | |||
2753 | deallocate_memory: | ||
2754 | w9968cf_deallocate_memory(cam); | ||
2755 | DBG(2, "Failed to open the video device") | ||
2756 | mutex_unlock(&cam->dev_mutex); | ||
2757 | up_read(&w9968cf_disconnect); | ||
2758 | return err; | ||
2759 | } | ||
2760 | |||
2761 | |||
2762 | static int w9968cf_release(struct inode* inode, struct file* filp) | ||
2763 | { | ||
2764 | struct w9968cf_device* cam; | ||
2765 | |||
2766 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
2767 | |||
2768 | mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ | ||
2769 | |||
2770 | w9968cf_stop_transfer(cam); | ||
2771 | |||
2772 | if (cam->disconnected) { | ||
2773 | w9968cf_release_resources(cam); | ||
2774 | mutex_unlock(&cam->dev_mutex); | ||
2775 | kfree(cam); | ||
2776 | return 0; | ||
2777 | } | ||
2778 | |||
2779 | cam->users--; | ||
2780 | w9968cf_deallocate_memory(cam); | ||
2781 | wake_up_interruptible_nr(&cam->open, 1); | ||
2782 | |||
2783 | DBG(5, "Video device closed") | ||
2784 | mutex_unlock(&cam->dev_mutex); | ||
2785 | return 0; | ||
2786 | } | ||
2787 | |||
2788 | |||
2789 | static ssize_t | ||
2790 | w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | ||
2791 | { | ||
2792 | struct w9968cf_device* cam; | ||
2793 | struct w9968cf_frame_t* fr; | ||
2794 | int err = 0; | ||
2795 | |||
2796 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
2797 | |||
2798 | if (filp->f_flags & O_NONBLOCK) | ||
2799 | return -EWOULDBLOCK; | ||
2800 | |||
2801 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
2802 | return -ERESTARTSYS; | ||
2803 | |||
2804 | if (cam->disconnected) { | ||
2805 | DBG(2, "Device not present") | ||
2806 | mutex_unlock(&cam->fileop_mutex); | ||
2807 | return -ENODEV; | ||
2808 | } | ||
2809 | |||
2810 | if (cam->misconfigured) { | ||
2811 | DBG(2, "The camera is misconfigured. Close and open it again.") | ||
2812 | mutex_unlock(&cam->fileop_mutex); | ||
2813 | return -EIO; | ||
2814 | } | ||
2815 | |||
2816 | if (!cam->frame[0].queued) | ||
2817 | w9968cf_push_frame(cam, 0); | ||
2818 | |||
2819 | if (!cam->frame[1].queued) | ||
2820 | w9968cf_push_frame(cam, 1); | ||
2821 | |||
2822 | err = wait_event_interruptible(cam->wait_queue, | ||
2823 | cam->frame[0].status == F_READY || | ||
2824 | cam->frame[1].status == F_READY || | ||
2825 | cam->disconnected); | ||
2826 | if (err) { | ||
2827 | mutex_unlock(&cam->fileop_mutex); | ||
2828 | return err; | ||
2829 | } | ||
2830 | if (cam->disconnected) { | ||
2831 | mutex_unlock(&cam->fileop_mutex); | ||
2832 | return -ENODEV; | ||
2833 | } | ||
2834 | |||
2835 | fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1]; | ||
2836 | |||
2837 | if (w9968cf_vpp) | ||
2838 | w9968cf_postprocess_frame(cam, fr); | ||
2839 | |||
2840 | if (count > fr->length) | ||
2841 | count = fr->length; | ||
2842 | |||
2843 | if (copy_to_user(buf, fr->buffer, count)) { | ||
2844 | fr->status = F_UNUSED; | ||
2845 | mutex_unlock(&cam->fileop_mutex); | ||
2846 | return -EFAULT; | ||
2847 | } | ||
2848 | *f_pos += count; | ||
2849 | |||
2850 | fr->status = F_UNUSED; | ||
2851 | |||
2852 | DBG(5, "%zu bytes read", count) | ||
2853 | |||
2854 | mutex_unlock(&cam->fileop_mutex); | ||
2855 | return count; | ||
2856 | } | ||
2857 | |||
2858 | |||
2859 | static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma) | ||
2860 | { | ||
2861 | struct w9968cf_device* cam = (struct w9968cf_device*) | ||
2862 | video_get_drvdata(video_devdata(filp)); | ||
2863 | unsigned long vsize = vma->vm_end - vma->vm_start, | ||
2864 | psize = cam->nbuffers * cam->frame[0].size, | ||
2865 | start = vma->vm_start, | ||
2866 | pos = (unsigned long)cam->frame[0].buffer, | ||
2867 | page; | ||
2868 | |||
2869 | if (cam->disconnected) { | ||
2870 | DBG(2, "Device not present") | ||
2871 | return -ENODEV; | ||
2872 | } | ||
2873 | |||
2874 | if (cam->misconfigured) { | ||
2875 | DBG(2, "The camera is misconfigured. Close and open it again") | ||
2876 | return -EIO; | ||
2877 | } | ||
2878 | |||
2879 | PDBGG("mmapping %lu bytes...", vsize) | ||
2880 | |||
2881 | if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT)) | ||
2882 | return -EINVAL; | ||
2883 | |||
2884 | while (vsize > 0) { | ||
2885 | page = vmalloc_to_pfn((void *)pos); | ||
2886 | if (remap_pfn_range(vma, start, page + vma->vm_pgoff, | ||
2887 | PAGE_SIZE, vma->vm_page_prot)) | ||
2888 | return -EAGAIN; | ||
2889 | start += PAGE_SIZE; | ||
2890 | pos += PAGE_SIZE; | ||
2891 | vsize -= PAGE_SIZE; | ||
2892 | } | ||
2893 | |||
2894 | DBG(5, "mmap method successfully called") | ||
2895 | return 0; | ||
2896 | } | ||
2897 | |||
2898 | |||
2899 | static int | ||
2900 | w9968cf_ioctl(struct inode* inode, struct file* filp, | ||
2901 | unsigned int cmd, unsigned long arg) | ||
2902 | { | ||
2903 | struct w9968cf_device* cam; | ||
2904 | int err; | ||
2905 | |||
2906 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
2907 | |||
2908 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
2909 | return -ERESTARTSYS; | ||
2910 | |||
2911 | if (cam->disconnected) { | ||
2912 | DBG(2, "Device not present") | ||
2913 | mutex_unlock(&cam->fileop_mutex); | ||
2914 | return -ENODEV; | ||
2915 | } | ||
2916 | |||
2917 | if (cam->misconfigured) { | ||
2918 | DBG(2, "The camera is misconfigured. Close and open it again.") | ||
2919 | mutex_unlock(&cam->fileop_mutex); | ||
2920 | return -EIO; | ||
2921 | } | ||
2922 | |||
2923 | err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg); | ||
2924 | |||
2925 | mutex_unlock(&cam->fileop_mutex); | ||
2926 | return err; | ||
2927 | } | ||
2928 | |||
2929 | |||
2930 | static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp, | ||
2931 | unsigned int cmd, void __user * arg) | ||
2932 | { | ||
2933 | struct w9968cf_device* cam; | ||
2934 | const char* v4l1_ioctls[] = { | ||
2935 | "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", | ||
2936 | "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF", | ||
2937 | "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO", | ||
2938 | "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE", | ||
2939 | "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE", | ||
2940 | "GVBIFMT", "SVBIFMT" | ||
2941 | }; | ||
2942 | |||
2943 | #define V4L1_IOCTL(cmd) \ | ||
2944 | ((_IOC_NR((cmd)) < ARRAY_SIZE(v4l1_ioctls)) ? \ | ||
2945 | v4l1_ioctls[_IOC_NR((cmd))] : "?") | ||
2946 | |||
2947 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | ||
2948 | |||
2949 | switch (cmd) { | ||
2950 | |||
2951 | case VIDIOCGCAP: /* get video capability */ | ||
2952 | { | ||
2953 | struct video_capability cap = { | ||
2954 | .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES, | ||
2955 | .channels = 1, | ||
2956 | .audios = 0, | ||
2957 | .minwidth = cam->minwidth, | ||
2958 | .minheight = cam->minheight, | ||
2959 | }; | ||
2960 | sprintf(cap.name, "W996[87]CF USB Camera #%d", | ||
2961 | cam->v4ldev->minor); | ||
2962 | cap.maxwidth = (cam->upscaling && w9968cf_vpp) | ||
2963 | ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) | ||
2964 | : cam->maxwidth; | ||
2965 | cap.maxheight = (cam->upscaling && w9968cf_vpp) | ||
2966 | ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) | ||
2967 | : cam->maxheight; | ||
2968 | |||
2969 | if (copy_to_user(arg, &cap, sizeof(cap))) | ||
2970 | return -EFAULT; | ||
2971 | |||
2972 | DBG(5, "VIDIOCGCAP successfully called") | ||
2973 | return 0; | ||
2974 | } | ||
2975 | |||
2976 | case VIDIOCGCHAN: /* get video channel informations */ | ||
2977 | { | ||
2978 | struct video_channel chan; | ||
2979 | if (copy_from_user(&chan, arg, sizeof(chan))) | ||
2980 | return -EFAULT; | ||
2981 | |||
2982 | if (chan.channel != 0) | ||
2983 | return -EINVAL; | ||
2984 | |||
2985 | strcpy(chan.name, "Camera"); | ||
2986 | chan.tuners = 0; | ||
2987 | chan.flags = 0; | ||
2988 | chan.type = VIDEO_TYPE_CAMERA; | ||
2989 | chan.norm = VIDEO_MODE_AUTO; | ||
2990 | |||
2991 | if (copy_to_user(arg, &chan, sizeof(chan))) | ||
2992 | return -EFAULT; | ||
2993 | |||
2994 | DBG(5, "VIDIOCGCHAN successfully called") | ||
2995 | return 0; | ||
2996 | } | ||
2997 | |||
2998 | case VIDIOCSCHAN: /* set active channel */ | ||
2999 | { | ||
3000 | struct video_channel chan; | ||
3001 | |||
3002 | if (copy_from_user(&chan, arg, sizeof(chan))) | ||
3003 | return -EFAULT; | ||
3004 | |||
3005 | if (chan.channel != 0) | ||
3006 | return -EINVAL; | ||
3007 | |||
3008 | DBG(5, "VIDIOCSCHAN successfully called") | ||
3009 | return 0; | ||
3010 | } | ||
3011 | |||
3012 | case VIDIOCGPICT: /* get image properties of the picture */ | ||
3013 | { | ||
3014 | if (w9968cf_sensor_get_picture(cam)) | ||
3015 | return -EIO; | ||
3016 | |||
3017 | if (copy_to_user(arg, &cam->picture, sizeof(cam->picture))) | ||
3018 | return -EFAULT; | ||
3019 | |||
3020 | DBG(5, "VIDIOCGPICT successfully called") | ||
3021 | return 0; | ||
3022 | } | ||
3023 | |||
3024 | case VIDIOCSPICT: /* change picture settings */ | ||
3025 | { | ||
3026 | struct video_picture pict; | ||
3027 | int err = 0; | ||
3028 | |||
3029 | if (copy_from_user(&pict, arg, sizeof(pict))) | ||
3030 | return -EFAULT; | ||
3031 | |||
3032 | if ( (cam->force_palette || !w9968cf_vpp) | ||
3033 | && pict.palette != cam->picture.palette ) { | ||
3034 | DBG(4, "Palette %s rejected: only %s is allowed", | ||
3035 | symbolic(v4l1_plist, pict.palette), | ||
3036 | symbolic(v4l1_plist, cam->picture.palette)) | ||
3037 | return -EINVAL; | ||
3038 | } | ||
3039 | |||
3040 | if (!w9968cf_valid_palette(pict.palette)) { | ||
3041 | DBG(4, "Palette %s not supported. VIDIOCSPICT failed", | ||
3042 | symbolic(v4l1_plist, pict.palette)) | ||
3043 | return -EINVAL; | ||
3044 | } | ||
3045 | |||
3046 | if (!cam->force_palette) { | ||
3047 | if (cam->decompression == 0) { | ||
3048 | if (w9968cf_need_decompression(pict.palette)) { | ||
3049 | DBG(4, "Decompression disabled: palette %s is not " | ||
3050 | "allowed. VIDIOCSPICT failed", | ||
3051 | symbolic(v4l1_plist, pict.palette)) | ||
3052 | return -EINVAL; | ||
3053 | } | ||
3054 | } else if (cam->decompression == 1) { | ||
3055 | if (!w9968cf_need_decompression(pict.palette)) { | ||
3056 | DBG(4, "Decompression forced: palette %s is not " | ||
3057 | "allowed. VIDIOCSPICT failed", | ||
3058 | symbolic(v4l1_plist, pict.palette)) | ||
3059 | return -EINVAL; | ||
3060 | } | ||
3061 | } | ||
3062 | } | ||
3063 | |||
3064 | if (pict.depth != w9968cf_valid_depth(pict.palette)) { | ||
3065 | DBG(4, "Requested depth %u bpp is not valid for %s " | ||
3066 | "palette: ignored and changed to %u bpp", | ||
3067 | pict.depth, symbolic(v4l1_plist, pict.palette), | ||
3068 | w9968cf_valid_depth(pict.palette)) | ||
3069 | pict.depth = w9968cf_valid_depth(pict.palette); | ||
3070 | } | ||
3071 | |||
3072 | if (pict.palette != cam->picture.palette) { | ||
3073 | if(*cam->requested_frame | ||
3074 | || cam->frame_current->queued) { | ||
3075 | err = wait_event_interruptible | ||
3076 | ( cam->wait_queue, | ||
3077 | cam->disconnected || | ||
3078 | (!*cam->requested_frame && | ||
3079 | !cam->frame_current->queued) ); | ||
3080 | if (err) | ||
3081 | return err; | ||
3082 | if (cam->disconnected) | ||
3083 | return -ENODEV; | ||
3084 | } | ||
3085 | |||
3086 | if (w9968cf_stop_transfer(cam)) | ||
3087 | goto ioctl_fail; | ||
3088 | |||
3089 | if (w9968cf_set_picture(cam, pict)) | ||
3090 | goto ioctl_fail; | ||
3091 | |||
3092 | if (w9968cf_start_transfer(cam)) | ||
3093 | goto ioctl_fail; | ||
3094 | |||
3095 | } else if (w9968cf_sensor_update_picture(cam, pict)) | ||
3096 | return -EIO; | ||
3097 | |||
3098 | |||
3099 | DBG(5, "VIDIOCSPICT successfully called") | ||
3100 | return 0; | ||
3101 | } | ||
3102 | |||
3103 | case VIDIOCSWIN: /* set capture area */ | ||
3104 | { | ||
3105 | struct video_window win; | ||
3106 | int err = 0; | ||
3107 | |||
3108 | if (copy_from_user(&win, arg, sizeof(win))) | ||
3109 | return -EFAULT; | ||
3110 | |||
3111 | DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, " | ||
3112 | "x=%u, y=%u, %ux%u", win.clipcount, win.flags, | ||
3113 | win.x, win.y, win.width, win.height) | ||
3114 | |||
3115 | if (win.clipcount != 0 || win.flags != 0) | ||
3116 | return -EINVAL; | ||
3117 | |||
3118 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, | ||
3119 | (u16*)&win.height))) { | ||
3120 | DBG(4, "Resolution not supported (%ux%u). " | ||
3121 | "VIDIOCSWIN failed", win.width, win.height) | ||
3122 | return err; | ||
3123 | } | ||
3124 | |||
3125 | if (win.x != cam->window.x || | ||
3126 | win.y != cam->window.y || | ||
3127 | win.width != cam->window.width || | ||
3128 | win.height != cam->window.height) { | ||
3129 | if(*cam->requested_frame | ||
3130 | || cam->frame_current->queued) { | ||
3131 | err = wait_event_interruptible | ||
3132 | ( cam->wait_queue, | ||
3133 | cam->disconnected || | ||
3134 | (!*cam->requested_frame && | ||
3135 | !cam->frame_current->queued) ); | ||
3136 | if (err) | ||
3137 | return err; | ||
3138 | if (cam->disconnected) | ||
3139 | return -ENODEV; | ||
3140 | } | ||
3141 | |||
3142 | if (w9968cf_stop_transfer(cam)) | ||
3143 | goto ioctl_fail; | ||
3144 | |||
3145 | /* This _must_ be called before set_window() */ | ||
3146 | if (w9968cf_set_picture(cam, cam->picture)) | ||
3147 | goto ioctl_fail; | ||
3148 | |||
3149 | if (w9968cf_set_window(cam, win)) | ||
3150 | goto ioctl_fail; | ||
3151 | |||
3152 | if (w9968cf_start_transfer(cam)) | ||
3153 | goto ioctl_fail; | ||
3154 | } | ||
3155 | |||
3156 | DBG(5, "VIDIOCSWIN successfully called. ") | ||
3157 | return 0; | ||
3158 | } | ||
3159 | |||
3160 | case VIDIOCGWIN: /* get current window properties */ | ||
3161 | { | ||
3162 | if (copy_to_user(arg,&cam->window,sizeof(struct video_window))) | ||
3163 | return -EFAULT; | ||
3164 | |||
3165 | DBG(5, "VIDIOCGWIN successfully called") | ||
3166 | return 0; | ||
3167 | } | ||
3168 | |||
3169 | case VIDIOCGMBUF: /* request for memory (mapped) buffer */ | ||
3170 | { | ||
3171 | struct video_mbuf mbuf; | ||
3172 | u8 i; | ||
3173 | |||
3174 | mbuf.size = cam->nbuffers * cam->frame[0].size; | ||
3175 | mbuf.frames = cam->nbuffers; | ||
3176 | for (i = 0; i < cam->nbuffers; i++) | ||
3177 | mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer - | ||
3178 | (unsigned long)cam->frame[0].buffer; | ||
3179 | |||
3180 | if (copy_to_user(arg, &mbuf, sizeof(mbuf))) | ||
3181 | return -EFAULT; | ||
3182 | |||
3183 | DBG(5, "VIDIOCGMBUF successfully called") | ||
3184 | return 0; | ||
3185 | } | ||
3186 | |||
3187 | case VIDIOCMCAPTURE: /* start the capture to a frame */ | ||
3188 | { | ||
3189 | struct video_mmap mmap; | ||
3190 | struct w9968cf_frame_t* fr; | ||
3191 | int err = 0; | ||
3192 | |||
3193 | if (copy_from_user(&mmap, arg, sizeof(mmap))) | ||
3194 | return -EFAULT; | ||
3195 | |||
3196 | DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d", | ||
3197 | mmap.frame, symbolic(v4l1_plist, mmap.format), | ||
3198 | mmap.width, mmap.height) | ||
3199 | |||
3200 | if (mmap.frame >= cam->nbuffers) { | ||
3201 | DBG(4, "Invalid frame number (%u). " | ||
3202 | "VIDIOCMCAPTURE failed", mmap.frame) | ||
3203 | return -EINVAL; | ||
3204 | } | ||
3205 | |||
3206 | if (mmap.format!=cam->picture.palette && | ||
3207 | (cam->force_palette || !w9968cf_vpp)) { | ||
3208 | DBG(4, "Palette %s rejected: only %s is allowed", | ||
3209 | symbolic(v4l1_plist, mmap.format), | ||
3210 | symbolic(v4l1_plist, cam->picture.palette)) | ||
3211 | return -EINVAL; | ||
3212 | } | ||
3213 | |||
3214 | if (!w9968cf_valid_palette(mmap.format)) { | ||
3215 | DBG(4, "Palette %s not supported. " | ||
3216 | "VIDIOCMCAPTURE failed", | ||
3217 | symbolic(v4l1_plist, mmap.format)) | ||
3218 | return -EINVAL; | ||
3219 | } | ||
3220 | |||
3221 | if (!cam->force_palette) { | ||
3222 | if (cam->decompression == 0) { | ||
3223 | if (w9968cf_need_decompression(mmap.format)) { | ||
3224 | DBG(4, "Decompression disabled: palette %s is not " | ||
3225 | "allowed. VIDIOCSPICT failed", | ||
3226 | symbolic(v4l1_plist, mmap.format)) | ||
3227 | return -EINVAL; | ||
3228 | } | ||
3229 | } else if (cam->decompression == 1) { | ||
3230 | if (!w9968cf_need_decompression(mmap.format)) { | ||
3231 | DBG(4, "Decompression forced: palette %s is not " | ||
3232 | "allowed. VIDIOCSPICT failed", | ||
3233 | symbolic(v4l1_plist, mmap.format)) | ||
3234 | return -EINVAL; | ||
3235 | } | ||
3236 | } | ||
3237 | } | ||
3238 | |||
3239 | if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width, | ||
3240 | (u16*)&mmap.height))) { | ||
3241 | DBG(4, "Resolution not supported (%dx%d). " | ||
3242 | "VIDIOCMCAPTURE failed", | ||
3243 | mmap.width, mmap.height) | ||
3244 | return err; | ||
3245 | } | ||
3246 | |||
3247 | fr = &cam->frame[mmap.frame]; | ||
3248 | |||
3249 | if (mmap.width != cam->window.width || | ||
3250 | mmap.height != cam->window.height || | ||
3251 | mmap.format != cam->picture.palette) { | ||
3252 | |||
3253 | struct video_window win; | ||
3254 | struct video_picture pict; | ||
3255 | |||
3256 | if(*cam->requested_frame | ||
3257 | || cam->frame_current->queued) { | ||
3258 | DBG(6, "VIDIOCMCAPTURE. Change settings for " | ||
3259 | "frame #%u: %dx%d, format %s. Wait...", | ||
3260 | mmap.frame, mmap.width, mmap.height, | ||
3261 | symbolic(v4l1_plist, mmap.format)) | ||
3262 | err = wait_event_interruptible | ||
3263 | ( cam->wait_queue, | ||
3264 | cam->disconnected || | ||
3265 | (!*cam->requested_frame && | ||
3266 | !cam->frame_current->queued) ); | ||
3267 | if (err) | ||
3268 | return err; | ||
3269 | if (cam->disconnected) | ||
3270 | return -ENODEV; | ||
3271 | } | ||
3272 | |||
3273 | memcpy(&win, &cam->window, sizeof(win)); | ||
3274 | memcpy(&pict, &cam->picture, sizeof(pict)); | ||
3275 | win.width = mmap.width; | ||
3276 | win.height = mmap.height; | ||
3277 | pict.palette = mmap.format; | ||
3278 | |||
3279 | if (w9968cf_stop_transfer(cam)) | ||
3280 | goto ioctl_fail; | ||
3281 | |||
3282 | /* This before set_window */ | ||
3283 | if (w9968cf_set_picture(cam, pict)) | ||
3284 | goto ioctl_fail; | ||
3285 | |||
3286 | if (w9968cf_set_window(cam, win)) | ||
3287 | goto ioctl_fail; | ||
3288 | |||
3289 | if (w9968cf_start_transfer(cam)) | ||
3290 | goto ioctl_fail; | ||
3291 | |||
3292 | } else if (fr->queued) { | ||
3293 | |||
3294 | DBG(6, "Wait until frame #%u is free", mmap.frame) | ||
3295 | |||
3296 | err = wait_event_interruptible(cam->wait_queue, | ||
3297 | cam->disconnected || | ||
3298 | (!fr->queued)); | ||
3299 | if (err) | ||
3300 | return err; | ||
3301 | if (cam->disconnected) | ||
3302 | return -ENODEV; | ||
3303 | } | ||
3304 | |||
3305 | w9968cf_push_frame(cam, mmap.frame); | ||
3306 | DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame) | ||
3307 | return 0; | ||
3308 | } | ||
3309 | |||
3310 | case VIDIOCSYNC: /* wait until the capture of a frame is finished */ | ||
3311 | { | ||
3312 | unsigned int f_num; | ||
3313 | struct w9968cf_frame_t* fr; | ||
3314 | int err = 0; | ||
3315 | |||
3316 | if (copy_from_user(&f_num, arg, sizeof(f_num))) | ||
3317 | return -EFAULT; | ||
3318 | |||
3319 | if (f_num >= cam->nbuffers) { | ||
3320 | DBG(4, "Invalid frame number (%u). " | ||
3321 | "VIDIOCMCAPTURE failed", f_num) | ||
3322 | return -EINVAL; | ||
3323 | } | ||
3324 | |||
3325 | DBG(6, "VIDIOCSYNC called for frame #%u", f_num) | ||
3326 | |||
3327 | fr = &cam->frame[f_num]; | ||
3328 | |||
3329 | switch (fr->status) { | ||
3330 | case F_UNUSED: | ||
3331 | if (!fr->queued) { | ||
3332 | DBG(4, "VIDIOSYNC: Frame #%u not requested!", | ||
3333 | f_num) | ||
3334 | return -EFAULT; | ||
3335 | } | ||
3336 | case F_ERROR: | ||
3337 | case F_GRABBING: | ||
3338 | err = wait_event_interruptible(cam->wait_queue, | ||
3339 | (fr->status == F_READY) | ||
3340 | || cam->disconnected); | ||
3341 | if (err) | ||
3342 | return err; | ||
3343 | if (cam->disconnected) | ||
3344 | return -ENODEV; | ||
3345 | break; | ||
3346 | case F_READY: | ||
3347 | break; | ||
3348 | } | ||
3349 | |||
3350 | if (w9968cf_vpp) | ||
3351 | w9968cf_postprocess_frame(cam, fr); | ||
3352 | |||
3353 | fr->status = F_UNUSED; | ||
3354 | |||
3355 | DBG(5, "VIDIOCSYNC(%u) successfully called", f_num) | ||
3356 | return 0; | ||
3357 | } | ||
3358 | |||
3359 | case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/ | ||
3360 | { | ||
3361 | struct video_unit unit = { | ||
3362 | .video = cam->v4ldev->minor, | ||
3363 | .vbi = VIDEO_NO_UNIT, | ||
3364 | .radio = VIDEO_NO_UNIT, | ||
3365 | .audio = VIDEO_NO_UNIT, | ||
3366 | .teletext = VIDEO_NO_UNIT, | ||
3367 | }; | ||
3368 | |||
3369 | if (copy_to_user(arg, &unit, sizeof(unit))) | ||
3370 | return -EFAULT; | ||
3371 | |||
3372 | DBG(5, "VIDIOCGUNIT successfully called") | ||
3373 | return 0; | ||
3374 | } | ||
3375 | |||
3376 | case VIDIOCKEY: | ||
3377 | return 0; | ||
3378 | |||
3379 | case VIDIOCGFBUF: | ||
3380 | { | ||
3381 | if (clear_user(arg, sizeof(struct video_buffer))) | ||
3382 | return -EFAULT; | ||
3383 | |||
3384 | DBG(5, "VIDIOCGFBUF successfully called") | ||
3385 | return 0; | ||
3386 | } | ||
3387 | |||
3388 | case VIDIOCGTUNER: | ||
3389 | { | ||
3390 | struct video_tuner tuner; | ||
3391 | if (copy_from_user(&tuner, arg, sizeof(tuner))) | ||
3392 | return -EFAULT; | ||
3393 | |||
3394 | if (tuner.tuner != 0) | ||
3395 | return -EINVAL; | ||
3396 | |||
3397 | strcpy(tuner.name, "no_tuner"); | ||
3398 | tuner.rangelow = 0; | ||
3399 | tuner.rangehigh = 0; | ||
3400 | tuner.flags = VIDEO_TUNER_NORM; | ||
3401 | tuner.mode = VIDEO_MODE_AUTO; | ||
3402 | tuner.signal = 0xffff; | ||
3403 | |||
3404 | if (copy_to_user(arg, &tuner, sizeof(tuner))) | ||
3405 | return -EFAULT; | ||
3406 | |||
3407 | DBG(5, "VIDIOCGTUNER successfully called") | ||
3408 | return 0; | ||
3409 | } | ||
3410 | |||
3411 | case VIDIOCSTUNER: | ||
3412 | { | ||
3413 | struct video_tuner tuner; | ||
3414 | if (copy_from_user(&tuner, arg, sizeof(tuner))) | ||
3415 | return -EFAULT; | ||
3416 | |||
3417 | if (tuner.tuner != 0) | ||
3418 | return -EINVAL; | ||
3419 | |||
3420 | if (tuner.mode != VIDEO_MODE_AUTO) | ||
3421 | return -EINVAL; | ||
3422 | |||
3423 | DBG(5, "VIDIOCSTUNER successfully called") | ||
3424 | return 0; | ||
3425 | } | ||
3426 | |||
3427 | case VIDIOCSFBUF: | ||
3428 | case VIDIOCCAPTURE: | ||
3429 | case VIDIOCGFREQ: | ||
3430 | case VIDIOCSFREQ: | ||
3431 | case VIDIOCGAUDIO: | ||
3432 | case VIDIOCSAUDIO: | ||
3433 | case VIDIOCSPLAYMODE: | ||
3434 | case VIDIOCSWRITEMODE: | ||
3435 | case VIDIOCGPLAYINFO: | ||
3436 | case VIDIOCSMICROCODE: | ||
3437 | case VIDIOCGVBIFMT: | ||
3438 | case VIDIOCSVBIFMT: | ||
3439 | DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s " | ||
3440 | "(type 0x%01X, " | ||
3441 | "n. 0x%01X, " | ||
3442 | "dir. 0x%01X, " | ||
3443 | "size 0x%02X)", | ||
3444 | V4L1_IOCTL(cmd), | ||
3445 | _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd)) | ||
3446 | |||
3447 | return -EINVAL; | ||
3448 | |||
3449 | default: | ||
3450 | DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s " | ||
3451 | "type 0x%01X, " | ||
3452 | "n. 0x%01X, " | ||
3453 | "dir. 0x%01X, " | ||
3454 | "size 0x%02X", | ||
3455 | V4L1_IOCTL(cmd), | ||
3456 | _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd)) | ||
3457 | |||
3458 | return -ENOIOCTLCMD; | ||
3459 | |||
3460 | } /* end of switch */ | ||
3461 | |||
3462 | ioctl_fail: | ||
3463 | cam->misconfigured = 1; | ||
3464 | DBG(1, "VIDIOC%s failed because of hardware problems. " | ||
3465 | "To use the camera, close and open it again.", V4L1_IOCTL(cmd)) | ||
3466 | return -EFAULT; | ||
3467 | } | ||
3468 | |||
3469 | |||
3470 | static struct file_operations w9968cf_fops = { | ||
3471 | .owner = THIS_MODULE, | ||
3472 | .open = w9968cf_open, | ||
3473 | .release = w9968cf_release, | ||
3474 | .read = w9968cf_read, | ||
3475 | .ioctl = w9968cf_ioctl, | ||
3476 | .compat_ioctl = v4l_compat_ioctl32, | ||
3477 | .mmap = w9968cf_mmap, | ||
3478 | .llseek = no_llseek, | ||
3479 | }; | ||
3480 | |||
3481 | |||
3482 | |||
3483 | /**************************************************************************** | ||
3484 | * USB probe and V4L registration, disconnect and id_table[] definition * | ||
3485 | ****************************************************************************/ | ||
3486 | |||
3487 | static int | ||
3488 | w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | ||
3489 | { | ||
3490 | struct usb_device *udev = interface_to_usbdev(intf); | ||
3491 | struct w9968cf_device* cam; | ||
3492 | int err = 0; | ||
3493 | enum w9968cf_model_id mod_id; | ||
3494 | struct list_head* ptr; | ||
3495 | u8 sc = 0; /* number of simultaneous cameras */ | ||
3496 | static unsigned short dev_nr = 0; /* we are handling device number n */ | ||
3497 | |||
3498 | if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[0].idVendor && | ||
3499 | le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct) | ||
3500 | mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */ | ||
3501 | else if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[1].idVendor && | ||
3502 | le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[1].idProduct) | ||
3503 | mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */ | ||
3504 | else | ||
3505 | return -ENODEV; | ||
3506 | |||
3507 | cam = (struct w9968cf_device*) | ||
3508 | kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL); | ||
3509 | if (!cam) | ||
3510 | return -ENOMEM; | ||
3511 | |||
3512 | mutex_init(&cam->dev_mutex); | ||
3513 | mutex_lock(&cam->dev_mutex); | ||
3514 | |||
3515 | cam->usbdev = udev; | ||
3516 | /* NOTE: a local copy is used to avoid possible race conditions */ | ||
3517 | memcpy(&cam->dev, &udev->dev, sizeof(struct device)); | ||
3518 | |||
3519 | DBG(2, "%s detected", symbolic(camlist, mod_id)) | ||
3520 | |||
3521 | if (simcams > W9968CF_MAX_DEVICES) | ||
3522 | simcams = W9968CF_SIMCAMS; | ||
3523 | |||
3524 | /* How many cameras are connected ? */ | ||
3525 | mutex_lock(&w9968cf_devlist_mutex); | ||
3526 | list_for_each(ptr, &w9968cf_dev_list) | ||
3527 | sc++; | ||
3528 | mutex_unlock(&w9968cf_devlist_mutex); | ||
3529 | |||
3530 | if (sc >= simcams) { | ||
3531 | DBG(2, "Device rejected: too many connected cameras " | ||
3532 | "(max. %u)", simcams) | ||
3533 | err = -EPERM; | ||
3534 | goto fail; | ||
3535 | } | ||
3536 | |||
3537 | |||
3538 | /* Allocate 2 bytes of memory for camera control USB transfers */ | ||
3539 | if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) { | ||
3540 | DBG(1,"Couldn't allocate memory for camera control transfers") | ||
3541 | err = -ENOMEM; | ||
3542 | goto fail; | ||
3543 | } | ||
3544 | |||
3545 | /* Allocate 8 bytes of memory for USB data transfers to the FSB */ | ||
3546 | if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) { | ||
3547 | DBG(1, "Couldn't allocate memory for data " | ||
3548 | "transfers to the FSB") | ||
3549 | err = -ENOMEM; | ||
3550 | goto fail; | ||
3551 | } | ||
3552 | |||
3553 | /* Register the V4L device */ | ||
3554 | cam->v4ldev = video_device_alloc(); | ||
3555 | if (!cam->v4ldev) { | ||
3556 | DBG(1, "Could not allocate memory for a V4L structure") | ||
3557 | err = -ENOMEM; | ||
3558 | goto fail; | ||
3559 | } | ||
3560 | |||
3561 | strcpy(cam->v4ldev->name, symbolic(camlist, mod_id)); | ||
3562 | cam->v4ldev->owner = THIS_MODULE; | ||
3563 | cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; | ||
3564 | cam->v4ldev->hardware = VID_HARDWARE_W9968CF; | ||
3565 | cam->v4ldev->fops = &w9968cf_fops; | ||
3566 | cam->v4ldev->minor = video_nr[dev_nr]; | ||
3567 | cam->v4ldev->release = video_device_release; | ||
3568 | video_set_drvdata(cam->v4ldev, cam); | ||
3569 | cam->v4ldev->dev = &cam->dev; | ||
3570 | |||
3571 | err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, | ||
3572 | video_nr[dev_nr]); | ||
3573 | if (err) { | ||
3574 | DBG(1, "V4L device registration failed") | ||
3575 | if (err == -ENFILE && video_nr[dev_nr] == -1) | ||
3576 | DBG(2, "Couldn't find a free /dev/videoX node") | ||
3577 | video_nr[dev_nr] = -1; | ||
3578 | dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
3579 | goto fail; | ||
3580 | } | ||
3581 | |||
3582 | DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->minor) | ||
3583 | |||
3584 | /* Set some basic constants */ | ||
3585 | w9968cf_configure_camera(cam, udev, mod_id, dev_nr); | ||
3586 | |||
3587 | /* Add a new entry into the list of V4L registered devices */ | ||
3588 | mutex_lock(&w9968cf_devlist_mutex); | ||
3589 | list_add(&cam->v4llist, &w9968cf_dev_list); | ||
3590 | mutex_unlock(&w9968cf_devlist_mutex); | ||
3591 | dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
3592 | |||
3593 | w9968cf_turn_on_led(cam); | ||
3594 | |||
3595 | w9968cf_i2c_init(cam); | ||
3596 | |||
3597 | usb_set_intfdata(intf, cam); | ||
3598 | mutex_unlock(&cam->dev_mutex); | ||
3599 | return 0; | ||
3600 | |||
3601 | fail: /* Free unused memory */ | ||
3602 | kfree(cam->control_buffer); | ||
3603 | kfree(cam->data_buffer); | ||
3604 | if (cam->v4ldev) | ||
3605 | video_device_release(cam->v4ldev); | ||
3606 | mutex_unlock(&cam->dev_mutex); | ||
3607 | kfree(cam); | ||
3608 | return err; | ||
3609 | } | ||
3610 | |||
3611 | |||
3612 | static void w9968cf_usb_disconnect(struct usb_interface* intf) | ||
3613 | { | ||
3614 | struct w9968cf_device* cam = | ||
3615 | (struct w9968cf_device*)usb_get_intfdata(intf); | ||
3616 | |||
3617 | down_write(&w9968cf_disconnect); | ||
3618 | |||
3619 | if (cam) { | ||
3620 | /* Prevent concurrent accesses to data */ | ||
3621 | mutex_lock(&cam->dev_mutex); | ||
3622 | |||
3623 | cam->disconnected = 1; | ||
3624 | |||
3625 | DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id)) | ||
3626 | |||
3627 | wake_up_interruptible_all(&cam->open); | ||
3628 | |||
3629 | if (cam->users) { | ||
3630 | DBG(2, "The device is open (/dev/video%d)! " | ||
3631 | "Process name: %s. Deregistration and memory " | ||
3632 | "deallocation are deferred on close.", | ||
3633 | cam->v4ldev->minor, cam->command) | ||
3634 | cam->misconfigured = 1; | ||
3635 | w9968cf_stop_transfer(cam); | ||
3636 | wake_up_interruptible(&cam->wait_queue); | ||
3637 | } else | ||
3638 | w9968cf_release_resources(cam); | ||
3639 | |||
3640 | mutex_unlock(&cam->dev_mutex); | ||
3641 | |||
3642 | if (!cam->users) | ||
3643 | kfree(cam); | ||
3644 | } | ||
3645 | |||
3646 | up_write(&w9968cf_disconnect); | ||
3647 | } | ||
3648 | |||
3649 | |||
3650 | static struct usb_driver w9968cf_usb_driver = { | ||
3651 | .name = "w9968cf", | ||
3652 | .id_table = winbond_id_table, | ||
3653 | .probe = w9968cf_usb_probe, | ||
3654 | .disconnect = w9968cf_usb_disconnect, | ||
3655 | }; | ||
3656 | |||
3657 | |||
3658 | |||
3659 | /**************************************************************************** | ||
3660 | * Module init, exit and intermodule communication * | ||
3661 | ****************************************************************************/ | ||
3662 | |||
3663 | static int __init w9968cf_module_init(void) | ||
3664 | { | ||
3665 | int err; | ||
3666 | |||
3667 | KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION) | ||
3668 | KDBG(3, W9968CF_MODULE_AUTHOR) | ||
3669 | |||
3670 | if (ovmod_load) | ||
3671 | request_module("ovcamchip"); | ||
3672 | |||
3673 | if ((err = usb_register(&w9968cf_usb_driver))) | ||
3674 | return err; | ||
3675 | |||
3676 | return 0; | ||
3677 | } | ||
3678 | |||
3679 | |||
3680 | static void __exit w9968cf_module_exit(void) | ||
3681 | { | ||
3682 | /* w9968cf_usb_disconnect() will be called */ | ||
3683 | usb_deregister(&w9968cf_usb_driver); | ||
3684 | |||
3685 | KDBG(2, W9968CF_MODULE_NAME" deregistered") | ||
3686 | } | ||
3687 | |||
3688 | |||
3689 | module_init(w9968cf_module_init); | ||
3690 | module_exit(w9968cf_module_exit); | ||
3691 | |||
diff --git a/drivers/media/video/w9968cf.h b/drivers/media/video/w9968cf.h new file mode 100644 index 000000000000..a87be719a281 --- /dev/null +++ b/drivers/media/video/w9968cf.h | |||
@@ -0,0 +1,330 @@ | |||
1 | /*************************************************************************** | ||
2 | * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. * | ||
3 | * * | ||
4 | * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program is distributed in the hope that it will be useful, * | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #ifndef _W9968CF_H_ | ||
22 | #define _W9968CF_H_ | ||
23 | |||
24 | #include <linux/videodev.h> | ||
25 | #include <linux/usb.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/device.h> | ||
28 | #include <linux/spinlock.h> | ||
29 | #include <linux/list.h> | ||
30 | #include <linux/wait.h> | ||
31 | #include <linux/config.h> | ||
32 | #include <linux/param.h> | ||
33 | #include <linux/types.h> | ||
34 | #include <linux/rwsem.h> | ||
35 | #include <linux/mutex.h> | ||
36 | |||
37 | #include <media/ovcamchip.h> | ||
38 | |||
39 | #include "w9968cf_vpp.h" | ||
40 | |||
41 | |||
42 | /**************************************************************************** | ||
43 | * Default values * | ||
44 | ****************************************************************************/ | ||
45 | |||
46 | #define W9968CF_OVMOD_LOAD 1 /* automatic 'ovcamchip' module loading */ | ||
47 | #define W9968CF_VPPMOD_LOAD 1 /* automatic 'w9968cf-vpp' module loading */ | ||
48 | |||
49 | /* Comment/uncomment the following line to enable/disable debugging messages */ | ||
50 | #define W9968CF_DEBUG | ||
51 | |||
52 | /* These have effect only if W9968CF_DEBUG is defined */ | ||
53 | #define W9968CF_DEBUG_LEVEL 2 /* from 0 to 6. 0 for no debug informations */ | ||
54 | #define W9968CF_SPECIFIC_DEBUG 0 /* 0 or 1 */ | ||
55 | |||
56 | #define W9968CF_MAX_DEVICES 32 | ||
57 | #define W9968CF_SIMCAMS W9968CF_MAX_DEVICES /* simultaneous cameras */ | ||
58 | |||
59 | #define W9968CF_MAX_BUFFERS 32 | ||
60 | #define W9968CF_BUFFERS 2 /* n. of frame buffers from 2 to MAX_BUFFERS */ | ||
61 | |||
62 | /* Maximum data payload sizes in bytes for alternate settings */ | ||
63 | static const u16 wMaxPacketSize[] = {1023, 959, 895, 831, 767, 703, 639, 575, | ||
64 | 511, 447, 383, 319, 255, 191, 127, 63}; | ||
65 | #define W9968CF_PACKET_SIZE 1023 /* according to wMaxPacketSizes[] */ | ||
66 | #define W9968CF_MIN_PACKET_SIZE 63 /* minimum value */ | ||
67 | #define W9968CF_ISO_PACKETS 5 /* n.of packets for isochronous transfers */ | ||
68 | #define W9968CF_USB_CTRL_TIMEOUT 1000 /* timeout (ms) for usb control commands */ | ||
69 | #define W9968CF_URBS 2 /* n. of scheduled URBs for ISO transfer */ | ||
70 | |||
71 | #define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */ | ||
72 | #define W9968CF_I2C_RW_RETRIES 15 /* number of max I2C r/w retries */ | ||
73 | |||
74 | /* Available video formats */ | ||
75 | struct w9968cf_format { | ||
76 | const u16 palette; | ||
77 | const u16 depth; | ||
78 | const u8 compression; | ||
79 | }; | ||
80 | |||
81 | static const struct w9968cf_format w9968cf_formatlist[] = { | ||
82 | { VIDEO_PALETTE_UYVY, 16, 0 }, /* original video */ | ||
83 | { VIDEO_PALETTE_YUV422P, 16, 1 }, /* with JPEG compression */ | ||
84 | { VIDEO_PALETTE_YUV420P, 12, 1 }, /* with JPEG compression */ | ||
85 | { VIDEO_PALETTE_YUV420, 12, 1 }, /* same as YUV420P */ | ||
86 | { VIDEO_PALETTE_YUYV, 16, 0 }, /* software conversion */ | ||
87 | { VIDEO_PALETTE_YUV422, 16, 0 }, /* software conversion */ | ||
88 | { VIDEO_PALETTE_GREY, 8, 0 }, /* software conversion */ | ||
89 | { VIDEO_PALETTE_RGB555, 16, 0 }, /* software conversion */ | ||
90 | { VIDEO_PALETTE_RGB565, 16, 0 }, /* software conversion */ | ||
91 | { VIDEO_PALETTE_RGB24, 24, 0 }, /* software conversion */ | ||
92 | { VIDEO_PALETTE_RGB32, 32, 0 }, /* software conversion */ | ||
93 | { 0, 0, 0 } /* 0 is a terminating entry */ | ||
94 | }; | ||
95 | |||
96 | #define W9968CF_DECOMPRESSION 2 /* decomp:0=disable,1=force,2=any formats */ | ||
97 | #define W9968CF_PALETTE_DECOMP_OFF VIDEO_PALETTE_UYVY /* when decomp=0 */ | ||
98 | #define W9968CF_PALETTE_DECOMP_FORCE VIDEO_PALETTE_YUV420P /* when decomp=1 */ | ||
99 | #define W9968CF_PALETTE_DECOMP_ON VIDEO_PALETTE_UYVY /* when decomp=2 */ | ||
100 | |||
101 | #define W9968CF_FORCE_RGB 0 /* read RGB instead of BGR, yes=1/no=0 */ | ||
102 | |||
103 | #define W9968CF_MAX_WIDTH 800 /* Has effect if up-scaling is on */ | ||
104 | #define W9968CF_MAX_HEIGHT 600 /* Has effect if up-scaling is on */ | ||
105 | #define W9968CF_WIDTH 320 /* from 128 to 352, multiple of 16 */ | ||
106 | #define W9968CF_HEIGHT 240 /* from 96 to 288, multiple of 16 */ | ||
107 | |||
108 | #define W9968CF_CLAMPING 0 /* 0 disable, 1 enable video data clamping */ | ||
109 | #define W9968CF_FILTER_TYPE 0 /* 0 disable 1 (1-2-1), 2 (2-3-6-3-2) */ | ||
110 | #define W9968CF_DOUBLE_BUFFER 1 /* 0 disable, 1 enable double buffer */ | ||
111 | #define W9968CF_LARGEVIEW 1 /* 0 disable, 1 enable */ | ||
112 | #define W9968CF_UPSCALING 0 /* 0 disable, 1 enable */ | ||
113 | |||
114 | #define W9968CF_MONOCHROME 0 /* 0 not monochrome, 1 monochrome sensor */ | ||
115 | #define W9968CF_BRIGHTNESS 31000 /* from 0 to 65535 */ | ||
116 | #define W9968CF_HUE 32768 /* from 0 to 65535 */ | ||
117 | #define W9968CF_COLOUR 32768 /* from 0 to 65535 */ | ||
118 | #define W9968CF_CONTRAST 50000 /* from 0 to 65535 */ | ||
119 | #define W9968CF_WHITENESS 32768 /* from 0 to 65535 */ | ||
120 | |||
121 | #define W9968CF_AUTOBRIGHT 0 /* 0 disable, 1 enable automatic brightness */ | ||
122 | #define W9968CF_AUTOEXP 1 /* 0 disable, 1 enable automatic exposure */ | ||
123 | #define W9968CF_LIGHTFREQ 50 /* light frequency. 50Hz (Europe) or 60Hz */ | ||
124 | #define W9968CF_BANDINGFILTER 0 /* 0 disable, 1 enable banding filter */ | ||
125 | #define W9968CF_BACKLIGHT 0 /* 0 or 1, 1=object is lit from behind */ | ||
126 | #define W9968CF_MIRROR 0 /* 0 or 1 [don't] reverse image horizontally*/ | ||
127 | |||
128 | #define W9968CF_CLOCKDIV -1 /* -1 = automatic clock divisor */ | ||
129 | #define W9968CF_DEF_CLOCKDIVISOR 0 /* default sensor clock divisor value */ | ||
130 | |||
131 | |||
132 | /**************************************************************************** | ||
133 | * Globals * | ||
134 | ****************************************************************************/ | ||
135 | |||
136 | #define W9968CF_MODULE_NAME "V4L driver for W996[87]CF JPEG USB " \ | ||
137 | "Dual Mode Camera Chip" | ||
138 | #define W9968CF_MODULE_VERSION "1:1.33-basic" | ||
139 | #define W9968CF_MODULE_AUTHOR "(C) 2002-2004 Luca Risolia" | ||
140 | #define W9968CF_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" | ||
141 | #define W9968CF_MODULE_LICENSE "GPL" | ||
142 | |||
143 | static const struct usb_device_id winbond_id_table[] = { | ||
144 | { | ||
145 | /* Creative Labs Video Blaster WebCam Go Plus */ | ||
146 | USB_DEVICE(0x041e, 0x4003), | ||
147 | .driver_info = (unsigned long)"w9968cf", | ||
148 | }, | ||
149 | { | ||
150 | /* Generic W996[87]CF JPEG USB Dual Mode Camera */ | ||
151 | USB_DEVICE(0x1046, 0x9967), | ||
152 | .driver_info = (unsigned long)"w9968cf", | ||
153 | }, | ||
154 | { } /* terminating entry */ | ||
155 | }; | ||
156 | |||
157 | /* W996[87]CF camera models, internal ids: */ | ||
158 | enum w9968cf_model_id { | ||
159 | W9968CF_MOD_GENERIC = 1, /* Generic W996[87]CF based device */ | ||
160 | W9968CF_MOD_CLVBWGP = 11,/*Creative Labs Video Blaster WebCam Go Plus*/ | ||
161 | W9968CF_MOD_ADPVDMA = 21, /* Aroma Digi Pen VGA Dual Mode ADG-5000 */ | ||
162 | W9986CF_MOD_AAU = 31, /* AVerMedia AVerTV USB */ | ||
163 | W9968CF_MOD_CLVBWG = 34, /* Creative Labs Video Blaster WebCam Go */ | ||
164 | W9968CF_MOD_LL = 37, /* Lebon LDC-035A */ | ||
165 | W9968CF_MOD_EEEMC = 40, /* Ezonics EZ-802 EZMega Cam */ | ||
166 | W9968CF_MOD_OOE = 42, /* OmniVision OV8610-EDE */ | ||
167 | W9968CF_MOD_ODPVDMPC = 43,/* OPCOM Digi Pen VGA Dual Mode Pen Camera */ | ||
168 | W9968CF_MOD_PDPII = 46, /* Pretec Digi Pen-II */ | ||
169 | W9968CF_MOD_PDP480 = 49, /* Pretec DigiPen-480 */ | ||
170 | }; | ||
171 | |||
172 | enum w9968cf_frame_status { | ||
173 | F_READY, /* finished grabbing & ready to be read/synced */ | ||
174 | F_GRABBING, /* in the process of being grabbed into */ | ||
175 | F_ERROR, /* something bad happened while processing */ | ||
176 | F_UNUSED /* unused (no VIDIOCMCAPTURE) */ | ||
177 | }; | ||
178 | |||
179 | struct w9968cf_frame_t { | ||
180 | void* buffer; | ||
181 | unsigned long size; | ||
182 | u32 length; | ||
183 | int number; | ||
184 | enum w9968cf_frame_status status; | ||
185 | struct w9968cf_frame_t* next; | ||
186 | u8 queued; | ||
187 | }; | ||
188 | |||
189 | enum w9968cf_vpp_flag { | ||
190 | VPP_NONE = 0x00, | ||
191 | VPP_UPSCALE = 0x01, | ||
192 | VPP_SWAP_YUV_BYTES = 0x02, | ||
193 | VPP_DECOMPRESSION = 0x04, | ||
194 | VPP_UYVY_TO_RGBX = 0x08, | ||
195 | }; | ||
196 | |||
197 | /* Main device driver structure */ | ||
198 | struct w9968cf_device { | ||
199 | struct device dev; /* device structure */ | ||
200 | |||
201 | enum w9968cf_model_id id; /* private device identifier */ | ||
202 | |||
203 | struct video_device* v4ldev; /* -> V4L structure */ | ||
204 | struct list_head v4llist; /* entry of the list of V4L cameras */ | ||
205 | |||
206 | struct usb_device* usbdev; /* -> main USB structure */ | ||
207 | struct urb* urb[W9968CF_URBS]; /* -> USB request block structs */ | ||
208 | void* transfer_buffer[W9968CF_URBS]; /* -> ISO transfer buffers */ | ||
209 | u16* control_buffer; /* -> buffer for control req.*/ | ||
210 | u16* data_buffer; /* -> data to send to the FSB */ | ||
211 | |||
212 | struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS]; | ||
213 | struct w9968cf_frame_t frame_tmp; /* temporary frame */ | ||
214 | struct w9968cf_frame_t frame_vpp; /* helper frame.*/ | ||
215 | struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */ | ||
216 | struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS]; | ||
217 | |||
218 | u8 max_buffers, /* number of requested buffers */ | ||
219 | force_palette, /* yes=1/no=0 */ | ||
220 | force_rgb, /* read RGB instead of BGR, yes=1, no=0 */ | ||
221 | double_buffer, /* hardware double buffering yes=1/no=0 */ | ||
222 | clamping, /* video data clamping yes=1/no=0 */ | ||
223 | filter_type, /* 0=disabled, 1=3 tap, 2=5 tap filter */ | ||
224 | capture, /* 0=disabled, 1=enabled */ | ||
225 | largeview, /* 0=disabled, 1=enabled */ | ||
226 | decompression, /* 0=disabled, 1=forced, 2=allowed */ | ||
227 | upscaling; /* software image scaling, 0=enabled, 1=disabled */ | ||
228 | |||
229 | struct video_picture picture; /* current picture settings */ | ||
230 | struct video_window window; /* current window settings */ | ||
231 | |||
232 | u16 hw_depth, /* depth (used by the chip) */ | ||
233 | hw_palette, /* palette (used by the chip) */ | ||
234 | hw_width, /* width (used by the chip) */ | ||
235 | hw_height, /* height (used by the chip) */ | ||
236 | hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */ | ||
237 | vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */ | ||
238 | start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/ | ||
239 | start_cropy; /* pixels from VS inactive edge to 1st cropped pixel*/ | ||
240 | |||
241 | enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */ | ||
242 | |||
243 | u8 nbuffers, /* number of allocated frame buffers */ | ||
244 | altsetting, /* camera alternate setting */ | ||
245 | disconnected, /* flag: yes=1, no=0 */ | ||
246 | misconfigured, /* flag: yes=1, no=0 */ | ||
247 | users, /* flag: number of users holding the device */ | ||
248 | streaming; /* flag: yes=1, no=0 */ | ||
249 | |||
250 | u8 sensor_initialized; /* flag: yes=1, no=0 */ | ||
251 | |||
252 | /* Determined by the image sensor type: */ | ||
253 | int sensor, /* type of image sensor chip (CC_*) */ | ||
254 | monochrome; /* image sensor is (probably) monochrome */ | ||
255 | u16 maxwidth, /* maximum width supported by the image sensor */ | ||
256 | maxheight, /* maximum height supported by the image sensor */ | ||
257 | minwidth, /* minimum width supported by the image sensor */ | ||
258 | minheight; /* minimum height supported by the image sensor */ | ||
259 | u8 auto_brt, /* auto brightness enabled flag */ | ||
260 | auto_exp, /* auto exposure enabled flag */ | ||
261 | backlight, /* backlight exposure algorithm flag */ | ||
262 | mirror, /* image is reversed horizontally */ | ||
263 | lightfreq, /* power (lighting) frequency */ | ||
264 | bandfilt; /* banding filter enabled flag */ | ||
265 | s8 clockdiv; /* clock divisor */ | ||
266 | |||
267 | /* I2C interface to kernel */ | ||
268 | struct i2c_adapter i2c_adapter; | ||
269 | struct i2c_client* sensor_client; | ||
270 | |||
271 | /* Locks */ | ||
272 | struct mutex dev_mutex, /* for probe, disconnect,open and close */ | ||
273 | fileop_mutex; /* for read and ioctl */ | ||
274 | spinlock_t urb_lock, /* for submit_urb() and unlink_urb() */ | ||
275 | flist_lock; /* for requested frame list accesses */ | ||
276 | wait_queue_head_t open, wait_queue; | ||
277 | |||
278 | char command[16]; /* name of the program holding the device */ | ||
279 | }; | ||
280 | |||
281 | |||
282 | /**************************************************************************** | ||
283 | * Macros for debugging * | ||
284 | ****************************************************************************/ | ||
285 | |||
286 | #undef DBG | ||
287 | #undef KDBG | ||
288 | #ifdef W9968CF_DEBUG | ||
289 | /* For device specific debugging messages */ | ||
290 | # define DBG(level, fmt, args...) \ | ||
291 | { \ | ||
292 | if ( ((specific_debug) && (debug == (level))) || \ | ||
293 | ((!specific_debug) && (debug >= (level))) ) { \ | ||
294 | if ((level) == 1) \ | ||
295 | dev_err(&cam->dev, fmt "\n", ## args); \ | ||
296 | else if ((level) == 2 || (level) == 3) \ | ||
297 | dev_info(&cam->dev, fmt "\n", ## args); \ | ||
298 | else if ((level) == 4) \ | ||
299 | dev_warn(&cam->dev, fmt "\n", ## args); \ | ||
300 | else if ((level) >= 5) \ | ||
301 | dev_info(&cam->dev, "[%s:%d] " fmt "\n", \ | ||
302 | __FUNCTION__, __LINE__ , ## args); \ | ||
303 | } \ | ||
304 | } | ||
305 | /* For generic kernel (not device specific) messages */ | ||
306 | # define KDBG(level, fmt, args...) \ | ||
307 | { \ | ||
308 | if ( ((specific_debug) && (debug == (level))) || \ | ||
309 | ((!specific_debug) && (debug >= (level))) ) { \ | ||
310 | if ((level) >= 1 && (level) <= 4) \ | ||
311 | pr_info("w9968cf: " fmt "\n", ## args); \ | ||
312 | else if ((level) >= 5) \ | ||
313 | pr_debug("w9968cf: [%s:%d] " fmt "\n", __FUNCTION__, \ | ||
314 | __LINE__ , ## args); \ | ||
315 | } \ | ||
316 | } | ||
317 | #else | ||
318 | /* Not debugging: nothing */ | ||
319 | # define DBG(level, fmt, args...) do {;} while(0); | ||
320 | # define KDBG(level, fmt, args...) do {;} while(0); | ||
321 | #endif | ||
322 | |||
323 | #undef PDBG | ||
324 | #define PDBG(fmt, args...) \ | ||
325 | dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args); | ||
326 | |||
327 | #undef PDBGG | ||
328 | #define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */ | ||
329 | |||
330 | #endif /* _W9968CF_H_ */ | ||
diff --git a/drivers/media/video/w9968cf_decoder.h b/drivers/media/video/w9968cf_decoder.h new file mode 100644 index 000000000000..31faccbe8f03 --- /dev/null +++ b/drivers/media/video/w9968cf_decoder.h | |||
@@ -0,0 +1,86 @@ | |||
1 | /*************************************************************************** | ||
2 | * Video decoder for the W996[87]CF driver for Linux. * | ||
3 | * * | ||
4 | * Copyright (C) 2003 2004 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program is distributed in the hope that it will be useful, * | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #ifndef _W9968CF_DECODER_H_ | ||
22 | #define _W9968CF_DECODER_H_ | ||
23 | |||
24 | /* Comment/uncomment this for high/low quality of compressed video */ | ||
25 | #define W9968CF_DEC_FAST_LOWQUALITY_VIDEO | ||
26 | |||
27 | #ifdef W9968CF_DEC_FAST_LOWQUALITY_VIDEO | ||
28 | static const unsigned char Y_QUANTABLE[64] = { | ||
29 | 16, 11, 10, 16, 24, 40, 51, 61, | ||
30 | 12, 12, 14, 19, 26, 58, 60, 55, | ||
31 | 14, 13, 16, 24, 40, 57, 69, 56, | ||
32 | 14, 17, 22, 29, 51, 87, 80, 62, | ||
33 | 18, 22, 37, 56, 68, 109, 103, 77, | ||
34 | 24, 35, 55, 64, 81, 104, 113, 92, | ||
35 | 49, 64, 78, 87, 103, 121, 120, 101, | ||
36 | 72, 92, 95, 98, 112, 100, 103, 99 | ||
37 | }; | ||
38 | |||
39 | static const unsigned char UV_QUANTABLE[64] = { | ||
40 | 17, 18, 24, 47, 99, 99, 99, 99, | ||
41 | 18, 21, 26, 66, 99, 99, 99, 99, | ||
42 | 24, 26, 56, 99, 99, 99, 99, 99, | ||
43 | 47, 66, 99, 99, 99, 99, 99, 99, | ||
44 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
45 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
46 | 99, 99, 99, 99, 99, 99, 99, 99, | ||
47 | 99, 99, 99, 99, 99, 99, 99, 99 | ||
48 | }; | ||
49 | #else | ||
50 | static const unsigned char Y_QUANTABLE[64] = { | ||
51 | 8, 5, 5, 8, 12, 20, 25, 30, | ||
52 | 6, 6, 7, 9, 13, 29, 30, 27, | ||
53 | 7, 6, 8, 12, 20, 28, 34, 28, | ||
54 | 7, 8, 11, 14, 25, 43, 40, 31, | ||
55 | 9, 11, 18, 28, 34, 54, 51, 38, | ||
56 | 12, 17, 27, 32, 40, 52, 56, 46, | ||
57 | 24, 32, 39, 43, 51, 60, 60, 50, | ||
58 | 36, 46, 47, 49, 56, 50, 51, 49 | ||
59 | }; | ||
60 | |||
61 | static const unsigned char UV_QUANTABLE[64] = { | ||
62 | 8, 9, 12, 23, 49, 49, 49, 49, | ||
63 | 9, 10, 13, 33, 49, 49, 49, 49, | ||
64 | 12, 13, 28, 49, 49, 49, 49, 49, | ||
65 | 23, 33, 49, 49, 49, 49, 49, 49, | ||
66 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
67 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
68 | 49, 49, 49, 49, 49, 49, 49, 49, | ||
69 | 49, 49, 49, 49, 49, 49, 49, 49 | ||
70 | }; | ||
71 | #endif | ||
72 | |||
73 | #define W9968CF_DEC_ERR_CORRUPTED_DATA -1 | ||
74 | #define W9968CF_DEC_ERR_BUF_OVERFLOW -2 | ||
75 | #define W9968CF_DEC_ERR_NO_SOI -3 | ||
76 | #define W9968CF_DEC_ERR_NO_SOF0 -4 | ||
77 | #define W9968CF_DEC_ERR_NO_SOS -5 | ||
78 | #define W9968CF_DEC_ERR_NO_EOI -6 | ||
79 | |||
80 | extern void w9968cf_init_decoder(void); | ||
81 | extern int w9968cf_check_headers(const unsigned char* Pin, | ||
82 | const unsigned long BUF_SIZE); | ||
83 | extern int w9968cf_decode(const char* Pin, const unsigned long BUF_SIZE, | ||
84 | const unsigned W, const unsigned H, char* Pout); | ||
85 | |||
86 | #endif /* _W9968CF_DECODER_H_ */ | ||
diff --git a/drivers/media/video/w9968cf_vpp.h b/drivers/media/video/w9968cf_vpp.h new file mode 100644 index 000000000000..f3b91b782671 --- /dev/null +++ b/drivers/media/video/w9968cf_vpp.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /*************************************************************************** | ||
2 | * Interface for video post-processing functions for the W996[87]CF driver * | ||
3 | * for Linux. * | ||
4 | * * | ||
5 | * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #ifndef _W9968CF_VPP_H_ | ||
23 | #define _W9968CF_VPP_H_ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <asm/types.h> | ||
27 | |||
28 | struct w9968cf_vpp_t { | ||
29 | struct module* owner; | ||
30 | int (*check_headers)(const unsigned char*, const unsigned long); | ||
31 | int (*decode)(const char*, const unsigned long, const unsigned, | ||
32 | const unsigned, char*); | ||
33 | void (*swap_yuvbytes)(void*, unsigned long); | ||
34 | void (*uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8); | ||
35 | void (*scale_up)(u8*, u8*, u16, u16, u16, u16, u16); | ||
36 | |||
37 | u8 busy; /* read-only flag: module is/is not in use */ | ||
38 | }; | ||
39 | |||
40 | #endif /* _W9968CF_VPP_H_ */ | ||
diff --git a/drivers/media/video/zc0301/Makefile b/drivers/media/video/zc0301/Makefile new file mode 100644 index 000000000000..d749199d8f06 --- /dev/null +++ b/drivers/media/video/zc0301/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | zc0301-objs := zc0301_core.o zc0301_pas202bcb.o | ||
2 | |||
3 | obj-$(CONFIG_USB_ZC0301) += zc0301.o | ||
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h new file mode 100644 index 000000000000..8e0655140e60 --- /dev/null +++ b/drivers/media/video/zc0301/zc0301.h | |||
@@ -0,0 +1,192 @@ | |||
1 | /*************************************************************************** | ||
2 | * V4L2 driver for ZC0301 Image Processor and Control Chip * | ||
3 | * * | ||
4 | * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | * * | ||
11 | * This program is distributed in the hope that it will be useful, * | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
14 | * GNU General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this program; if not, write to the Free Software * | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
19 | ***************************************************************************/ | ||
20 | |||
21 | #ifndef _ZC0301_H_ | ||
22 | #define _ZC0301_H_ | ||
23 | |||
24 | #include <linux/version.h> | ||
25 | #include <linux/usb.h> | ||
26 | #include <linux/videodev2.h> | ||
27 | #include <media/v4l2-common.h> | ||
28 | #include <linux/device.h> | ||
29 | #include <linux/list.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/time.h> | ||
32 | #include <linux/wait.h> | ||
33 | #include <linux/types.h> | ||
34 | #include <linux/param.h> | ||
35 | #include <linux/mutex.h> | ||
36 | #include <linux/rwsem.h> | ||
37 | #include <linux/stddef.h> | ||
38 | #include <linux/string.h> | ||
39 | |||
40 | #include "zc0301_sensor.h" | ||
41 | |||
42 | /*****************************************************************************/ | ||
43 | |||
44 | #define ZC0301_DEBUG | ||
45 | #define ZC0301_DEBUG_LEVEL 2 | ||
46 | #define ZC0301_MAX_DEVICES 64 | ||
47 | #define ZC0301_FORCE_MUNMAP 0 | ||
48 | #define ZC0301_MAX_FRAMES 32 | ||
49 | #define ZC0301_COMPRESSION_QUALITY 0 | ||
50 | #define ZC0301_URBS 2 | ||
51 | #define ZC0301_ISO_PACKETS 7 | ||
52 | #define ZC0301_ALTERNATE_SETTING 7 | ||
53 | #define ZC0301_URB_TIMEOUT msecs_to_jiffies(2 * ZC0301_ISO_PACKETS) | ||
54 | #define ZC0301_CTRL_TIMEOUT 100 | ||
55 | #define ZC0301_FRAME_TIMEOUT 2 | ||
56 | |||
57 | /*****************************************************************************/ | ||
58 | |||
59 | ZC0301_ID_TABLE | ||
60 | ZC0301_SENSOR_TABLE | ||
61 | |||
62 | enum zc0301_frame_state { | ||
63 | F_UNUSED, | ||
64 | F_QUEUED, | ||
65 | F_GRABBING, | ||
66 | F_DONE, | ||
67 | F_ERROR, | ||
68 | }; | ||
69 | |||
70 | struct zc0301_frame_t { | ||
71 | void* bufmem; | ||
72 | struct v4l2_buffer buf; | ||
73 | enum zc0301_frame_state state; | ||
74 | struct list_head frame; | ||
75 | unsigned long vma_use_count; | ||
76 | }; | ||
77 | |||
78 | enum zc0301_dev_state { | ||
79 | DEV_INITIALIZED = 0x01, | ||
80 | DEV_DISCONNECTED = 0x02, | ||
81 | DEV_MISCONFIGURED = 0x04, | ||
82 | }; | ||
83 | |||
84 | enum zc0301_io_method { | ||
85 | IO_NONE, | ||
86 | IO_READ, | ||
87 | IO_MMAP, | ||
88 | }; | ||
89 | |||
90 | enum zc0301_stream_state { | ||
91 | STREAM_OFF, | ||
92 | STREAM_INTERRUPT, | ||
93 | STREAM_ON, | ||
94 | }; | ||
95 | |||
96 | struct zc0301_module_param { | ||
97 | u8 force_munmap; | ||
98 | u16 frame_timeout; | ||
99 | }; | ||
100 | |||
101 | static DECLARE_RWSEM(zc0301_disconnect); | ||
102 | |||
103 | struct zc0301_device { | ||
104 | struct video_device* v4ldev; | ||
105 | |||
106 | struct zc0301_sensor sensor; | ||
107 | |||
108 | struct usb_device* usbdev; | ||
109 | struct urb* urb[ZC0301_URBS]; | ||
110 | void* transfer_buffer[ZC0301_URBS]; | ||
111 | u8* control_buffer; | ||
112 | |||
113 | struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES]; | ||
114 | struct list_head inqueue, outqueue; | ||
115 | u32 frame_count, nbuffers, nreadbuffers; | ||
116 | |||
117 | enum zc0301_io_method io; | ||
118 | enum zc0301_stream_state stream; | ||
119 | |||
120 | struct v4l2_jpegcompression compression; | ||
121 | |||
122 | struct zc0301_module_param module_param; | ||
123 | |||
124 | enum zc0301_dev_state state; | ||
125 | u8 users; | ||
126 | |||
127 | struct mutex dev_mutex, fileop_mutex; | ||
128 | spinlock_t queue_lock; | ||
129 | wait_queue_head_t open, wait_frame, wait_stream; | ||
130 | }; | ||
131 | |||
132 | /*****************************************************************************/ | ||
133 | |||
134 | struct zc0301_device* | ||
135 | zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id) | ||
136 | { | ||
137 | return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL; | ||
138 | } | ||
139 | |||
140 | void | ||
141 | zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor) | ||
142 | { | ||
143 | memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor)); | ||
144 | } | ||
145 | |||
146 | /*****************************************************************************/ | ||
147 | |||
148 | #undef DBG | ||
149 | #undef KDBG | ||
150 | #ifdef ZC0301_DEBUG | ||
151 | # define DBG(level, fmt, args...) \ | ||
152 | do { \ | ||
153 | if (debug >= (level)) { \ | ||
154 | if ((level) == 1) \ | ||
155 | dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ | ||
156 | else if ((level) == 2) \ | ||
157 | dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ | ||
158 | else if ((level) >= 3) \ | ||
159 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | ||
160 | __FUNCTION__, __LINE__ , ## args); \ | ||
161 | } \ | ||
162 | } while (0) | ||
163 | # define KDBG(level, fmt, args...) \ | ||
164 | do { \ | ||
165 | if (debug >= (level)) { \ | ||
166 | if ((level) == 1 || (level) == 2) \ | ||
167 | pr_info("zc0301: " fmt "\n", ## args); \ | ||
168 | else if ((level) == 3) \ | ||
169 | pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__, \ | ||
170 | __LINE__ , ## args); \ | ||
171 | } \ | ||
172 | } while (0) | ||
173 | # define V4LDBG(level, name, cmd) \ | ||
174 | do { \ | ||
175 | if (debug >= (level)) \ | ||
176 | v4l_print_ioctl(name, cmd); \ | ||
177 | } while (0) | ||
178 | #else | ||
179 | # define DBG(level, fmt, args...) do {;} while(0) | ||
180 | # define KDBG(level, fmt, args...) do {;} while(0) | ||
181 | # define V4LDBG(level, name, cmd) do {;} while(0) | ||
182 | #endif | ||
183 | |||
184 | #undef PDBG | ||
185 | #define PDBG(fmt, args...) \ | ||
186 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | ||
187 | __FUNCTION__, __LINE__ , ## args) | ||
188 | |||
189 | #undef PDBGG | ||
190 | #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ | ||
191 | |||
192 | #endif /* _ZC0301_H_ */ | ||
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c new file mode 100644 index 000000000000..4036c6268bff --- /dev/null +++ b/drivers/media/video/zc0301/zc0301_core.c | |||
@@ -0,0 +1,2055 @@ | |||
1 | /*************************************************************************** | ||
2 | * Video4Linux2 driver for ZC0301 Image Processor and Control Chip * | ||
3 | * * | ||
4 | * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
5 | * * | ||
6 | * Informations about the chip internals needed to enable the I2C protocol * | ||
7 | * have been taken from the documentation of the ZC030x Video4Linux1 * | ||
8 | * driver written by Andrew Birkett <andy@nobugs.org> * | ||
9 | * * | ||
10 | * This program is free software; you can redistribute it and/or modify * | ||
11 | * it under the terms of the GNU General Public License as published by * | ||
12 | * the Free Software Foundation; either version 2 of the License, or * | ||
13 | * (at your option) any later version. * | ||
14 | * * | ||
15 | * This program is distributed in the hope that it will be useful, * | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
18 | * GNU General Public License for more details. * | ||
19 | * * | ||
20 | * You should have received a copy of the GNU General Public License * | ||
21 | * along with this program; if not, write to the Free Software * | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
23 | ***************************************************************************/ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/param.h> | ||
29 | #include <linux/moduleparam.h> | ||
30 | #include <linux/errno.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/device.h> | ||
33 | #include <linux/fs.h> | ||
34 | #include <linux/delay.h> | ||
35 | #include <linux/compiler.h> | ||
36 | #include <linux/ioctl.h> | ||
37 | #include <linux/poll.h> | ||
38 | #include <linux/stat.h> | ||
39 | #include <linux/mm.h> | ||
40 | #include <linux/vmalloc.h> | ||
41 | #include <linux/page-flags.h> | ||
42 | #include <linux/byteorder/generic.h> | ||
43 | #include <asm/page.h> | ||
44 | #include <asm/uaccess.h> | ||
45 | |||
46 | #include "zc0301.h" | ||
47 | |||
48 | /*****************************************************************************/ | ||
49 | |||
50 | #define ZC0301_MODULE_NAME "V4L2 driver for ZC0301 " \ | ||
51 | "Image Processor and Control Chip" | ||
52 | #define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia" | ||
53 | #define ZC0301_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" | ||
54 | #define ZC0301_MODULE_LICENSE "GPL" | ||
55 | #define ZC0301_MODULE_VERSION "1:1.03" | ||
56 | #define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 3) | ||
57 | |||
58 | /*****************************************************************************/ | ||
59 | |||
60 | MODULE_DEVICE_TABLE(usb, zc0301_id_table); | ||
61 | |||
62 | MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL); | ||
63 | MODULE_DESCRIPTION(ZC0301_MODULE_NAME); | ||
64 | MODULE_VERSION(ZC0301_MODULE_VERSION); | ||
65 | MODULE_LICENSE(ZC0301_MODULE_LICENSE); | ||
66 | |||
67 | static short video_nr[] = {[0 ... ZC0301_MAX_DEVICES-1] = -1}; | ||
68 | module_param_array(video_nr, short, NULL, 0444); | ||
69 | MODULE_PARM_DESC(video_nr, | ||
70 | "\n<-1|n[,...]> Specify V4L2 minor mode number." | ||
71 | "\n -1 = use next available (default)" | ||
72 | "\n n = use minor number n (integer >= 0)" | ||
73 | "\nYou can specify up to " | ||
74 | __MODULE_STRING(ZC0301_MAX_DEVICES) " cameras this way." | ||
75 | "\nFor example:" | ||
76 | "\nvideo_nr=-1,2,-1 would assign minor number 2 to" | ||
77 | "\nthe second registered camera and use auto for the first" | ||
78 | "\none and for every other camera." | ||
79 | "\n"); | ||
80 | |||
81 | static short force_munmap[] = {[0 ... ZC0301_MAX_DEVICES-1] = | ||
82 | ZC0301_FORCE_MUNMAP}; | ||
83 | module_param_array(force_munmap, bool, NULL, 0444); | ||
84 | MODULE_PARM_DESC(force_munmap, | ||
85 | "\n<0|1[,...]> Force the application to unmap previously" | ||
86 | "\nmapped buffer memory before calling any VIDIOC_S_CROP or" | ||
87 | "\nVIDIOC_S_FMT ioctl's. Not all the applications support" | ||
88 | "\nthis feature. This parameter is specific for each" | ||
89 | "\ndetected camera." | ||
90 | "\n 0 = do not force memory unmapping" | ||
91 | "\n 1 = force memory unmapping (save memory)" | ||
92 | "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." | ||
93 | "\n"); | ||
94 | |||
95 | static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] = | ||
96 | ZC0301_FRAME_TIMEOUT}; | ||
97 | module_param_array(frame_timeout, uint, NULL, 0644); | ||
98 | MODULE_PARM_DESC(frame_timeout, | ||
99 | "\n<n[,...]> Timeout for a video frame in seconds." | ||
100 | "\nThis parameter is specific for each detected camera." | ||
101 | "\nDefault value is "__MODULE_STRING(ZC0301_FRAME_TIMEOUT)"." | ||
102 | "\n"); | ||
103 | |||
104 | #ifdef ZC0301_DEBUG | ||
105 | static unsigned short debug = ZC0301_DEBUG_LEVEL; | ||
106 | module_param(debug, ushort, 0644); | ||
107 | MODULE_PARM_DESC(debug, | ||
108 | "\n<n> Debugging information level, from 0 to 3:" | ||
109 | "\n0 = none (use carefully)" | ||
110 | "\n1 = critical errors" | ||
111 | "\n2 = significant informations" | ||
112 | "\n3 = more verbose messages" | ||
113 | "\nLevel 3 is useful for testing only, when only " | ||
114 | "one device is used." | ||
115 | "\nDefault value is "__MODULE_STRING(ZC0301_DEBUG_LEVEL)"." | ||
116 | "\n"); | ||
117 | #endif | ||
118 | |||
119 | /*****************************************************************************/ | ||
120 | |||
121 | static u32 | ||
122 | zc0301_request_buffers(struct zc0301_device* cam, u32 count, | ||
123 | enum zc0301_io_method io) | ||
124 | { | ||
125 | struct v4l2_pix_format* p = &(cam->sensor.pix_format); | ||
126 | struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); | ||
127 | const size_t imagesize = cam->module_param.force_munmap || | ||
128 | io == IO_READ ? | ||
129 | (p->width * p->height * p->priv) / 8 : | ||
130 | (r->width * r->height * p->priv) / 8; | ||
131 | void* buff = NULL; | ||
132 | u32 i; | ||
133 | |||
134 | if (count > ZC0301_MAX_FRAMES) | ||
135 | count = ZC0301_MAX_FRAMES; | ||
136 | |||
137 | cam->nbuffers = count; | ||
138 | while (cam->nbuffers > 0) { | ||
139 | if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize)))) | ||
140 | break; | ||
141 | cam->nbuffers--; | ||
142 | } | ||
143 | |||
144 | for (i = 0; i < cam->nbuffers; i++) { | ||
145 | cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); | ||
146 | cam->frame[i].buf.index = i; | ||
147 | cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); | ||
148 | cam->frame[i].buf.length = imagesize; | ||
149 | cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
150 | cam->frame[i].buf.sequence = 0; | ||
151 | cam->frame[i].buf.field = V4L2_FIELD_NONE; | ||
152 | cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; | ||
153 | cam->frame[i].buf.flags = 0; | ||
154 | } | ||
155 | |||
156 | return cam->nbuffers; | ||
157 | } | ||
158 | |||
159 | |||
160 | static void zc0301_release_buffers(struct zc0301_device* cam) | ||
161 | { | ||
162 | if (cam->nbuffers) { | ||
163 | vfree(cam->frame[0].bufmem); | ||
164 | cam->nbuffers = 0; | ||
165 | } | ||
166 | cam->frame_current = NULL; | ||
167 | } | ||
168 | |||
169 | |||
170 | static void zc0301_empty_framequeues(struct zc0301_device* cam) | ||
171 | { | ||
172 | u32 i; | ||
173 | |||
174 | INIT_LIST_HEAD(&cam->inqueue); | ||
175 | INIT_LIST_HEAD(&cam->outqueue); | ||
176 | |||
177 | for (i = 0; i < ZC0301_MAX_FRAMES; i++) { | ||
178 | cam->frame[i].state = F_UNUSED; | ||
179 | cam->frame[i].buf.bytesused = 0; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | |||
184 | static void zc0301_requeue_outqueue(struct zc0301_device* cam) | ||
185 | { | ||
186 | struct zc0301_frame_t *i; | ||
187 | |||
188 | list_for_each_entry(i, &cam->outqueue, frame) { | ||
189 | i->state = F_QUEUED; | ||
190 | list_add(&i->frame, &cam->inqueue); | ||
191 | } | ||
192 | |||
193 | INIT_LIST_HEAD(&cam->outqueue); | ||
194 | } | ||
195 | |||
196 | |||
197 | static void zc0301_queue_unusedframes(struct zc0301_device* cam) | ||
198 | { | ||
199 | unsigned long lock_flags; | ||
200 | u32 i; | ||
201 | |||
202 | for (i = 0; i < cam->nbuffers; i++) | ||
203 | if (cam->frame[i].state == F_UNUSED) { | ||
204 | cam->frame[i].state = F_QUEUED; | ||
205 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
206 | list_add_tail(&cam->frame[i].frame, &cam->inqueue); | ||
207 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | /*****************************************************************************/ | ||
212 | |||
213 | int zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value) | ||
214 | { | ||
215 | struct usb_device* udev = cam->usbdev; | ||
216 | int res; | ||
217 | |||
218 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40, | ||
219 | value, index, NULL, 0, ZC0301_CTRL_TIMEOUT); | ||
220 | if (res < 0) { | ||
221 | DBG(3, "Failed to write a register (index 0x%04X, " | ||
222 | "value 0x%02X, error %d)",index, value, res); | ||
223 | return -1; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | |||
230 | int zc0301_read_reg(struct zc0301_device* cam, u16 index) | ||
231 | { | ||
232 | struct usb_device* udev = cam->usbdev; | ||
233 | u8* buff = cam->control_buffer; | ||
234 | int res; | ||
235 | |||
236 | res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa1, 0xc0, | ||
237 | 0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT); | ||
238 | if (res < 0) | ||
239 | DBG(3, "Failed to read a register (index 0x%04X, error %d)", | ||
240 | index, res); | ||
241 | |||
242 | PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff)); | ||
243 | |||
244 | return (res >= 0) ? (int)(*buff) : -1; | ||
245 | } | ||
246 | |||
247 | |||
248 | int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length) | ||
249 | { | ||
250 | int err = 0, res, r0, r1; | ||
251 | |||
252 | err += zc0301_write_reg(cam, 0x0092, address); | ||
253 | err += zc0301_write_reg(cam, 0x0090, 0x02); | ||
254 | |||
255 | msleep(1); | ||
256 | |||
257 | res = zc0301_read_reg(cam, 0x0091); | ||
258 | if (res < 0) | ||
259 | err += res; | ||
260 | r0 = zc0301_read_reg(cam, 0x0095); | ||
261 | if (r0 < 0) | ||
262 | err += r0; | ||
263 | r1 = zc0301_read_reg(cam, 0x0096); | ||
264 | if (r1 < 0) | ||
265 | err += r1; | ||
266 | |||
267 | res = (length <= 1) ? r0 : r0 | (r1 << 8); | ||
268 | |||
269 | if (err) | ||
270 | DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X", | ||
271 | address, res); | ||
272 | |||
273 | |||
274 | PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res); | ||
275 | |||
276 | return err ? -1 : res; | ||
277 | } | ||
278 | |||
279 | |||
280 | int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value) | ||
281 | { | ||
282 | int err = 0, res; | ||
283 | |||
284 | err += zc0301_write_reg(cam, 0x0092, address); | ||
285 | err += zc0301_write_reg(cam, 0x0093, value & 0xff); | ||
286 | err += zc0301_write_reg(cam, 0x0094, value >> 8); | ||
287 | err += zc0301_write_reg(cam, 0x0090, 0x01); | ||
288 | |||
289 | msleep(1); | ||
290 | |||
291 | res = zc0301_read_reg(cam, 0x0091); | ||
292 | if (res < 0) | ||
293 | err += res; | ||
294 | |||
295 | if (err) | ||
296 | DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X", | ||
297 | address, value); | ||
298 | |||
299 | PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value); | ||
300 | |||
301 | return err ? -1 : 0; | ||
302 | } | ||
303 | |||
304 | /*****************************************************************************/ | ||
305 | |||
306 | static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs) | ||
307 | { | ||
308 | struct zc0301_device* cam = urb->context; | ||
309 | struct zc0301_frame_t** f; | ||
310 | size_t imagesize; | ||
311 | u8 i; | ||
312 | int err = 0; | ||
313 | |||
314 | if (urb->status == -ENOENT) | ||
315 | return; | ||
316 | |||
317 | f = &cam->frame_current; | ||
318 | |||
319 | if (cam->stream == STREAM_INTERRUPT) { | ||
320 | cam->stream = STREAM_OFF; | ||
321 | if ((*f)) | ||
322 | (*f)->state = F_QUEUED; | ||
323 | DBG(3, "Stream interrupted"); | ||
324 | wake_up(&cam->wait_stream); | ||
325 | } | ||
326 | |||
327 | if (cam->state & DEV_DISCONNECTED) | ||
328 | return; | ||
329 | |||
330 | if (cam->state & DEV_MISCONFIGURED) { | ||
331 | wake_up_interruptible(&cam->wait_frame); | ||
332 | return; | ||
333 | } | ||
334 | |||
335 | if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) | ||
336 | goto resubmit_urb; | ||
337 | |||
338 | if (!(*f)) | ||
339 | (*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t, | ||
340 | frame); | ||
341 | |||
342 | imagesize = (cam->sensor.pix_format.width * | ||
343 | cam->sensor.pix_format.height * | ||
344 | cam->sensor.pix_format.priv) / 8; | ||
345 | |||
346 | for (i = 0; i < urb->number_of_packets; i++) { | ||
347 | unsigned int len, status; | ||
348 | void *pos; | ||
349 | u16* soi; | ||
350 | u8 sof; | ||
351 | |||
352 | len = urb->iso_frame_desc[i].actual_length; | ||
353 | status = urb->iso_frame_desc[i].status; | ||
354 | pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; | ||
355 | |||
356 | if (status) { | ||
357 | DBG(3, "Error in isochronous frame"); | ||
358 | (*f)->state = F_ERROR; | ||
359 | continue; | ||
360 | } | ||
361 | |||
362 | sof = (*(soi = pos) == 0xd8ff); | ||
363 | |||
364 | PDBGG("Isochrnous frame: length %u, #%u i,", len, i); | ||
365 | |||
366 | if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) | ||
367 | start_of_frame: | ||
368 | if (sof) { | ||
369 | (*f)->state = F_GRABBING; | ||
370 | (*f)->buf.bytesused = 0; | ||
371 | do_gettimeofday(&(*f)->buf.timestamp); | ||
372 | DBG(3, "SOF detected: new video frame"); | ||
373 | } | ||
374 | |||
375 | if ((*f)->state == F_GRABBING) { | ||
376 | if (sof && (*f)->buf.bytesused) | ||
377 | goto end_of_frame; | ||
378 | |||
379 | if ((*f)->buf.bytesused + len > imagesize) { | ||
380 | DBG(3, "Video frame size exceeded"); | ||
381 | (*f)->state = F_ERROR; | ||
382 | continue; | ||
383 | } | ||
384 | |||
385 | memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len); | ||
386 | (*f)->buf.bytesused += len; | ||
387 | |||
388 | if ((*f)->buf.bytesused == imagesize) { | ||
389 | u32 b; | ||
390 | end_of_frame: | ||
391 | b = (*f)->buf.bytesused; | ||
392 | (*f)->state = F_DONE; | ||
393 | (*f)->buf.sequence= ++cam->frame_count; | ||
394 | spin_lock(&cam->queue_lock); | ||
395 | list_move_tail(&(*f)->frame, &cam->outqueue); | ||
396 | if (!list_empty(&cam->inqueue)) | ||
397 | (*f) = list_entry(cam->inqueue.next, | ||
398 | struct zc0301_frame_t, | ||
399 | frame); | ||
400 | else | ||
401 | (*f) = NULL; | ||
402 | spin_unlock(&cam->queue_lock); | ||
403 | DBG(3, "Video frame captured: : %lu bytes", | ||
404 | (unsigned long)(b)); | ||
405 | |||
406 | if (!(*f)) | ||
407 | goto resubmit_urb; | ||
408 | |||
409 | if (sof) | ||
410 | goto start_of_frame; | ||
411 | } | ||
412 | } | ||
413 | } | ||
414 | |||
415 | resubmit_urb: | ||
416 | urb->dev = cam->usbdev; | ||
417 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
418 | if (err < 0 && err != -EPERM) { | ||
419 | cam->state |= DEV_MISCONFIGURED; | ||
420 | DBG(1, "usb_submit_urb() failed"); | ||
421 | } | ||
422 | |||
423 | wake_up_interruptible(&cam->wait_frame); | ||
424 | } | ||
425 | |||
426 | |||
427 | static int zc0301_start_transfer(struct zc0301_device* cam) | ||
428 | { | ||
429 | struct usb_device *udev = cam->usbdev; | ||
430 | struct urb* urb; | ||
431 | const unsigned int wMaxPacketSize[] = {0, 128, 192, 256, 384, | ||
432 | 512, 768, 1023}; | ||
433 | const unsigned int psz = wMaxPacketSize[ZC0301_ALTERNATE_SETTING]; | ||
434 | s8 i, j; | ||
435 | int err = 0; | ||
436 | |||
437 | for (i = 0; i < ZC0301_URBS; i++) { | ||
438 | cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz, | ||
439 | GFP_KERNEL); | ||
440 | if (!cam->transfer_buffer[i]) { | ||
441 | err = -ENOMEM; | ||
442 | DBG(1, "Not enough memory"); | ||
443 | goto free_buffers; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | for (i = 0; i < ZC0301_URBS; i++) { | ||
448 | urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL); | ||
449 | cam->urb[i] = urb; | ||
450 | if (!urb) { | ||
451 | err = -ENOMEM; | ||
452 | DBG(1, "usb_alloc_urb() failed"); | ||
453 | goto free_urbs; | ||
454 | } | ||
455 | urb->dev = udev; | ||
456 | urb->context = cam; | ||
457 | urb->pipe = usb_rcvisocpipe(udev, 1); | ||
458 | urb->transfer_flags = URB_ISO_ASAP; | ||
459 | urb->number_of_packets = ZC0301_ISO_PACKETS; | ||
460 | urb->complete = zc0301_urb_complete; | ||
461 | urb->transfer_buffer = cam->transfer_buffer[i]; | ||
462 | urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS; | ||
463 | urb->interval = 1; | ||
464 | for (j = 0; j < ZC0301_ISO_PACKETS; j++) { | ||
465 | urb->iso_frame_desc[j].offset = psz * j; | ||
466 | urb->iso_frame_desc[j].length = psz; | ||
467 | } | ||
468 | } | ||
469 | |||
470 | err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING); | ||
471 | if (err) { | ||
472 | DBG(1, "usb_set_interface() failed"); | ||
473 | goto free_urbs; | ||
474 | } | ||
475 | |||
476 | cam->frame_current = NULL; | ||
477 | |||
478 | for (i = 0; i < ZC0301_URBS; i++) { | ||
479 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); | ||
480 | if (err) { | ||
481 | for (j = i-1; j >= 0; j--) | ||
482 | usb_kill_urb(cam->urb[j]); | ||
483 | DBG(1, "usb_submit_urb() failed, error %d", err); | ||
484 | goto free_urbs; | ||
485 | } | ||
486 | } | ||
487 | |||
488 | return 0; | ||
489 | |||
490 | free_urbs: | ||
491 | for (i = 0; (i < ZC0301_URBS) && cam->urb[i]; i++) | ||
492 | usb_free_urb(cam->urb[i]); | ||
493 | |||
494 | free_buffers: | ||
495 | for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++) | ||
496 | kfree(cam->transfer_buffer[i]); | ||
497 | |||
498 | return err; | ||
499 | } | ||
500 | |||
501 | |||
502 | static int zc0301_stop_transfer(struct zc0301_device* cam) | ||
503 | { | ||
504 | struct usb_device *udev = cam->usbdev; | ||
505 | s8 i; | ||
506 | int err = 0; | ||
507 | |||
508 | if (cam->state & DEV_DISCONNECTED) | ||
509 | return 0; | ||
510 | |||
511 | for (i = ZC0301_URBS-1; i >= 0; i--) { | ||
512 | usb_kill_urb(cam->urb[i]); | ||
513 | usb_free_urb(cam->urb[i]); | ||
514 | kfree(cam->transfer_buffer[i]); | ||
515 | } | ||
516 | |||
517 | err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ | ||
518 | if (err) | ||
519 | DBG(3, "usb_set_interface() failed"); | ||
520 | |||
521 | return err; | ||
522 | } | ||
523 | |||
524 | |||
525 | static int zc0301_stream_interrupt(struct zc0301_device* cam) | ||
526 | { | ||
527 | long timeout; | ||
528 | |||
529 | cam->stream = STREAM_INTERRUPT; | ||
530 | timeout = wait_event_timeout(cam->wait_stream, | ||
531 | (cam->stream == STREAM_OFF) || | ||
532 | (cam->state & DEV_DISCONNECTED), | ||
533 | ZC0301_URB_TIMEOUT); | ||
534 | if (cam->state & DEV_DISCONNECTED) | ||
535 | return -ENODEV; | ||
536 | else if (cam->stream != STREAM_OFF) { | ||
537 | cam->state |= DEV_MISCONFIGURED; | ||
538 | DBG(1, "URB timeout reached. The camera is misconfigured. To " | ||
539 | "use it, close and open /dev/video%d again.", | ||
540 | cam->v4ldev->minor); | ||
541 | return -EIO; | ||
542 | } | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | /*****************************************************************************/ | ||
548 | |||
549 | static int | ||
550 | zc0301_set_compression(struct zc0301_device* cam, | ||
551 | struct v4l2_jpegcompression* compression) | ||
552 | { | ||
553 | int r, err = 0; | ||
554 | |||
555 | if ((r = zc0301_read_reg(cam, 0x0008)) < 0) | ||
556 | err += r; | ||
557 | err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality); | ||
558 | |||
559 | return err ? -EIO : 0; | ||
560 | } | ||
561 | |||
562 | |||
563 | static int zc0301_init(struct zc0301_device* cam) | ||
564 | { | ||
565 | struct zc0301_sensor* s = &cam->sensor; | ||
566 | struct v4l2_control ctrl; | ||
567 | struct v4l2_queryctrl *qctrl; | ||
568 | struct v4l2_rect* rect; | ||
569 | u8 i = 0; | ||
570 | int err = 0; | ||
571 | |||
572 | if (!(cam->state & DEV_INITIALIZED)) { | ||
573 | init_waitqueue_head(&cam->open); | ||
574 | qctrl = s->qctrl; | ||
575 | rect = &(s->cropcap.defrect); | ||
576 | cam->compression.quality = ZC0301_COMPRESSION_QUALITY; | ||
577 | } else { /* use current values */ | ||
578 | qctrl = s->_qctrl; | ||
579 | rect = &(s->_rect); | ||
580 | } | ||
581 | |||
582 | if (s->init) { | ||
583 | err = s->init(cam); | ||
584 | if (err) { | ||
585 | DBG(3, "Sensor initialization failed"); | ||
586 | return err; | ||
587 | } | ||
588 | } | ||
589 | |||
590 | if ((err = zc0301_set_compression(cam, &cam->compression))) { | ||
591 | DBG(3, "set_compression() failed"); | ||
592 | return err; | ||
593 | } | ||
594 | |||
595 | if (s->set_crop) | ||
596 | if ((err = s->set_crop(cam, rect))) { | ||
597 | DBG(3, "set_crop() failed"); | ||
598 | return err; | ||
599 | } | ||
600 | |||
601 | if (s->set_ctrl) { | ||
602 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
603 | if (s->qctrl[i].id != 0 && | ||
604 | !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { | ||
605 | ctrl.id = s->qctrl[i].id; | ||
606 | ctrl.value = qctrl[i].default_value; | ||
607 | err = s->set_ctrl(cam, &ctrl); | ||
608 | if (err) { | ||
609 | DBG(3, "Set %s control failed", | ||
610 | s->qctrl[i].name); | ||
611 | return err; | ||
612 | } | ||
613 | DBG(3, "Image sensor supports '%s' control", | ||
614 | s->qctrl[i].name); | ||
615 | } | ||
616 | } | ||
617 | |||
618 | if (!(cam->state & DEV_INITIALIZED)) { | ||
619 | mutex_init(&cam->fileop_mutex); | ||
620 | spin_lock_init(&cam->queue_lock); | ||
621 | init_waitqueue_head(&cam->wait_frame); | ||
622 | init_waitqueue_head(&cam->wait_stream); | ||
623 | cam->nreadbuffers = 2; | ||
624 | memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); | ||
625 | memcpy(&(s->_rect), &(s->cropcap.defrect), | ||
626 | sizeof(struct v4l2_rect)); | ||
627 | cam->state |= DEV_INITIALIZED; | ||
628 | } | ||
629 | |||
630 | DBG(2, "Initialization succeeded"); | ||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | |||
635 | static void zc0301_release_resources(struct zc0301_device* cam) | ||
636 | { | ||
637 | DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); | ||
638 | video_set_drvdata(cam->v4ldev, NULL); | ||
639 | video_unregister_device(cam->v4ldev); | ||
640 | kfree(cam->control_buffer); | ||
641 | } | ||
642 | |||
643 | /*****************************************************************************/ | ||
644 | |||
645 | static int zc0301_open(struct inode* inode, struct file* filp) | ||
646 | { | ||
647 | struct zc0301_device* cam; | ||
648 | int err = 0; | ||
649 | |||
650 | /* | ||
651 | This is the only safe way to prevent race conditions with | ||
652 | disconnect | ||
653 | */ | ||
654 | if (!down_read_trylock(&zc0301_disconnect)) | ||
655 | return -ERESTARTSYS; | ||
656 | |||
657 | cam = video_get_drvdata(video_devdata(filp)); | ||
658 | |||
659 | if (mutex_lock_interruptible(&cam->dev_mutex)) { | ||
660 | up_read(&zc0301_disconnect); | ||
661 | return -ERESTARTSYS; | ||
662 | } | ||
663 | |||
664 | if (cam->users) { | ||
665 | DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); | ||
666 | if ((filp->f_flags & O_NONBLOCK) || | ||
667 | (filp->f_flags & O_NDELAY)) { | ||
668 | err = -EWOULDBLOCK; | ||
669 | goto out; | ||
670 | } | ||
671 | mutex_unlock(&cam->dev_mutex); | ||
672 | err = wait_event_interruptible_exclusive(cam->open, | ||
673 | cam->state & DEV_DISCONNECTED | ||
674 | || !cam->users); | ||
675 | if (err) { | ||
676 | up_read(&zc0301_disconnect); | ||
677 | return err; | ||
678 | } | ||
679 | if (cam->state & DEV_DISCONNECTED) { | ||
680 | up_read(&zc0301_disconnect); | ||
681 | return -ENODEV; | ||
682 | } | ||
683 | mutex_lock(&cam->dev_mutex); | ||
684 | } | ||
685 | |||
686 | |||
687 | if (cam->state & DEV_MISCONFIGURED) { | ||
688 | err = zc0301_init(cam); | ||
689 | if (err) { | ||
690 | DBG(1, "Initialization failed again. " | ||
691 | "I will retry on next open()."); | ||
692 | goto out; | ||
693 | } | ||
694 | cam->state &= ~DEV_MISCONFIGURED; | ||
695 | } | ||
696 | |||
697 | if ((err = zc0301_start_transfer(cam))) | ||
698 | goto out; | ||
699 | |||
700 | filp->private_data = cam; | ||
701 | cam->users++; | ||
702 | cam->io = IO_NONE; | ||
703 | cam->stream = STREAM_OFF; | ||
704 | cam->nbuffers = 0; | ||
705 | cam->frame_count = 0; | ||
706 | zc0301_empty_framequeues(cam); | ||
707 | |||
708 | DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); | ||
709 | |||
710 | out: | ||
711 | mutex_unlock(&cam->dev_mutex); | ||
712 | up_read(&zc0301_disconnect); | ||
713 | return err; | ||
714 | } | ||
715 | |||
716 | |||
717 | static int zc0301_release(struct inode* inode, struct file* filp) | ||
718 | { | ||
719 | struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); | ||
720 | |||
721 | mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ | ||
722 | |||
723 | zc0301_stop_transfer(cam); | ||
724 | |||
725 | zc0301_release_buffers(cam); | ||
726 | |||
727 | if (cam->state & DEV_DISCONNECTED) { | ||
728 | zc0301_release_resources(cam); | ||
729 | usb_put_dev(cam->usbdev); | ||
730 | mutex_unlock(&cam->dev_mutex); | ||
731 | kfree(cam); | ||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | cam->users--; | ||
736 | wake_up_interruptible_nr(&cam->open, 1); | ||
737 | |||
738 | DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); | ||
739 | |||
740 | mutex_unlock(&cam->dev_mutex); | ||
741 | |||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | |||
746 | static ssize_t | ||
747 | zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | ||
748 | { | ||
749 | struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); | ||
750 | struct zc0301_frame_t* f, * i; | ||
751 | unsigned long lock_flags; | ||
752 | long timeout; | ||
753 | int err = 0; | ||
754 | |||
755 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
756 | return -ERESTARTSYS; | ||
757 | |||
758 | if (cam->state & DEV_DISCONNECTED) { | ||
759 | DBG(1, "Device not present"); | ||
760 | mutex_unlock(&cam->fileop_mutex); | ||
761 | return -ENODEV; | ||
762 | } | ||
763 | |||
764 | if (cam->state & DEV_MISCONFIGURED) { | ||
765 | DBG(1, "The camera is misconfigured. Close and open it " | ||
766 | "again."); | ||
767 | mutex_unlock(&cam->fileop_mutex); | ||
768 | return -EIO; | ||
769 | } | ||
770 | |||
771 | if (cam->io == IO_MMAP) { | ||
772 | DBG(3, "Close and open the device again to choose the read " | ||
773 | "method"); | ||
774 | mutex_unlock(&cam->fileop_mutex); | ||
775 | return -EINVAL; | ||
776 | } | ||
777 | |||
778 | if (cam->io == IO_NONE) { | ||
779 | if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) { | ||
780 | DBG(1, "read() failed, not enough memory"); | ||
781 | mutex_unlock(&cam->fileop_mutex); | ||
782 | return -ENOMEM; | ||
783 | } | ||
784 | cam->io = IO_READ; | ||
785 | cam->stream = STREAM_ON; | ||
786 | } | ||
787 | |||
788 | if (list_empty(&cam->inqueue)) { | ||
789 | if (!list_empty(&cam->outqueue)) | ||
790 | zc0301_empty_framequeues(cam); | ||
791 | zc0301_queue_unusedframes(cam); | ||
792 | } | ||
793 | |||
794 | if (!count) { | ||
795 | mutex_unlock(&cam->fileop_mutex); | ||
796 | return 0; | ||
797 | } | ||
798 | |||
799 | if (list_empty(&cam->outqueue)) { | ||
800 | if (filp->f_flags & O_NONBLOCK) { | ||
801 | mutex_unlock(&cam->fileop_mutex); | ||
802 | return -EAGAIN; | ||
803 | } | ||
804 | timeout = wait_event_interruptible_timeout | ||
805 | ( cam->wait_frame, | ||
806 | (!list_empty(&cam->outqueue)) || | ||
807 | (cam->state & DEV_DISCONNECTED) || | ||
808 | (cam->state & DEV_MISCONFIGURED), | ||
809 | cam->module_param.frame_timeout * | ||
810 | 1000 * msecs_to_jiffies(1) ); | ||
811 | if (timeout < 0) { | ||
812 | mutex_unlock(&cam->fileop_mutex); | ||
813 | return timeout; | ||
814 | } | ||
815 | if (cam->state & DEV_DISCONNECTED) { | ||
816 | mutex_unlock(&cam->fileop_mutex); | ||
817 | return -ENODEV; | ||
818 | } | ||
819 | if (!timeout || (cam->state & DEV_MISCONFIGURED)) { | ||
820 | mutex_unlock(&cam->fileop_mutex); | ||
821 | return -EIO; | ||
822 | } | ||
823 | } | ||
824 | |||
825 | f = list_entry(cam->outqueue.prev, struct zc0301_frame_t, frame); | ||
826 | |||
827 | if (count > f->buf.bytesused) | ||
828 | count = f->buf.bytesused; | ||
829 | |||
830 | if (copy_to_user(buf, f->bufmem, count)) { | ||
831 | err = -EFAULT; | ||
832 | goto exit; | ||
833 | } | ||
834 | *f_pos += count; | ||
835 | |||
836 | exit: | ||
837 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
838 | list_for_each_entry(i, &cam->outqueue, frame) | ||
839 | i->state = F_UNUSED; | ||
840 | INIT_LIST_HEAD(&cam->outqueue); | ||
841 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
842 | |||
843 | zc0301_queue_unusedframes(cam); | ||
844 | |||
845 | PDBGG("Frame #%lu, bytes read: %zu", | ||
846 | (unsigned long)f->buf.index, count); | ||
847 | |||
848 | mutex_unlock(&cam->fileop_mutex); | ||
849 | |||
850 | return err ? err : count; | ||
851 | } | ||
852 | |||
853 | |||
854 | static unsigned int zc0301_poll(struct file *filp, poll_table *wait) | ||
855 | { | ||
856 | struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); | ||
857 | struct zc0301_frame_t* f; | ||
858 | unsigned long lock_flags; | ||
859 | unsigned int mask = 0; | ||
860 | |||
861 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
862 | return POLLERR; | ||
863 | |||
864 | if (cam->state & DEV_DISCONNECTED) { | ||
865 | DBG(1, "Device not present"); | ||
866 | goto error; | ||
867 | } | ||
868 | |||
869 | if (cam->state & DEV_MISCONFIGURED) { | ||
870 | DBG(1, "The camera is misconfigured. Close and open it " | ||
871 | "again."); | ||
872 | goto error; | ||
873 | } | ||
874 | |||
875 | if (cam->io == IO_NONE) { | ||
876 | if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) { | ||
877 | DBG(1, "poll() failed, not enough memory"); | ||
878 | goto error; | ||
879 | } | ||
880 | cam->io = IO_READ; | ||
881 | cam->stream = STREAM_ON; | ||
882 | } | ||
883 | |||
884 | if (cam->io == IO_READ) { | ||
885 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
886 | list_for_each_entry(f, &cam->outqueue, frame) | ||
887 | f->state = F_UNUSED; | ||
888 | INIT_LIST_HEAD(&cam->outqueue); | ||
889 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
890 | zc0301_queue_unusedframes(cam); | ||
891 | } | ||
892 | |||
893 | poll_wait(filp, &cam->wait_frame, wait); | ||
894 | |||
895 | if (!list_empty(&cam->outqueue)) | ||
896 | mask |= POLLIN | POLLRDNORM; | ||
897 | |||
898 | mutex_unlock(&cam->fileop_mutex); | ||
899 | |||
900 | return mask; | ||
901 | |||
902 | error: | ||
903 | mutex_unlock(&cam->fileop_mutex); | ||
904 | return POLLERR; | ||
905 | } | ||
906 | |||
907 | |||
908 | static void zc0301_vm_open(struct vm_area_struct* vma) | ||
909 | { | ||
910 | struct zc0301_frame_t* f = vma->vm_private_data; | ||
911 | f->vma_use_count++; | ||
912 | } | ||
913 | |||
914 | |||
915 | static void zc0301_vm_close(struct vm_area_struct* vma) | ||
916 | { | ||
917 | /* NOTE: buffers are not freed here */ | ||
918 | struct zc0301_frame_t* f = vma->vm_private_data; | ||
919 | f->vma_use_count--; | ||
920 | } | ||
921 | |||
922 | |||
923 | static struct vm_operations_struct zc0301_vm_ops = { | ||
924 | .open = zc0301_vm_open, | ||
925 | .close = zc0301_vm_close, | ||
926 | }; | ||
927 | |||
928 | |||
929 | static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma) | ||
930 | { | ||
931 | struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); | ||
932 | unsigned long size = vma->vm_end - vma->vm_start, | ||
933 | start = vma->vm_start; | ||
934 | void *pos; | ||
935 | u32 i; | ||
936 | |||
937 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
938 | return -ERESTARTSYS; | ||
939 | |||
940 | if (cam->state & DEV_DISCONNECTED) { | ||
941 | DBG(1, "Device not present"); | ||
942 | mutex_unlock(&cam->fileop_mutex); | ||
943 | return -ENODEV; | ||
944 | } | ||
945 | |||
946 | if (cam->state & DEV_MISCONFIGURED) { | ||
947 | DBG(1, "The camera is misconfigured. Close and open it " | ||
948 | "again."); | ||
949 | mutex_unlock(&cam->fileop_mutex); | ||
950 | return -EIO; | ||
951 | } | ||
952 | |||
953 | if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || | ||
954 | size != PAGE_ALIGN(cam->frame[0].buf.length)) { | ||
955 | mutex_unlock(&cam->fileop_mutex); | ||
956 | return -EINVAL; | ||
957 | } | ||
958 | |||
959 | for (i = 0; i < cam->nbuffers; i++) { | ||
960 | if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) | ||
961 | break; | ||
962 | } | ||
963 | if (i == cam->nbuffers) { | ||
964 | mutex_unlock(&cam->fileop_mutex); | ||
965 | return -EINVAL; | ||
966 | } | ||
967 | |||
968 | vma->vm_flags |= VM_IO; | ||
969 | vma->vm_flags |= VM_RESERVED; | ||
970 | |||
971 | pos = cam->frame[i].bufmem; | ||
972 | while (size > 0) { /* size is page-aligned */ | ||
973 | if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { | ||
974 | mutex_unlock(&cam->fileop_mutex); | ||
975 | return -EAGAIN; | ||
976 | } | ||
977 | start += PAGE_SIZE; | ||
978 | pos += PAGE_SIZE; | ||
979 | size -= PAGE_SIZE; | ||
980 | } | ||
981 | |||
982 | vma->vm_ops = &zc0301_vm_ops; | ||
983 | vma->vm_private_data = &cam->frame[i]; | ||
984 | |||
985 | zc0301_vm_open(vma); | ||
986 | |||
987 | mutex_unlock(&cam->fileop_mutex); | ||
988 | |||
989 | return 0; | ||
990 | } | ||
991 | |||
992 | /*****************************************************************************/ | ||
993 | |||
994 | static int | ||
995 | zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg) | ||
996 | { | ||
997 | struct v4l2_capability cap = { | ||
998 | .driver = "zc0301", | ||
999 | .version = ZC0301_MODULE_VERSION_CODE, | ||
1000 | .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | | ||
1001 | V4L2_CAP_STREAMING, | ||
1002 | }; | ||
1003 | |||
1004 | strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); | ||
1005 | if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) | ||
1006 | strlcpy(cap.bus_info, cam->usbdev->dev.bus_id, | ||
1007 | sizeof(cap.bus_info)); | ||
1008 | |||
1009 | if (copy_to_user(arg, &cap, sizeof(cap))) | ||
1010 | return -EFAULT; | ||
1011 | |||
1012 | return 0; | ||
1013 | } | ||
1014 | |||
1015 | |||
1016 | static int | ||
1017 | zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg) | ||
1018 | { | ||
1019 | struct v4l2_input i; | ||
1020 | |||
1021 | if (copy_from_user(&i, arg, sizeof(i))) | ||
1022 | return -EFAULT; | ||
1023 | |||
1024 | if (i.index) | ||
1025 | return -EINVAL; | ||
1026 | |||
1027 | memset(&i, 0, sizeof(i)); | ||
1028 | strcpy(i.name, "Camera"); | ||
1029 | i.type = V4L2_INPUT_TYPE_CAMERA; | ||
1030 | |||
1031 | if (copy_to_user(arg, &i, sizeof(i))) | ||
1032 | return -EFAULT; | ||
1033 | |||
1034 | return 0; | ||
1035 | } | ||
1036 | |||
1037 | |||
1038 | static int | ||
1039 | zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg) | ||
1040 | { | ||
1041 | int index = 0; | ||
1042 | |||
1043 | if (copy_to_user(arg, &index, sizeof(index))) | ||
1044 | return -EFAULT; | ||
1045 | |||
1046 | return 0; | ||
1047 | } | ||
1048 | |||
1049 | |||
1050 | static int | ||
1051 | zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg) | ||
1052 | { | ||
1053 | int index; | ||
1054 | |||
1055 | if (copy_from_user(&index, arg, sizeof(index))) | ||
1056 | return -EFAULT; | ||
1057 | |||
1058 | if (index != 0) | ||
1059 | return -EINVAL; | ||
1060 | |||
1061 | return 0; | ||
1062 | } | ||
1063 | |||
1064 | |||
1065 | static int | ||
1066 | zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg) | ||
1067 | { | ||
1068 | struct zc0301_sensor* s = &cam->sensor; | ||
1069 | struct v4l2_queryctrl qc; | ||
1070 | u8 i; | ||
1071 | |||
1072 | if (copy_from_user(&qc, arg, sizeof(qc))) | ||
1073 | return -EFAULT; | ||
1074 | |||
1075 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
1076 | if (qc.id && qc.id == s->qctrl[i].id) { | ||
1077 | memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); | ||
1078 | if (copy_to_user(arg, &qc, sizeof(qc))) | ||
1079 | return -EFAULT; | ||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | return -EINVAL; | ||
1084 | } | ||
1085 | |||
1086 | |||
1087 | static int | ||
1088 | zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg) | ||
1089 | { | ||
1090 | struct zc0301_sensor* s = &cam->sensor; | ||
1091 | struct v4l2_control ctrl; | ||
1092 | int err = 0; | ||
1093 | u8 i; | ||
1094 | |||
1095 | if (!s->get_ctrl && !s->set_ctrl) | ||
1096 | return -EINVAL; | ||
1097 | |||
1098 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
1099 | return -EFAULT; | ||
1100 | |||
1101 | if (!s->get_ctrl) { | ||
1102 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
1103 | if (ctrl.id == s->qctrl[i].id) { | ||
1104 | ctrl.value = s->_qctrl[i].default_value; | ||
1105 | goto exit; | ||
1106 | } | ||
1107 | return -EINVAL; | ||
1108 | } else | ||
1109 | err = s->get_ctrl(cam, &ctrl); | ||
1110 | |||
1111 | exit: | ||
1112 | if (copy_to_user(arg, &ctrl, sizeof(ctrl))) | ||
1113 | return -EFAULT; | ||
1114 | |||
1115 | return err; | ||
1116 | } | ||
1117 | |||
1118 | |||
1119 | static int | ||
1120 | zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg) | ||
1121 | { | ||
1122 | struct zc0301_sensor* s = &cam->sensor; | ||
1123 | struct v4l2_control ctrl; | ||
1124 | u8 i; | ||
1125 | int err = 0; | ||
1126 | |||
1127 | if (!s->set_ctrl) | ||
1128 | return -EINVAL; | ||
1129 | |||
1130 | if (copy_from_user(&ctrl, arg, sizeof(ctrl))) | ||
1131 | return -EFAULT; | ||
1132 | |||
1133 | for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) | ||
1134 | if (ctrl.id == s->qctrl[i].id) { | ||
1135 | if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) | ||
1136 | return -EINVAL; | ||
1137 | if (ctrl.value < s->qctrl[i].minimum || | ||
1138 | ctrl.value > s->qctrl[i].maximum) | ||
1139 | return -ERANGE; | ||
1140 | ctrl.value -= ctrl.value % s->qctrl[i].step; | ||
1141 | break; | ||
1142 | } | ||
1143 | |||
1144 | if ((err = s->set_ctrl(cam, &ctrl))) | ||
1145 | return err; | ||
1146 | |||
1147 | s->_qctrl[i].default_value = ctrl.value; | ||
1148 | |||
1149 | return 0; | ||
1150 | } | ||
1151 | |||
1152 | |||
1153 | static int | ||
1154 | zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg) | ||
1155 | { | ||
1156 | struct v4l2_cropcap* cc = &(cam->sensor.cropcap); | ||
1157 | |||
1158 | cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1159 | cc->pixelaspect.numerator = 1; | ||
1160 | cc->pixelaspect.denominator = 1; | ||
1161 | |||
1162 | if (copy_to_user(arg, cc, sizeof(*cc))) | ||
1163 | return -EFAULT; | ||
1164 | |||
1165 | return 0; | ||
1166 | } | ||
1167 | |||
1168 | |||
1169 | static int | ||
1170 | zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg) | ||
1171 | { | ||
1172 | struct zc0301_sensor* s = &cam->sensor; | ||
1173 | struct v4l2_crop crop = { | ||
1174 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
1175 | }; | ||
1176 | |||
1177 | memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); | ||
1178 | |||
1179 | if (copy_to_user(arg, &crop, sizeof(crop))) | ||
1180 | return -EFAULT; | ||
1181 | |||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1185 | |||
1186 | static int | ||
1187 | zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg) | ||
1188 | { | ||
1189 | struct zc0301_sensor* s = &cam->sensor; | ||
1190 | struct v4l2_crop crop; | ||
1191 | struct v4l2_rect* rect; | ||
1192 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
1193 | const enum zc0301_stream_state stream = cam->stream; | ||
1194 | const u32 nbuffers = cam->nbuffers; | ||
1195 | u32 i; | ||
1196 | int err = 0; | ||
1197 | |||
1198 | if (copy_from_user(&crop, arg, sizeof(crop))) | ||
1199 | return -EFAULT; | ||
1200 | |||
1201 | rect = &(crop.c); | ||
1202 | |||
1203 | if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1204 | return -EINVAL; | ||
1205 | |||
1206 | if (cam->module_param.force_munmap) | ||
1207 | for (i = 0; i < cam->nbuffers; i++) | ||
1208 | if (cam->frame[i].vma_use_count) { | ||
1209 | DBG(3, "VIDIOC_S_CROP failed. " | ||
1210 | "Unmap the buffers first."); | ||
1211 | return -EINVAL; | ||
1212 | } | ||
1213 | |||
1214 | if (!s->set_crop) { | ||
1215 | memcpy(rect, &(s->_rect), sizeof(*rect)); | ||
1216 | if (copy_to_user(arg, &crop, sizeof(crop))) | ||
1217 | return -EFAULT; | ||
1218 | return 0; | ||
1219 | } | ||
1220 | |||
1221 | rect->left &= ~7L; | ||
1222 | rect->top &= ~7L; | ||
1223 | if (rect->width < 8) | ||
1224 | rect->width = 8; | ||
1225 | if (rect->height < 8) | ||
1226 | rect->height = 8; | ||
1227 | if (rect->width > bounds->width) | ||
1228 | rect->width = bounds->width; | ||
1229 | if (rect->height > bounds->height) | ||
1230 | rect->height = bounds->height; | ||
1231 | if (rect->left < bounds->left) | ||
1232 | rect->left = bounds->left; | ||
1233 | if (rect->top < bounds->top) | ||
1234 | rect->top = bounds->top; | ||
1235 | if (rect->left + rect->width > bounds->left + bounds->width) | ||
1236 | rect->left = bounds->left+bounds->width - rect->width; | ||
1237 | if (rect->top + rect->height > bounds->top + bounds->height) | ||
1238 | rect->top = bounds->top+bounds->height - rect->height; | ||
1239 | rect->width &= ~7L; | ||
1240 | rect->height &= ~7L; | ||
1241 | |||
1242 | if (cam->stream == STREAM_ON) | ||
1243 | if ((err = zc0301_stream_interrupt(cam))) | ||
1244 | return err; | ||
1245 | |||
1246 | if (copy_to_user(arg, &crop, sizeof(crop))) { | ||
1247 | cam->stream = stream; | ||
1248 | return -EFAULT; | ||
1249 | } | ||
1250 | |||
1251 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
1252 | zc0301_release_buffers(cam); | ||
1253 | |||
1254 | if (s->set_crop) | ||
1255 | err += s->set_crop(cam, rect); | ||
1256 | |||
1257 | if (err) { /* atomic, no rollback in ioctl() */ | ||
1258 | cam->state |= DEV_MISCONFIGURED; | ||
1259 | DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " | ||
1260 | "use the camera, close and open /dev/video%d again.", | ||
1261 | cam->v4ldev->minor); | ||
1262 | return -EIO; | ||
1263 | } | ||
1264 | |||
1265 | s->pix_format.width = rect->width; | ||
1266 | s->pix_format.height = rect->height; | ||
1267 | memcpy(&(s->_rect), rect, sizeof(*rect)); | ||
1268 | |||
1269 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
1270 | nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) { | ||
1271 | cam->state |= DEV_MISCONFIGURED; | ||
1272 | DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " | ||
1273 | "use the camera, close and open /dev/video%d again.", | ||
1274 | cam->v4ldev->minor); | ||
1275 | return -ENOMEM; | ||
1276 | } | ||
1277 | |||
1278 | if (cam->io == IO_READ) | ||
1279 | zc0301_empty_framequeues(cam); | ||
1280 | else if (cam->module_param.force_munmap) | ||
1281 | zc0301_requeue_outqueue(cam); | ||
1282 | |||
1283 | cam->stream = stream; | ||
1284 | |||
1285 | return 0; | ||
1286 | } | ||
1287 | |||
1288 | |||
1289 | static int | ||
1290 | zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg) | ||
1291 | { | ||
1292 | struct v4l2_fmtdesc fmtd; | ||
1293 | |||
1294 | if (copy_from_user(&fmtd, arg, sizeof(fmtd))) | ||
1295 | return -EFAULT; | ||
1296 | |||
1297 | if (fmtd.index == 0) { | ||
1298 | strcpy(fmtd.description, "JPEG"); | ||
1299 | fmtd.pixelformat = V4L2_PIX_FMT_JPEG; | ||
1300 | fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; | ||
1301 | } else | ||
1302 | return -EINVAL; | ||
1303 | |||
1304 | fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1305 | memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); | ||
1306 | |||
1307 | if (copy_to_user(arg, &fmtd, sizeof(fmtd))) | ||
1308 | return -EFAULT; | ||
1309 | |||
1310 | return 0; | ||
1311 | } | ||
1312 | |||
1313 | |||
1314 | static int | ||
1315 | zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg) | ||
1316 | { | ||
1317 | struct v4l2_format format; | ||
1318 | struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); | ||
1319 | |||
1320 | if (copy_from_user(&format, arg, sizeof(format))) | ||
1321 | return -EFAULT; | ||
1322 | |||
1323 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1324 | return -EINVAL; | ||
1325 | |||
1326 | pfmt->bytesperline = 0; | ||
1327 | pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); | ||
1328 | pfmt->field = V4L2_FIELD_NONE; | ||
1329 | memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); | ||
1330 | |||
1331 | if (copy_to_user(arg, &format, sizeof(format))) | ||
1332 | return -EFAULT; | ||
1333 | |||
1334 | return 0; | ||
1335 | } | ||
1336 | |||
1337 | |||
1338 | static int | ||
1339 | zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd, | ||
1340 | void __user * arg) | ||
1341 | { | ||
1342 | struct zc0301_sensor* s = &cam->sensor; | ||
1343 | struct v4l2_format format; | ||
1344 | struct v4l2_pix_format* pix; | ||
1345 | struct v4l2_pix_format* pfmt = &(s->pix_format); | ||
1346 | struct v4l2_rect* bounds = &(s->cropcap.bounds); | ||
1347 | struct v4l2_rect rect; | ||
1348 | const enum zc0301_stream_state stream = cam->stream; | ||
1349 | const u32 nbuffers = cam->nbuffers; | ||
1350 | u32 i; | ||
1351 | int err = 0; | ||
1352 | |||
1353 | if (copy_from_user(&format, arg, sizeof(format))) | ||
1354 | return -EFAULT; | ||
1355 | |||
1356 | pix = &(format.fmt.pix); | ||
1357 | |||
1358 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1359 | return -EINVAL; | ||
1360 | |||
1361 | memcpy(&rect, &(s->_rect), sizeof(rect)); | ||
1362 | |||
1363 | if (!s->set_crop) { | ||
1364 | pix->width = rect.width; | ||
1365 | pix->height = rect.height; | ||
1366 | } else { | ||
1367 | rect.width = pix->width; | ||
1368 | rect.height = pix->height; | ||
1369 | } | ||
1370 | |||
1371 | if (rect.width < 8) | ||
1372 | rect.width = 8; | ||
1373 | if (rect.height < 8) | ||
1374 | rect.height = 8; | ||
1375 | if (rect.width > bounds->left + bounds->width - rect.left) | ||
1376 | rect.width = bounds->left + bounds->width - rect.left; | ||
1377 | if (rect.height > bounds->top + bounds->height - rect.top) | ||
1378 | rect.height = bounds->top + bounds->height - rect.top; | ||
1379 | rect.width &= ~7L; | ||
1380 | rect.height &= ~7L; | ||
1381 | |||
1382 | pix->width = rect.width; | ||
1383 | pix->height = rect.height; | ||
1384 | pix->pixelformat = pfmt->pixelformat; | ||
1385 | pix->priv = pfmt->priv; | ||
1386 | pix->colorspace = pfmt->colorspace; | ||
1387 | pix->bytesperline = 0; | ||
1388 | pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); | ||
1389 | pix->field = V4L2_FIELD_NONE; | ||
1390 | |||
1391 | if (cmd == VIDIOC_TRY_FMT) { | ||
1392 | if (copy_to_user(arg, &format, sizeof(format))) | ||
1393 | return -EFAULT; | ||
1394 | return 0; | ||
1395 | } | ||
1396 | |||
1397 | if (cam->module_param.force_munmap) | ||
1398 | for (i = 0; i < cam->nbuffers; i++) | ||
1399 | if (cam->frame[i].vma_use_count) { | ||
1400 | DBG(3, "VIDIOC_S_FMT failed. " | ||
1401 | "Unmap the buffers first."); | ||
1402 | return -EINVAL; | ||
1403 | } | ||
1404 | |||
1405 | if (cam->stream == STREAM_ON) | ||
1406 | if ((err = zc0301_stream_interrupt(cam))) | ||
1407 | return err; | ||
1408 | |||
1409 | if (copy_to_user(arg, &format, sizeof(format))) { | ||
1410 | cam->stream = stream; | ||
1411 | return -EFAULT; | ||
1412 | } | ||
1413 | |||
1414 | if (cam->module_param.force_munmap || cam->io == IO_READ) | ||
1415 | zc0301_release_buffers(cam); | ||
1416 | |||
1417 | if (s->set_crop) | ||
1418 | err += s->set_crop(cam, &rect); | ||
1419 | |||
1420 | if (err) { /* atomic, no rollback in ioctl() */ | ||
1421 | cam->state |= DEV_MISCONFIGURED; | ||
1422 | DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " | ||
1423 | "use the camera, close and open /dev/video%d again.", | ||
1424 | cam->v4ldev->minor); | ||
1425 | return -EIO; | ||
1426 | } | ||
1427 | |||
1428 | memcpy(pfmt, pix, sizeof(*pix)); | ||
1429 | memcpy(&(s->_rect), &rect, sizeof(rect)); | ||
1430 | |||
1431 | if ((cam->module_param.force_munmap || cam->io == IO_READ) && | ||
1432 | nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) { | ||
1433 | cam->state |= DEV_MISCONFIGURED; | ||
1434 | DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " | ||
1435 | "use the camera, close and open /dev/video%d again.", | ||
1436 | cam->v4ldev->minor); | ||
1437 | return -ENOMEM; | ||
1438 | } | ||
1439 | |||
1440 | if (cam->io == IO_READ) | ||
1441 | zc0301_empty_framequeues(cam); | ||
1442 | else if (cam->module_param.force_munmap) | ||
1443 | zc0301_requeue_outqueue(cam); | ||
1444 | |||
1445 | cam->stream = stream; | ||
1446 | |||
1447 | return 0; | ||
1448 | } | ||
1449 | |||
1450 | |||
1451 | static int | ||
1452 | zc0301_vidioc_g_jpegcomp(struct zc0301_device* cam, void __user * arg) | ||
1453 | { | ||
1454 | if (copy_to_user(arg, &cam->compression, sizeof(cam->compression))) | ||
1455 | return -EFAULT; | ||
1456 | |||
1457 | return 0; | ||
1458 | } | ||
1459 | |||
1460 | |||
1461 | static int | ||
1462 | zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg) | ||
1463 | { | ||
1464 | struct v4l2_jpegcompression jc; | ||
1465 | const enum zc0301_stream_state stream = cam->stream; | ||
1466 | int err = 0; | ||
1467 | |||
1468 | if (copy_from_user(&jc, arg, sizeof(jc))) | ||
1469 | return -EFAULT; | ||
1470 | |||
1471 | if (jc.quality != 0) | ||
1472 | return -EINVAL; | ||
1473 | |||
1474 | if (cam->stream == STREAM_ON) | ||
1475 | if ((err = zc0301_stream_interrupt(cam))) | ||
1476 | return err; | ||
1477 | |||
1478 | err += zc0301_set_compression(cam, &jc); | ||
1479 | if (err) { /* atomic, no rollback in ioctl() */ | ||
1480 | cam->state |= DEV_MISCONFIGURED; | ||
1481 | DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " | ||
1482 | "problems. To use the camera, close and open " | ||
1483 | "/dev/video%d again.", cam->v4ldev->minor); | ||
1484 | return -EIO; | ||
1485 | } | ||
1486 | |||
1487 | cam->compression.quality = jc.quality; | ||
1488 | |||
1489 | cam->stream = stream; | ||
1490 | |||
1491 | return 0; | ||
1492 | } | ||
1493 | |||
1494 | |||
1495 | static int | ||
1496 | zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg) | ||
1497 | { | ||
1498 | struct v4l2_requestbuffers rb; | ||
1499 | u32 i; | ||
1500 | int err; | ||
1501 | |||
1502 | if (copy_from_user(&rb, arg, sizeof(rb))) | ||
1503 | return -EFAULT; | ||
1504 | |||
1505 | if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
1506 | rb.memory != V4L2_MEMORY_MMAP) | ||
1507 | return -EINVAL; | ||
1508 | |||
1509 | if (cam->io == IO_READ) { | ||
1510 | DBG(3, "Close and open the device again to choose the mmap " | ||
1511 | "I/O method"); | ||
1512 | return -EINVAL; | ||
1513 | } | ||
1514 | |||
1515 | for (i = 0; i < cam->nbuffers; i++) | ||
1516 | if (cam->frame[i].vma_use_count) { | ||
1517 | DBG(3, "VIDIOC_REQBUFS failed. " | ||
1518 | "Previous buffers are still mapped."); | ||
1519 | return -EINVAL; | ||
1520 | } | ||
1521 | |||
1522 | if (cam->stream == STREAM_ON) | ||
1523 | if ((err = zc0301_stream_interrupt(cam))) | ||
1524 | return err; | ||
1525 | |||
1526 | zc0301_empty_framequeues(cam); | ||
1527 | |||
1528 | zc0301_release_buffers(cam); | ||
1529 | if (rb.count) | ||
1530 | rb.count = zc0301_request_buffers(cam, rb.count, IO_MMAP); | ||
1531 | |||
1532 | if (copy_to_user(arg, &rb, sizeof(rb))) { | ||
1533 | zc0301_release_buffers(cam); | ||
1534 | cam->io = IO_NONE; | ||
1535 | return -EFAULT; | ||
1536 | } | ||
1537 | |||
1538 | cam->io = rb.count ? IO_MMAP : IO_NONE; | ||
1539 | |||
1540 | return 0; | ||
1541 | } | ||
1542 | |||
1543 | |||
1544 | static int | ||
1545 | zc0301_vidioc_querybuf(struct zc0301_device* cam, void __user * arg) | ||
1546 | { | ||
1547 | struct v4l2_buffer b; | ||
1548 | |||
1549 | if (copy_from_user(&b, arg, sizeof(b))) | ||
1550 | return -EFAULT; | ||
1551 | |||
1552 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
1553 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
1554 | return -EINVAL; | ||
1555 | |||
1556 | memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); | ||
1557 | |||
1558 | if (cam->frame[b.index].vma_use_count) | ||
1559 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
1560 | |||
1561 | if (cam->frame[b.index].state == F_DONE) | ||
1562 | b.flags |= V4L2_BUF_FLAG_DONE; | ||
1563 | else if (cam->frame[b.index].state != F_UNUSED) | ||
1564 | b.flags |= V4L2_BUF_FLAG_QUEUED; | ||
1565 | |||
1566 | if (copy_to_user(arg, &b, sizeof(b))) | ||
1567 | return -EFAULT; | ||
1568 | |||
1569 | return 0; | ||
1570 | } | ||
1571 | |||
1572 | |||
1573 | static int | ||
1574 | zc0301_vidioc_qbuf(struct zc0301_device* cam, void __user * arg) | ||
1575 | { | ||
1576 | struct v4l2_buffer b; | ||
1577 | unsigned long lock_flags; | ||
1578 | |||
1579 | if (copy_from_user(&b, arg, sizeof(b))) | ||
1580 | return -EFAULT; | ||
1581 | |||
1582 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
1583 | b.index >= cam->nbuffers || cam->io != IO_MMAP) | ||
1584 | return -EINVAL; | ||
1585 | |||
1586 | if (cam->frame[b.index].state != F_UNUSED) | ||
1587 | return -EINVAL; | ||
1588 | |||
1589 | cam->frame[b.index].state = F_QUEUED; | ||
1590 | |||
1591 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
1592 | list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); | ||
1593 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
1594 | |||
1595 | PDBGG("Frame #%lu queued", (unsigned long)b.index); | ||
1596 | |||
1597 | return 0; | ||
1598 | } | ||
1599 | |||
1600 | |||
1601 | static int | ||
1602 | zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp, | ||
1603 | void __user * arg) | ||
1604 | { | ||
1605 | struct v4l2_buffer b; | ||
1606 | struct zc0301_frame_t *f; | ||
1607 | unsigned long lock_flags; | ||
1608 | long timeout; | ||
1609 | |||
1610 | if (copy_from_user(&b, arg, sizeof(b))) | ||
1611 | return -EFAULT; | ||
1612 | |||
1613 | if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP) | ||
1614 | return -EINVAL; | ||
1615 | |||
1616 | if (list_empty(&cam->outqueue)) { | ||
1617 | if (cam->stream == STREAM_OFF) | ||
1618 | return -EINVAL; | ||
1619 | if (filp->f_flags & O_NONBLOCK) | ||
1620 | return -EAGAIN; | ||
1621 | timeout = wait_event_interruptible_timeout | ||
1622 | ( cam->wait_frame, | ||
1623 | (!list_empty(&cam->outqueue)) || | ||
1624 | (cam->state & DEV_DISCONNECTED) || | ||
1625 | (cam->state & DEV_MISCONFIGURED), | ||
1626 | cam->module_param.frame_timeout * | ||
1627 | 1000 * msecs_to_jiffies(1) ); | ||
1628 | if (timeout < 0) | ||
1629 | return timeout; | ||
1630 | if (cam->state & DEV_DISCONNECTED) | ||
1631 | return -ENODEV; | ||
1632 | if (!timeout || (cam->state & DEV_MISCONFIGURED)) | ||
1633 | return -EIO; | ||
1634 | } | ||
1635 | |||
1636 | spin_lock_irqsave(&cam->queue_lock, lock_flags); | ||
1637 | f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame); | ||
1638 | list_del(cam->outqueue.next); | ||
1639 | spin_unlock_irqrestore(&cam->queue_lock, lock_flags); | ||
1640 | |||
1641 | f->state = F_UNUSED; | ||
1642 | |||
1643 | memcpy(&b, &f->buf, sizeof(b)); | ||
1644 | if (f->vma_use_count) | ||
1645 | b.flags |= V4L2_BUF_FLAG_MAPPED; | ||
1646 | |||
1647 | if (copy_to_user(arg, &b, sizeof(b))) | ||
1648 | return -EFAULT; | ||
1649 | |||
1650 | PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); | ||
1651 | |||
1652 | return 0; | ||
1653 | } | ||
1654 | |||
1655 | |||
1656 | static int | ||
1657 | zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg) | ||
1658 | { | ||
1659 | int type; | ||
1660 | |||
1661 | if (copy_from_user(&type, arg, sizeof(type))) | ||
1662 | return -EFAULT; | ||
1663 | |||
1664 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
1665 | return -EINVAL; | ||
1666 | |||
1667 | if (list_empty(&cam->inqueue)) | ||
1668 | return -EINVAL; | ||
1669 | |||
1670 | cam->stream = STREAM_ON; | ||
1671 | |||
1672 | DBG(3, "Stream on"); | ||
1673 | |||
1674 | return 0; | ||
1675 | } | ||
1676 | |||
1677 | |||
1678 | static int | ||
1679 | zc0301_vidioc_streamoff(struct zc0301_device* cam, void __user * arg) | ||
1680 | { | ||
1681 | int type, err; | ||
1682 | |||
1683 | if (copy_from_user(&type, arg, sizeof(type))) | ||
1684 | return -EFAULT; | ||
1685 | |||
1686 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | ||
1687 | return -EINVAL; | ||
1688 | |||
1689 | if (cam->stream == STREAM_ON) | ||
1690 | if ((err = zc0301_stream_interrupt(cam))) | ||
1691 | return err; | ||
1692 | |||
1693 | zc0301_empty_framequeues(cam); | ||
1694 | |||
1695 | DBG(3, "Stream off"); | ||
1696 | |||
1697 | return 0; | ||
1698 | } | ||
1699 | |||
1700 | |||
1701 | static int | ||
1702 | zc0301_vidioc_g_parm(struct zc0301_device* cam, void __user * arg) | ||
1703 | { | ||
1704 | struct v4l2_streamparm sp; | ||
1705 | |||
1706 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
1707 | return -EFAULT; | ||
1708 | |||
1709 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1710 | return -EINVAL; | ||
1711 | |||
1712 | sp.parm.capture.extendedmode = 0; | ||
1713 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
1714 | |||
1715 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
1716 | return -EFAULT; | ||
1717 | |||
1718 | return 0; | ||
1719 | } | ||
1720 | |||
1721 | |||
1722 | static int | ||
1723 | zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg) | ||
1724 | { | ||
1725 | struct v4l2_streamparm sp; | ||
1726 | |||
1727 | if (copy_from_user(&sp, arg, sizeof(sp))) | ||
1728 | return -EFAULT; | ||
1729 | |||
1730 | if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1731 | return -EINVAL; | ||
1732 | |||
1733 | sp.parm.capture.extendedmode = 0; | ||
1734 | |||
1735 | if (sp.parm.capture.readbuffers == 0) | ||
1736 | sp.parm.capture.readbuffers = cam->nreadbuffers; | ||
1737 | |||
1738 | if (sp.parm.capture.readbuffers > ZC0301_MAX_FRAMES) | ||
1739 | sp.parm.capture.readbuffers = ZC0301_MAX_FRAMES; | ||
1740 | |||
1741 | if (copy_to_user(arg, &sp, sizeof(sp))) | ||
1742 | return -EFAULT; | ||
1743 | |||
1744 | cam->nreadbuffers = sp.parm.capture.readbuffers; | ||
1745 | |||
1746 | return 0; | ||
1747 | } | ||
1748 | |||
1749 | |||
1750 | static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp, | ||
1751 | unsigned int cmd, void __user * arg) | ||
1752 | { | ||
1753 | struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1754 | |||
1755 | switch (cmd) { | ||
1756 | |||
1757 | case VIDIOC_QUERYCAP: | ||
1758 | return zc0301_vidioc_querycap(cam, arg); | ||
1759 | |||
1760 | case VIDIOC_ENUMINPUT: | ||
1761 | return zc0301_vidioc_enuminput(cam, arg); | ||
1762 | |||
1763 | case VIDIOC_G_INPUT: | ||
1764 | return zc0301_vidioc_g_input(cam, arg); | ||
1765 | |||
1766 | case VIDIOC_S_INPUT: | ||
1767 | return zc0301_vidioc_s_input(cam, arg); | ||
1768 | |||
1769 | case VIDIOC_QUERYCTRL: | ||
1770 | return zc0301_vidioc_query_ctrl(cam, arg); | ||
1771 | |||
1772 | case VIDIOC_G_CTRL: | ||
1773 | return zc0301_vidioc_g_ctrl(cam, arg); | ||
1774 | |||
1775 | case VIDIOC_S_CTRL_OLD: | ||
1776 | case VIDIOC_S_CTRL: | ||
1777 | return zc0301_vidioc_s_ctrl(cam, arg); | ||
1778 | |||
1779 | case VIDIOC_CROPCAP_OLD: | ||
1780 | case VIDIOC_CROPCAP: | ||
1781 | return zc0301_vidioc_cropcap(cam, arg); | ||
1782 | |||
1783 | case VIDIOC_G_CROP: | ||
1784 | return zc0301_vidioc_g_crop(cam, arg); | ||
1785 | |||
1786 | case VIDIOC_S_CROP: | ||
1787 | return zc0301_vidioc_s_crop(cam, arg); | ||
1788 | |||
1789 | case VIDIOC_ENUM_FMT: | ||
1790 | return zc0301_vidioc_enum_fmt(cam, arg); | ||
1791 | |||
1792 | case VIDIOC_G_FMT: | ||
1793 | return zc0301_vidioc_g_fmt(cam, arg); | ||
1794 | |||
1795 | case VIDIOC_TRY_FMT: | ||
1796 | case VIDIOC_S_FMT: | ||
1797 | return zc0301_vidioc_try_s_fmt(cam, cmd, arg); | ||
1798 | |||
1799 | case VIDIOC_G_JPEGCOMP: | ||
1800 | return zc0301_vidioc_g_jpegcomp(cam, arg); | ||
1801 | |||
1802 | case VIDIOC_S_JPEGCOMP: | ||
1803 | return zc0301_vidioc_s_jpegcomp(cam, arg); | ||
1804 | |||
1805 | case VIDIOC_REQBUFS: | ||
1806 | return zc0301_vidioc_reqbufs(cam, arg); | ||
1807 | |||
1808 | case VIDIOC_QUERYBUF: | ||
1809 | return zc0301_vidioc_querybuf(cam, arg); | ||
1810 | |||
1811 | case VIDIOC_QBUF: | ||
1812 | return zc0301_vidioc_qbuf(cam, arg); | ||
1813 | |||
1814 | case VIDIOC_DQBUF: | ||
1815 | return zc0301_vidioc_dqbuf(cam, filp, arg); | ||
1816 | |||
1817 | case VIDIOC_STREAMON: | ||
1818 | return zc0301_vidioc_streamon(cam, arg); | ||
1819 | |||
1820 | case VIDIOC_STREAMOFF: | ||
1821 | return zc0301_vidioc_streamoff(cam, arg); | ||
1822 | |||
1823 | case VIDIOC_G_PARM: | ||
1824 | return zc0301_vidioc_g_parm(cam, arg); | ||
1825 | |||
1826 | case VIDIOC_S_PARM_OLD: | ||
1827 | case VIDIOC_S_PARM: | ||
1828 | return zc0301_vidioc_s_parm(cam, arg); | ||
1829 | |||
1830 | case VIDIOC_G_STD: | ||
1831 | case VIDIOC_S_STD: | ||
1832 | case VIDIOC_QUERYSTD: | ||
1833 | case VIDIOC_ENUMSTD: | ||
1834 | case VIDIOC_QUERYMENU: | ||
1835 | return -EINVAL; | ||
1836 | |||
1837 | default: | ||
1838 | return -EINVAL; | ||
1839 | |||
1840 | } | ||
1841 | } | ||
1842 | |||
1843 | |||
1844 | static int zc0301_ioctl(struct inode* inode, struct file* filp, | ||
1845 | unsigned int cmd, unsigned long arg) | ||
1846 | { | ||
1847 | struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); | ||
1848 | int err = 0; | ||
1849 | |||
1850 | if (mutex_lock_interruptible(&cam->fileop_mutex)) | ||
1851 | return -ERESTARTSYS; | ||
1852 | |||
1853 | if (cam->state & DEV_DISCONNECTED) { | ||
1854 | DBG(1, "Device not present"); | ||
1855 | mutex_unlock(&cam->fileop_mutex); | ||
1856 | return -ENODEV; | ||
1857 | } | ||
1858 | |||
1859 | if (cam->state & DEV_MISCONFIGURED) { | ||
1860 | DBG(1, "The camera is misconfigured. Close and open it " | ||
1861 | "again."); | ||
1862 | mutex_unlock(&cam->fileop_mutex); | ||
1863 | return -EIO; | ||
1864 | } | ||
1865 | |||
1866 | V4LDBG(3, "zc0301", cmd); | ||
1867 | |||
1868 | err = zc0301_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); | ||
1869 | |||
1870 | mutex_unlock(&cam->fileop_mutex); | ||
1871 | |||
1872 | return err; | ||
1873 | } | ||
1874 | |||
1875 | |||
1876 | static struct file_operations zc0301_fops = { | ||
1877 | .owner = THIS_MODULE, | ||
1878 | .open = zc0301_open, | ||
1879 | .release = zc0301_release, | ||
1880 | .ioctl = zc0301_ioctl, | ||
1881 | .read = zc0301_read, | ||
1882 | .poll = zc0301_poll, | ||
1883 | .mmap = zc0301_mmap, | ||
1884 | .llseek = no_llseek, | ||
1885 | }; | ||
1886 | |||
1887 | /*****************************************************************************/ | ||
1888 | |||
1889 | static int | ||
1890 | zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | ||
1891 | { | ||
1892 | struct usb_device *udev = interface_to_usbdev(intf); | ||
1893 | struct zc0301_device* cam; | ||
1894 | static unsigned int dev_nr = 0; | ||
1895 | unsigned int i; | ||
1896 | int err = 0; | ||
1897 | |||
1898 | if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL))) | ||
1899 | return -ENOMEM; | ||
1900 | |||
1901 | cam->usbdev = udev; | ||
1902 | |||
1903 | if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL))) { | ||
1904 | DBG(1, "kmalloc() failed"); | ||
1905 | err = -ENOMEM; | ||
1906 | goto fail; | ||
1907 | } | ||
1908 | |||
1909 | if (!(cam->v4ldev = video_device_alloc())) { | ||
1910 | DBG(1, "video_device_alloc() failed"); | ||
1911 | err = -ENOMEM; | ||
1912 | goto fail; | ||
1913 | } | ||
1914 | |||
1915 | mutex_init(&cam->dev_mutex); | ||
1916 | |||
1917 | DBG(2, "ZC0301 Image Processor and Control Chip detected " | ||
1918 | "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct); | ||
1919 | |||
1920 | for (i = 0; zc0301_sensor_table[i]; i++) { | ||
1921 | err = zc0301_sensor_table[i](cam); | ||
1922 | if (!err) | ||
1923 | break; | ||
1924 | } | ||
1925 | |||
1926 | if (!err) | ||
1927 | DBG(2, "%s image sensor detected", cam->sensor.name); | ||
1928 | else { | ||
1929 | DBG(1, "No supported image sensor detected"); | ||
1930 | err = -ENODEV; | ||
1931 | goto fail; | ||
1932 | } | ||
1933 | |||
1934 | if (zc0301_init(cam)) { | ||
1935 | DBG(1, "Initialization failed. I will retry on open()."); | ||
1936 | cam->state |= DEV_MISCONFIGURED; | ||
1937 | } | ||
1938 | |||
1939 | strcpy(cam->v4ldev->name, "ZC0301 PC Camera"); | ||
1940 | cam->v4ldev->owner = THIS_MODULE; | ||
1941 | cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; | ||
1942 | cam->v4ldev->hardware = 0; | ||
1943 | cam->v4ldev->fops = &zc0301_fops; | ||
1944 | cam->v4ldev->minor = video_nr[dev_nr]; | ||
1945 | cam->v4ldev->release = video_device_release; | ||
1946 | video_set_drvdata(cam->v4ldev, cam); | ||
1947 | |||
1948 | mutex_lock(&cam->dev_mutex); | ||
1949 | |||
1950 | err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, | ||
1951 | video_nr[dev_nr]); | ||
1952 | if (err) { | ||
1953 | DBG(1, "V4L2 device registration failed"); | ||
1954 | if (err == -ENFILE && video_nr[dev_nr] == -1) | ||
1955 | DBG(1, "Free /dev/videoX node not found"); | ||
1956 | video_nr[dev_nr] = -1; | ||
1957 | dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
1958 | mutex_unlock(&cam->dev_mutex); | ||
1959 | goto fail; | ||
1960 | } | ||
1961 | |||
1962 | DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); | ||
1963 | |||
1964 | cam->module_param.force_munmap = force_munmap[dev_nr]; | ||
1965 | cam->module_param.frame_timeout = frame_timeout[dev_nr]; | ||
1966 | |||
1967 | dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0; | ||
1968 | |||
1969 | usb_set_intfdata(intf, cam); | ||
1970 | |||
1971 | mutex_unlock(&cam->dev_mutex); | ||
1972 | |||
1973 | return 0; | ||
1974 | |||
1975 | fail: | ||
1976 | if (cam) { | ||
1977 | kfree(cam->control_buffer); | ||
1978 | if (cam->v4ldev) | ||
1979 | video_device_release(cam->v4ldev); | ||
1980 | kfree(cam); | ||
1981 | } | ||
1982 | return err; | ||
1983 | } | ||
1984 | |||
1985 | |||
1986 | static void zc0301_usb_disconnect(struct usb_interface* intf) | ||
1987 | { | ||
1988 | struct zc0301_device* cam = usb_get_intfdata(intf); | ||
1989 | |||
1990 | if (!cam) | ||
1991 | return; | ||
1992 | |||
1993 | down_write(&zc0301_disconnect); | ||
1994 | |||
1995 | mutex_lock(&cam->dev_mutex); | ||
1996 | |||
1997 | DBG(2, "Disconnecting %s...", cam->v4ldev->name); | ||
1998 | |||
1999 | wake_up_interruptible_all(&cam->open); | ||
2000 | |||
2001 | if (cam->users) { | ||
2002 | DBG(2, "Device /dev/video%d is open! Deregistration and " | ||
2003 | "memory deallocation are deferred on close.", | ||
2004 | cam->v4ldev->minor); | ||
2005 | cam->state |= DEV_MISCONFIGURED; | ||
2006 | zc0301_stop_transfer(cam); | ||
2007 | cam->state |= DEV_DISCONNECTED; | ||
2008 | wake_up_interruptible(&cam->wait_frame); | ||
2009 | wake_up(&cam->wait_stream); | ||
2010 | usb_get_dev(cam->usbdev); | ||
2011 | } else { | ||
2012 | cam->state |= DEV_DISCONNECTED; | ||
2013 | zc0301_release_resources(cam); | ||
2014 | } | ||
2015 | |||
2016 | mutex_unlock(&cam->dev_mutex); | ||
2017 | |||
2018 | if (!cam->users) | ||
2019 | kfree(cam); | ||
2020 | |||
2021 | up_write(&zc0301_disconnect); | ||
2022 | } | ||
2023 | |||
2024 | |||
2025 | static struct usb_driver zc0301_usb_driver = { | ||
2026 | .name = "zc0301", | ||
2027 | .id_table = zc0301_id_table, | ||
2028 | .probe = zc0301_usb_probe, | ||
2029 | .disconnect = zc0301_usb_disconnect, | ||
2030 | }; | ||
2031 | |||
2032 | /*****************************************************************************/ | ||
2033 | |||
2034 | static int __init zc0301_module_init(void) | ||
2035 | { | ||
2036 | int err = 0; | ||
2037 | |||
2038 | KDBG(2, ZC0301_MODULE_NAME " v" ZC0301_MODULE_VERSION); | ||
2039 | KDBG(3, ZC0301_MODULE_AUTHOR); | ||
2040 | |||
2041 | if ((err = usb_register(&zc0301_usb_driver))) | ||
2042 | KDBG(1, "usb_register() failed"); | ||
2043 | |||
2044 | return err; | ||
2045 | } | ||
2046 | |||
2047 | |||
2048 | static void __exit zc0301_module_exit(void) | ||
2049 | { | ||
2050 | usb_deregister(&zc0301_usb_driver); | ||
2051 | } | ||
2052 | |||
2053 | |||
2054 | module_init(zc0301_module_init); | ||
2055 | module_exit(zc0301_module_exit); | ||
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c new file mode 100644 index 000000000000..9d282a22c15f --- /dev/null +++ b/drivers/media/video/zc0301/zc0301_pas202bcb.c | |||
@@ -0,0 +1,361 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for PAS202BCB image sensor connected to the ZC030! Image * | ||
3 | * Processor and Control Chip * | ||
4 | * * | ||
5 | * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * Initialization values of the ZC0301 have been taken from the SPCA5XX * | ||
8 | * driver maintained by Michel Xhaard <mxhaard@magic.fr> * | ||
9 | * * | ||
10 | * This program is free software; you can redistribute it and/or modify * | ||
11 | * it under the terms of the GNU General Public License as published by * | ||
12 | * the Free Software Foundation; either version 2 of the License, or * | ||
13 | * (at your option) any later version. * | ||
14 | * * | ||
15 | * This program is distributed in the hope that it will be useful, * | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
18 | * GNU General Public License for more details. * | ||
19 | * * | ||
20 | * You should have received a copy of the GNU General Public License * | ||
21 | * along with this program; if not, write to the Free Software * | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
23 | ***************************************************************************/ | ||
24 | |||
25 | /* | ||
26 | NOTE: Sensor controls are disabled for now, becouse changing them while | ||
27 | streaming sometimes results in out-of-sync video frames. We'll use | ||
28 | the default initialization, until we know how to stop and start video | ||
29 | in the chip. However, the image quality still looks good under various | ||
30 | light conditions. | ||
31 | */ | ||
32 | |||
33 | #include <linux/delay.h> | ||
34 | #include "zc0301_sensor.h" | ||
35 | |||
36 | |||
37 | static struct zc0301_sensor pas202bcb; | ||
38 | |||
39 | |||
40 | static int pas202bcb_init(struct zc0301_device* cam) | ||
41 | { | ||
42 | int err = 0; | ||
43 | |||
44 | err += zc0301_write_reg(cam, 0x0002, 0x00); | ||
45 | err += zc0301_write_reg(cam, 0x0003, 0x02); | ||
46 | err += zc0301_write_reg(cam, 0x0004, 0x80); | ||
47 | err += zc0301_write_reg(cam, 0x0005, 0x01); | ||
48 | err += zc0301_write_reg(cam, 0x0006, 0xE0); | ||
49 | err += zc0301_write_reg(cam, 0x0098, 0x00); | ||
50 | err += zc0301_write_reg(cam, 0x009A, 0x03); | ||
51 | err += zc0301_write_reg(cam, 0x011A, 0x00); | ||
52 | err += zc0301_write_reg(cam, 0x011C, 0x03); | ||
53 | err += zc0301_write_reg(cam, 0x009B, 0x01); | ||
54 | err += zc0301_write_reg(cam, 0x009C, 0xE6); | ||
55 | err += zc0301_write_reg(cam, 0x009D, 0x02); | ||
56 | err += zc0301_write_reg(cam, 0x009E, 0x86); | ||
57 | |||
58 | err += zc0301_i2c_write(cam, 0x02, 0x02); | ||
59 | err += zc0301_i2c_write(cam, 0x0A, 0x01); | ||
60 | err += zc0301_i2c_write(cam, 0x0B, 0x01); | ||
61 | err += zc0301_i2c_write(cam, 0x0D, 0x00); | ||
62 | err += zc0301_i2c_write(cam, 0x12, 0x05); | ||
63 | err += zc0301_i2c_write(cam, 0x13, 0x63); | ||
64 | err += zc0301_i2c_write(cam, 0x15, 0x70); | ||
65 | |||
66 | err += zc0301_write_reg(cam, 0x0101, 0xB7); | ||
67 | err += zc0301_write_reg(cam, 0x0100, 0x0D); | ||
68 | err += zc0301_write_reg(cam, 0x0189, 0x06); | ||
69 | err += zc0301_write_reg(cam, 0x01AD, 0x00); | ||
70 | err += zc0301_write_reg(cam, 0x01C5, 0x03); | ||
71 | err += zc0301_write_reg(cam, 0x01CB, 0x13); | ||
72 | err += zc0301_write_reg(cam, 0x0250, 0x08); | ||
73 | err += zc0301_write_reg(cam, 0x0301, 0x08); | ||
74 | err += zc0301_write_reg(cam, 0x018D, 0x70); | ||
75 | err += zc0301_write_reg(cam, 0x0008, 0x03); | ||
76 | err += zc0301_write_reg(cam, 0x01C6, 0x04); | ||
77 | err += zc0301_write_reg(cam, 0x01CB, 0x07); | ||
78 | err += zc0301_write_reg(cam, 0x0120, 0x11); | ||
79 | err += zc0301_write_reg(cam, 0x0121, 0x37); | ||
80 | err += zc0301_write_reg(cam, 0x0122, 0x58); | ||
81 | err += zc0301_write_reg(cam, 0x0123, 0x79); | ||
82 | err += zc0301_write_reg(cam, 0x0124, 0x91); | ||
83 | err += zc0301_write_reg(cam, 0x0125, 0xA6); | ||
84 | err += zc0301_write_reg(cam, 0x0126, 0xB8); | ||
85 | err += zc0301_write_reg(cam, 0x0127, 0xC7); | ||
86 | err += zc0301_write_reg(cam, 0x0128, 0xD3); | ||
87 | err += zc0301_write_reg(cam, 0x0129, 0xDE); | ||
88 | err += zc0301_write_reg(cam, 0x012A, 0xE6); | ||
89 | err += zc0301_write_reg(cam, 0x012B, 0xED); | ||
90 | err += zc0301_write_reg(cam, 0x012C, 0xF3); | ||
91 | err += zc0301_write_reg(cam, 0x012D, 0xF8); | ||
92 | err += zc0301_write_reg(cam, 0x012E, 0xFB); | ||
93 | err += zc0301_write_reg(cam, 0x012F, 0xFF); | ||
94 | err += zc0301_write_reg(cam, 0x0130, 0x26); | ||
95 | err += zc0301_write_reg(cam, 0x0131, 0x23); | ||
96 | err += zc0301_write_reg(cam, 0x0132, 0x20); | ||
97 | err += zc0301_write_reg(cam, 0x0133, 0x1C); | ||
98 | err += zc0301_write_reg(cam, 0x0134, 0x16); | ||
99 | err += zc0301_write_reg(cam, 0x0135, 0x13); | ||
100 | err += zc0301_write_reg(cam, 0x0136, 0x10); | ||
101 | err += zc0301_write_reg(cam, 0x0137, 0x0D); | ||
102 | err += zc0301_write_reg(cam, 0x0138, 0x0B); | ||
103 | err += zc0301_write_reg(cam, 0x0139, 0x09); | ||
104 | err += zc0301_write_reg(cam, 0x013A, 0x07); | ||
105 | err += zc0301_write_reg(cam, 0x013B, 0x06); | ||
106 | err += zc0301_write_reg(cam, 0x013C, 0x05); | ||
107 | err += zc0301_write_reg(cam, 0x013D, 0x04); | ||
108 | err += zc0301_write_reg(cam, 0x013E, 0x03); | ||
109 | err += zc0301_write_reg(cam, 0x013F, 0x02); | ||
110 | err += zc0301_write_reg(cam, 0x010A, 0x4C); | ||
111 | err += zc0301_write_reg(cam, 0x010B, 0xF5); | ||
112 | err += zc0301_write_reg(cam, 0x010C, 0xFF); | ||
113 | err += zc0301_write_reg(cam, 0x010D, 0xF9); | ||
114 | err += zc0301_write_reg(cam, 0x010E, 0x51); | ||
115 | err += zc0301_write_reg(cam, 0x010F, 0xF5); | ||
116 | err += zc0301_write_reg(cam, 0x0110, 0xFB); | ||
117 | err += zc0301_write_reg(cam, 0x0111, 0xED); | ||
118 | err += zc0301_write_reg(cam, 0x0112, 0x5F); | ||
119 | err += zc0301_write_reg(cam, 0x0180, 0x00); | ||
120 | err += zc0301_write_reg(cam, 0x0019, 0x00); | ||
121 | err += zc0301_write_reg(cam, 0x0087, 0x20); | ||
122 | err += zc0301_write_reg(cam, 0x0088, 0x21); | ||
123 | |||
124 | err += zc0301_i2c_write(cam, 0x20, 0x02); | ||
125 | err += zc0301_i2c_write(cam, 0x21, 0x1B); | ||
126 | err += zc0301_i2c_write(cam, 0x03, 0x44); | ||
127 | err += zc0301_i2c_write(cam, 0x0E, 0x01); | ||
128 | err += zc0301_i2c_write(cam, 0x0F, 0x00); | ||
129 | |||
130 | err += zc0301_write_reg(cam, 0x01A9, 0x14); | ||
131 | err += zc0301_write_reg(cam, 0x01AA, 0x24); | ||
132 | err += zc0301_write_reg(cam, 0x0190, 0x00); | ||
133 | err += zc0301_write_reg(cam, 0x0191, 0x02); | ||
134 | err += zc0301_write_reg(cam, 0x0192, 0x1B); | ||
135 | err += zc0301_write_reg(cam, 0x0195, 0x00); | ||
136 | err += zc0301_write_reg(cam, 0x0196, 0x00); | ||
137 | err += zc0301_write_reg(cam, 0x0197, 0x4D); | ||
138 | err += zc0301_write_reg(cam, 0x018C, 0x10); | ||
139 | err += zc0301_write_reg(cam, 0x018F, 0x20); | ||
140 | err += zc0301_write_reg(cam, 0x001D, 0x44); | ||
141 | err += zc0301_write_reg(cam, 0x001E, 0x6F); | ||
142 | err += zc0301_write_reg(cam, 0x001F, 0xAD); | ||
143 | err += zc0301_write_reg(cam, 0x0020, 0xEB); | ||
144 | err += zc0301_write_reg(cam, 0x0087, 0x0F); | ||
145 | err += zc0301_write_reg(cam, 0x0088, 0x0E); | ||
146 | err += zc0301_write_reg(cam, 0x0180, 0x40); | ||
147 | err += zc0301_write_reg(cam, 0x0192, 0x1B); | ||
148 | err += zc0301_write_reg(cam, 0x0191, 0x02); | ||
149 | err += zc0301_write_reg(cam, 0x0190, 0x00); | ||
150 | err += zc0301_write_reg(cam, 0x0116, 0x1D); | ||
151 | err += zc0301_write_reg(cam, 0x0117, 0x40); | ||
152 | err += zc0301_write_reg(cam, 0x0118, 0x99); | ||
153 | err += zc0301_write_reg(cam, 0x0180, 0x42); | ||
154 | err += zc0301_write_reg(cam, 0x0116, 0x1D); | ||
155 | err += zc0301_write_reg(cam, 0x0117, 0x40); | ||
156 | err += zc0301_write_reg(cam, 0x0118, 0x99); | ||
157 | err += zc0301_write_reg(cam, 0x0007, 0x00); | ||
158 | |||
159 | err += zc0301_i2c_write(cam, 0x11, 0x01); | ||
160 | |||
161 | msleep(100); | ||
162 | |||
163 | return err; | ||
164 | } | ||
165 | |||
166 | |||
167 | static int pas202bcb_get_ctrl(struct zc0301_device* cam, | ||
168 | struct v4l2_control* ctrl) | ||
169 | { | ||
170 | switch (ctrl->id) { | ||
171 | case V4L2_CID_EXPOSURE: | ||
172 | { | ||
173 | int r1 = zc0301_i2c_read(cam, 0x04, 1), | ||
174 | r2 = zc0301_i2c_read(cam, 0x05, 1); | ||
175 | if (r1 < 0 || r2 < 0) | ||
176 | return -EIO; | ||
177 | ctrl->value = (r1 << 6) | (r2 & 0x3f); | ||
178 | } | ||
179 | return 0; | ||
180 | case V4L2_CID_RED_BALANCE: | ||
181 | if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0) | ||
182 | return -EIO; | ||
183 | ctrl->value &= 0x0f; | ||
184 | return 0; | ||
185 | case V4L2_CID_BLUE_BALANCE: | ||
186 | if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0) | ||
187 | return -EIO; | ||
188 | ctrl->value &= 0x0f; | ||
189 | return 0; | ||
190 | case V4L2_CID_GAIN: | ||
191 | if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0) | ||
192 | return -EIO; | ||
193 | ctrl->value &= 0x1f; | ||
194 | return 0; | ||
195 | case ZC0301_V4L2_CID_GREEN_BALANCE: | ||
196 | if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0) | ||
197 | return -EIO; | ||
198 | ctrl->value &= 0x0f; | ||
199 | return 0; | ||
200 | case ZC0301_V4L2_CID_DAC_MAGNITUDE: | ||
201 | if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0) | ||
202 | return -EIO; | ||
203 | return 0; | ||
204 | default: | ||
205 | return -EINVAL; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | |||
210 | static int pas202bcb_set_ctrl(struct zc0301_device* cam, | ||
211 | const struct v4l2_control* ctrl) | ||
212 | { | ||
213 | int err = 0; | ||
214 | |||
215 | switch (ctrl->id) { | ||
216 | case V4L2_CID_EXPOSURE: | ||
217 | err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6); | ||
218 | err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f); | ||
219 | break; | ||
220 | case V4L2_CID_RED_BALANCE: | ||
221 | err += zc0301_i2c_write(cam, 0x09, ctrl->value); | ||
222 | break; | ||
223 | case V4L2_CID_BLUE_BALANCE: | ||
224 | err += zc0301_i2c_write(cam, 0x07, ctrl->value); | ||
225 | break; | ||
226 | case V4L2_CID_GAIN: | ||
227 | err += zc0301_i2c_write(cam, 0x10, ctrl->value); | ||
228 | break; | ||
229 | case ZC0301_V4L2_CID_GREEN_BALANCE: | ||
230 | err += zc0301_i2c_write(cam, 0x08, ctrl->value); | ||
231 | break; | ||
232 | case ZC0301_V4L2_CID_DAC_MAGNITUDE: | ||
233 | err += zc0301_i2c_write(cam, 0x0c, ctrl->value); | ||
234 | break; | ||
235 | default: | ||
236 | return -EINVAL; | ||
237 | } | ||
238 | err += zc0301_i2c_write(cam, 0x11, 0x01); | ||
239 | |||
240 | return err ? -EIO : 0; | ||
241 | } | ||
242 | |||
243 | |||
244 | static struct zc0301_sensor pas202bcb = { | ||
245 | .name = "PAS202BCB", | ||
246 | .init = &pas202bcb_init, | ||
247 | .qctrl = { | ||
248 | { | ||
249 | .id = V4L2_CID_EXPOSURE, | ||
250 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
251 | .name = "exposure", | ||
252 | .minimum = 0x01e5, | ||
253 | .maximum = 0x3fff, | ||
254 | .step = 0x0001, | ||
255 | .default_value = 0x01e5, | ||
256 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
257 | }, | ||
258 | { | ||
259 | .id = V4L2_CID_GAIN, | ||
260 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
261 | .name = "global gain", | ||
262 | .minimum = 0x00, | ||
263 | .maximum = 0x1f, | ||
264 | .step = 0x01, | ||
265 | .default_value = 0x0c, | ||
266 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
267 | }, | ||
268 | { | ||
269 | .id = ZC0301_V4L2_CID_DAC_MAGNITUDE, | ||
270 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
271 | .name = "DAC magnitude", | ||
272 | .minimum = 0x00, | ||
273 | .maximum = 0xff, | ||
274 | .step = 0x01, | ||
275 | .default_value = 0x00, | ||
276 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
277 | }, | ||
278 | { | ||
279 | .id = V4L2_CID_RED_BALANCE, | ||
280 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
281 | .name = "red balance", | ||
282 | .minimum = 0x00, | ||
283 | .maximum = 0x0f, | ||
284 | .step = 0x01, | ||
285 | .default_value = 0x01, | ||
286 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
287 | }, | ||
288 | { | ||
289 | .id = V4L2_CID_BLUE_BALANCE, | ||
290 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
291 | .name = "blue balance", | ||
292 | .minimum = 0x00, | ||
293 | .maximum = 0x0f, | ||
294 | .step = 0x01, | ||
295 | .default_value = 0x05, | ||
296 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
297 | }, | ||
298 | { | ||
299 | .id = ZC0301_V4L2_CID_GREEN_BALANCE, | ||
300 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
301 | .name = "green balance", | ||
302 | .minimum = 0x00, | ||
303 | .maximum = 0x0f, | ||
304 | .step = 0x01, | ||
305 | .default_value = 0x00, | ||
306 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
307 | }, | ||
308 | }, | ||
309 | .get_ctrl = &pas202bcb_get_ctrl, | ||
310 | .set_ctrl = &pas202bcb_set_ctrl, | ||
311 | .cropcap = { | ||
312 | .bounds = { | ||
313 | .left = 0, | ||
314 | .top = 0, | ||
315 | .width = 640, | ||
316 | .height = 480, | ||
317 | }, | ||
318 | .defrect = { | ||
319 | .left = 0, | ||
320 | .top = 0, | ||
321 | .width = 640, | ||
322 | .height = 480, | ||
323 | }, | ||
324 | }, | ||
325 | .pix_format = { | ||
326 | .width = 640, | ||
327 | .height = 480, | ||
328 | .pixelformat = V4L2_PIX_FMT_JPEG, | ||
329 | .priv = 8, | ||
330 | }, | ||
331 | }; | ||
332 | |||
333 | |||
334 | int zc0301_probe_pas202bcb(struct zc0301_device* cam) | ||
335 | { | ||
336 | int r0 = 0, r1 = 0, err = 0; | ||
337 | unsigned int pid = 0; | ||
338 | |||
339 | err += zc0301_write_reg(cam, 0x0000, 0x01); | ||
340 | err += zc0301_write_reg(cam, 0x0010, 0x0e); | ||
341 | err += zc0301_write_reg(cam, 0x0001, 0x01); | ||
342 | err += zc0301_write_reg(cam, 0x0012, 0x03); | ||
343 | err += zc0301_write_reg(cam, 0x0012, 0x01); | ||
344 | err += zc0301_write_reg(cam, 0x008d, 0x08); | ||
345 | |||
346 | msleep(10); | ||
347 | |||
348 | r0 = zc0301_i2c_read(cam, 0x00, 1); | ||
349 | r1 = zc0301_i2c_read(cam, 0x01, 1); | ||
350 | |||
351 | if (r0 < 0 || r1 < 0 || err) | ||
352 | return -EIO; | ||
353 | |||
354 | pid = (r0 << 4) | ((r1 & 0xf0) >> 4); | ||
355 | if (pid != 0x017) | ||
356 | return -ENODEV; | ||
357 | |||
358 | zc0301_attach_sensor(cam, &pas202bcb); | ||
359 | |||
360 | return 0; | ||
361 | } | ||
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h new file mode 100644 index 000000000000..cf0965a81d01 --- /dev/null +++ b/drivers/media/video/zc0301/zc0301_sensor.h | |||
@@ -0,0 +1,103 @@ | |||
1 | /*************************************************************************** | ||
2 | * API for image sensors connected to the ZC030! Image Processor and * | ||
3 | * Control Chip * | ||
4 | * * | ||
5 | * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #ifndef _ZC0301_SENSOR_H_ | ||
23 | #define _ZC0301_SENSOR_H_ | ||
24 | |||
25 | #include <linux/usb.h> | ||
26 | #include <linux/videodev.h> | ||
27 | #include <linux/device.h> | ||
28 | #include <linux/stddef.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <asm/types.h> | ||
31 | |||
32 | struct zc0301_device; | ||
33 | struct zc0301_sensor; | ||
34 | |||
35 | /*****************************************************************************/ | ||
36 | |||
37 | extern int zc0301_probe_pas202bcb(struct zc0301_device* cam); | ||
38 | |||
39 | #define ZC0301_SENSOR_TABLE \ | ||
40 | /* Weak detections must go at the end of the list */ \ | ||
41 | static int (*zc0301_sensor_table[])(struct zc0301_device*) = { \ | ||
42 | &zc0301_probe_pas202bcb, \ | ||
43 | NULL, \ | ||
44 | }; | ||
45 | |||
46 | extern struct zc0301_device* | ||
47 | zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id); | ||
48 | |||
49 | extern void | ||
50 | zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor); | ||
51 | |||
52 | #define ZC0301_USB_DEVICE(vend, prod, intclass) \ | ||
53 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ | ||
54 | USB_DEVICE_ID_MATCH_INT_CLASS, \ | ||
55 | .idVendor = (vend), \ | ||
56 | .idProduct = (prod), \ | ||
57 | .bInterfaceClass = (intclass) | ||
58 | |||
59 | #define ZC0301_ID_TABLE \ | ||
60 | static const struct usb_device_id zc0301_id_table[] = { \ | ||
61 | { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, \ | ||
62 | { ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */ \ | ||
63 | { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */ \ | ||
64 | { ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */ \ | ||
65 | { ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */ \ | ||
66 | { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */ \ | ||
67 | { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \ | ||
68 | { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */ \ | ||
69 | { } \ | ||
70 | }; | ||
71 | |||
72 | /*****************************************************************************/ | ||
73 | |||
74 | extern int zc0301_write_reg(struct zc0301_device*, u16 index, u16 value); | ||
75 | extern int zc0301_read_reg(struct zc0301_device*, u16 index); | ||
76 | extern int zc0301_i2c_write(struct zc0301_device*, u16 address, u16 value); | ||
77 | extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length); | ||
78 | |||
79 | /*****************************************************************************/ | ||
80 | |||
81 | #define ZC0301_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10 | ||
82 | #define ZC0301_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE | ||
83 | #define ZC0301_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1 | ||
84 | |||
85 | struct zc0301_sensor { | ||
86 | char name[32]; | ||
87 | |||
88 | struct v4l2_queryctrl qctrl[ZC0301_MAX_CTRLS]; | ||
89 | struct v4l2_cropcap cropcap; | ||
90 | struct v4l2_pix_format pix_format; | ||
91 | |||
92 | int (*init)(struct zc0301_device*); | ||
93 | int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl); | ||
94 | int (*set_ctrl)(struct zc0301_device*, | ||
95 | const struct v4l2_control* ctrl); | ||
96 | int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect); | ||
97 | |||
98 | /* Private */ | ||
99 | struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS]; | ||
100 | struct v4l2_rect _rect; | ||
101 | }; | ||
102 | |||
103 | #endif /* _ZC0301_SENSOR_H_ */ | ||