diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-24 00:12:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-24 00:12:49 -0400 |
commit | df462b3dbeeaae7141f1b63cbfcc1e1bae6a85fc (patch) | |
tree | bca52fce066159f136d75c69e79016422212cb1d /drivers/media/video | |
parent | 343800e7d20944aead238c2c6e3f7789f8b6587c (diff) | |
parent | cf25220677b3f10468a74278130fe224f73632a6 (diff) |
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (247 commits)
[media] gspca - sunplus: Fix some warnings and simplify code
[media] gspca: Fix some warnings tied to 'no debug'
[media] gspca: Unset debug by default
[media] gspca - cpia1: Remove a bad conditional compilation instruction
[media] gspca - main: Remove USB traces
[media] gspca - main: Version change to 2.13
[media] gspca - stk014 / t613: Accept the index 0 in querymenu
[media] gspca - kinect: Remove __devinitdata
[media] gspca - cpia1: Fix some warnings
[media] video/Kconfig: Fix mis-classified devices
[media] support for medion dvb stick 1660:1921
[media] tm6000: fix uninitialized field, change prink to dprintk
[media] cx231xx: Add support for Iconbit U100
[media] saa7134 add new TV cards
[media] Use a more consistent value for RC repeat period
[media] cx18: Move spinlock and vb_type initialisation into stream_init
[media] tm6000: remove tm6010 sif audio start and stop
[media] tm6000: remove unused exports
[media] tm6000: add pts logging
[media] tm6000: change from ioctl to unlocked_ioctl
...
Diffstat (limited to 'drivers/media/video')
86 files changed, 4649 insertions, 903 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 00f51dd121f3..3be180b3ba27 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -128,10 +128,10 @@ config VIDEO_IR_I2C | |||
128 | # Encoder / Decoder module configuration | 128 | # Encoder / Decoder module configuration |
129 | # | 129 | # |
130 | 130 | ||
131 | menu "Encoders/decoders and other helper chips" | 131 | menu "Encoders, decoders, sensors and other helper chips" |
132 | visible if !VIDEO_HELPER_CHIPS_AUTO | 132 | visible if !VIDEO_HELPER_CHIPS_AUTO |
133 | 133 | ||
134 | comment "Audio decoders" | 134 | comment "Audio decoders, processors and mixers" |
135 | 135 | ||
136 | config VIDEO_TVAUDIO | 136 | config VIDEO_TVAUDIO |
137 | tristate "Simple audio decoder chips" | 137 | tristate "Simple audio decoder chips" |
@@ -210,15 +210,6 @@ config VIDEO_CS53L32A | |||
210 | To compile this driver as a module, choose M here: the | 210 | To compile this driver as a module, choose M here: the |
211 | module will be called cs53l32a. | 211 | module will be called cs53l32a. |
212 | 212 | ||
213 | config VIDEO_M52790 | ||
214 | tristate "Mitsubishi M52790 A/V switch" | ||
215 | depends on VIDEO_V4L2 && I2C | ||
216 | ---help--- | ||
217 | Support for the Mitsubishi M52790 A/V switch. | ||
218 | |||
219 | To compile this driver as a module, choose M here: the | ||
220 | module will be called m52790. | ||
221 | |||
222 | config VIDEO_TLV320AIC23B | 213 | config VIDEO_TLV320AIC23B |
223 | tristate "Texas Instruments TLV320AIC23B audio codec" | 214 | tristate "Texas Instruments TLV320AIC23B audio codec" |
224 | depends on VIDEO_V4L2 && I2C && EXPERIMENTAL | 215 | depends on VIDEO_V4L2 && I2C && EXPERIMENTAL |
@@ -321,29 +312,6 @@ config VIDEO_KS0127 | |||
321 | To compile this driver as a module, choose M here: the | 312 | To compile this driver as a module, choose M here: the |
322 | module will be called ks0127. | 313 | module will be called ks0127. |
323 | 314 | ||
324 | config VIDEO_OV7670 | ||
325 | tristate "OmniVision OV7670 sensor support" | ||
326 | depends on I2C && VIDEO_V4L2 | ||
327 | ---help--- | ||
328 | This is a Video4Linux2 sensor-level driver for the OmniVision | ||
329 | OV7670 VGA camera. It currently only works with the M88ALP01 | ||
330 | controller. | ||
331 | |||
332 | config VIDEO_MT9V011 | ||
333 | tristate "Micron mt9v011 sensor support" | ||
334 | depends on I2C && VIDEO_V4L2 | ||
335 | ---help--- | ||
336 | This is a Video4Linux2 sensor-level driver for the Micron | ||
337 | mt0v011 1.3 Mpixel camera. It currently only works with the | ||
338 | em28xx driver. | ||
339 | |||
340 | config VIDEO_TCM825X | ||
341 | tristate "TCM825x camera sensor support" | ||
342 | depends on I2C && VIDEO_V4L2 | ||
343 | ---help--- | ||
344 | This is a driver for the Toshiba TCM825x VGA camera sensor. | ||
345 | It is used for example in Nokia N800. | ||
346 | |||
347 | config VIDEO_SAA7110 | 315 | config VIDEO_SAA7110 |
348 | tristate "Philips SAA7110 video decoder" | 316 | tristate "Philips SAA7110 video decoder" |
349 | depends on VIDEO_V4L2 && I2C | 317 | depends on VIDEO_V4L2 && I2C |
@@ -362,15 +330,6 @@ config VIDEO_SAA711X | |||
362 | To compile this driver as a module, choose M here: the | 330 | To compile this driver as a module, choose M here: the |
363 | module will be called saa7115. | 331 | module will be called saa7115. |
364 | 332 | ||
365 | config VIDEO_SAA717X | ||
366 | tristate "Philips SAA7171/3/4 audio/video decoders" | ||
367 | depends on VIDEO_V4L2 && I2C | ||
368 | ---help--- | ||
369 | Support for the Philips SAA7171/3/4 audio/video decoders. | ||
370 | |||
371 | To compile this driver as a module, choose M here: the | ||
372 | module will be called saa717x. | ||
373 | |||
374 | config VIDEO_SAA7191 | 333 | config VIDEO_SAA7191 |
375 | tristate "Philips SAA7191 video decoder" | 334 | tristate "Philips SAA7191 video decoder" |
376 | depends on VIDEO_V4L2 && I2C | 335 | depends on VIDEO_V4L2 && I2C |
@@ -420,6 +379,15 @@ config VIDEO_VPX3220 | |||
420 | 379 | ||
421 | comment "Video and audio decoders" | 380 | comment "Video and audio decoders" |
422 | 381 | ||
382 | config VIDEO_SAA717X | ||
383 | tristate "Philips SAA7171/3/4 audio/video decoders" | ||
384 | depends on VIDEO_V4L2 && I2C | ||
385 | ---help--- | ||
386 | Support for the Philips SAA7171/3/4 audio/video decoders. | ||
387 | |||
388 | To compile this driver as a module, choose M here: the | ||
389 | module will be called saa717x. | ||
390 | |||
423 | source "drivers/media/video/cx25840/Kconfig" | 391 | source "drivers/media/video/cx25840/Kconfig" |
424 | 392 | ||
425 | comment "MPEG video encoders" | 393 | comment "MPEG video encoders" |
@@ -474,15 +442,6 @@ config VIDEO_ADV7175 | |||
474 | To compile this driver as a module, choose M here: the | 442 | To compile this driver as a module, choose M here: the |
475 | module will be called adv7175. | 443 | module will be called adv7175. |
476 | 444 | ||
477 | config VIDEO_THS7303 | ||
478 | tristate "THS7303 Video Amplifier" | ||
479 | depends on I2C | ||
480 | help | ||
481 | Support for TI THS7303 video amplifier | ||
482 | |||
483 | To compile this driver as a module, choose M here: the | ||
484 | module will be called ths7303. | ||
485 | |||
486 | config VIDEO_ADV7343 | 445 | config VIDEO_ADV7343 |
487 | tristate "ADV7343 video encoder" | 446 | tristate "ADV7343 video encoder" |
488 | depends on I2C | 447 | depends on I2C |
@@ -498,6 +457,38 @@ config VIDEO_AK881X | |||
498 | help | 457 | help |
499 | Video output driver for AKM AK8813 and AK8814 TV encoders | 458 | Video output driver for AKM AK8813 and AK8814 TV encoders |
500 | 459 | ||
460 | comment "Camera sensor devices" | ||
461 | |||
462 | config VIDEO_OV7670 | ||
463 | tristate "OmniVision OV7670 sensor support" | ||
464 | depends on I2C && VIDEO_V4L2 | ||
465 | ---help--- | ||
466 | This is a Video4Linux2 sensor-level driver for the OmniVision | ||
467 | OV7670 VGA camera. It currently only works with the M88ALP01 | ||
468 | controller. | ||
469 | |||
470 | config VIDEO_MT9V011 | ||
471 | tristate "Micron mt9v011 sensor support" | ||
472 | depends on I2C && VIDEO_V4L2 | ||
473 | ---help--- | ||
474 | This is a Video4Linux2 sensor-level driver for the Micron | ||
475 | mt0v011 1.3 Mpixel camera. It currently only works with the | ||
476 | em28xx driver. | ||
477 | |||
478 | config VIDEO_MT9V032 | ||
479 | tristate "Micron MT9V032 sensor support" | ||
480 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | ||
481 | ---help--- | ||
482 | This is a Video4Linux2 sensor-level driver for the Micron | ||
483 | MT9V032 752x480 CMOS sensor. | ||
484 | |||
485 | config VIDEO_TCM825X | ||
486 | tristate "TCM825x camera sensor support" | ||
487 | depends on I2C && VIDEO_V4L2 | ||
488 | ---help--- | ||
489 | This is a driver for the Toshiba TCM825x VGA camera sensor. | ||
490 | It is used for example in Nokia N800. | ||
491 | |||
501 | comment "Video improvement chips" | 492 | comment "Video improvement chips" |
502 | 493 | ||
503 | config VIDEO_UPD64031A | 494 | config VIDEO_UPD64031A |
@@ -523,6 +514,26 @@ config VIDEO_UPD64083 | |||
523 | To compile this driver as a module, choose M here: the | 514 | To compile this driver as a module, choose M here: the |
524 | module will be called upd64083. | 515 | module will be called upd64083. |
525 | 516 | ||
517 | comment "Miscelaneous helper chips" | ||
518 | |||
519 | config VIDEO_THS7303 | ||
520 | tristate "THS7303 Video Amplifier" | ||
521 | depends on I2C | ||
522 | help | ||
523 | Support for TI THS7303 video amplifier | ||
524 | |||
525 | To compile this driver as a module, choose M here: the | ||
526 | module will be called ths7303. | ||
527 | |||
528 | config VIDEO_M52790 | ||
529 | tristate "Mitsubishi M52790 A/V switch" | ||
530 | depends on VIDEO_V4L2 && I2C | ||
531 | ---help--- | ||
532 | Support for the Mitsubishi M52790 A/V switch. | ||
533 | |||
534 | To compile this driver as a module, choose M here: the | ||
535 | module will be called m52790. | ||
536 | |||
526 | endmenu # encoder / decoder chips | 537 | endmenu # encoder / decoder chips |
527 | 538 | ||
528 | config VIDEO_SH_VOU | 539 | config VIDEO_SH_VOU |
@@ -682,7 +693,7 @@ config VIDEO_TIMBERDALE | |||
682 | select VIDEO_ADV7180 | 693 | select VIDEO_ADV7180 |
683 | select VIDEOBUF_DMA_CONTIG | 694 | select VIDEOBUF_DMA_CONTIG |
684 | ---help--- | 695 | ---help--- |
685 | Add support for the Video In peripherial of the timberdale FPGA. | 696 | Add support for the Video In peripherial of the timberdale FPGA. |
686 | 697 | ||
687 | source "drivers/media/video/cx88/Kconfig" | 698 | source "drivers/media/video/cx88/Kconfig" |
688 | 699 | ||
@@ -916,7 +927,7 @@ config VIDEO_OMAP2 | |||
916 | This is a v4l2 driver for the TI OMAP2 camera capture interface | 927 | This is a v4l2 driver for the TI OMAP2 camera capture interface |
917 | 928 | ||
918 | config VIDEO_MX2_HOSTSUPPORT | 929 | config VIDEO_MX2_HOSTSUPPORT |
919 | bool | 930 | bool |
920 | 931 | ||
921 | config VIDEO_MX2 | 932 | config VIDEO_MX2 |
922 | tristate "i.MX27/i.MX25 Camera Sensor Interface driver" | 933 | tristate "i.MX27/i.MX25 Camera Sensor Interface driver" |
@@ -927,6 +938,26 @@ config VIDEO_MX2 | |||
927 | This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor | 938 | This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor |
928 | Interface | 939 | Interface |
929 | 940 | ||
941 | config VIDEO_SAMSUNG_S5P_FIMC | ||
942 | tristate "Samsung S5P and EXYNOS4 camera host interface driver" | ||
943 | depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P | ||
944 | select VIDEOBUF2_DMA_CONTIG | ||
945 | select V4L2_MEM2MEM_DEV | ||
946 | ---help--- | ||
947 | This is a v4l2 driver for Samsung S5P and EXYNOS4 camera | ||
948 | host interface and video postprocessor. | ||
949 | |||
950 | To compile this driver as a module, choose M here: the | ||
951 | module will be called s5p-fimc. | ||
952 | |||
953 | config VIDEO_S5P_MIPI_CSIS | ||
954 | tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver" | ||
955 | depends on VIDEO_V4L2 && PM_RUNTIME && VIDEO_V4L2_SUBDEV_API | ||
956 | ---help--- | ||
957 | This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver. | ||
958 | |||
959 | To compile this driver as a module, choose M here: the | ||
960 | module will be called s5p-csis. | ||
930 | 961 | ||
931 | # | 962 | # |
932 | # USB Multimedia device configuration | 963 | # USB Multimedia device configuration |
@@ -983,7 +1014,7 @@ config USB_STKWEBCAM | |||
983 | Supported devices are typically found in some Asus laptops, | 1014 | Supported devices are typically found in some Asus laptops, |
984 | with USB id 174f:a311 and 05e1:0501. Other Syntek cameras | 1015 | with USB id 174f:a311 and 05e1:0501. Other Syntek cameras |
985 | may be supported by the stk11xx driver, from which this is | 1016 | may be supported by the stk11xx driver, from which this is |
986 | derived, see <http://sourceforge.net/projects/syntekdriver/> | 1017 | derived, see <http://sourceforge.net/projects/syntekdriver/> |
987 | 1018 | ||
988 | To compile this driver as a module, choose M here: the | 1019 | To compile this driver as a module, choose M here: the |
989 | module will be called stkwebcam. | 1020 | module will be called stkwebcam. |
@@ -1022,13 +1053,5 @@ config VIDEO_MEM2MEM_TESTDEV | |||
1022 | This is a virtual test device for the memory-to-memory driver | 1053 | This is a virtual test device for the memory-to-memory driver |
1023 | framework. | 1054 | framework. |
1024 | 1055 | ||
1025 | config VIDEO_SAMSUNG_S5P_FIMC | ||
1026 | tristate "Samsung S5P FIMC (video postprocessor) driver" | ||
1027 | depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P | ||
1028 | select VIDEOBUF2_DMA_CONTIG | ||
1029 | select V4L2_MEM2MEM_DEV | ||
1030 | help | ||
1031 | This is a v4l2 driver for the S5P camera interface | ||
1032 | (video postprocessor) | ||
1033 | 1056 | ||
1034 | endif # V4L_MEM2MEM_DRIVERS | 1057 | endif # V4L_MEM2MEM_DRIVERS |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index ace5d8b57221..9519160c2e01 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -66,6 +66,7 @@ obj-$(CONFIG_VIDEO_OV7670) += ov7670.o | |||
66 | obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o | 66 | obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o |
67 | obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o | 67 | obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o |
68 | obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o | 68 | obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o |
69 | obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o | ||
69 | obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o | 70 | obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o |
70 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o | 71 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o |
71 | 72 | ||
@@ -164,6 +165,7 @@ obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o | |||
164 | obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o | 165 | obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o |
165 | obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o | 166 | obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o |
166 | obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o | 167 | obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o |
168 | |||
167 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ | 169 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ |
168 | 170 | ||
169 | obj-$(CONFIG_ARCH_DAVINCI) += davinci/ | 171 | obj-$(CONFIG_ARCH_DAVINCI) += davinci/ |
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 91399c94cd18..a97cf2750bd9 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c | |||
@@ -4303,7 +4303,7 @@ static int __devinit bttv_probe(struct pci_dev *dev, | |||
4303 | goto fail0; | 4303 | goto fail0; |
4304 | } | 4304 | } |
4305 | 4305 | ||
4306 | pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision); | 4306 | btv->revision = dev->revision; |
4307 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); | 4307 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); |
4308 | printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ", | 4308 | printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ", |
4309 | bttv_num,btv->id, btv->revision, pci_name(dev)); | 4309 | bttv_num,btv->id, btv->revision, pci_name(dev)); |
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 5111bbcefad5..0073a8c55336 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c | |||
@@ -1313,7 +1313,7 @@ static int cpia2_g_priority(struct file *file, void *_fh, enum v4l2_priority *p) | |||
1313 | static int cpia2_s_priority(struct file *file, void *_fh, enum v4l2_priority prio) | 1313 | static int cpia2_s_priority(struct file *file, void *_fh, enum v4l2_priority prio) |
1314 | { | 1314 | { |
1315 | struct camera_data *cam = video_drvdata(file); | 1315 | struct camera_data *cam = video_drvdata(file); |
1316 | struct cpia2_fh *fh = fh; | 1316 | struct cpia2_fh *fh = _fh; |
1317 | 1317 | ||
1318 | if (cam->streaming && prio != fh->prio && | 1318 | if (cam->streaming && prio != fh->prio && |
1319 | fh->prio == V4L2_PRIORITY_RECORD) | 1319 | fh->prio == V4L2_PRIORITY_RECORD) |
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig index d9d2f6ad6ffb..53b3c7702573 100644 --- a/drivers/media/video/cx18/Kconfig +++ b/drivers/media/video/cx18/Kconfig | |||
@@ -2,6 +2,7 @@ config VIDEO_CX18 | |||
2 | tristate "Conexant cx23418 MPEG encoder support" | 2 | tristate "Conexant cx23418 MPEG encoder support" |
3 | depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL | 3 | depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL |
4 | select I2C_ALGOBIT | 4 | select I2C_ALGOBIT |
5 | select VIDEOBUF_VMALLOC | ||
5 | depends on RC_CORE | 6 | depends on RC_CORE |
6 | select VIDEO_TUNER | 7 | select VIDEO_TUNER |
7 | select VIDEO_TVEEPROM | 8 | select VIDEO_TVEEPROM |
@@ -9,6 +10,9 @@ config VIDEO_CX18 | |||
9 | select VIDEO_CS5345 | 10 | select VIDEO_CS5345 |
10 | select DVB_S5H1409 if !DVB_FE_CUSTOMISE | 11 | select DVB_S5H1409 if !DVB_FE_CUSTOMISE |
11 | select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE | 12 | select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE |
13 | select DVB_S5H1411 if !DVB_FE_CUSTOMISE | ||
14 | select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE | ||
15 | select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE | ||
12 | ---help--- | 16 | ---help--- |
13 | This is a video4linux driver for Conexant cx23418 based | 17 | This is a video4linux driver for Conexant cx23418 based |
14 | PCI combo video recorder devices. | 18 | PCI combo video recorder devices. |
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c index 68ad1963f421..c07c849b1aaf 100644 --- a/drivers/media/video/cx18/cx18-cards.c +++ b/drivers/media/video/cx18/cx18-cards.c | |||
@@ -39,6 +39,16 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = { | |||
39 | .tv = { 0x61, 0x60, I2C_CLIENT_END }, | 39 | .tv = { 0x61, 0x60, I2C_CLIENT_END }, |
40 | }; | 40 | }; |
41 | 41 | ||
42 | /* | ||
43 | * usual i2c tuner addresses to probe with additional demod address for | ||
44 | * an NXP TDA8295 at 0x42 (N.B. it can possibly be at 0x4b or 0x4c too). | ||
45 | */ | ||
46 | static struct cx18_card_tuner_i2c cx18_i2c_nxp = { | ||
47 | .radio = { I2C_CLIENT_END }, | ||
48 | .demod = { 0x42, 0x43, I2C_CLIENT_END }, | ||
49 | .tv = { 0x61, 0x60, I2C_CLIENT_END }, | ||
50 | }; | ||
51 | |||
42 | /* Please add new PCI IDs to: http://pci-ids.ucw.cz/ | 52 | /* Please add new PCI IDs to: http://pci-ids.ucw.cz/ |
43 | This keeps the PCI ID database up to date. Note that the entries | 53 | This keeps the PCI ID database up to date. Note that the entries |
44 | must be added under vendor 0x4444 (Conexant) as subsystem IDs. | 54 | must be added under vendor 0x4444 (Conexant) as subsystem IDs. |
@@ -131,15 +141,15 @@ static const struct cx18_card cx18_card_hvr1600_s5h1411 = { | |||
131 | .tune_lane = 0, | 141 | .tune_lane = 0, |
132 | .initial_emrs = 0, | 142 | .initial_emrs = 0, |
133 | }, | 143 | }, |
134 | .gpio_init.initial_value = 0x3001, | 144 | .gpio_init.initial_value = 0x3801, |
135 | .gpio_init.direction = 0x3001, | 145 | .gpio_init.direction = 0x3801, |
136 | .gpio_i2c_slave_reset = { | 146 | .gpio_i2c_slave_reset = { |
137 | .active_lo_mask = 0x3001, | 147 | .active_lo_mask = 0x3801, |
138 | .msecs_asserted = 10, | 148 | .msecs_asserted = 10, |
139 | .msecs_recovery = 40, | 149 | .msecs_recovery = 40, |
140 | .ir_reset_mask = 0x0001, | 150 | .ir_reset_mask = 0x0001, |
141 | }, | 151 | }, |
142 | .i2c = &cx18_i2c_std, | 152 | .i2c = &cx18_i2c_nxp, |
143 | }; | 153 | }; |
144 | 154 | ||
145 | static const struct cx18_card cx18_card_hvr1600_samsung = { | 155 | static const struct cx18_card cx18_card_hvr1600_samsung = { |
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h index 3e750068f275..add7391ecaba 100644 --- a/drivers/media/video/cx18/cx18-cards.h +++ b/drivers/media/video/cx18/cx18-cards.h | |||
@@ -109,7 +109,7 @@ struct cx18_card_tuner { | |||
109 | 109 | ||
110 | struct cx18_card_tuner_i2c { | 110 | struct cx18_card_tuner_i2c { |
111 | unsigned short radio[2];/* radio tuner i2c address to probe */ | 111 | unsigned short radio[2];/* radio tuner i2c address to probe */ |
112 | unsigned short demod[2];/* demodulator i2c address to probe */ | 112 | unsigned short demod[3];/* demodulator i2c address to probe */ |
113 | unsigned short tv[4]; /* tv tuner i2c addresses to probe */ | 113 | unsigned short tv[4]; /* tv tuner i2c addresses to probe */ |
114 | }; | 114 | }; |
115 | 115 | ||
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 321c1b79794c..9e2f870f4258 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c | |||
@@ -423,7 +423,16 @@ static void cx18_process_eeprom(struct cx18 *cx) | |||
423 | return; | 423 | return; |
424 | 424 | ||
425 | /* autodetect tuner standard */ | 425 | /* autodetect tuner standard */ |
426 | if (tv.tuner_formats & V4L2_STD_PAL) { | 426 | #define TVEEPROM_TUNER_FORMAT_ALL (V4L2_STD_B | V4L2_STD_GH | \ |
427 | V4L2_STD_MN | \ | ||
428 | V4L2_STD_PAL_I | \ | ||
429 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC | \ | ||
430 | V4L2_STD_DK) | ||
431 | if ((tv.tuner_formats & TVEEPROM_TUNER_FORMAT_ALL) | ||
432 | == TVEEPROM_TUNER_FORMAT_ALL) { | ||
433 | CX18_DEBUG_INFO("Worldwide tuner detected\n"); | ||
434 | cx->std = V4L2_STD_ALL; | ||
435 | } else if (tv.tuner_formats & V4L2_STD_PAL) { | ||
427 | CX18_DEBUG_INFO("PAL tuner detected\n"); | 436 | CX18_DEBUG_INFO("PAL tuner detected\n"); |
428 | cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; | 437 | cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; |
429 | } else if (tv.tuner_formats & V4L2_STD_NTSC) { | 438 | } else if (tv.tuner_formats & V4L2_STD_NTSC) { |
@@ -818,7 +827,7 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, | |||
818 | cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; | 827 | cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; |
819 | pci_write_config_word(pci_dev, PCI_COMMAND, cmd); | 828 | pci_write_config_word(pci_dev, PCI_COMMAND, cmd); |
820 | 829 | ||
821 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &cx->card_rev); | 830 | cx->card_rev = pci_dev->revision; |
822 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); | 831 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); |
823 | 832 | ||
824 | if (pci_latency < 64 && cx18_pci_latency) { | 833 | if (pci_latency < 64 && cx18_pci_latency) { |
@@ -1001,7 +1010,15 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, | |||
1001 | if (cx->card->hw_all & CX18_HW_TVEEPROM) { | 1010 | if (cx->card->hw_all & CX18_HW_TVEEPROM) { |
1002 | /* Based on the model number the cardtype may be changed. | 1011 | /* Based on the model number the cardtype may be changed. |
1003 | The PCI IDs are not always reliable. */ | 1012 | The PCI IDs are not always reliable. */ |
1013 | const struct cx18_card *orig_card = cx->card; | ||
1004 | cx18_process_eeprom(cx); | 1014 | cx18_process_eeprom(cx); |
1015 | |||
1016 | if (cx->card != orig_card) { | ||
1017 | /* Changed the cardtype; re-reset the I2C chips */ | ||
1018 | cx18_gpio_init(cx); | ||
1019 | cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, | ||
1020 | core, reset, (u32) CX18_GPIO_RESET_I2C); | ||
1021 | } | ||
1005 | } | 1022 | } |
1006 | if (cx->card->comment) | 1023 | if (cx->card->comment) |
1007 | CX18_INFO("%s", cx->card->comment); | 1024 | CX18_INFO("%s", cx->card->comment); |
@@ -1087,6 +1104,8 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, | |||
1087 | /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) | 1104 | /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) |
1088 | are not. */ | 1105 | are not. */ |
1089 | cx->tuner_std = cx->std; | 1106 | cx->tuner_std = cx->std; |
1107 | if (cx->std == V4L2_STD_ALL) | ||
1108 | cx->std = V4L2_STD_NTSC_M; | ||
1090 | 1109 | ||
1091 | retval = cx18_streams_setup(cx); | 1110 | retval = cx18_streams_setup(cx); |
1092 | if (retval) { | 1111 | if (retval) { |
@@ -1133,6 +1152,7 @@ int cx18_init_on_first_open(struct cx18 *cx) | |||
1133 | int fw_retry_count = 3; | 1152 | int fw_retry_count = 3; |
1134 | struct v4l2_frequency vf; | 1153 | struct v4l2_frequency vf; |
1135 | struct cx18_open_id fh; | 1154 | struct cx18_open_id fh; |
1155 | v4l2_std_id std; | ||
1136 | 1156 | ||
1137 | fh.cx = cx; | 1157 | fh.cx = cx; |
1138 | 1158 | ||
@@ -1220,7 +1240,8 @@ int cx18_init_on_first_open(struct cx18 *cx) | |||
1220 | /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code | 1240 | /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code |
1221 | in one place. */ | 1241 | in one place. */ |
1222 | cx->std++; /* Force full standard initialization */ | 1242 | cx->std++; /* Force full standard initialization */ |
1223 | cx18_s_std(NULL, &fh, &cx->tuner_std); | 1243 | std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std; |
1244 | cx18_s_std(NULL, &fh, &std); | ||
1224 | cx18_s_frequency(NULL, &fh, &vf); | 1245 | cx18_s_frequency(NULL, &fh, &vf); |
1225 | return 0; | 1246 | return 0; |
1226 | } | 1247 | } |
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index b86a740c68df..086427288de8 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h | |||
@@ -65,6 +65,10 @@ | |||
65 | #include "dvb_net.h" | 65 | #include "dvb_net.h" |
66 | #include "dvbdev.h" | 66 | #include "dvbdev.h" |
67 | 67 | ||
68 | /* Videobuf / YUV support */ | ||
69 | #include <media/videobuf-core.h> | ||
70 | #include <media/videobuf-vmalloc.h> | ||
71 | |||
68 | #ifndef CONFIG_PCI | 72 | #ifndef CONFIG_PCI |
69 | # error "This driver requires kernel PCI support." | 73 | # error "This driver requires kernel PCI support." |
70 | #endif | 74 | #endif |
@@ -403,6 +407,23 @@ struct cx18_stream { | |||
403 | struct cx18_queue q_idle; /* idle - not in rotation */ | 407 | struct cx18_queue q_idle; /* idle - not in rotation */ |
404 | 408 | ||
405 | struct work_struct out_work_order; | 409 | struct work_struct out_work_order; |
410 | |||
411 | /* Videobuf for YUV video */ | ||
412 | u32 pixelformat; | ||
413 | struct list_head vb_capture; /* video capture queue */ | ||
414 | spinlock_t vb_lock; | ||
415 | struct timer_list vb_timeout; | ||
416 | |||
417 | struct videobuf_queue vbuf_q; | ||
418 | spinlock_t vbuf_q_lock; /* Protect vbuf_q */ | ||
419 | enum v4l2_buf_type vb_type; | ||
420 | }; | ||
421 | |||
422 | struct cx18_videobuf_buffer { | ||
423 | /* Common video buffer sub-system struct */ | ||
424 | struct videobuf_buffer vb; | ||
425 | v4l2_std_id tvnorm; /* selected tv norm */ | ||
426 | u32 bytes_used; | ||
406 | }; | 427 | }; |
407 | 428 | ||
408 | struct cx18_open_id { | 429 | struct cx18_open_id { |
@@ -410,6 +431,10 @@ struct cx18_open_id { | |||
410 | u32 open_id; | 431 | u32 open_id; |
411 | int type; | 432 | int type; |
412 | struct cx18 *cx; | 433 | struct cx18 *cx; |
434 | |||
435 | struct videobuf_queue vbuf_q; | ||
436 | spinlock_t s_lock; /* Protect vbuf_q */ | ||
437 | enum v4l2_buf_type vb_type; | ||
413 | }; | 438 | }; |
414 | 439 | ||
415 | static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh) | 440 | static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh) |
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index e9802d99439b..07411f34885a 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c | |||
@@ -597,6 +597,13 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, | |||
597 | mutex_unlock(&cx->serialize_lock); | 597 | mutex_unlock(&cx->serialize_lock); |
598 | if (rc) | 598 | if (rc) |
599 | return rc; | 599 | return rc; |
600 | |||
601 | if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
602 | (id->type == CX18_ENC_STREAM_TYPE_YUV)) { | ||
603 | return videobuf_read_stream(&s->vbuf_q, buf, count, pos, 0, | ||
604 | filp->f_flags & O_NONBLOCK); | ||
605 | } | ||
606 | |||
600 | return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); | 607 | return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); |
601 | } | 608 | } |
602 | 609 | ||
@@ -622,6 +629,15 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) | |||
622 | CX18_DEBUG_FILE("Encoder poll started capture\n"); | 629 | CX18_DEBUG_FILE("Encoder poll started capture\n"); |
623 | } | 630 | } |
624 | 631 | ||
632 | if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
633 | (id->type == CX18_ENC_STREAM_TYPE_YUV)) { | ||
634 | int videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait); | ||
635 | if (eof && videobuf_poll == POLLERR) | ||
636 | return POLLHUP; | ||
637 | else | ||
638 | return videobuf_poll; | ||
639 | } | ||
640 | |||
625 | /* add stream's waitq to the poll list */ | 641 | /* add stream's waitq to the poll list */ |
626 | CX18_DEBUG_HI_FILE("Encoder poll\n"); | 642 | CX18_DEBUG_HI_FILE("Encoder poll\n"); |
627 | poll_wait(filp, &s->waitq, wait); | 643 | poll_wait(filp, &s->waitq, wait); |
@@ -633,6 +649,58 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) | |||
633 | return 0; | 649 | return 0; |
634 | } | 650 | } |
635 | 651 | ||
652 | int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma) | ||
653 | { | ||
654 | struct cx18_open_id *id = file->private_data; | ||
655 | struct cx18 *cx = id->cx; | ||
656 | struct cx18_stream *s = &cx->streams[id->type]; | ||
657 | int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); | ||
658 | |||
659 | if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
660 | (id->type == CX18_ENC_STREAM_TYPE_YUV)) { | ||
661 | |||
662 | /* Start a capture if there is none */ | ||
663 | if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) { | ||
664 | int rc; | ||
665 | |||
666 | mutex_lock(&cx->serialize_lock); | ||
667 | rc = cx18_start_capture(id); | ||
668 | mutex_unlock(&cx->serialize_lock); | ||
669 | if (rc) { | ||
670 | CX18_DEBUG_INFO( | ||
671 | "Could not start capture for %s (%d)\n", | ||
672 | s->name, rc); | ||
673 | return -EINVAL; | ||
674 | } | ||
675 | CX18_DEBUG_FILE("Encoder mmap started capture\n"); | ||
676 | } | ||
677 | |||
678 | return videobuf_mmap_mapper(&s->vbuf_q, vma); | ||
679 | } | ||
680 | |||
681 | return -EINVAL; | ||
682 | } | ||
683 | |||
684 | void cx18_vb_timeout(unsigned long data) | ||
685 | { | ||
686 | struct cx18_stream *s = (struct cx18_stream *)data; | ||
687 | struct cx18_videobuf_buffer *buf; | ||
688 | unsigned long flags; | ||
689 | |||
690 | /* Return all of the buffers in error state, so the vbi/vid inode | ||
691 | * can return from blocking. | ||
692 | */ | ||
693 | spin_lock_irqsave(&s->vb_lock, flags); | ||
694 | while (!list_empty(&s->vb_capture)) { | ||
695 | buf = list_entry(s->vb_capture.next, | ||
696 | struct cx18_videobuf_buffer, vb.queue); | ||
697 | list_del(&buf->vb.queue); | ||
698 | buf->vb.state = VIDEOBUF_ERROR; | ||
699 | wake_up(&buf->vb.done); | ||
700 | } | ||
701 | spin_unlock_irqrestore(&s->vb_lock, flags); | ||
702 | } | ||
703 | |||
636 | void cx18_stop_capture(struct cx18_open_id *id, int gop_end) | 704 | void cx18_stop_capture(struct cx18_open_id *id, int gop_end) |
637 | { | 705 | { |
638 | struct cx18 *cx = id->cx; | 706 | struct cx18 *cx = id->cx; |
@@ -716,6 +784,8 @@ int cx18_v4l2_close(struct file *filp) | |||
716 | cx18_release_stream(s); | 784 | cx18_release_stream(s); |
717 | } else { | 785 | } else { |
718 | cx18_stop_capture(id, 0); | 786 | cx18_stop_capture(id, 0); |
787 | if (id->type == CX18_ENC_STREAM_TYPE_YUV) | ||
788 | videobuf_mmap_free(&id->vbuf_q); | ||
719 | } | 789 | } |
720 | kfree(id); | 790 | kfree(id); |
721 | mutex_unlock(&cx->serialize_lock); | 791 | mutex_unlock(&cx->serialize_lock); |
diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h index 5c8fcb884f0a..b9e5110ad043 100644 --- a/drivers/media/video/cx18/cx18-fileops.h +++ b/drivers/media/video/cx18/cx18-fileops.h | |||
@@ -33,6 +33,8 @@ int cx18_start_capture(struct cx18_open_id *id); | |||
33 | void cx18_stop_capture(struct cx18_open_id *id, int gop_end); | 33 | void cx18_stop_capture(struct cx18_open_id *id, int gop_end); |
34 | void cx18_mute(struct cx18 *cx); | 34 | void cx18_mute(struct cx18 *cx); |
35 | void cx18_unmute(struct cx18 *cx); | 35 | void cx18_unmute(struct cx18 *cx); |
36 | int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma); | ||
37 | void cx18_vb_timeout(unsigned long data); | ||
36 | 38 | ||
37 | /* Shared with cx18-alsa module */ | 39 | /* Shared with cx18-alsa module */ |
38 | int cx18_claim_stream(struct cx18_open_id *id, int type); | 40 | int cx18_claim_stream(struct cx18_open_id *id, int type); |
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 4f041c033c54..1933d4d11bf2 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c | |||
@@ -150,6 +150,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh, | |||
150 | { | 150 | { |
151 | struct cx18_open_id *id = fh2id(fh); | 151 | struct cx18_open_id *id = fh2id(fh); |
152 | struct cx18 *cx = id->cx; | 152 | struct cx18 *cx = id->cx; |
153 | struct cx18_stream *s = &cx->streams[id->type]; | ||
153 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | 154 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; |
154 | 155 | ||
155 | pixfmt->width = cx->cxhdl.width; | 156 | pixfmt->width = cx->cxhdl.width; |
@@ -158,9 +159,13 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh, | |||
158 | pixfmt->field = V4L2_FIELD_INTERLACED; | 159 | pixfmt->field = V4L2_FIELD_INTERLACED; |
159 | pixfmt->priv = 0; | 160 | pixfmt->priv = 0; |
160 | if (id->type == CX18_ENC_STREAM_TYPE_YUV) { | 161 | if (id->type == CX18_ENC_STREAM_TYPE_YUV) { |
161 | pixfmt->pixelformat = V4L2_PIX_FMT_HM12; | 162 | pixfmt->pixelformat = s->pixelformat; |
162 | /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */ | 163 | /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) |
163 | pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; | 164 | UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ |
165 | if (s->pixelformat == V4L2_PIX_FMT_HM12) | ||
166 | pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; | ||
167 | else | ||
168 | pixfmt->sizeimage = pixfmt->height * 720 * 2; | ||
164 | pixfmt->bytesperline = 720; | 169 | pixfmt->bytesperline = 720; |
165 | } else { | 170 | } else { |
166 | pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; | 171 | pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; |
@@ -237,7 +242,6 @@ static int cx18_try_fmt_vid_cap(struct file *file, void *fh, | |||
237 | h = min(h, cx->is_50hz ? 576 : 480); | 242 | h = min(h, cx->is_50hz ? 576 : 480); |
238 | h = max(h, min_h); | 243 | h = max(h, min_h); |
239 | 244 | ||
240 | cx18_g_fmt_vid_cap(file, fh, fmt); | ||
241 | fmt->fmt.pix.width = w; | 245 | fmt->fmt.pix.width = w; |
242 | fmt->fmt.pix.height = h; | 246 | fmt->fmt.pix.height = h; |
243 | return 0; | 247 | return 0; |
@@ -274,6 +278,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, | |||
274 | struct cx18_open_id *id = fh2id(fh); | 278 | struct cx18_open_id *id = fh2id(fh); |
275 | struct cx18 *cx = id->cx; | 279 | struct cx18 *cx = id->cx; |
276 | struct v4l2_mbus_framefmt mbus_fmt; | 280 | struct v4l2_mbus_framefmt mbus_fmt; |
281 | struct cx18_stream *s = &cx->streams[id->type]; | ||
277 | int ret; | 282 | int ret; |
278 | int w, h; | 283 | int w, h; |
279 | 284 | ||
@@ -283,12 +288,15 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, | |||
283 | w = fmt->fmt.pix.width; | 288 | w = fmt->fmt.pix.width; |
284 | h = fmt->fmt.pix.height; | 289 | h = fmt->fmt.pix.height; |
285 | 290 | ||
286 | if (cx->cxhdl.width == w && cx->cxhdl.height == h) | 291 | if (cx->cxhdl.width == w && cx->cxhdl.height == h && |
292 | s->pixelformat == fmt->fmt.pix.pixelformat) | ||
287 | return 0; | 293 | return 0; |
288 | 294 | ||
289 | if (atomic_read(&cx->ana_capturing) > 0) | 295 | if (atomic_read(&cx->ana_capturing) > 0) |
290 | return -EBUSY; | 296 | return -EBUSY; |
291 | 297 | ||
298 | s->pixelformat = fmt->fmt.pix.pixelformat; | ||
299 | |||
292 | mbus_fmt.width = cx->cxhdl.width = w; | 300 | mbus_fmt.width = cx->cxhdl.width = w; |
293 | mbus_fmt.height = cx->cxhdl.height = h; | 301 | mbus_fmt.height = cx->cxhdl.height = h; |
294 | mbus_fmt.code = V4L2_MBUS_FMT_FIXED; | 302 | mbus_fmt.code = V4L2_MBUS_FMT_FIXED; |
@@ -540,16 +548,19 @@ static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) | |||
540 | static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, | 548 | static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, |
541 | struct v4l2_fmtdesc *fmt) | 549 | struct v4l2_fmtdesc *fmt) |
542 | { | 550 | { |
543 | static struct v4l2_fmtdesc formats[] = { | 551 | static const struct v4l2_fmtdesc formats[] = { |
544 | { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, | 552 | { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, |
545 | "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } | 553 | "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } |
546 | }, | 554 | }, |
547 | { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED, | 555 | { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED, |
548 | "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 } | 556 | "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 } |
549 | } | 557 | }, |
558 | { 2, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, | ||
559 | "UYVY 4:2:2", V4L2_PIX_FMT_UYVY, { 0, 0, 0, 0 } | ||
560 | }, | ||
550 | }; | 561 | }; |
551 | 562 | ||
552 | if (fmt->index > 1) | 563 | if (fmt->index > ARRAY_SIZE(formats) - 1) |
553 | return -EINVAL; | 564 | return -EINVAL; |
554 | *fmt = formats[fmt->index]; | 565 | *fmt = formats[fmt->index]; |
555 | return 0; | 566 | return 0; |
@@ -863,6 +874,117 @@ static int cx18_g_enc_index(struct file *file, void *fh, | |||
863 | return 0; | 874 | return 0; |
864 | } | 875 | } |
865 | 876 | ||
877 | static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id) | ||
878 | { | ||
879 | struct videobuf_queue *q = NULL; | ||
880 | struct cx18 *cx = id->cx; | ||
881 | struct cx18_stream *s = &cx->streams[id->type]; | ||
882 | |||
883 | switch (s->vb_type) { | ||
884 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
885 | q = &s->vbuf_q; | ||
886 | break; | ||
887 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
888 | break; | ||
889 | default: | ||
890 | break; | ||
891 | } | ||
892 | return q; | ||
893 | } | ||
894 | |||
895 | static int cx18_streamon(struct file *file, void *priv, | ||
896 | enum v4l2_buf_type type) | ||
897 | { | ||
898 | struct cx18_open_id *id = file->private_data; | ||
899 | struct cx18 *cx = id->cx; | ||
900 | struct cx18_stream *s = &cx->streams[id->type]; | ||
901 | |||
902 | /* Start the hardware only if we're the video device */ | ||
903 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
904 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
905 | return -EINVAL; | ||
906 | |||
907 | if (id->type != CX18_ENC_STREAM_TYPE_YUV) | ||
908 | return -EINVAL; | ||
909 | |||
910 | /* Establish a buffer timeout */ | ||
911 | mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); | ||
912 | |||
913 | return videobuf_streamon(cx18_vb_queue(id)); | ||
914 | } | ||
915 | |||
916 | static int cx18_streamoff(struct file *file, void *priv, | ||
917 | enum v4l2_buf_type type) | ||
918 | { | ||
919 | struct cx18_open_id *id = file->private_data; | ||
920 | struct cx18 *cx = id->cx; | ||
921 | struct cx18_stream *s = &cx->streams[id->type]; | ||
922 | |||
923 | /* Start the hardware only if we're the video device */ | ||
924 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
925 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
926 | return -EINVAL; | ||
927 | |||
928 | if (id->type != CX18_ENC_STREAM_TYPE_YUV) | ||
929 | return -EINVAL; | ||
930 | |||
931 | return videobuf_streamoff(cx18_vb_queue(id)); | ||
932 | } | ||
933 | |||
934 | static int cx18_reqbufs(struct file *file, void *priv, | ||
935 | struct v4l2_requestbuffers *rb) | ||
936 | { | ||
937 | struct cx18_open_id *id = file->private_data; | ||
938 | struct cx18 *cx = id->cx; | ||
939 | struct cx18_stream *s = &cx->streams[id->type]; | ||
940 | |||
941 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
942 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
943 | return -EINVAL; | ||
944 | |||
945 | return videobuf_reqbufs(cx18_vb_queue(id), rb); | ||
946 | } | ||
947 | |||
948 | static int cx18_querybuf(struct file *file, void *priv, | ||
949 | struct v4l2_buffer *b) | ||
950 | { | ||
951 | struct cx18_open_id *id = file->private_data; | ||
952 | struct cx18 *cx = id->cx; | ||
953 | struct cx18_stream *s = &cx->streams[id->type]; | ||
954 | |||
955 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
956 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
957 | return -EINVAL; | ||
958 | |||
959 | return videobuf_querybuf(cx18_vb_queue(id), b); | ||
960 | } | ||
961 | |||
962 | static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) | ||
963 | { | ||
964 | struct cx18_open_id *id = file->private_data; | ||
965 | struct cx18 *cx = id->cx; | ||
966 | struct cx18_stream *s = &cx->streams[id->type]; | ||
967 | |||
968 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
969 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
970 | return -EINVAL; | ||
971 | |||
972 | return videobuf_qbuf(cx18_vb_queue(id), b); | ||
973 | } | ||
974 | |||
975 | static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) | ||
976 | { | ||
977 | struct cx18_open_id *id = file->private_data; | ||
978 | struct cx18 *cx = id->cx; | ||
979 | struct cx18_stream *s = &cx->streams[id->type]; | ||
980 | |||
981 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
982 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
983 | return -EINVAL; | ||
984 | |||
985 | return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK); | ||
986 | } | ||
987 | |||
866 | static int cx18_encoder_cmd(struct file *file, void *fh, | 988 | static int cx18_encoder_cmd(struct file *file, void *fh, |
867 | struct v4l2_encoder_cmd *enc) | 989 | struct v4l2_encoder_cmd *enc) |
868 | { | 990 | { |
@@ -1081,6 +1203,12 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = { | |||
1081 | .vidioc_s_register = cx18_s_register, | 1203 | .vidioc_s_register = cx18_s_register, |
1082 | #endif | 1204 | #endif |
1083 | .vidioc_default = cx18_default, | 1205 | .vidioc_default = cx18_default, |
1206 | .vidioc_streamon = cx18_streamon, | ||
1207 | .vidioc_streamoff = cx18_streamoff, | ||
1208 | .vidioc_reqbufs = cx18_reqbufs, | ||
1209 | .vidioc_querybuf = cx18_querybuf, | ||
1210 | .vidioc_qbuf = cx18_qbuf, | ||
1211 | .vidioc_dqbuf = cx18_dqbuf, | ||
1084 | }; | 1212 | }; |
1085 | 1213 | ||
1086 | void cx18_set_funcs(struct video_device *vdev) | 1214 | void cx18_set_funcs(struct video_device *vdev) |
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index 9605d54bd083..c07191e09fcb 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c | |||
@@ -81,6 +81,7 @@ static const struct cx18_api_info api_info[] = { | |||
81 | API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0), | 81 | API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0), |
82 | API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0), | 82 | API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0), |
83 | API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), | 83 | API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), |
84 | API_ENTRY(CPU, CX18_CPU_SET_VFC_PARAM, 0), | ||
84 | API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), | 85 | API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), |
85 | API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), | 86 | API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), |
86 | API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), | 87 | API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), |
@@ -158,6 +159,60 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl) | |||
158 | } | 159 | } |
159 | } | 160 | } |
160 | 161 | ||
162 | static void cx18_mdl_send_to_videobuf(struct cx18_stream *s, | ||
163 | struct cx18_mdl *mdl) | ||
164 | { | ||
165 | struct cx18_videobuf_buffer *vb_buf; | ||
166 | struct cx18_buffer *buf; | ||
167 | u8 *p; | ||
168 | u32 offset = 0; | ||
169 | int dispatch = 0; | ||
170 | |||
171 | if (mdl->bytesused == 0) | ||
172 | return; | ||
173 | |||
174 | /* Acquire a videobuf buffer, clone to and and release it */ | ||
175 | spin_lock(&s->vb_lock); | ||
176 | if (list_empty(&s->vb_capture)) | ||
177 | goto out; | ||
178 | |||
179 | vb_buf = list_first_entry(&s->vb_capture, struct cx18_videobuf_buffer, | ||
180 | vb.queue); | ||
181 | |||
182 | p = videobuf_to_vmalloc(&vb_buf->vb); | ||
183 | if (!p) | ||
184 | goto out; | ||
185 | |||
186 | offset = vb_buf->bytes_used; | ||
187 | list_for_each_entry(buf, &mdl->buf_list, list) { | ||
188 | if (buf->bytesused == 0) | ||
189 | break; | ||
190 | |||
191 | if ((offset + buf->bytesused) <= vb_buf->vb.bsize) { | ||
192 | memcpy(p + offset, buf->buf, buf->bytesused); | ||
193 | offset += buf->bytesused; | ||
194 | vb_buf->bytes_used += buf->bytesused; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | /* If we've filled the buffer as per the callers res then dispatch it */ | ||
199 | if (vb_buf->bytes_used >= (vb_buf->vb.width * vb_buf->vb.height * 2)) { | ||
200 | dispatch = 1; | ||
201 | vb_buf->bytes_used = 0; | ||
202 | } | ||
203 | |||
204 | if (dispatch) { | ||
205 | vb_buf->vb.ts = ktime_to_timeval(ktime_get()); | ||
206 | list_del(&vb_buf->vb.queue); | ||
207 | vb_buf->vb.state = VIDEOBUF_DONE; | ||
208 | wake_up(&vb_buf->vb.done); | ||
209 | } | ||
210 | |||
211 | mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); | ||
212 | |||
213 | out: | ||
214 | spin_unlock(&s->vb_lock); | ||
215 | } | ||
161 | 216 | ||
162 | static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s, | 217 | static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s, |
163 | struct cx18_mdl *mdl) | 218 | struct cx18_mdl *mdl) |
@@ -263,6 +318,9 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) | |||
263 | } else { | 318 | } else { |
264 | cx18_enqueue(s, mdl, &s->q_full); | 319 | cx18_enqueue(s, mdl, &s->q_full); |
265 | } | 320 | } |
321 | } else if (s->type == CX18_ENC_STREAM_TYPE_YUV) { | ||
322 | cx18_mdl_send_to_videobuf(s, mdl); | ||
323 | cx18_enqueue(s, mdl, &s->q_free); | ||
266 | } else { | 324 | } else { |
267 | cx18_enqueue(s, mdl, &s->q_full); | 325 | cx18_enqueue(s, mdl, &s->q_full); |
268 | if (s->type == CX18_ENC_STREAM_TYPE_IDX) | 326 | if (s->type == CX18_ENC_STREAM_TYPE_IDX) |
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 6fbc356113c1..852f420fd271 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c | |||
@@ -44,6 +44,7 @@ static struct v4l2_file_operations cx18_v4l2_enc_fops = { | |||
44 | .unlocked_ioctl = cx18_v4l2_ioctl, | 44 | .unlocked_ioctl = cx18_v4l2_ioctl, |
45 | .release = cx18_v4l2_close, | 45 | .release = cx18_v4l2_close, |
46 | .poll = cx18_v4l2_enc_poll, | 46 | .poll = cx18_v4l2_enc_poll, |
47 | .mmap = cx18_v4l2_mmap, | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | /* offset from 0 to register ts v4l2 minors on */ | 50 | /* offset from 0 to register ts v4l2 minors on */ |
@@ -97,6 +98,141 @@ static struct { | |||
97 | }, | 98 | }, |
98 | }; | 99 | }; |
99 | 100 | ||
101 | |||
102 | void cx18_dma_free(struct videobuf_queue *q, | ||
103 | struct cx18_stream *s, struct cx18_videobuf_buffer *buf) | ||
104 | { | ||
105 | videobuf_waiton(q, &buf->vb, 0, 0); | ||
106 | videobuf_vmalloc_free(&buf->vb); | ||
107 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | ||
108 | } | ||
109 | |||
110 | static int cx18_prepare_buffer(struct videobuf_queue *q, | ||
111 | struct cx18_stream *s, | ||
112 | struct cx18_videobuf_buffer *buf, | ||
113 | u32 pixelformat, | ||
114 | unsigned int width, unsigned int height, | ||
115 | enum v4l2_field field) | ||
116 | { | ||
117 | struct cx18 *cx = s->cx; | ||
118 | int rc = 0; | ||
119 | |||
120 | /* check settings */ | ||
121 | buf->bytes_used = 0; | ||
122 | |||
123 | if ((width < 48) || (height < 32)) | ||
124 | return -EINVAL; | ||
125 | |||
126 | buf->vb.size = (width * height * 2); | ||
127 | if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) | ||
128 | return -EINVAL; | ||
129 | |||
130 | /* alloc + fill struct (if changed) */ | ||
131 | if (buf->vb.width != width || buf->vb.height != height || | ||
132 | buf->vb.field != field || s->pixelformat != pixelformat || | ||
133 | buf->tvnorm != cx->std) { | ||
134 | |||
135 | buf->vb.width = width; | ||
136 | buf->vb.height = height; | ||
137 | buf->vb.field = field; | ||
138 | buf->tvnorm = cx->std; | ||
139 | s->pixelformat = pixelformat; | ||
140 | |||
141 | cx18_dma_free(q, s, buf); | ||
142 | } | ||
143 | |||
144 | if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) | ||
145 | return -EINVAL; | ||
146 | |||
147 | if (buf->vb.field == 0) | ||
148 | buf->vb.field = V4L2_FIELD_INTERLACED; | ||
149 | |||
150 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
151 | buf->vb.width = width; | ||
152 | buf->vb.height = height; | ||
153 | buf->vb.field = field; | ||
154 | buf->tvnorm = cx->std; | ||
155 | s->pixelformat = pixelformat; | ||
156 | |||
157 | rc = videobuf_iolock(q, &buf->vb, NULL); | ||
158 | if (rc != 0) | ||
159 | goto fail; | ||
160 | } | ||
161 | buf->vb.state = VIDEOBUF_PREPARED; | ||
162 | return 0; | ||
163 | |||
164 | fail: | ||
165 | cx18_dma_free(q, s, buf); | ||
166 | return rc; | ||
167 | |||
168 | } | ||
169 | |||
170 | /* VB_MIN_BUFSIZE is lcm(1440 * 480, 1440 * 576) | ||
171 | 1440 is a single line of 4:2:2 YUV at 720 luma samples wide | ||
172 | */ | ||
173 | #define VB_MIN_BUFFERS 32 | ||
174 | #define VB_MIN_BUFSIZE 4147200 | ||
175 | |||
176 | static int buffer_setup(struct videobuf_queue *q, | ||
177 | unsigned int *count, unsigned int *size) | ||
178 | { | ||
179 | struct cx18_stream *s = q->priv_data; | ||
180 | struct cx18 *cx = s->cx; | ||
181 | |||
182 | *size = 2 * cx->cxhdl.width * cx->cxhdl.height; | ||
183 | if (*count == 0) | ||
184 | *count = VB_MIN_BUFFERS; | ||
185 | |||
186 | while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE) | ||
187 | (*count)--; | ||
188 | |||
189 | q->field = V4L2_FIELD_INTERLACED; | ||
190 | q->last = V4L2_FIELD_INTERLACED; | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int buffer_prepare(struct videobuf_queue *q, | ||
196 | struct videobuf_buffer *vb, | ||
197 | enum v4l2_field field) | ||
198 | { | ||
199 | struct cx18_videobuf_buffer *buf = | ||
200 | container_of(vb, struct cx18_videobuf_buffer, vb); | ||
201 | struct cx18_stream *s = q->priv_data; | ||
202 | struct cx18 *cx = s->cx; | ||
203 | |||
204 | return cx18_prepare_buffer(q, s, buf, s->pixelformat, | ||
205 | cx->cxhdl.width, cx->cxhdl.height, field); | ||
206 | } | ||
207 | |||
208 | static void buffer_release(struct videobuf_queue *q, | ||
209 | struct videobuf_buffer *vb) | ||
210 | { | ||
211 | struct cx18_videobuf_buffer *buf = | ||
212 | container_of(vb, struct cx18_videobuf_buffer, vb); | ||
213 | struct cx18_stream *s = q->priv_data; | ||
214 | |||
215 | cx18_dma_free(q, s, buf); | ||
216 | } | ||
217 | |||
218 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
219 | { | ||
220 | struct cx18_videobuf_buffer *buf = | ||
221 | container_of(vb, struct cx18_videobuf_buffer, vb); | ||
222 | struct cx18_stream *s = q->priv_data; | ||
223 | |||
224 | buf->vb.state = VIDEOBUF_QUEUED; | ||
225 | |||
226 | list_add_tail(&buf->vb.queue, &s->vb_capture); | ||
227 | } | ||
228 | |||
229 | static struct videobuf_queue_ops cx18_videobuf_qops = { | ||
230 | .buf_setup = buffer_setup, | ||
231 | .buf_prepare = buffer_prepare, | ||
232 | .buf_queue = buffer_queue, | ||
233 | .buf_release = buffer_release, | ||
234 | }; | ||
235 | |||
100 | static void cx18_stream_init(struct cx18 *cx, int type) | 236 | static void cx18_stream_init(struct cx18 *cx, int type) |
101 | { | 237 | { |
102 | struct cx18_stream *s = &cx->streams[type]; | 238 | struct cx18_stream *s = &cx->streams[type]; |
@@ -132,6 +268,26 @@ static void cx18_stream_init(struct cx18 *cx, int type) | |||
132 | cx18_queue_init(&s->q_idle); | 268 | cx18_queue_init(&s->q_idle); |
133 | 269 | ||
134 | INIT_WORK(&s->out_work_order, cx18_out_work_handler); | 270 | INIT_WORK(&s->out_work_order, cx18_out_work_handler); |
271 | |||
272 | INIT_LIST_HEAD(&s->vb_capture); | ||
273 | s->vb_timeout.function = cx18_vb_timeout; | ||
274 | s->vb_timeout.data = (unsigned long)s; | ||
275 | init_timer(&s->vb_timeout); | ||
276 | spin_lock_init(&s->vb_lock); | ||
277 | if (type == CX18_ENC_STREAM_TYPE_YUV) { | ||
278 | spin_lock_init(&s->vbuf_q_lock); | ||
279 | |||
280 | s->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
281 | videobuf_queue_vmalloc_init(&s->vbuf_q, &cx18_videobuf_qops, | ||
282 | &cx->pci_dev->dev, &s->vbuf_q_lock, | ||
283 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
284 | V4L2_FIELD_INTERLACED, | ||
285 | sizeof(struct cx18_videobuf_buffer), | ||
286 | s, &cx->serialize_lock); | ||
287 | |||
288 | /* Assume the previous pixel default */ | ||
289 | s->pixelformat = V4L2_PIX_FMT_HM12; | ||
290 | } | ||
135 | } | 291 | } |
136 | 292 | ||
137 | static int cx18_prep_dev(struct cx18 *cx, int type) | 293 | static int cx18_prep_dev(struct cx18 *cx, int type) |
@@ -372,6 +528,9 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) | |||
372 | if (vdev == NULL) | 528 | if (vdev == NULL) |
373 | continue; | 529 | continue; |
374 | 530 | ||
531 | if (type == CX18_ENC_STREAM_TYPE_YUV) | ||
532 | videobuf_mmap_free(&cx->streams[type].vbuf_q); | ||
533 | |||
375 | cx18_stream_free(&cx->streams[type]); | 534 | cx18_stream_free(&cx->streams[type]); |
376 | 535 | ||
377 | /* Unregister or release device */ | 536 | /* Unregister or release device */ |
@@ -581,7 +740,10 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s) | |||
581 | * Set the MDL size to the exact size needed for one frame. | 740 | * Set the MDL size to the exact size needed for one frame. |
582 | * Use enough buffers per MDL to cover the MDL size | 741 | * Use enough buffers per MDL to cover the MDL size |
583 | */ | 742 | */ |
584 | s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2; | 743 | if (s->pixelformat == V4L2_PIX_FMT_HM12) |
744 | s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2; | ||
745 | else | ||
746 | s->mdl_size = 720 * s->cx->cxhdl.height * 2; | ||
585 | s->bufs_per_mdl = s->mdl_size / s->buf_size; | 747 | s->bufs_per_mdl = s->mdl_size / s->buf_size; |
586 | if (s->mdl_size % s->buf_size) | 748 | if (s->mdl_size % s->buf_size) |
587 | s->bufs_per_mdl++; | 749 | s->bufs_per_mdl++; |
@@ -729,6 +891,19 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | |||
729 | test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) | 891 | test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) |
730 | cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, | 892 | cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, |
731 | (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); | 893 | (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); |
894 | |||
895 | /* Enable the Video Format Converter for UYVY 4:2:2 support, | ||
896 | * rather than the default HM12 Macroblovk 4:2:0 support. | ||
897 | */ | ||
898 | if (captype == CAPTURE_CHANNEL_TYPE_YUV) { | ||
899 | if (s->pixelformat == V4L2_PIX_FMT_UYVY) | ||
900 | cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, | ||
901 | s->handle, 1); | ||
902 | else | ||
903 | /* If in doubt, default to HM12 */ | ||
904 | cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, | ||
905 | s->handle, 0); | ||
906 | } | ||
732 | } | 907 | } |
733 | 908 | ||
734 | if (atomic_read(&cx->tot_capturing) == 0) { | 909 | if (atomic_read(&cx->tot_capturing) == 0) { |
diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h index 3e1aec4bcfde..cd189b6bbe20 100644 --- a/drivers/media/video/cx18/cx18-version.h +++ b/drivers/media/video/cx18/cx18-version.h | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | #define CX18_DRIVER_NAME "cx18" | 25 | #define CX18_DRIVER_NAME "cx18" |
26 | #define CX18_DRIVER_VERSION_MAJOR 1 | 26 | #define CX18_DRIVER_VERSION_MAJOR 1 |
27 | #define CX18_DRIVER_VERSION_MINOR 4 | 27 | #define CX18_DRIVER_VERSION_MINOR 5 |
28 | #define CX18_DRIVER_VERSION_PATCHLEVEL 0 | 28 | #define CX18_DRIVER_VERSION_PATCHLEVEL 0 |
29 | 29 | ||
30 | #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) | 30 | #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) |
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h index 935f557acbd0..767a8d23e3f2 100644 --- a/drivers/media/video/cx18/cx23418.h +++ b/drivers/media/video/cx18/cx23418.h | |||
@@ -342,6 +342,12 @@ | |||
342 | ReturnCode */ | 342 | ReturnCode */ |
343 | #define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022) | 343 | #define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022) |
344 | 344 | ||
345 | /* Description: Set VFC parameters | ||
346 | IN[0] - task handle | ||
347 | IN[1] - VFC enable flag, 1 - enable, 0 - disable | ||
348 | */ | ||
349 | #define CX18_CPU_SET_VFC_PARAM (CPU_CMD_MASK_CAPTURE | 0x0023) | ||
350 | |||
345 | /* Below is the list of commands related to the data exchange */ | 351 | /* Below is the list of commands related to the data exchange */ |
346 | #define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000) | 352 | #define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000) |
347 | 353 | ||
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index f49230d170e6..22703815a31f 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c | |||
@@ -401,6 +401,44 @@ struct cx231xx_board cx231xx_boards[] = { | |||
401 | .gpio = NULL, | 401 | .gpio = NULL, |
402 | } }, | 402 | } }, |
403 | }, | 403 | }, |
404 | [CX231XX_BOARD_KWORLD_UB430_USB_HYBRID] = { | ||
405 | .name = "Kworld UB430 USB Hybrid", | ||
406 | .tuner_type = TUNER_NXP_TDA18271, | ||
407 | .tuner_addr = 0x60, | ||
408 | .decoder = CX231XX_AVDECODER, | ||
409 | .output_mode = OUT_MODE_VIP11, | ||
410 | .demod_xfer_mode = 0, | ||
411 | .ctl_pin_status_mask = 0xFFFFFFC4, | ||
412 | .agc_analog_digital_select_gpio = 0x11, /* According with PV cxPolaris.inf file */ | ||
413 | .tuner_sif_gpio = -1, | ||
414 | .tuner_scl_gpio = -1, | ||
415 | .tuner_sda_gpio = -1, | ||
416 | .gpio_pin_status_mask = 0x4001000, | ||
417 | .tuner_i2c_master = 2, | ||
418 | .demod_i2c_master = 1, | ||
419 | .ir_i2c_master = 2, | ||
420 | .has_dvb = 1, | ||
421 | .demod_addr = 0x10, | ||
422 | .norm = V4L2_STD_PAL_M, | ||
423 | .input = {{ | ||
424 | .type = CX231XX_VMUX_TELEVISION, | ||
425 | .vmux = CX231XX_VIN_3_1, | ||
426 | .amux = CX231XX_AMUX_VIDEO, | ||
427 | .gpio = NULL, | ||
428 | }, { | ||
429 | .type = CX231XX_VMUX_COMPOSITE1, | ||
430 | .vmux = CX231XX_VIN_2_1, | ||
431 | .amux = CX231XX_AMUX_LINE_IN, | ||
432 | .gpio = NULL, | ||
433 | }, { | ||
434 | .type = CX231XX_VMUX_SVIDEO, | ||
435 | .vmux = CX231XX_VIN_1_1 | | ||
436 | (CX231XX_VIN_1_2 << 8) | | ||
437 | CX25840_SVIDEO_ON, | ||
438 | .amux = CX231XX_AMUX_LINE_IN, | ||
439 | .gpio = NULL, | ||
440 | } }, | ||
441 | }, | ||
404 | [CX231XX_BOARD_PV_PLAYTV_USB_HYBRID] = { | 442 | [CX231XX_BOARD_PV_PLAYTV_USB_HYBRID] = { |
405 | .name = "Pixelview PlayTV USB Hybrid", | 443 | .name = "Pixelview PlayTV USB Hybrid", |
406 | .tuner_type = TUNER_NXP_TDA18271, | 444 | .tuner_type = TUNER_NXP_TDA18271, |
@@ -469,6 +507,31 @@ struct cx231xx_board cx231xx_boards[] = { | |||
469 | } | 507 | } |
470 | }, | 508 | }, |
471 | }, | 509 | }, |
510 | |||
511 | [CX231XX_BOARD_ICONBIT_U100] = { | ||
512 | .name = "Iconbit Analog Stick U100 FM", | ||
513 | .tuner_type = TUNER_ABSENT, | ||
514 | .decoder = CX231XX_AVDECODER, | ||
515 | .output_mode = OUT_MODE_VIP11, | ||
516 | .demod_xfer_mode = 0, | ||
517 | .ctl_pin_status_mask = 0xFFFFFFC4, | ||
518 | .agc_analog_digital_select_gpio = 0x1C, | ||
519 | .gpio_pin_status_mask = 0x4001000, | ||
520 | |||
521 | .input = {{ | ||
522 | .type = CX231XX_VMUX_COMPOSITE1, | ||
523 | .vmux = CX231XX_VIN_2_1, | ||
524 | .amux = CX231XX_AMUX_LINE_IN, | ||
525 | .gpio = NULL, | ||
526 | }, { | ||
527 | .type = CX231XX_VMUX_SVIDEO, | ||
528 | .vmux = CX231XX_VIN_1_1 | | ||
529 | (CX231XX_VIN_1_2 << 8) | | ||
530 | CX25840_SVIDEO_ON, | ||
531 | .amux = CX231XX_AMUX_LINE_IN, | ||
532 | .gpio = NULL, | ||
533 | } }, | ||
534 | }, | ||
472 | }; | 535 | }; |
473 | const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); | 536 | const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); |
474 | 537 | ||
@@ -500,6 +563,10 @@ struct usb_device_id cx231xx_id_table[] = { | |||
500 | .driver_info = CX231XX_BOARD_PV_PLAYTV_USB_HYBRID}, | 563 | .driver_info = CX231XX_BOARD_PV_PLAYTV_USB_HYBRID}, |
501 | {USB_DEVICE(USB_VID_PIXELVIEW, 0x5014), | 564 | {USB_DEVICE(USB_VID_PIXELVIEW, 0x5014), |
502 | .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB}, | 565 | .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB}, |
566 | {USB_DEVICE(0x1b80, 0xe424), | ||
567 | .driver_info = CX231XX_BOARD_KWORLD_UB430_USB_HYBRID}, | ||
568 | {USB_DEVICE(0x1f4d, 0x0237), | ||
569 | .driver_info = CX231XX_BOARD_ICONBIT_U100}, | ||
503 | {}, | 570 | {}, |
504 | }; | 571 | }; |
505 | 572 | ||
diff --git a/drivers/media/video/cx231xx/cx231xx-dvb.c b/drivers/media/video/cx231xx/cx231xx-dvb.c index 363aa6004221..da9a4a0aab79 100644 --- a/drivers/media/video/cx231xx/cx231xx-dvb.c +++ b/drivers/media/video/cx231xx/cx231xx-dvb.c | |||
@@ -704,6 +704,7 @@ static int dvb_init(struct cx231xx *dev) | |||
704 | break; | 704 | break; |
705 | 705 | ||
706 | case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: | 706 | case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: |
707 | case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID: | ||
707 | 708 | ||
708 | printk(KERN_INFO "%s: looking for demod on i2c bus: %d\n", | 709 | printk(KERN_INFO "%s: looking for demod on i2c bus: %d\n", |
709 | __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap)); | 710 | __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap)); |
diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h index bd4a9cf29577..46dd84067816 100644 --- a/drivers/media/video/cx231xx/cx231xx.h +++ b/drivers/media/video/cx231xx/cx231xx.h | |||
@@ -65,6 +65,8 @@ | |||
65 | #define CX231XX_BOARD_HAUPPAUGE_USBLIVE2 9 | 65 | #define CX231XX_BOARD_HAUPPAUGE_USBLIVE2 9 |
66 | #define CX231XX_BOARD_PV_PLAYTV_USB_HYBRID 10 | 66 | #define CX231XX_BOARD_PV_PLAYTV_USB_HYBRID 10 |
67 | #define CX231XX_BOARD_PV_XCAPTURE_USB 11 | 67 | #define CX231XX_BOARD_PV_XCAPTURE_USB 11 |
68 | #define CX231XX_BOARD_KWORLD_UB430_USB_HYBRID 12 | ||
69 | #define CX231XX_BOARD_ICONBIT_U100 13 | ||
68 | 70 | ||
69 | /* Limits minimum and default number of buffers */ | 71 | /* Limits minimum and default number of buffers */ |
70 | #define CX231XX_MIN_BUF 4 | 72 | #define CX231XX_MIN_BUF 4 |
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index ea88722cb4ab..2354336862cf 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c | |||
@@ -1399,6 +1399,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) | |||
1399 | else | 1399 | else |
1400 | altera_init(&netup_config, fw); | 1400 | altera_init(&netup_config, fw); |
1401 | 1401 | ||
1402 | release_firmware(fw); | ||
1402 | break; | 1403 | break; |
1403 | } | 1404 | } |
1404 | } | 1405 | } |
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 9933810b4e33..64d9b2136ff6 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c | |||
@@ -2045,7 +2045,7 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev, | |||
2045 | } | 2045 | } |
2046 | 2046 | ||
2047 | /* print pci info */ | 2047 | /* print pci info */ |
2048 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); | 2048 | dev->pci_rev = pci_dev->revision; |
2049 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); | 2049 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); |
2050 | printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " | 2050 | printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " |
2051 | "latency: %d, mmio: 0x%llx\n", dev->name, | 2051 | "latency: %d, mmio: 0x%llx\n", dev->name, |
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index bca307eb1e24..11e49bbc4a66 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c | |||
@@ -1060,18 +1060,21 @@ static int mpeg_open(struct file *file) | |||
1060 | 1060 | ||
1061 | /* Make sure we can acquire the hardware */ | 1061 | /* Make sure we can acquire the hardware */ |
1062 | drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); | 1062 | drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); |
1063 | if (drv) { | 1063 | if (!drv) { |
1064 | err = drv->request_acquire(drv); | 1064 | dprintk(1, "%s: blackbird driver is not loaded\n", __func__); |
1065 | if(err != 0) { | 1065 | mutex_unlock(&dev->core->lock); |
1066 | dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err); | 1066 | return -ENODEV; |
1067 | mutex_unlock(&dev->core->lock); | 1067 | } |
1068 | return err; | 1068 | |
1069 | } | 1069 | err = drv->request_acquire(drv); |
1070 | if (err != 0) { | ||
1071 | dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err); | ||
1072 | mutex_unlock(&dev->core->lock); | ||
1073 | return err; | ||
1070 | } | 1074 | } |
1071 | 1075 | ||
1072 | if (!atomic_read(&dev->core->mpeg_users) && blackbird_initialize_codec(dev) < 0) { | 1076 | if (!dev->core->mpeg_users && blackbird_initialize_codec(dev) < 0) { |
1073 | if (drv) | 1077 | drv->request_release(drv); |
1074 | drv->request_release(drv); | ||
1075 | mutex_unlock(&dev->core->lock); | 1078 | mutex_unlock(&dev->core->lock); |
1076 | return -EINVAL; | 1079 | return -EINVAL; |
1077 | } | 1080 | } |
@@ -1080,8 +1083,7 @@ static int mpeg_open(struct file *file) | |||
1080 | /* allocate + initialize per filehandle data */ | 1083 | /* allocate + initialize per filehandle data */ |
1081 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); | 1084 | fh = kzalloc(sizeof(*fh),GFP_KERNEL); |
1082 | if (NULL == fh) { | 1085 | if (NULL == fh) { |
1083 | if (drv) | 1086 | drv->request_release(drv); |
1084 | drv->request_release(drv); | ||
1085 | mutex_unlock(&dev->core->lock); | 1087 | mutex_unlock(&dev->core->lock); |
1086 | return -ENOMEM; | 1088 | return -ENOMEM; |
1087 | } | 1089 | } |
@@ -1099,7 +1101,7 @@ static int mpeg_open(struct file *file) | |||
1099 | cx88_set_scale(dev->core, dev->width, dev->height, | 1101 | cx88_set_scale(dev->core, dev->width, dev->height, |
1100 | fh->mpegq.field); | 1102 | fh->mpegq.field); |
1101 | 1103 | ||
1102 | atomic_inc(&dev->core->mpeg_users); | 1104 | dev->core->mpeg_users++; |
1103 | mutex_unlock(&dev->core->lock); | 1105 | mutex_unlock(&dev->core->lock); |
1104 | return 0; | 1106 | return 0; |
1105 | } | 1107 | } |
@@ -1110,7 +1112,9 @@ static int mpeg_release(struct file *file) | |||
1110 | struct cx8802_dev *dev = fh->dev; | 1112 | struct cx8802_dev *dev = fh->dev; |
1111 | struct cx8802_driver *drv = NULL; | 1113 | struct cx8802_driver *drv = NULL; |
1112 | 1114 | ||
1113 | if (dev->mpeg_active && atomic_read(&dev->core->mpeg_users) == 1) | 1115 | mutex_lock(&dev->core->lock); |
1116 | |||
1117 | if (dev->mpeg_active && dev->core->mpeg_users == 1) | ||
1114 | blackbird_stop_codec(dev); | 1118 | blackbird_stop_codec(dev); |
1115 | 1119 | ||
1116 | cx8802_cancel_buffers(fh->dev); | 1120 | cx8802_cancel_buffers(fh->dev); |
@@ -1119,17 +1123,18 @@ static int mpeg_release(struct file *file) | |||
1119 | 1123 | ||
1120 | videobuf_mmap_free(&fh->mpegq); | 1124 | videobuf_mmap_free(&fh->mpegq); |
1121 | 1125 | ||
1122 | mutex_lock(&dev->core->lock); | ||
1123 | file->private_data = NULL; | 1126 | file->private_data = NULL; |
1124 | kfree(fh); | 1127 | kfree(fh); |
1125 | mutex_unlock(&dev->core->lock); | ||
1126 | 1128 | ||
1127 | /* Make sure we release the hardware */ | 1129 | /* Make sure we release the hardware */ |
1128 | drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); | 1130 | drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); |
1131 | WARN_ON(!drv); | ||
1129 | if (drv) | 1132 | if (drv) |
1130 | drv->request_release(drv); | 1133 | drv->request_release(drv); |
1131 | 1134 | ||
1132 | atomic_dec(&dev->core->mpeg_users); | 1135 | dev->core->mpeg_users--; |
1136 | |||
1137 | mutex_unlock(&dev->core->lock); | ||
1133 | 1138 | ||
1134 | return 0; | 1139 | return 0; |
1135 | } | 1140 | } |
@@ -1334,11 +1339,9 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) | |||
1334 | blackbird_register_video(dev); | 1339 | blackbird_register_video(dev); |
1335 | 1340 | ||
1336 | /* initial device configuration: needed ? */ | 1341 | /* initial device configuration: needed ? */ |
1337 | mutex_lock(&dev->core->lock); | ||
1338 | // init_controls(core); | 1342 | // init_controls(core); |
1339 | cx88_set_tvnorm(core,core->tvnorm); | 1343 | cx88_set_tvnorm(core,core->tvnorm); |
1340 | cx88_video_mux(core,0); | 1344 | cx88_video_mux(core,0); |
1341 | mutex_unlock(&dev->core->lock); | ||
1342 | 1345 | ||
1343 | return 0; | 1346 | return 0; |
1344 | 1347 | ||
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 7b8c9d3b6efc..c69df7ebb6a7 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c | |||
@@ -133,6 +133,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire) | |||
133 | return -EINVAL; | 133 | return -EINVAL; |
134 | } | 134 | } |
135 | 135 | ||
136 | mutex_lock(&dev->core->lock); | ||
136 | drv = cx8802_get_driver(dev, CX88_MPEG_DVB); | 137 | drv = cx8802_get_driver(dev, CX88_MPEG_DVB); |
137 | if (drv) { | 138 | if (drv) { |
138 | if (acquire){ | 139 | if (acquire){ |
@@ -143,6 +144,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire) | |||
143 | dev->frontends.active_fe_id = 0; | 144 | dev->frontends.active_fe_id = 0; |
144 | } | 145 | } |
145 | } | 146 | } |
147 | mutex_unlock(&dev->core->lock); | ||
146 | 148 | ||
147 | return ret; | 149 | return ret; |
148 | } | 150 | } |
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index addf9545e9bf..1a7b983f8297 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c | |||
@@ -78,6 +78,7 @@ static void flush_request_modules(struct cx8802_dev *dev) | |||
78 | 78 | ||
79 | 79 | ||
80 | static LIST_HEAD(cx8802_devlist); | 80 | static LIST_HEAD(cx8802_devlist); |
81 | static DEFINE_MUTEX(cx8802_mutex); | ||
81 | /* ------------------------------------------------------------------ */ | 82 | /* ------------------------------------------------------------------ */ |
82 | 83 | ||
83 | static int cx8802_start_dma(struct cx8802_dev *dev, | 84 | static int cx8802_start_dma(struct cx8802_dev *dev, |
@@ -474,7 +475,7 @@ static int cx8802_init_common(struct cx8802_dev *dev) | |||
474 | return -EIO; | 475 | return -EIO; |
475 | } | 476 | } |
476 | 477 | ||
477 | pci_read_config_byte(dev->pci, PCI_CLASS_REVISION, &dev->pci_rev); | 478 | dev->pci_rev = dev->pci->revision; |
478 | pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER, &dev->pci_lat); | 479 | pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER, &dev->pci_lat); |
479 | printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, " | 480 | printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, " |
480 | "latency: %d, mmio: 0x%llx\n", dev->core->name, | 481 | "latency: %d, mmio: 0x%llx\n", dev->core->name, |
@@ -624,13 +625,11 @@ static int cx8802_request_acquire(struct cx8802_driver *drv) | |||
624 | 625 | ||
625 | if (drv->advise_acquire) | 626 | if (drv->advise_acquire) |
626 | { | 627 | { |
627 | mutex_lock(&drv->core->lock); | ||
628 | core->active_ref++; | 628 | core->active_ref++; |
629 | if (core->active_type_id == CX88_BOARD_NONE) { | 629 | if (core->active_type_id == CX88_BOARD_NONE) { |
630 | core->active_type_id = drv->type_id; | 630 | core->active_type_id = drv->type_id; |
631 | drv->advise_acquire(drv); | 631 | drv->advise_acquire(drv); |
632 | } | 632 | } |
633 | mutex_unlock(&drv->core->lock); | ||
634 | 633 | ||
635 | mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); | 634 | mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); |
636 | } | 635 | } |
@@ -643,14 +642,12 @@ static int cx8802_request_release(struct cx8802_driver *drv) | |||
643 | { | 642 | { |
644 | struct cx88_core *core = drv->core; | 643 | struct cx88_core *core = drv->core; |
645 | 644 | ||
646 | mutex_lock(&drv->core->lock); | ||
647 | if (drv->advise_release && --core->active_ref == 0) | 645 | if (drv->advise_release && --core->active_ref == 0) |
648 | { | 646 | { |
649 | drv->advise_release(drv); | 647 | drv->advise_release(drv); |
650 | core->active_type_id = CX88_BOARD_NONE; | 648 | core->active_type_id = CX88_BOARD_NONE; |
651 | mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); | 649 | mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); |
652 | } | 650 | } |
653 | mutex_unlock(&drv->core->lock); | ||
654 | 651 | ||
655 | return 0; | 652 | return 0; |
656 | } | 653 | } |
@@ -693,6 +690,8 @@ int cx8802_register_driver(struct cx8802_driver *drv) | |||
693 | return err; | 690 | return err; |
694 | } | 691 | } |
695 | 692 | ||
693 | mutex_lock(&cx8802_mutex); | ||
694 | |||
696 | list_for_each_entry(dev, &cx8802_devlist, devlist) { | 695 | list_for_each_entry(dev, &cx8802_devlist, devlist) { |
697 | printk(KERN_INFO | 696 | printk(KERN_INFO |
698 | "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", | 697 | "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", |
@@ -702,8 +701,10 @@ int cx8802_register_driver(struct cx8802_driver *drv) | |||
702 | 701 | ||
703 | /* Bring up a new struct for each driver instance */ | 702 | /* Bring up a new struct for each driver instance */ |
704 | driver = kzalloc(sizeof(*drv),GFP_KERNEL); | 703 | driver = kzalloc(sizeof(*drv),GFP_KERNEL); |
705 | if (driver == NULL) | 704 | if (driver == NULL) { |
706 | return -ENOMEM; | 705 | err = -ENOMEM; |
706 | goto out; | ||
707 | } | ||
707 | 708 | ||
708 | /* Snapshot of the driver registration data */ | 709 | /* Snapshot of the driver registration data */ |
709 | drv->core = dev->core; | 710 | drv->core = dev->core; |
@@ -713,21 +714,23 @@ int cx8802_register_driver(struct cx8802_driver *drv) | |||
713 | drv->request_release = cx8802_request_release; | 714 | drv->request_release = cx8802_request_release; |
714 | memcpy(driver, drv, sizeof(*driver)); | 715 | memcpy(driver, drv, sizeof(*driver)); |
715 | 716 | ||
717 | mutex_lock(&drv->core->lock); | ||
716 | err = drv->probe(driver); | 718 | err = drv->probe(driver); |
717 | if (err == 0) { | 719 | if (err == 0) { |
718 | i++; | 720 | i++; |
719 | mutex_lock(&drv->core->lock); | ||
720 | list_add_tail(&driver->drvlist, &dev->drvlist); | 721 | list_add_tail(&driver->drvlist, &dev->drvlist); |
721 | mutex_unlock(&drv->core->lock); | ||
722 | } else { | 722 | } else { |
723 | printk(KERN_ERR | 723 | printk(KERN_ERR |
724 | "%s/2: cx8802 probe failed, err = %d\n", | 724 | "%s/2: cx8802 probe failed, err = %d\n", |
725 | dev->core->name, err); | 725 | dev->core->name, err); |
726 | } | 726 | } |
727 | 727 | mutex_unlock(&drv->core->lock); | |
728 | } | 728 | } |
729 | 729 | ||
730 | return i ? 0 : -ENODEV; | 730 | err = i ? 0 : -ENODEV; |
731 | out: | ||
732 | mutex_unlock(&cx8802_mutex); | ||
733 | return err; | ||
731 | } | 734 | } |
732 | 735 | ||
733 | int cx8802_unregister_driver(struct cx8802_driver *drv) | 736 | int cx8802_unregister_driver(struct cx8802_driver *drv) |
@@ -741,6 +744,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) | |||
741 | drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", | 744 | drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", |
742 | drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); | 745 | drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); |
743 | 746 | ||
747 | mutex_lock(&cx8802_mutex); | ||
748 | |||
744 | list_for_each_entry(dev, &cx8802_devlist, devlist) { | 749 | list_for_each_entry(dev, &cx8802_devlist, devlist) { |
745 | printk(KERN_INFO | 750 | printk(KERN_INFO |
746 | "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", | 751 | "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", |
@@ -748,6 +753,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) | |||
748 | dev->pci->subsystem_device, dev->core->board.name, | 753 | dev->pci->subsystem_device, dev->core->board.name, |
749 | dev->core->boardnr); | 754 | dev->core->boardnr); |
750 | 755 | ||
756 | mutex_lock(&dev->core->lock); | ||
757 | |||
751 | list_for_each_entry_safe(d, dtmp, &dev->drvlist, drvlist) { | 758 | list_for_each_entry_safe(d, dtmp, &dev->drvlist, drvlist) { |
752 | /* only unregister the correct driver type */ | 759 | /* only unregister the correct driver type */ |
753 | if (d->type_id != drv->type_id) | 760 | if (d->type_id != drv->type_id) |
@@ -755,17 +762,18 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) | |||
755 | 762 | ||
756 | err = d->remove(d); | 763 | err = d->remove(d); |
757 | if (err == 0) { | 764 | if (err == 0) { |
758 | mutex_lock(&drv->core->lock); | ||
759 | list_del(&d->drvlist); | 765 | list_del(&d->drvlist); |
760 | mutex_unlock(&drv->core->lock); | ||
761 | kfree(d); | 766 | kfree(d); |
762 | } else | 767 | } else |
763 | printk(KERN_ERR "%s/2: cx8802 driver remove " | 768 | printk(KERN_ERR "%s/2: cx8802 driver remove " |
764 | "failed (%d)\n", dev->core->name, err); | 769 | "failed (%d)\n", dev->core->name, err); |
765 | } | 770 | } |
766 | 771 | ||
772 | mutex_unlock(&dev->core->lock); | ||
767 | } | 773 | } |
768 | 774 | ||
775 | mutex_unlock(&cx8802_mutex); | ||
776 | |||
769 | return err; | 777 | return err; |
770 | } | 778 | } |
771 | 779 | ||
@@ -803,7 +811,9 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev, | |||
803 | goto fail_free; | 811 | goto fail_free; |
804 | 812 | ||
805 | INIT_LIST_HEAD(&dev->drvlist); | 813 | INIT_LIST_HEAD(&dev->drvlist); |
814 | mutex_lock(&cx8802_mutex); | ||
806 | list_add_tail(&dev->devlist,&cx8802_devlist); | 815 | list_add_tail(&dev->devlist,&cx8802_devlist); |
816 | mutex_unlock(&cx8802_mutex); | ||
807 | 817 | ||
808 | /* now autoload cx88-dvb or cx88-blackbird */ | 818 | /* now autoload cx88-dvb or cx88-blackbird */ |
809 | request_modules(dev); | 819 | request_modules(dev); |
@@ -827,6 +837,8 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev) | |||
827 | 837 | ||
828 | flush_request_modules(dev); | 838 | flush_request_modules(dev); |
829 | 839 | ||
840 | mutex_lock(&dev->core->lock); | ||
841 | |||
830 | if (!list_empty(&dev->drvlist)) { | 842 | if (!list_empty(&dev->drvlist)) { |
831 | struct cx8802_driver *drv, *tmp; | 843 | struct cx8802_driver *drv, *tmp; |
832 | int err; | 844 | int err; |
@@ -838,9 +850,7 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev) | |||
838 | list_for_each_entry_safe(drv, tmp, &dev->drvlist, drvlist) { | 850 | list_for_each_entry_safe(drv, tmp, &dev->drvlist, drvlist) { |
839 | err = drv->remove(drv); | 851 | err = drv->remove(drv); |
840 | if (err == 0) { | 852 | if (err == 0) { |
841 | mutex_lock(&drv->core->lock); | ||
842 | list_del(&drv->drvlist); | 853 | list_del(&drv->drvlist); |
843 | mutex_unlock(&drv->core->lock); | ||
844 | } else | 854 | } else |
845 | printk(KERN_ERR "%s/2: cx8802 driver remove " | 855 | printk(KERN_ERR "%s/2: cx8802 driver remove " |
846 | "failed (%d)\n", dev->core->name, err); | 856 | "failed (%d)\n", dev->core->name, err); |
@@ -848,6 +858,8 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev) | |||
848 | } | 858 | } |
849 | } | 859 | } |
850 | 860 | ||
861 | mutex_unlock(&dev->core->lock); | ||
862 | |||
851 | /* Destroy any 8802 reference. */ | 863 | /* Destroy any 8802 reference. */ |
852 | dev->core->dvbdev = NULL; | 864 | dev->core->dvbdev = NULL; |
853 | 865 | ||
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 287a41ee1c4f..cef4f282e5aa 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c | |||
@@ -824,7 +824,7 @@ static int video_open(struct file *file) | |||
824 | call_all(core, tuner, s_radio); | 824 | call_all(core, tuner, s_radio); |
825 | } | 825 | } |
826 | 826 | ||
827 | atomic_inc(&core->users); | 827 | core->users++; |
828 | mutex_unlock(&core->lock); | 828 | mutex_unlock(&core->lock); |
829 | 829 | ||
830 | return 0; | 830 | return 0; |
@@ -922,7 +922,8 @@ static int video_release(struct file *file) | |||
922 | file->private_data = NULL; | 922 | file->private_data = NULL; |
923 | kfree(fh); | 923 | kfree(fh); |
924 | 924 | ||
925 | if(atomic_dec_and_test(&dev->core->users)) | 925 | dev->core->users--; |
926 | if (!dev->core->users) | ||
926 | call_all(dev->core, core, s_power, 0); | 927 | call_all(dev->core, core, s_power, 0); |
927 | mutex_unlock(&dev->core->lock); | 928 | mutex_unlock(&dev->core->lock); |
928 | 929 | ||
@@ -1832,7 +1833,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
1832 | dev->core = core; | 1833 | dev->core = core; |
1833 | 1834 | ||
1834 | /* print pci info */ | 1835 | /* print pci info */ |
1835 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); | 1836 | dev->pci_rev = pci_dev->revision; |
1836 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); | 1837 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); |
1837 | printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " | 1838 | printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " |
1838 | "latency: %d, mmio: 0x%llx\n", core->name, | 1839 | "latency: %d, mmio: 0x%llx\n", core->name, |
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 9b3742a7746c..a399a8b086ba 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h | |||
@@ -389,8 +389,8 @@ struct cx88_core { | |||
389 | struct mutex lock; | 389 | struct mutex lock; |
390 | /* various v4l controls */ | 390 | /* various v4l controls */ |
391 | u32 freq; | 391 | u32 freq; |
392 | atomic_t users; | 392 | int users; |
393 | atomic_t mpeg_users; | 393 | int mpeg_users; |
394 | 394 | ||
395 | /* cx88-video needs to access cx8802 for hybrid tuner pll access. */ | 395 | /* cx88-video needs to access cx8802 for hybrid tuner pll access. */ |
396 | struct cx8802_dev *dvbdev; | 396 | struct cx8802_dev *dvbdev; |
@@ -505,6 +505,8 @@ struct cx8802_driver { | |||
505 | int (*suspend)(struct pci_dev *pci_dev, pm_message_t state); | 505 | int (*suspend)(struct pci_dev *pci_dev, pm_message_t state); |
506 | int (*resume)(struct pci_dev *pci_dev); | 506 | int (*resume)(struct pci_dev *pci_dev); |
507 | 507 | ||
508 | /* Callers to the following functions must hold core->lock */ | ||
509 | |||
508 | /* MPEG 8802 -> mini driver - Driver probe and configuration */ | 510 | /* MPEG 8802 -> mini driver - Driver probe and configuration */ |
509 | int (*probe)(struct cx8802_driver *drv); | 511 | int (*probe)(struct cx8802_driver *drv); |
510 | int (*remove)(struct cx8802_driver *drv); | 512 | int (*remove)(struct cx8802_driver *drv); |
@@ -561,8 +563,9 @@ struct cx8802_dev { | |||
561 | /* for switching modulation types */ | 563 | /* for switching modulation types */ |
562 | unsigned char ts_gen_cntrl; | 564 | unsigned char ts_gen_cntrl; |
563 | 565 | ||
564 | /* List of attached drivers */ | 566 | /* List of attached drivers; must hold core->lock to access */ |
565 | struct list_head drvlist; | 567 | struct list_head drvlist; |
568 | |||
566 | struct work_struct request_module_wk; | 569 | struct work_struct request_module_wk; |
567 | }; | 570 | }; |
568 | 571 | ||
@@ -685,6 +688,8 @@ int cx88_audio_thread(void *data); | |||
685 | 688 | ||
686 | int cx8802_register_driver(struct cx8802_driver *drv); | 689 | int cx8802_register_driver(struct cx8802_driver *drv); |
687 | int cx8802_unregister_driver(struct cx8802_driver *drv); | 690 | int cx8802_unregister_driver(struct cx8802_driver *drv); |
691 | |||
692 | /* Caller must hold core->lock */ | ||
688 | struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); | 693 | struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); |
689 | 694 | ||
690 | /* ----------------------------------------------------------- */ | 695 | /* ----------------------------------------------------------- */ |
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index 985100ea17a4..3cb78f26df90 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig | |||
@@ -38,6 +38,8 @@ config VIDEO_EM28XX_DVB | |||
38 | select DVB_ZL10353 if !DVB_FE_CUSTOMISE | 38 | select DVB_ZL10353 if !DVB_FE_CUSTOMISE |
39 | select DVB_TDA10023 if !DVB_FE_CUSTOMISE | 39 | select DVB_TDA10023 if !DVB_FE_CUSTOMISE |
40 | select DVB_S921 if !DVB_FE_CUSTOMISE | 40 | select DVB_S921 if !DVB_FE_CUSTOMISE |
41 | select DVB_DRXD if !DVB_FE_CUSTOMISE | ||
42 | select DVB_CXD2820R if !DVB_FE_CUSTOMISE | ||
41 | select VIDEOBUF_DVB | 43 | select VIDEOBUF_DVB |
42 | ---help--- | 44 | ---help--- |
43 | This adds support for DVB cards based on the | 45 | This adds support for DVB cards based on the |
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 69fcea82d01c..4e37375decf5 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c | |||
@@ -100,6 +100,13 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { | |||
100 | { -1, -1, -1, -1}, | 100 | { -1, -1, -1, -1}, |
101 | }; | 101 | }; |
102 | 102 | ||
103 | /* Board Hauppauge WinTV HVR 900 (R2) digital */ | ||
104 | static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = { | ||
105 | {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10}, | ||
106 | {EM2880_R04_GPO, 0x0c, 0x0f, 10}, | ||
107 | { -1, -1, -1, -1}, | ||
108 | }; | ||
109 | |||
103 | /* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ | 110 | /* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ |
104 | static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { | 111 | static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { |
105 | {EM28XX_R08_GPIO, 0x69, ~EM_GPIO_4, 10}, | 112 | {EM28XX_R08_GPIO, 0x69, ~EM_GPIO_4, 10}, |
@@ -282,6 +289,16 @@ static struct em28xx_reg_seq leadership_reset[] = { | |||
282 | { -1, -1, -1, -1}, | 289 | { -1, -1, -1, -1}, |
283 | }; | 290 | }; |
284 | 291 | ||
292 | /* 2013:024f PCTV Systems nanoStick T2 290e | ||
293 | * GPIO_6 - demod reset | ||
294 | * GPIO_7 - LED | ||
295 | */ | ||
296 | static struct em28xx_reg_seq pctv_290e[] = { | ||
297 | {EM2874_R80_GPIO, 0x00, 0xff, 80}, | ||
298 | {EM2874_R80_GPIO, 0x40, 0xff, 80}, /* GPIO_6 = 1 */ | ||
299 | {EM2874_R80_GPIO, 0xc0, 0xff, 80}, /* GPIO_7 = 1 */ | ||
300 | {-1, -1, -1, -1}, | ||
301 | }; | ||
285 | 302 | ||
286 | /* | 303 | /* |
287 | * Board definitions | 304 | * Board definitions |
@@ -859,6 +876,8 @@ struct em28xx_board em28xx_boards[] = { | |||
859 | .tuner_type = TUNER_XC2028, | 876 | .tuner_type = TUNER_XC2028, |
860 | .tuner_gpio = default_tuner_gpio, | 877 | .tuner_gpio = default_tuner_gpio, |
861 | .mts_firmware = 1, | 878 | .mts_firmware = 1, |
879 | .has_dvb = 1, | ||
880 | .dvb_gpio = hauppauge_wintv_hvr_900R2_digital, | ||
862 | .ir_codes = RC_MAP_HAUPPAUGE, | 881 | .ir_codes = RC_MAP_HAUPPAUGE, |
863 | .decoder = EM28XX_TVP5150, | 882 | .decoder = EM28XX_TVP5150, |
864 | .input = { { | 883 | .input = { { |
@@ -1448,12 +1467,14 @@ struct em28xx_board em28xx_boards[] = { | |||
1448 | .gpio = pinnacle_hybrid_pro_analog, | 1467 | .gpio = pinnacle_hybrid_pro_analog, |
1449 | } }, | 1468 | } }, |
1450 | }, | 1469 | }, |
1451 | [EM2882_BOARD_PINNACLE_HYBRID_PRO] = { | 1470 | [EM2882_BOARD_PINNACLE_HYBRID_PRO_330E] = { |
1452 | .name = "Pinnacle Hybrid Pro (2)", | 1471 | .name = "Pinnacle Hybrid Pro (330e)", |
1453 | .valid = EM28XX_BOARD_NOT_VALIDATED, | ||
1454 | .tuner_type = TUNER_XC2028, | 1472 | .tuner_type = TUNER_XC2028, |
1455 | .tuner_gpio = default_tuner_gpio, | 1473 | .tuner_gpio = default_tuner_gpio, |
1456 | .mts_firmware = 1, | 1474 | .mts_firmware = 1, |
1475 | .has_dvb = 1, | ||
1476 | .dvb_gpio = hauppauge_wintv_hvr_900R2_digital, | ||
1477 | .ir_codes = RC_MAP_PINNACLE_PCTV_HD, | ||
1457 | .decoder = EM28XX_TVP5150, | 1478 | .decoder = EM28XX_TVP5150, |
1458 | .input = { { | 1479 | .input = { { |
1459 | .type = EM28XX_VMUX_TELEVISION, | 1480 | .type = EM28XX_VMUX_TELEVISION, |
@@ -1749,6 +1770,17 @@ struct em28xx_board em28xx_boards[] = { | |||
1749 | .dvb_gpio = kworld_a340_digital, | 1770 | .dvb_gpio = kworld_a340_digital, |
1750 | .tuner_gpio = default_tuner_gpio, | 1771 | .tuner_gpio = default_tuner_gpio, |
1751 | }, | 1772 | }, |
1773 | /* 2013:024f PCTV Systems nanoStick T2 290e. | ||
1774 | * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */ | ||
1775 | [EM28174_BOARD_PCTV_290E] = { | ||
1776 | .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | | ||
1777 | EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ, | ||
1778 | .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, | ||
1779 | .name = "PCTV Systems nanoStick T2 290e", | ||
1780 | .tuner_type = TUNER_ABSENT, | ||
1781 | .tuner_gpio = pctv_290e, | ||
1782 | .has_dvb = 1, | ||
1783 | }, | ||
1752 | }; | 1784 | }; |
1753 | const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); | 1785 | const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); |
1754 | 1786 | ||
@@ -1863,7 +1895,7 @@ struct usb_device_id em28xx_id_table[] = { | |||
1863 | { USB_DEVICE(0x2304, 0x021a), | 1895 | { USB_DEVICE(0x2304, 0x021a), |
1864 | .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, | 1896 | .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, |
1865 | { USB_DEVICE(0x2304, 0x0226), | 1897 | { USB_DEVICE(0x2304, 0x0226), |
1866 | .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO }, | 1898 | .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO_330E }, |
1867 | { USB_DEVICE(0x2304, 0x0227), | 1899 | { USB_DEVICE(0x2304, 0x0227), |
1868 | .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, | 1900 | .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, |
1869 | { USB_DEVICE(0x0413, 0x6023), | 1901 | { USB_DEVICE(0x0413, 0x6023), |
@@ -1876,6 +1908,8 @@ struct usb_device_id em28xx_id_table[] = { | |||
1876 | .driver_info = EM2860_BOARD_GADMEI_UTV330 }, | 1908 | .driver_info = EM2860_BOARD_GADMEI_UTV330 }, |
1877 | { USB_DEVICE(0x1b80, 0xa340), | 1909 | { USB_DEVICE(0x1b80, 0xa340), |
1878 | .driver_info = EM2870_BOARD_KWORLD_A340 }, | 1910 | .driver_info = EM2870_BOARD_KWORLD_A340 }, |
1911 | { USB_DEVICE(0x2013, 0x024f), | ||
1912 | .driver_info = EM28174_BOARD_PCTV_290E }, | ||
1879 | { }, | 1913 | { }, |
1880 | }; | 1914 | }; |
1881 | MODULE_DEVICE_TABLE(usb, em28xx_id_table); | 1915 | MODULE_DEVICE_TABLE(usb, em28xx_id_table); |
@@ -2229,7 +2263,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) | |||
2229 | ctl->demod = XC3028_FE_ZARLINK456; | 2263 | ctl->demod = XC3028_FE_ZARLINK456; |
2230 | break; | 2264 | break; |
2231 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: | 2265 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: |
2232 | /* djh - Not sure which demod we need here */ | 2266 | case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: |
2233 | ctl->demod = XC3028_FE_DEFAULT; | 2267 | ctl->demod = XC3028_FE_DEFAULT; |
2234 | break; | 2268 | break; |
2235 | case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: | 2269 | case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: |
@@ -2799,6 +2833,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
2799 | dev->reg_gpio_num = EM2874_R80_GPIO; | 2833 | dev->reg_gpio_num = EM2874_R80_GPIO; |
2800 | dev->wait_after_write = 0; | 2834 | dev->wait_after_write = 0; |
2801 | break; | 2835 | break; |
2836 | case CHIP_ID_EM28174: | ||
2837 | em28xx_info("chip ID is em28174\n"); | ||
2838 | dev->reg_gpio_num = EM2874_R80_GPIO; | ||
2839 | dev->wait_after_write = 0; | ||
2840 | break; | ||
2802 | case CHIP_ID_EM2883: | 2841 | case CHIP_ID_EM2883: |
2803 | em28xx_info("chip ID is em2882/em2883\n"); | 2842 | em28xx_info("chip ID is em2882/em2883\n"); |
2804 | dev->wait_after_write = 0; | 2843 | dev->wait_after_write = 0; |
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 44c63cbd6dda..e33f145d867a 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c | |||
@@ -489,7 +489,8 @@ int em28xx_audio_setup(struct em28xx *dev) | |||
489 | int vid1, vid2, feat, cfg; | 489 | int vid1, vid2, feat, cfg; |
490 | u32 vid; | 490 | u32 vid; |
491 | 491 | ||
492 | if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874) { | 492 | if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874 |
493 | || dev->chip_id == CHIP_ID_EM28174) { | ||
493 | /* Digital only device - don't load any alsa module */ | 494 | /* Digital only device - don't load any alsa module */ |
494 | dev->audio_mode.has_audio = 0; | 495 | dev->audio_mode.has_audio = 0; |
495 | dev->has_audio_class = 0; | 496 | dev->has_audio_class = 0; |
@@ -614,7 +615,7 @@ int em28xx_capture_start(struct em28xx *dev, int start) | |||
614 | { | 615 | { |
615 | int rc; | 616 | int rc; |
616 | 617 | ||
617 | if (dev->chip_id == CHIP_ID_EM2874) { | 618 | if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) { |
618 | /* The Transport Stream Enable Register moved in em2874 */ | 619 | /* The Transport Stream Enable Register moved in em2874 */ |
619 | if (!start) { | 620 | if (!start) { |
620 | rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, | 621 | rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, |
@@ -1111,6 +1112,10 @@ int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev) | |||
1111 | /* FIXME - for now assume 564 like it was before, but the | 1112 | /* FIXME - for now assume 564 like it was before, but the |
1112 | em2874 code should be added to return the proper value... */ | 1113 | em2874 code should be added to return the proper value... */ |
1113 | packet_size = 564; | 1114 | packet_size = 564; |
1115 | } else if (dev->chip_id == CHIP_ID_EM28174) { | ||
1116 | /* FIXME same as em2874. 564 was enough for 22 Mbit DVB-T | ||
1117 | but too much for 44 Mbit DVB-C. */ | ||
1118 | packet_size = 752; | ||
1114 | } else { | 1119 | } else { |
1115 | /* TS max packet size stored in bits 1-0 of R01 */ | 1120 | /* TS max packet size stored in bits 1-0 of R01 */ |
1116 | chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2); | 1121 | chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2); |
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index c7c04bf712aa..7904ca4b6913 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c | |||
@@ -38,6 +38,8 @@ | |||
38 | #include "tda1002x.h" | 38 | #include "tda1002x.h" |
39 | #include "tda18271.h" | 39 | #include "tda18271.h" |
40 | #include "s921.h" | 40 | #include "s921.h" |
41 | #include "drxd.h" | ||
42 | #include "cxd2820r.h" | ||
41 | 43 | ||
42 | MODULE_DESCRIPTION("driver for em28xx based DVB cards"); | 44 | MODULE_DESCRIPTION("driver for em28xx based DVB cards"); |
43 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | 45 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); |
@@ -58,7 +60,7 @@ if (debug >= level) \ | |||
58 | #define EM28XX_DVB_MAX_PACKETS 64 | 60 | #define EM28XX_DVB_MAX_PACKETS 64 |
59 | 61 | ||
60 | struct em28xx_dvb { | 62 | struct em28xx_dvb { |
61 | struct dvb_frontend *frontend; | 63 | struct dvb_frontend *fe[2]; |
62 | 64 | ||
63 | /* feed count management */ | 65 | /* feed count management */ |
64 | struct mutex lock; | 66 | struct mutex lock; |
@@ -285,12 +287,13 @@ static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = { | |||
285 | .if2 = 45600, | 287 | .if2 = 45600, |
286 | }; | 288 | }; |
287 | 289 | ||
288 | #ifdef EM28XX_DRX397XD_SUPPORT | 290 | static struct drxd_config em28xx_drxd = { |
289 | /* [TODO] djh - not sure yet what the device config needs to contain */ | 291 | .index = 0, .demod_address = 0x70, .demod_revision = 0xa2, |
290 | static struct drx397xD_config em28xx_drx397xD_with_xc3028 = { | 292 | .demoda_address = 0x00, .pll_address = 0x00, |
291 | .demod_address = (0xe0 >> 1), | 293 | .pll_type = DRXD_PLL_NONE, .clock = 12000, .insert_rs_byte = 1, |
294 | .pll_set = NULL, .osc_deviation = NULL, .IF = 42800000, | ||
295 | .disable_i2c_gate_ctrl = 1, | ||
292 | }; | 296 | }; |
293 | #endif | ||
294 | 297 | ||
295 | static int mt352_terratec_xs_init(struct dvb_frontend *fe) | 298 | static int mt352_terratec_xs_init(struct dvb_frontend *fe) |
296 | { | 299 | { |
@@ -332,6 +335,26 @@ static struct tda10023_config em28xx_tda10023_config = { | |||
332 | .invert = 1, | 335 | .invert = 1, |
333 | }; | 336 | }; |
334 | 337 | ||
338 | static struct cxd2820r_config em28xx_cxd2820r_config = { | ||
339 | .i2c_address = (0xd8 >> 1), | ||
340 | .ts_mode = CXD2820R_TS_SERIAL, | ||
341 | .if_dvbt_6 = 3300, | ||
342 | .if_dvbt_7 = 3500, | ||
343 | .if_dvbt_8 = 4000, | ||
344 | .if_dvbt2_6 = 3300, | ||
345 | .if_dvbt2_7 = 3500, | ||
346 | .if_dvbt2_8 = 4000, | ||
347 | .if_dvbc = 5000, | ||
348 | |||
349 | /* enable LNA for DVB-T2 and DVB-C */ | ||
350 | .gpio_dvbt2[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L, | ||
351 | .gpio_dvbc[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L, | ||
352 | }; | ||
353 | |||
354 | static struct tda18271_config em28xx_cxd2820r_tda18271_config = { | ||
355 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
356 | }; | ||
357 | |||
335 | /* ------------------------------------------------------------------ */ | 358 | /* ------------------------------------------------------------------ */ |
336 | 359 | ||
337 | static int attach_xc3028(u8 addr, struct em28xx *dev) | 360 | static int attach_xc3028(u8 addr, struct em28xx *dev) |
@@ -343,17 +366,17 @@ static int attach_xc3028(u8 addr, struct em28xx *dev) | |||
343 | cfg.i2c_adap = &dev->i2c_adap; | 366 | cfg.i2c_adap = &dev->i2c_adap; |
344 | cfg.i2c_addr = addr; | 367 | cfg.i2c_addr = addr; |
345 | 368 | ||
346 | if (!dev->dvb->frontend) { | 369 | if (!dev->dvb->fe[0]) { |
347 | em28xx_errdev("/2: dvb frontend not attached. " | 370 | em28xx_errdev("/2: dvb frontend not attached. " |
348 | "Can't attach xc3028\n"); | 371 | "Can't attach xc3028\n"); |
349 | return -EINVAL; | 372 | return -EINVAL; |
350 | } | 373 | } |
351 | 374 | ||
352 | fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg); | 375 | fe = dvb_attach(xc2028_attach, dev->dvb->fe[0], &cfg); |
353 | if (!fe) { | 376 | if (!fe) { |
354 | em28xx_errdev("/2: xc3028 attach failed\n"); | 377 | em28xx_errdev("/2: xc3028 attach failed\n"); |
355 | dvb_frontend_detach(dev->dvb->frontend); | 378 | dvb_frontend_detach(dev->dvb->fe[0]); |
356 | dev->dvb->frontend = NULL; | 379 | dev->dvb->fe[0] = NULL; |
357 | return -EINVAL; | 380 | return -EINVAL; |
358 | } | 381 | } |
359 | 382 | ||
@@ -383,16 +406,28 @@ static int register_dvb(struct em28xx_dvb *dvb, | |||
383 | } | 406 | } |
384 | 407 | ||
385 | /* Ensure all frontends negotiate bus access */ | 408 | /* Ensure all frontends negotiate bus access */ |
386 | dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl; | 409 | dvb->fe[0]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl; |
410 | if (dvb->fe[1]) | ||
411 | dvb->fe[1]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl; | ||
387 | 412 | ||
388 | dvb->adapter.priv = dev; | 413 | dvb->adapter.priv = dev; |
389 | 414 | ||
390 | /* register frontend */ | 415 | /* register frontend */ |
391 | result = dvb_register_frontend(&dvb->adapter, dvb->frontend); | 416 | result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]); |
392 | if (result < 0) { | 417 | if (result < 0) { |
393 | printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", | 418 | printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", |
394 | dev->name, result); | 419 | dev->name, result); |
395 | goto fail_frontend; | 420 | goto fail_frontend0; |
421 | } | ||
422 | |||
423 | /* register 2nd frontend */ | ||
424 | if (dvb->fe[1]) { | ||
425 | result = dvb_register_frontend(&dvb->adapter, dvb->fe[1]); | ||
426 | if (result < 0) { | ||
427 | printk(KERN_WARNING "%s: 2nd dvb_register_frontend failed (errno = %d)\n", | ||
428 | dev->name, result); | ||
429 | goto fail_frontend1; | ||
430 | } | ||
396 | } | 431 | } |
397 | 432 | ||
398 | /* register demux stuff */ | 433 | /* register demux stuff */ |
@@ -458,9 +493,14 @@ fail_fe_hw: | |||
458 | fail_dmxdev: | 493 | fail_dmxdev: |
459 | dvb_dmx_release(&dvb->demux); | 494 | dvb_dmx_release(&dvb->demux); |
460 | fail_dmx: | 495 | fail_dmx: |
461 | dvb_unregister_frontend(dvb->frontend); | 496 | if (dvb->fe[1]) |
462 | fail_frontend: | 497 | dvb_unregister_frontend(dvb->fe[1]); |
463 | dvb_frontend_detach(dvb->frontend); | 498 | dvb_unregister_frontend(dvb->fe[0]); |
499 | fail_frontend1: | ||
500 | if (dvb->fe[1]) | ||
501 | dvb_frontend_detach(dvb->fe[1]); | ||
502 | fail_frontend0: | ||
503 | dvb_frontend_detach(dvb->fe[0]); | ||
464 | dvb_unregister_adapter(&dvb->adapter); | 504 | dvb_unregister_adapter(&dvb->adapter); |
465 | fail_adapter: | 505 | fail_adapter: |
466 | return result; | 506 | return result; |
@@ -473,12 +513,15 @@ static void unregister_dvb(struct em28xx_dvb *dvb) | |||
473 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); | 513 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); |
474 | dvb_dmxdev_release(&dvb->dmxdev); | 514 | dvb_dmxdev_release(&dvb->dmxdev); |
475 | dvb_dmx_release(&dvb->demux); | 515 | dvb_dmx_release(&dvb->demux); |
476 | dvb_unregister_frontend(dvb->frontend); | 516 | if (dvb->fe[1]) |
477 | dvb_frontend_detach(dvb->frontend); | 517 | dvb_unregister_frontend(dvb->fe[1]); |
518 | dvb_unregister_frontend(dvb->fe[0]); | ||
519 | if (dvb->fe[1]) | ||
520 | dvb_frontend_detach(dvb->fe[1]); | ||
521 | dvb_frontend_detach(dvb->fe[0]); | ||
478 | dvb_unregister_adapter(&dvb->adapter); | 522 | dvb_unregister_adapter(&dvb->adapter); |
479 | } | 523 | } |
480 | 524 | ||
481 | |||
482 | static int dvb_init(struct em28xx *dev) | 525 | static int dvb_init(struct em28xx *dev) |
483 | { | 526 | { |
484 | int result = 0; | 527 | int result = 0; |
@@ -497,16 +540,17 @@ static int dvb_init(struct em28xx *dev) | |||
497 | return -ENOMEM; | 540 | return -ENOMEM; |
498 | } | 541 | } |
499 | dev->dvb = dvb; | 542 | dev->dvb = dvb; |
543 | dvb->fe[0] = dvb->fe[1] = NULL; | ||
500 | 544 | ||
501 | mutex_lock(&dev->lock); | 545 | mutex_lock(&dev->lock); |
502 | em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); | 546 | em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); |
503 | /* init frontend */ | 547 | /* init frontend */ |
504 | switch (dev->model) { | 548 | switch (dev->model) { |
505 | case EM2874_LEADERSHIP_ISDBT: | 549 | case EM2874_LEADERSHIP_ISDBT: |
506 | dvb->frontend = dvb_attach(s921_attach, | 550 | dvb->fe[0] = dvb_attach(s921_attach, |
507 | &sharp_isdbt, &dev->i2c_adap); | 551 | &sharp_isdbt, &dev->i2c_adap); |
508 | 552 | ||
509 | if (!dvb->frontend) { | 553 | if (!dvb->fe[0]) { |
510 | result = -EINVAL; | 554 | result = -EINVAL; |
511 | goto out_free; | 555 | goto out_free; |
512 | } | 556 | } |
@@ -516,7 +560,7 @@ static int dvb_init(struct em28xx *dev) | |||
516 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: | 560 | case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: |
517 | case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: | 561 | case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: |
518 | case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: | 562 | case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: |
519 | dvb->frontend = dvb_attach(lgdt330x_attach, | 563 | dvb->fe[0] = dvb_attach(lgdt330x_attach, |
520 | &em2880_lgdt3303_dev, | 564 | &em2880_lgdt3303_dev, |
521 | &dev->i2c_adap); | 565 | &dev->i2c_adap); |
522 | if (attach_xc3028(0x61, dev) < 0) { | 566 | if (attach_xc3028(0x61, dev) < 0) { |
@@ -525,7 +569,7 @@ static int dvb_init(struct em28xx *dev) | |||
525 | } | 569 | } |
526 | break; | 570 | break; |
527 | case EM2880_BOARD_KWORLD_DVB_310U: | 571 | case EM2880_BOARD_KWORLD_DVB_310U: |
528 | dvb->frontend = dvb_attach(zl10353_attach, | 572 | dvb->fe[0] = dvb_attach(zl10353_attach, |
529 | &em28xx_zl10353_with_xc3028, | 573 | &em28xx_zl10353_with_xc3028, |
530 | &dev->i2c_adap); | 574 | &dev->i2c_adap); |
531 | if (attach_xc3028(0x61, dev) < 0) { | 575 | if (attach_xc3028(0x61, dev) < 0) { |
@@ -536,7 +580,7 @@ static int dvb_init(struct em28xx *dev) | |||
536 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: | 580 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: |
537 | case EM2882_BOARD_TERRATEC_HYBRID_XS: | 581 | case EM2882_BOARD_TERRATEC_HYBRID_XS: |
538 | case EM2880_BOARD_EMPIRE_DUAL_TV: | 582 | case EM2880_BOARD_EMPIRE_DUAL_TV: |
539 | dvb->frontend = dvb_attach(zl10353_attach, | 583 | dvb->fe[0] = dvb_attach(zl10353_attach, |
540 | &em28xx_zl10353_xc3028_no_i2c_gate, | 584 | &em28xx_zl10353_xc3028_no_i2c_gate, |
541 | &dev->i2c_adap); | 585 | &dev->i2c_adap); |
542 | if (attach_xc3028(0x61, dev) < 0) { | 586 | if (attach_xc3028(0x61, dev) < 0) { |
@@ -549,13 +593,13 @@ static int dvb_init(struct em28xx *dev) | |||
549 | case EM2881_BOARD_PINNACLE_HYBRID_PRO: | 593 | case EM2881_BOARD_PINNACLE_HYBRID_PRO: |
550 | case EM2882_BOARD_DIKOM_DK300: | 594 | case EM2882_BOARD_DIKOM_DK300: |
551 | case EM2882_BOARD_KWORLD_VS_DVBT: | 595 | case EM2882_BOARD_KWORLD_VS_DVBT: |
552 | dvb->frontend = dvb_attach(zl10353_attach, | 596 | dvb->fe[0] = dvb_attach(zl10353_attach, |
553 | &em28xx_zl10353_xc3028_no_i2c_gate, | 597 | &em28xx_zl10353_xc3028_no_i2c_gate, |
554 | &dev->i2c_adap); | 598 | &dev->i2c_adap); |
555 | if (dvb->frontend == NULL) { | 599 | if (dvb->fe[0] == NULL) { |
556 | /* This board could have either a zl10353 or a mt352. | 600 | /* This board could have either a zl10353 or a mt352. |
557 | If the chip id isn't for zl10353, try mt352 */ | 601 | If the chip id isn't for zl10353, try mt352 */ |
558 | dvb->frontend = dvb_attach(mt352_attach, | 602 | dvb->fe[0] = dvb_attach(mt352_attach, |
559 | &terratec_xs_mt352_cfg, | 603 | &terratec_xs_mt352_cfg, |
560 | &dev->i2c_adap); | 604 | &dev->i2c_adap); |
561 | } | 605 | } |
@@ -567,7 +611,7 @@ static int dvb_init(struct em28xx *dev) | |||
567 | break; | 611 | break; |
568 | case EM2883_BOARD_KWORLD_HYBRID_330U: | 612 | case EM2883_BOARD_KWORLD_HYBRID_330U: |
569 | case EM2882_BOARD_EVGA_INDTUBE: | 613 | case EM2882_BOARD_EVGA_INDTUBE: |
570 | dvb->frontend = dvb_attach(s5h1409_attach, | 614 | dvb->fe[0] = dvb_attach(s5h1409_attach, |
571 | &em28xx_s5h1409_with_xc3028, | 615 | &em28xx_s5h1409_with_xc3028, |
572 | &dev->i2c_adap); | 616 | &dev->i2c_adap); |
573 | if (attach_xc3028(0x61, dev) < 0) { | 617 | if (attach_xc3028(0x61, dev) < 0) { |
@@ -576,11 +620,11 @@ static int dvb_init(struct em28xx *dev) | |||
576 | } | 620 | } |
577 | break; | 621 | break; |
578 | case EM2882_BOARD_KWORLD_ATSC_315U: | 622 | case EM2882_BOARD_KWORLD_ATSC_315U: |
579 | dvb->frontend = dvb_attach(lgdt330x_attach, | 623 | dvb->fe[0] = dvb_attach(lgdt330x_attach, |
580 | &em2880_lgdt3303_dev, | 624 | &em2880_lgdt3303_dev, |
581 | &dev->i2c_adap); | 625 | &dev->i2c_adap); |
582 | if (dvb->frontend != NULL) { | 626 | if (dvb->fe[0] != NULL) { |
583 | if (!dvb_attach(simple_tuner_attach, dvb->frontend, | 627 | if (!dvb_attach(simple_tuner_attach, dvb->fe[0], |
584 | &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) { | 628 | &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) { |
585 | result = -EINVAL; | 629 | result = -EINVAL; |
586 | goto out_free; | 630 | goto out_free; |
@@ -588,25 +632,21 @@ static int dvb_init(struct em28xx *dev) | |||
588 | } | 632 | } |
589 | break; | 633 | break; |
590 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: | 634 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: |
591 | #ifdef EM28XX_DRX397XD_SUPPORT | 635 | case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: |
592 | /* We don't have the config structure properly populated, so | 636 | dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL, |
593 | this is commented out for now */ | 637 | &dev->i2c_adap, &dev->udev->dev); |
594 | dvb->frontend = dvb_attach(drx397xD_attach, | ||
595 | &em28xx_drx397xD_with_xc3028, | ||
596 | &dev->i2c_adap); | ||
597 | if (attach_xc3028(0x61, dev) < 0) { | 638 | if (attach_xc3028(0x61, dev) < 0) { |
598 | result = -EINVAL; | 639 | result = -EINVAL; |
599 | goto out_free; | 640 | goto out_free; |
600 | } | 641 | } |
601 | break; | 642 | break; |
602 | #endif | ||
603 | case EM2870_BOARD_REDDO_DVB_C_USB_BOX: | 643 | case EM2870_BOARD_REDDO_DVB_C_USB_BOX: |
604 | /* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */ | 644 | /* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */ |
605 | dvb->frontend = dvb_attach(tda10023_attach, | 645 | dvb->fe[0] = dvb_attach(tda10023_attach, |
606 | &em28xx_tda10023_config, | 646 | &em28xx_tda10023_config, |
607 | &dev->i2c_adap, 0x48); | 647 | &dev->i2c_adap, 0x48); |
608 | if (dvb->frontend) { | 648 | if (dvb->fe[0]) { |
609 | if (!dvb_attach(simple_tuner_attach, dvb->frontend, | 649 | if (!dvb_attach(simple_tuner_attach, dvb->fe[0], |
610 | &dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) { | 650 | &dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) { |
611 | result = -EINVAL; | 651 | result = -EINVAL; |
612 | goto out_free; | 652 | goto out_free; |
@@ -614,25 +654,53 @@ static int dvb_init(struct em28xx *dev) | |||
614 | } | 654 | } |
615 | break; | 655 | break; |
616 | case EM2870_BOARD_KWORLD_A340: | 656 | case EM2870_BOARD_KWORLD_A340: |
617 | dvb->frontend = dvb_attach(lgdt3305_attach, | 657 | dvb->fe[0] = dvb_attach(lgdt3305_attach, |
618 | &em2870_lgdt3304_dev, | 658 | &em2870_lgdt3304_dev, |
619 | &dev->i2c_adap); | 659 | &dev->i2c_adap); |
620 | if (dvb->frontend != NULL) | 660 | if (dvb->fe[0] != NULL) |
621 | dvb_attach(tda18271_attach, dvb->frontend, 0x60, | 661 | dvb_attach(tda18271_attach, dvb->fe[0], 0x60, |
622 | &dev->i2c_adap, &kworld_a340_config); | 662 | &dev->i2c_adap, &kworld_a340_config); |
623 | break; | 663 | break; |
664 | case EM28174_BOARD_PCTV_290E: | ||
665 | /* MFE | ||
666 | * FE 0 = DVB-T/T2 + FE 1 = DVB-C, both sharing same tuner. */ | ||
667 | /* FE 0 */ | ||
668 | dvb->fe[0] = dvb_attach(cxd2820r_attach, | ||
669 | &em28xx_cxd2820r_config, &dev->i2c_adap, NULL); | ||
670 | if (dvb->fe[0]) { | ||
671 | struct i2c_adapter *i2c_tuner; | ||
672 | i2c_tuner = cxd2820r_get_tuner_i2c_adapter(dvb->fe[0]); | ||
673 | /* FE 0 attach tuner */ | ||
674 | if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, | ||
675 | i2c_tuner, &em28xx_cxd2820r_tda18271_config)) { | ||
676 | dvb_frontend_detach(dvb->fe[0]); | ||
677 | result = -EINVAL; | ||
678 | goto out_free; | ||
679 | } | ||
680 | /* FE 1. This dvb_attach() cannot fail. */ | ||
681 | dvb->fe[1] = dvb_attach(cxd2820r_attach, NULL, NULL, | ||
682 | dvb->fe[0]); | ||
683 | dvb->fe[1]->id = 1; | ||
684 | /* FE 1 attach tuner */ | ||
685 | if (!dvb_attach(tda18271_attach, dvb->fe[1], 0x60, | ||
686 | i2c_tuner, &em28xx_cxd2820r_tda18271_config)) { | ||
687 | dvb_frontend_detach(dvb->fe[1]); | ||
688 | /* leave FE 0 still active */ | ||
689 | } | ||
690 | } | ||
691 | break; | ||
624 | default: | 692 | default: |
625 | em28xx_errdev("/2: The frontend of your DVB/ATSC card" | 693 | em28xx_errdev("/2: The frontend of your DVB/ATSC card" |
626 | " isn't supported yet\n"); | 694 | " isn't supported yet\n"); |
627 | break; | 695 | break; |
628 | } | 696 | } |
629 | if (NULL == dvb->frontend) { | 697 | if (NULL == dvb->fe[0]) { |
630 | em28xx_errdev("/2: frontend initialization failed\n"); | 698 | em28xx_errdev("/2: frontend initialization failed\n"); |
631 | result = -EINVAL; | 699 | result = -EINVAL; |
632 | goto out_free; | 700 | goto out_free; |
633 | } | 701 | } |
634 | /* define general-purpose callback pointer */ | 702 | /* define general-purpose callback pointer */ |
635 | dvb->frontend->callback = em28xx_tuner_callback; | 703 | dvb->fe[0]->callback = em28xx_tuner_callback; |
636 | 704 | ||
637 | /* register everything */ | 705 | /* register everything */ |
638 | result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); | 706 | result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); |
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index 71474d31e155..4739fc7e6eb3 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c | |||
@@ -332,7 +332,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) | |||
332 | struct em28xx_eeprom *em_eeprom = (void *)eedata; | 332 | struct em28xx_eeprom *em_eeprom = (void *)eedata; |
333 | int i, err, size = len, block; | 333 | int i, err, size = len, block; |
334 | 334 | ||
335 | if (dev->chip_id == CHIP_ID_EM2874) { | 335 | if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) { |
336 | /* Empia switched to a 16-bit addressable eeprom in newer | 336 | /* Empia switched to a 16-bit addressable eeprom in newer |
337 | devices. While we could certainly write a routine to read | 337 | devices. While we could certainly write a routine to read |
338 | the eeprom, there is nothing of use in there that cannot be | 338 | the eeprom, there is nothing of use in there that cannot be |
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h index 91e90559642b..e92a28ede434 100644 --- a/drivers/media/video/em28xx/em28xx-reg.h +++ b/drivers/media/video/em28xx/em28xx-reg.h | |||
@@ -201,6 +201,7 @@ enum em28xx_chip_id { | |||
201 | CHIP_ID_EM2870 = 35, | 201 | CHIP_ID_EM2870 = 35, |
202 | CHIP_ID_EM2883 = 36, | 202 | CHIP_ID_EM2883 = 36, |
203 | CHIP_ID_EM2874 = 65, | 203 | CHIP_ID_EM2874 = 65, |
204 | CHIP_ID_EM28174 = 113, | ||
204 | }; | 205 | }; |
205 | 206 | ||
206 | /* | 207 | /* |
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 6f2795a3d4b7..3cca33122450 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
@@ -97,7 +97,7 @@ | |||
97 | #define EM2881_BOARD_PINNACLE_HYBRID_PRO 53 | 97 | #define EM2881_BOARD_PINNACLE_HYBRID_PRO 53 |
98 | #define EM2882_BOARD_KWORLD_VS_DVBT 54 | 98 | #define EM2882_BOARD_KWORLD_VS_DVBT 54 |
99 | #define EM2882_BOARD_TERRATEC_HYBRID_XS 55 | 99 | #define EM2882_BOARD_TERRATEC_HYBRID_XS 55 |
100 | #define EM2882_BOARD_PINNACLE_HYBRID_PRO 56 | 100 | #define EM2882_BOARD_PINNACLE_HYBRID_PRO_330E 56 |
101 | #define EM2883_BOARD_KWORLD_HYBRID_330U 57 | 101 | #define EM2883_BOARD_KWORLD_HYBRID_330U 57 |
102 | #define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 | 102 | #define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 |
103 | #define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60 | 103 | #define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60 |
@@ -118,6 +118,7 @@ | |||
118 | #define EM2882_BOARD_DIKOM_DK300 75 | 118 | #define EM2882_BOARD_DIKOM_DK300 75 |
119 | #define EM2870_BOARD_KWORLD_A340 76 | 119 | #define EM2870_BOARD_KWORLD_A340 76 |
120 | #define EM2874_LEADERSHIP_ISDBT 77 | 120 | #define EM2874_LEADERSHIP_ISDBT 77 |
121 | #define EM28174_BOARD_PCTV_290E 78 | ||
121 | 122 | ||
122 | 123 | ||
123 | /* Limits minimum and default number of buffers */ | 124 | /* Limits minimum and default number of buffers */ |
diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c index 031af1610154..908d7012c3f2 100644 --- a/drivers/media/video/fsl-viu.c +++ b/drivers/media/video/fsl-viu.c | |||
@@ -766,7 +766,7 @@ inline void viu_activate_overlay(struct viu_reg *viu_reg) | |||
766 | out_be32(&vr->picture_count, reg_val.picture_count); | 766 | out_be32(&vr->picture_count, reg_val.picture_count); |
767 | } | 767 | } |
768 | 768 | ||
769 | static int viu_start_preview(struct viu_dev *dev, struct viu_fh *fh) | 769 | static int viu_setup_preview(struct viu_dev *dev, struct viu_fh *fh) |
770 | { | 770 | { |
771 | int bpp; | 771 | int bpp; |
772 | 772 | ||
@@ -805,11 +805,6 @@ static int viu_start_preview(struct viu_dev *dev, struct viu_fh *fh) | |||
805 | /* setup the base address of the overlay buffer */ | 805 | /* setup the base address of the overlay buffer */ |
806 | reg_val.field_base_addr = (u32)dev->ovbuf.base; | 806 | reg_val.field_base_addr = (u32)dev->ovbuf.base; |
807 | 807 | ||
808 | dev->ovenable = 1; | ||
809 | viu_activate_overlay(dev->vr); | ||
810 | |||
811 | /* start dma */ | ||
812 | viu_start_dma(dev); | ||
813 | return 0; | 808 | return 0; |
814 | } | 809 | } |
815 | 810 | ||
@@ -825,13 +820,11 @@ static int vidioc_s_fmt_overlay(struct file *file, void *priv, | |||
825 | if (err) | 820 | if (err) |
826 | return err; | 821 | return err; |
827 | 822 | ||
828 | mutex_lock(&dev->lock); | ||
829 | fh->win = f->fmt.win; | 823 | fh->win = f->fmt.win; |
830 | 824 | ||
831 | spin_lock_irqsave(&dev->slock, flags); | 825 | spin_lock_irqsave(&dev->slock, flags); |
832 | viu_start_preview(dev, fh); | 826 | viu_setup_preview(dev, fh); |
833 | spin_unlock_irqrestore(&dev->slock, flags); | 827 | spin_unlock_irqrestore(&dev->slock, flags); |
834 | mutex_unlock(&dev->lock); | ||
835 | return 0; | 828 | return 0; |
836 | } | 829 | } |
837 | 830 | ||
@@ -841,6 +834,28 @@ static int vidioc_try_fmt_overlay(struct file *file, void *priv, | |||
841 | return 0; | 834 | return 0; |
842 | } | 835 | } |
843 | 836 | ||
837 | static int vidioc_overlay(struct file *file, void *priv, unsigned int on) | ||
838 | { | ||
839 | struct viu_fh *fh = priv; | ||
840 | struct viu_dev *dev = (struct viu_dev *)fh->dev; | ||
841 | unsigned long flags; | ||
842 | |||
843 | if (on) { | ||
844 | spin_lock_irqsave(&dev->slock, flags); | ||
845 | viu_activate_overlay(dev->vr); | ||
846 | dev->ovenable = 1; | ||
847 | |||
848 | /* start dma */ | ||
849 | viu_start_dma(dev); | ||
850 | spin_unlock_irqrestore(&dev->slock, flags); | ||
851 | } else { | ||
852 | viu_stop_dma(dev); | ||
853 | dev->ovenable = 0; | ||
854 | } | ||
855 | |||
856 | return 0; | ||
857 | } | ||
858 | |||
844 | int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg) | 859 | int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg) |
845 | { | 860 | { |
846 | struct viu_fh *fh = priv; | 861 | struct viu_fh *fh = priv; |
@@ -911,12 +926,16 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) | |||
911 | static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) | 926 | static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) |
912 | { | 927 | { |
913 | struct viu_fh *fh = priv; | 928 | struct viu_fh *fh = priv; |
929 | struct viu_dev *dev = fh->dev; | ||
914 | 930 | ||
915 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 931 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
916 | return -EINVAL; | 932 | return -EINVAL; |
917 | if (fh->type != i) | 933 | if (fh->type != i) |
918 | return -EINVAL; | 934 | return -EINVAL; |
919 | 935 | ||
936 | if (dev->ovenable) | ||
937 | dev->ovenable = 0; | ||
938 | |||
920 | viu_start_dma(fh->dev); | 939 | viu_start_dma(fh->dev); |
921 | 940 | ||
922 | return videobuf_streamon(&fh->vb_vidq); | 941 | return videobuf_streamon(&fh->vb_vidq); |
@@ -1311,7 +1330,8 @@ static int viu_open(struct file *file) | |||
1311 | videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops, | 1330 | videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops, |
1312 | dev->dev, &fh->vbq_lock, | 1331 | dev->dev, &fh->vbq_lock, |
1313 | fh->type, V4L2_FIELD_INTERLACED, | 1332 | fh->type, V4L2_FIELD_INTERLACED, |
1314 | sizeof(struct viu_buf), fh, NULL); | 1333 | sizeof(struct viu_buf), fh, |
1334 | &fh->dev->lock); | ||
1315 | return 0; | 1335 | return 0; |
1316 | } | 1336 | } |
1317 | 1337 | ||
@@ -1401,7 +1421,7 @@ static struct v4l2_file_operations viu_fops = { | |||
1401 | .release = viu_release, | 1421 | .release = viu_release, |
1402 | .read = viu_read, | 1422 | .read = viu_read, |
1403 | .poll = viu_poll, | 1423 | .poll = viu_poll, |
1404 | .ioctl = video_ioctl2, /* V4L2 ioctl handler */ | 1424 | .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ |
1405 | .mmap = viu_mmap, | 1425 | .mmap = viu_mmap, |
1406 | }; | 1426 | }; |
1407 | 1427 | ||
@@ -1415,6 +1435,7 @@ static const struct v4l2_ioctl_ops viu_ioctl_ops = { | |||
1415 | .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay, | 1435 | .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay, |
1416 | .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay, | 1436 | .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay, |
1417 | .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay, | 1437 | .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay, |
1438 | .vidioc_overlay = vidioc_overlay, | ||
1418 | .vidioc_g_fbuf = vidioc_g_fbuf, | 1439 | .vidioc_g_fbuf = vidioc_g_fbuf, |
1419 | .vidioc_s_fbuf = vidioc_s_fbuf, | 1440 | .vidioc_s_fbuf = vidioc_s_fbuf, |
1420 | .vidioc_reqbufs = vidioc_reqbufs, | 1441 | .vidioc_reqbufs = vidioc_reqbufs, |
@@ -1498,9 +1519,6 @@ static int __devinit viu_of_probe(struct platform_device *op) | |||
1498 | INIT_LIST_HEAD(&viu_dev->vidq.active); | 1519 | INIT_LIST_HEAD(&viu_dev->vidq.active); |
1499 | INIT_LIST_HEAD(&viu_dev->vidq.queued); | 1520 | INIT_LIST_HEAD(&viu_dev->vidq.queued); |
1500 | 1521 | ||
1501 | /* initialize locks */ | ||
1502 | mutex_init(&viu_dev->lock); | ||
1503 | |||
1504 | snprintf(viu_dev->v4l2_dev.name, | 1522 | snprintf(viu_dev->v4l2_dev.name, |
1505 | sizeof(viu_dev->v4l2_dev.name), "%s", "VIU"); | 1523 | sizeof(viu_dev->v4l2_dev.name), "%s", "VIU"); |
1506 | ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev); | 1524 | ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev); |
@@ -1531,8 +1549,15 @@ static int __devinit viu_of_probe(struct platform_device *op) | |||
1531 | 1549 | ||
1532 | viu_dev->vdev = vdev; | 1550 | viu_dev->vdev = vdev; |
1533 | 1551 | ||
1552 | /* initialize locks */ | ||
1553 | mutex_init(&viu_dev->lock); | ||
1554 | viu_dev->vdev->lock = &viu_dev->lock; | ||
1555 | spin_lock_init(&viu_dev->slock); | ||
1556 | |||
1534 | video_set_drvdata(viu_dev->vdev, viu_dev); | 1557 | video_set_drvdata(viu_dev->vdev, viu_dev); |
1535 | 1558 | ||
1559 | mutex_lock(&viu_dev->lock); | ||
1560 | |||
1536 | ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1); | 1561 | ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1); |
1537 | if (ret < 0) { | 1562 | if (ret < 0) { |
1538 | video_device_release(viu_dev->vdev); | 1563 | video_device_release(viu_dev->vdev); |
@@ -1559,6 +1584,8 @@ static int __devinit viu_of_probe(struct platform_device *op) | |||
1559 | goto err_irq; | 1584 | goto err_irq; |
1560 | } | 1585 | } |
1561 | 1586 | ||
1587 | mutex_unlock(&viu_dev->lock); | ||
1588 | |||
1562 | dev_info(&op->dev, "Freescale VIU Video Capture Board\n"); | 1589 | dev_info(&op->dev, "Freescale VIU Video Capture Board\n"); |
1563 | return ret; | 1590 | return ret; |
1564 | 1591 | ||
@@ -1568,6 +1595,7 @@ err_irq: | |||
1568 | err_clk: | 1595 | err_clk: |
1569 | video_unregister_device(viu_dev->vdev); | 1596 | video_unregister_device(viu_dev->vdev); |
1570 | err_vdev: | 1597 | err_vdev: |
1598 | mutex_unlock(&viu_dev->lock); | ||
1571 | i2c_put_adapter(ad); | 1599 | i2c_put_adapter(ad); |
1572 | v4l2_device_unregister(&viu_dev->v4l2_dev); | 1600 | v4l2_device_unregister(&viu_dev->v4l2_dev); |
1573 | err: | 1601 | err: |
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig index eb04e8b59989..34ae2c299799 100644 --- a/drivers/media/video/gspca/Kconfig +++ b/drivers/media/video/gspca/Kconfig | |||
@@ -77,6 +77,15 @@ config USB_GSPCA_JEILINJ | |||
77 | To compile this driver as a module, choose M here: the | 77 | To compile this driver as a module, choose M here: the |
78 | module will be called gspca_jeilinj. | 78 | module will be called gspca_jeilinj. |
79 | 79 | ||
80 | config USB_GSPCA_KINECT | ||
81 | tristate "Kinect sensor device USB Camera Driver" | ||
82 | depends on VIDEO_V4L2 && USB_GSPCA | ||
83 | help | ||
84 | Say Y here if you want support for the Microsoft Kinect sensor device. | ||
85 | |||
86 | To compile this driver as a module, choose M here: the | ||
87 | module will be called gspca_kinect. | ||
88 | |||
80 | config USB_GSPCA_KONICA | 89 | config USB_GSPCA_KONICA |
81 | tristate "Konica USB Camera V4L2 driver" | 90 | tristate "Konica USB Camera V4L2 driver" |
82 | depends on VIDEO_V4L2 && USB_GSPCA | 91 | depends on VIDEO_V4L2 && USB_GSPCA |
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index 855fbc8c9c47..802fbe1bff4a 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile | |||
@@ -5,6 +5,7 @@ obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o | |||
5 | obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o | 5 | obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o |
6 | obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o | 6 | obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o |
7 | obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o | 7 | obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o |
8 | obj-$(CONFIG_USB_GSPCA_KINECT) += gspca_kinect.o | ||
8 | obj-$(CONFIG_USB_GSPCA_KONICA) += gspca_konica.o | 9 | obj-$(CONFIG_USB_GSPCA_KONICA) += gspca_konica.o |
9 | obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o | 10 | obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o |
10 | obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o | 11 | obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o |
@@ -46,6 +47,7 @@ gspca_cpia1-objs := cpia1.o | |||
46 | gspca_etoms-objs := etoms.o | 47 | gspca_etoms-objs := etoms.o |
47 | gspca_finepix-objs := finepix.o | 48 | gspca_finepix-objs := finepix.o |
48 | gspca_jeilinj-objs := jeilinj.o | 49 | gspca_jeilinj-objs := jeilinj.o |
50 | gspca_kinect-objs := kinect.o | ||
49 | gspca_konica-objs := konica.o | 51 | gspca_konica-objs := konica.o |
50 | gspca_mars-objs := mars.o | 52 | gspca_mars-objs := mars.o |
51 | gspca_mr97310a-objs := mr97310a.o | 53 | gspca_mr97310a-objs := mr97310a.o |
diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c index 9ddbac680663..f2a9451eea19 100644 --- a/drivers/media/video/gspca/cpia1.c +++ b/drivers/media/video/gspca/cpia1.c | |||
@@ -1262,7 +1262,7 @@ static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply) | |||
1262 | static void monitor_exposure(struct gspca_dev *gspca_dev) | 1262 | static void monitor_exposure(struct gspca_dev *gspca_dev) |
1263 | { | 1263 | { |
1264 | struct sd *sd = (struct sd *) gspca_dev; | 1264 | struct sd *sd = (struct sd *) gspca_dev; |
1265 | u8 exp_acc, bcomp, gain, coarseL, cmd[8]; | 1265 | u8 exp_acc, bcomp, cmd[8]; |
1266 | int ret, light_exp, dark_exp, very_dark_exp; | 1266 | int ret, light_exp, dark_exp, very_dark_exp; |
1267 | int old_exposure, new_exposure, framerate; | 1267 | int old_exposure, new_exposure, framerate; |
1268 | int setfps = 0, setexp = 0, setflicker = 0; | 1268 | int setfps = 0, setexp = 0, setflicker = 0; |
@@ -1284,8 +1284,6 @@ static void monitor_exposure(struct gspca_dev *gspca_dev) | |||
1284 | } | 1284 | } |
1285 | exp_acc = gspca_dev->usb_buf[0]; | 1285 | exp_acc = gspca_dev->usb_buf[0]; |
1286 | bcomp = gspca_dev->usb_buf[1]; | 1286 | bcomp = gspca_dev->usb_buf[1]; |
1287 | gain = gspca_dev->usb_buf[2]; | ||
1288 | coarseL = gspca_dev->usb_buf[3]; | ||
1289 | 1287 | ||
1290 | light_exp = sd->params.colourParams.brightness + | 1288 | light_exp = sd->params.colourParams.brightness + |
1291 | TC - 50 + EXP_ACC_LIGHT; | 1289 | TC - 50 + EXP_ACC_LIGHT; |
@@ -1772,9 +1770,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) | |||
1772 | /* this function is called at probe and resume time */ | 1770 | /* this function is called at probe and resume time */ |
1773 | static int sd_init(struct gspca_dev *gspca_dev) | 1771 | static int sd_init(struct gspca_dev *gspca_dev) |
1774 | { | 1772 | { |
1775 | #ifdef GSPCA_DEBUG | ||
1776 | struct sd *sd = (struct sd *) gspca_dev; | 1773 | struct sd *sd = (struct sd *) gspca_dev; |
1777 | #endif | ||
1778 | int ret; | 1774 | int ret; |
1779 | 1775 | ||
1780 | /* Start / Stop the camera to make sure we are talking to | 1776 | /* Start / Stop the camera to make sure we are talking to |
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c index 99083038cec3..e8e071aa212f 100644 --- a/drivers/media/video/gspca/gl860/gl860.c +++ b/drivers/media/video/gspca/gl860/gl860.c | |||
@@ -499,21 +499,8 @@ MODULE_DEVICE_TABLE(usb, device_table); | |||
499 | static int sd_probe(struct usb_interface *intf, | 499 | static int sd_probe(struct usb_interface *intf, |
500 | const struct usb_device_id *id) | 500 | const struct usb_device_id *id) |
501 | { | 501 | { |
502 | struct gspca_dev *gspca_dev; | 502 | return gspca_dev_probe(intf, id, |
503 | s32 ret; | ||
504 | |||
505 | ret = gspca_dev_probe(intf, id, | ||
506 | &sd_desc_mi1320, sizeof(struct sd), THIS_MODULE); | 503 | &sd_desc_mi1320, sizeof(struct sd), THIS_MODULE); |
507 | |||
508 | if (ret >= 0) { | ||
509 | gspca_dev = usb_get_intfdata(intf); | ||
510 | |||
511 | PDEBUG(D_PROBE, | ||
512 | "Camera is now controlling video device %s", | ||
513 | video_device_node_name(&gspca_dev->vdev)); | ||
514 | } | ||
515 | |||
516 | return ret; | ||
517 | } | 504 | } |
518 | 505 | ||
519 | static void sd_disconnect(struct usb_interface *intf) | 506 | static void sd_disconnect(struct usb_interface *intf) |
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index e526aa3dedaf..08ce9948d99b 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c | |||
@@ -55,7 +55,7 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>"); | |||
55 | MODULE_DESCRIPTION("GSPCA USB Camera Driver"); | 55 | MODULE_DESCRIPTION("GSPCA USB Camera Driver"); |
56 | MODULE_LICENSE("GPL"); | 56 | MODULE_LICENSE("GPL"); |
57 | 57 | ||
58 | #define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 12, 0) | 58 | #define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 13, 0) |
59 | 59 | ||
60 | #ifdef GSPCA_DEBUG | 60 | #ifdef GSPCA_DEBUG |
61 | int gspca_debug = D_ERR | D_PROBE; | 61 | int gspca_debug = D_ERR | D_PROBE; |
@@ -2495,6 +2495,6 @@ module_exit(gspca_exit); | |||
2495 | module_param_named(debug, gspca_debug, int, 0644); | 2495 | module_param_named(debug, gspca_debug, int, 0644); |
2496 | MODULE_PARM_DESC(debug, | 2496 | MODULE_PARM_DESC(debug, |
2497 | "Debug (bit) 0x01:error 0x02:probe 0x04:config" | 2497 | "Debug (bit) 0x01:error 0x02:probe 0x04:config" |
2498 | " 0x08:stream 0x10:frame 0x20:packet 0x40:USBin 0x80:USBout" | 2498 | " 0x08:stream 0x10:frame 0x20:packet" |
2499 | " 0x0100: v4l2"); | 2499 | " 0x0100: v4l2"); |
2500 | #endif | 2500 | #endif |
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index 41755226d389..49e2fcbe81fb 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h | |||
@@ -9,7 +9,7 @@ | |||
9 | #include <linux/mutex.h> | 9 | #include <linux/mutex.h> |
10 | 10 | ||
11 | /* compilation option */ | 11 | /* compilation option */ |
12 | #define GSPCA_DEBUG 1 | 12 | /*#define GSPCA_DEBUG 1*/ |
13 | 13 | ||
14 | #ifdef GSPCA_DEBUG | 14 | #ifdef GSPCA_DEBUG |
15 | /* GSPCA our debug messages */ | 15 | /* GSPCA our debug messages */ |
@@ -25,8 +25,8 @@ extern int gspca_debug; | |||
25 | #define D_STREAM 0x08 | 25 | #define D_STREAM 0x08 |
26 | #define D_FRAM 0x10 | 26 | #define D_FRAM 0x10 |
27 | #define D_PACK 0x20 | 27 | #define D_PACK 0x20 |
28 | #define D_USBI 0x40 | 28 | #define D_USBI 0x00 |
29 | #define D_USBO 0x80 | 29 | #define D_USBO 0x00 |
30 | #define D_V4L2 0x0100 | 30 | #define D_V4L2 0x0100 |
31 | #else | 31 | #else |
32 | #define PDEBUG(level, fmt, args...) | 32 | #define PDEBUG(level, fmt, args...) |
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c index 36dae38b1e38..1bd9c4b542dd 100644 --- a/drivers/media/video/gspca/jeilinj.c +++ b/drivers/media/video/gspca/jeilinj.c | |||
@@ -6,6 +6,9 @@ | |||
6 | * | 6 | * |
7 | * Copyright (C) 2009 Theodore Kilgore | 7 | * Copyright (C) 2009 Theodore Kilgore |
8 | * | 8 | * |
9 | * Sportscam DV15 support and control settings are | ||
10 | * Copyright (C) 2011 Patrice Chotard | ||
11 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
11 | * the Free Software Foundation; either version 2 of the License, or | 14 | * the Free Software Foundation; either version 2 of the License, or |
@@ -23,7 +26,6 @@ | |||
23 | 26 | ||
24 | #define MODULE_NAME "jeilinj" | 27 | #define MODULE_NAME "jeilinj" |
25 | 28 | ||
26 | #include <linux/workqueue.h> | ||
27 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
28 | #include "gspca.h" | 30 | #include "gspca.h" |
29 | #include "jpeg.h" | 31 | #include "jpeg.h" |
@@ -34,29 +36,51 @@ MODULE_LICENSE("GPL"); | |||
34 | 36 | ||
35 | /* Default timeouts, in ms */ | 37 | /* Default timeouts, in ms */ |
36 | #define JEILINJ_CMD_TIMEOUT 500 | 38 | #define JEILINJ_CMD_TIMEOUT 500 |
39 | #define JEILINJ_CMD_DELAY 160 | ||
37 | #define JEILINJ_DATA_TIMEOUT 1000 | 40 | #define JEILINJ_DATA_TIMEOUT 1000 |
38 | 41 | ||
39 | /* Maximum transfer size to use. */ | 42 | /* Maximum transfer size to use. */ |
40 | #define JEILINJ_MAX_TRANSFER 0x200 | 43 | #define JEILINJ_MAX_TRANSFER 0x200 |
41 | |||
42 | #define FRAME_HEADER_LEN 0x10 | 44 | #define FRAME_HEADER_LEN 0x10 |
45 | #define FRAME_START 0xFFFFFFFF | ||
46 | |||
47 | enum { | ||
48 | SAKAR_57379, | ||
49 | SPORTSCAM_DV15, | ||
50 | }; | ||
51 | |||
52 | #define CAMQUALITY_MIN 0 /* highest cam quality */ | ||
53 | #define CAMQUALITY_MAX 97 /* lowest cam quality */ | ||
54 | |||
55 | enum e_ctrl { | ||
56 | LIGHTFREQ, | ||
57 | AUTOGAIN, | ||
58 | RED, | ||
59 | GREEN, | ||
60 | BLUE, | ||
61 | NCTRLS /* number of controls */ | ||
62 | }; | ||
43 | 63 | ||
44 | /* Structure to hold all of our device specific stuff */ | 64 | /* Structure to hold all of our device specific stuff */ |
45 | struct sd { | 65 | struct sd { |
46 | struct gspca_dev gspca_dev; /* !! must be the first item */ | 66 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
67 | struct gspca_ctrl ctrls[NCTRLS]; | ||
68 | int blocks_left; | ||
47 | const struct v4l2_pix_format *cap_mode; | 69 | const struct v4l2_pix_format *cap_mode; |
48 | /* Driver stuff */ | 70 | /* Driver stuff */ |
49 | struct work_struct work_struct; | 71 | u8 type; |
50 | struct workqueue_struct *work_thread; | ||
51 | u8 quality; /* image quality */ | 72 | u8 quality; /* image quality */ |
52 | u8 jpegqual; /* webcam quality */ | 73 | #define QUALITY_MIN 35 |
74 | #define QUALITY_MAX 85 | ||
75 | #define QUALITY_DEF 85 | ||
53 | u8 jpeg_hdr[JPEG_HDR_SZ]; | 76 | u8 jpeg_hdr[JPEG_HDR_SZ]; |
54 | }; | 77 | }; |
55 | 78 | ||
56 | struct jlj_command { | 79 | struct jlj_command { |
57 | unsigned char instruction[2]; | 80 | unsigned char instruction[2]; |
58 | unsigned char ack_wanted; | 81 | unsigned char ack_wanted; |
59 | }; | 82 | unsigned char delay; |
83 | }; | ||
60 | 84 | ||
61 | /* AFAICT these cameras will only do 320x240. */ | 85 | /* AFAICT these cameras will only do 320x240. */ |
62 | static struct v4l2_pix_format jlj_mode[] = { | 86 | static struct v4l2_pix_format jlj_mode[] = { |
@@ -64,6 +88,11 @@ static struct v4l2_pix_format jlj_mode[] = { | |||
64 | .bytesperline = 320, | 88 | .bytesperline = 320, |
65 | .sizeimage = 320 * 240, | 89 | .sizeimage = 320 * 240, |
66 | .colorspace = V4L2_COLORSPACE_JPEG, | 90 | .colorspace = V4L2_COLORSPACE_JPEG, |
91 | .priv = 0}, | ||
92 | { 640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, | ||
93 | .bytesperline = 640, | ||
94 | .sizeimage = 640 * 480, | ||
95 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
67 | .priv = 0} | 96 | .priv = 0} |
68 | }; | 97 | }; |
69 | 98 | ||
@@ -73,178 +102,295 @@ static struct v4l2_pix_format jlj_mode[] = { | |||
73 | */ | 102 | */ |
74 | 103 | ||
75 | /* All commands are two bytes only */ | 104 | /* All commands are two bytes only */ |
76 | static int jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command) | 105 | static void jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command) |
77 | { | 106 | { |
78 | int retval; | 107 | int retval; |
79 | 108 | ||
109 | if (gspca_dev->usb_err < 0) | ||
110 | return; | ||
80 | memcpy(gspca_dev->usb_buf, command, 2); | 111 | memcpy(gspca_dev->usb_buf, command, 2); |
81 | retval = usb_bulk_msg(gspca_dev->dev, | 112 | retval = usb_bulk_msg(gspca_dev->dev, |
82 | usb_sndbulkpipe(gspca_dev->dev, 3), | 113 | usb_sndbulkpipe(gspca_dev->dev, 3), |
83 | gspca_dev->usb_buf, 2, NULL, 500); | 114 | gspca_dev->usb_buf, 2, NULL, 500); |
84 | if (retval < 0) | 115 | if (retval < 0) { |
85 | err("command write [%02x] error %d", | 116 | err("command write [%02x] error %d", |
86 | gspca_dev->usb_buf[0], retval); | 117 | gspca_dev->usb_buf[0], retval); |
87 | return retval; | 118 | gspca_dev->usb_err = retval; |
119 | } | ||
88 | } | 120 | } |
89 | 121 | ||
90 | /* Responses are one byte only */ | 122 | /* Responses are one byte only */ |
91 | static int jlj_read1(struct gspca_dev *gspca_dev, unsigned char response) | 123 | static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char response) |
92 | { | 124 | { |
93 | int retval; | 125 | int retval; |
94 | 126 | ||
127 | if (gspca_dev->usb_err < 0) | ||
128 | return; | ||
95 | retval = usb_bulk_msg(gspca_dev->dev, | 129 | retval = usb_bulk_msg(gspca_dev->dev, |
96 | usb_rcvbulkpipe(gspca_dev->dev, 0x84), | 130 | usb_rcvbulkpipe(gspca_dev->dev, 0x84), |
97 | gspca_dev->usb_buf, 1, NULL, 500); | 131 | gspca_dev->usb_buf, 1, NULL, 500); |
98 | response = gspca_dev->usb_buf[0]; | 132 | response = gspca_dev->usb_buf[0]; |
99 | if (retval < 0) | 133 | if (retval < 0) { |
100 | err("read command [%02x] error %d", | 134 | err("read command [%02x] error %d", |
101 | gspca_dev->usb_buf[0], retval); | 135 | gspca_dev->usb_buf[0], retval); |
102 | return retval; | 136 | gspca_dev->usb_err = retval; |
137 | } | ||
103 | } | 138 | } |
104 | 139 | ||
105 | static int jlj_start(struct gspca_dev *gspca_dev) | 140 | static void setfreq(struct gspca_dev *gspca_dev) |
106 | { | 141 | { |
107 | int i; | 142 | struct sd *sd = (struct sd *) gspca_dev; |
108 | int retval = -1; | 143 | u8 freq_commands[][2] = { |
109 | u8 response = 0xff; | 144 | {0x71, 0x80}, |
110 | struct jlj_command start_commands[] = { | 145 | {0x70, 0x07} |
111 | {{0x71, 0x81}, 0}, | ||
112 | {{0x70, 0x05}, 0}, | ||
113 | {{0x95, 0x70}, 1}, | ||
114 | {{0x71, 0x81}, 0}, | ||
115 | {{0x70, 0x04}, 0}, | ||
116 | {{0x95, 0x70}, 1}, | ||
117 | {{0x71, 0x00}, 0}, | ||
118 | {{0x70, 0x08}, 0}, | ||
119 | {{0x95, 0x70}, 1}, | ||
120 | {{0x94, 0x02}, 0}, | ||
121 | {{0xde, 0x24}, 0}, | ||
122 | {{0x94, 0x02}, 0}, | ||
123 | {{0xdd, 0xf0}, 0}, | ||
124 | {{0x94, 0x02}, 0}, | ||
125 | {{0xe3, 0x2c}, 0}, | ||
126 | {{0x94, 0x02}, 0}, | ||
127 | {{0xe4, 0x00}, 0}, | ||
128 | {{0x94, 0x02}, 0}, | ||
129 | {{0xe5, 0x00}, 0}, | ||
130 | {{0x94, 0x02}, 0}, | ||
131 | {{0xe6, 0x2c}, 0}, | ||
132 | {{0x94, 0x03}, 0}, | ||
133 | {{0xaa, 0x00}, 0}, | ||
134 | {{0x71, 0x1e}, 0}, | ||
135 | {{0x70, 0x06}, 0}, | ||
136 | {{0x71, 0x80}, 0}, | ||
137 | {{0x70, 0x07}, 0} | ||
138 | }; | 146 | }; |
139 | for (i = 0; i < ARRAY_SIZE(start_commands); i++) { | 147 | |
140 | retval = jlj_write2(gspca_dev, start_commands[i].instruction); | 148 | freq_commands[0][1] |= (sd->ctrls[LIGHTFREQ].val >> 1); |
141 | if (retval < 0) | 149 | |
142 | return retval; | 150 | jlj_write2(gspca_dev, freq_commands[0]); |
143 | if (start_commands[i].ack_wanted) | 151 | jlj_write2(gspca_dev, freq_commands[1]); |
144 | retval = jlj_read1(gspca_dev, response); | ||
145 | if (retval < 0) | ||
146 | return retval; | ||
147 | } | ||
148 | PDEBUG(D_ERR, "jlj_start retval is %d", retval); | ||
149 | return retval; | ||
150 | } | 152 | } |
151 | 153 | ||
152 | static int jlj_stop(struct gspca_dev *gspca_dev) | 154 | static void setcamquality(struct gspca_dev *gspca_dev) |
155 | { | ||
156 | struct sd *sd = (struct sd *) gspca_dev; | ||
157 | u8 quality_commands[][2] = { | ||
158 | {0x71, 0x1E}, | ||
159 | {0x70, 0x06} | ||
160 | }; | ||
161 | u8 camquality; | ||
162 | |||
163 | /* adapt camera quality from jpeg quality */ | ||
164 | camquality = ((QUALITY_MAX - sd->quality) * CAMQUALITY_MAX) | ||
165 | / (QUALITY_MAX - QUALITY_MIN); | ||
166 | quality_commands[0][1] += camquality; | ||
167 | |||
168 | jlj_write2(gspca_dev, quality_commands[0]); | ||
169 | jlj_write2(gspca_dev, quality_commands[1]); | ||
170 | } | ||
171 | |||
172 | static void setautogain(struct gspca_dev *gspca_dev) | ||
173 | { | ||
174 | struct sd *sd = (struct sd *) gspca_dev; | ||
175 | u8 autogain_commands[][2] = { | ||
176 | {0x94, 0x02}, | ||
177 | {0xcf, 0x00} | ||
178 | }; | ||
179 | |||
180 | autogain_commands[1][1] = (sd->ctrls[AUTOGAIN].val << 4); | ||
181 | |||
182 | jlj_write2(gspca_dev, autogain_commands[0]); | ||
183 | jlj_write2(gspca_dev, autogain_commands[1]); | ||
184 | } | ||
185 | |||
186 | static void setred(struct gspca_dev *gspca_dev) | ||
187 | { | ||
188 | struct sd *sd = (struct sd *) gspca_dev; | ||
189 | u8 setred_commands[][2] = { | ||
190 | {0x94, 0x02}, | ||
191 | {0xe6, 0x00} | ||
192 | }; | ||
193 | |||
194 | setred_commands[1][1] = sd->ctrls[RED].val; | ||
195 | |||
196 | jlj_write2(gspca_dev, setred_commands[0]); | ||
197 | jlj_write2(gspca_dev, setred_commands[1]); | ||
198 | } | ||
199 | |||
200 | static void setgreen(struct gspca_dev *gspca_dev) | ||
201 | { | ||
202 | struct sd *sd = (struct sd *) gspca_dev; | ||
203 | u8 setgreen_commands[][2] = { | ||
204 | {0x94, 0x02}, | ||
205 | {0xe7, 0x00} | ||
206 | }; | ||
207 | |||
208 | setgreen_commands[1][1] = sd->ctrls[GREEN].val; | ||
209 | |||
210 | jlj_write2(gspca_dev, setgreen_commands[0]); | ||
211 | jlj_write2(gspca_dev, setgreen_commands[1]); | ||
212 | } | ||
213 | |||
214 | static void setblue(struct gspca_dev *gspca_dev) | ||
215 | { | ||
216 | struct sd *sd = (struct sd *) gspca_dev; | ||
217 | u8 setblue_commands[][2] = { | ||
218 | {0x94, 0x02}, | ||
219 | {0xe9, 0x00} | ||
220 | }; | ||
221 | |||
222 | setblue_commands[1][1] = sd->ctrls[BLUE].val; | ||
223 | |||
224 | jlj_write2(gspca_dev, setblue_commands[0]); | ||
225 | jlj_write2(gspca_dev, setblue_commands[1]); | ||
226 | } | ||
227 | |||
228 | static const struct ctrl sd_ctrls[NCTRLS] = { | ||
229 | [LIGHTFREQ] = { | ||
230 | { | ||
231 | .id = V4L2_CID_POWER_LINE_FREQUENCY, | ||
232 | .type = V4L2_CTRL_TYPE_MENU, | ||
233 | .name = "Light frequency filter", | ||
234 | .minimum = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, /* 1 */ | ||
235 | .maximum = V4L2_CID_POWER_LINE_FREQUENCY_60HZ, /* 2 */ | ||
236 | .step = 1, | ||
237 | .default_value = V4L2_CID_POWER_LINE_FREQUENCY_60HZ, | ||
238 | }, | ||
239 | .set_control = setfreq | ||
240 | }, | ||
241 | [AUTOGAIN] = { | ||
242 | { | ||
243 | .id = V4L2_CID_AUTOGAIN, | ||
244 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
245 | .name = "Automatic Gain (and Exposure)", | ||
246 | .minimum = 0, | ||
247 | .maximum = 3, | ||
248 | .step = 1, | ||
249 | #define AUTOGAIN_DEF 0 | ||
250 | .default_value = AUTOGAIN_DEF, | ||
251 | }, | ||
252 | .set_control = setautogain | ||
253 | }, | ||
254 | [RED] = { | ||
255 | { | ||
256 | .id = V4L2_CID_RED_BALANCE, | ||
257 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
258 | .name = "red balance", | ||
259 | .minimum = 0, | ||
260 | .maximum = 3, | ||
261 | .step = 1, | ||
262 | #define RED_BALANCE_DEF 2 | ||
263 | .default_value = RED_BALANCE_DEF, | ||
264 | }, | ||
265 | .set_control = setred | ||
266 | }, | ||
267 | |||
268 | [GREEN] = { | ||
269 | { | ||
270 | .id = V4L2_CID_GAIN, | ||
271 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
272 | .name = "green balance", | ||
273 | .minimum = 0, | ||
274 | .maximum = 3, | ||
275 | .step = 1, | ||
276 | #define GREEN_BALANCE_DEF 2 | ||
277 | .default_value = GREEN_BALANCE_DEF, | ||
278 | }, | ||
279 | .set_control = setgreen | ||
280 | }, | ||
281 | [BLUE] = { | ||
282 | { | ||
283 | .id = V4L2_CID_BLUE_BALANCE, | ||
284 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
285 | .name = "blue balance", | ||
286 | .minimum = 0, | ||
287 | .maximum = 3, | ||
288 | .step = 1, | ||
289 | #define BLUE_BALANCE_DEF 2 | ||
290 | .default_value = BLUE_BALANCE_DEF, | ||
291 | }, | ||
292 | .set_control = setblue | ||
293 | }, | ||
294 | }; | ||
295 | |||
296 | static int jlj_start(struct gspca_dev *gspca_dev) | ||
153 | { | 297 | { |
154 | int i; | 298 | int i; |
155 | int retval; | 299 | int start_commands_size; |
156 | struct jlj_command stop_commands[] = { | 300 | u8 response = 0xff; |
157 | {{0x71, 0x00}, 0}, | 301 | struct sd *sd = (struct sd *) gspca_dev; |
158 | {{0x70, 0x09}, 0}, | 302 | struct jlj_command start_commands[] = { |
159 | {{0x71, 0x80}, 0}, | 303 | {{0x71, 0x81}, 0, 0}, |
160 | {{0x70, 0x05}, 0} | 304 | {{0x70, 0x05}, 0, JEILINJ_CMD_DELAY}, |
305 | {{0x95, 0x70}, 1, 0}, | ||
306 | {{0x71, 0x81 - gspca_dev->curr_mode}, 0, 0}, | ||
307 | {{0x70, 0x04}, 0, JEILINJ_CMD_DELAY}, | ||
308 | {{0x95, 0x70}, 1, 0}, | ||
309 | {{0x71, 0x00}, 0, 0}, /* start streaming ??*/ | ||
310 | {{0x70, 0x08}, 0, JEILINJ_CMD_DELAY}, | ||
311 | {{0x95, 0x70}, 1, 0}, | ||
312 | #define SPORTSCAM_DV15_CMD_SIZE 9 | ||
313 | {{0x94, 0x02}, 0, 0}, | ||
314 | {{0xde, 0x24}, 0, 0}, | ||
315 | {{0x94, 0x02}, 0, 0}, | ||
316 | {{0xdd, 0xf0}, 0, 0}, | ||
317 | {{0x94, 0x02}, 0, 0}, | ||
318 | {{0xe3, 0x2c}, 0, 0}, | ||
319 | {{0x94, 0x02}, 0, 0}, | ||
320 | {{0xe4, 0x00}, 0, 0}, | ||
321 | {{0x94, 0x02}, 0, 0}, | ||
322 | {{0xe5, 0x00}, 0, 0}, | ||
323 | {{0x94, 0x02}, 0, 0}, | ||
324 | {{0xe6, 0x2c}, 0, 0}, | ||
325 | {{0x94, 0x03}, 0, 0}, | ||
326 | {{0xaa, 0x00}, 0, 0} | ||
161 | }; | 327 | }; |
162 | for (i = 0; i < ARRAY_SIZE(stop_commands); i++) { | 328 | |
163 | retval = jlj_write2(gspca_dev, stop_commands[i].instruction); | 329 | sd->blocks_left = 0; |
164 | if (retval < 0) | 330 | /* Under Windows, USB spy shows that only the 9 first start |
165 | return retval; | 331 | * commands are used for SPORTSCAM_DV15 webcam |
332 | */ | ||
333 | if (sd->type == SPORTSCAM_DV15) | ||
334 | start_commands_size = SPORTSCAM_DV15_CMD_SIZE; | ||
335 | else | ||
336 | start_commands_size = ARRAY_SIZE(start_commands); | ||
337 | |||
338 | for (i = 0; i < start_commands_size; i++) { | ||
339 | jlj_write2(gspca_dev, start_commands[i].instruction); | ||
340 | if (start_commands[i].delay) | ||
341 | msleep(start_commands[i].delay); | ||
342 | if (start_commands[i].ack_wanted) | ||
343 | jlj_read1(gspca_dev, response); | ||
166 | } | 344 | } |
167 | return retval; | 345 | setcamquality(gspca_dev); |
346 | msleep(2); | ||
347 | setfreq(gspca_dev); | ||
348 | if (gspca_dev->usb_err < 0) | ||
349 | PDEBUG(D_ERR, "Start streaming command failed"); | ||
350 | return gspca_dev->usb_err; | ||
168 | } | 351 | } |
169 | 352 | ||
170 | /* This function is called as a workqueue function and runs whenever the camera | 353 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, |
171 | * is streaming data. Because it is a workqueue function it is allowed to sleep | 354 | u8 *data, int len) |
172 | * so we can use synchronous USB calls. To avoid possible collisions with other | ||
173 | * threads attempting to use the camera's USB interface the gspca usb_lock is | ||
174 | * used when performing the one USB control operation inside the workqueue, | ||
175 | * which tells the camera to close the stream. In practice the only thing | ||
176 | * which needs to be protected against is the usb_set_interface call that | ||
177 | * gspca makes during stream_off. Otherwise the camera doesn't provide any | ||
178 | * controls that the user could try to change. | ||
179 | */ | ||
180 | |||
181 | static void jlj_dostream(struct work_struct *work) | ||
182 | { | 355 | { |
183 | struct sd *dev = container_of(work, struct sd, work_struct); | 356 | struct sd *sd = (struct sd *) gspca_dev; |
184 | struct gspca_dev *gspca_dev = &dev->gspca_dev; | ||
185 | int blocks_left; /* 0x200-sized blocks remaining in current frame. */ | ||
186 | int act_len; | ||
187 | int packet_type; | 357 | int packet_type; |
188 | int ret; | 358 | u32 header_marker; |
189 | u8 *buffer; | ||
190 | 359 | ||
191 | buffer = kmalloc(JEILINJ_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); | 360 | PDEBUG(D_STREAM, "Got %d bytes out of %d for Block 0", |
192 | if (!buffer) { | 361 | len, JEILINJ_MAX_TRANSFER); |
193 | err("Couldn't allocate USB buffer"); | 362 | if (len != JEILINJ_MAX_TRANSFER) { |
194 | goto quit_stream; | 363 | PDEBUG(D_PACK, "bad length"); |
364 | goto discard; | ||
195 | } | 365 | } |
196 | while (gspca_dev->present && gspca_dev->streaming) { | 366 | /* check if it's start of frame */ |
197 | /* | 367 | header_marker = ((u32 *)data)[0]; |
198 | * Now request data block 0. Line 0 reports the size | 368 | if (header_marker == FRAME_START) { |
199 | * to download, in blocks of size 0x200, and also tells the | 369 | sd->blocks_left = data[0x0a] - 1; |
200 | * "actual" data size, in bytes, which seems best to ignore. | 370 | PDEBUG(D_STREAM, "blocks_left = 0x%x", sd->blocks_left); |
201 | */ | ||
202 | ret = usb_bulk_msg(gspca_dev->dev, | ||
203 | usb_rcvbulkpipe(gspca_dev->dev, 0x82), | ||
204 | buffer, JEILINJ_MAX_TRANSFER, &act_len, | ||
205 | JEILINJ_DATA_TIMEOUT); | ||
206 | PDEBUG(D_STREAM, | ||
207 | "Got %d bytes out of %d for Block 0", | ||
208 | act_len, JEILINJ_MAX_TRANSFER); | ||
209 | if (ret < 0 || act_len < FRAME_HEADER_LEN) | ||
210 | goto quit_stream; | ||
211 | blocks_left = buffer[0x0a] - 1; | ||
212 | PDEBUG(D_STREAM, "blocks_left = 0x%x", blocks_left); | ||
213 | |||
214 | /* Start a new frame, and add the JPEG header, first thing */ | 371 | /* Start a new frame, and add the JPEG header, first thing */ |
215 | gspca_frame_add(gspca_dev, FIRST_PACKET, | 372 | gspca_frame_add(gspca_dev, FIRST_PACKET, |
216 | dev->jpeg_hdr, JPEG_HDR_SZ); | 373 | sd->jpeg_hdr, JPEG_HDR_SZ); |
217 | /* Toss line 0 of data block 0, keep the rest. */ | 374 | /* Toss line 0 of data block 0, keep the rest. */ |
218 | gspca_frame_add(gspca_dev, INTER_PACKET, | 375 | gspca_frame_add(gspca_dev, INTER_PACKET, |
219 | buffer + FRAME_HEADER_LEN, | 376 | data + FRAME_HEADER_LEN, |
220 | JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN); | 377 | JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN); |
221 | 378 | } else if (sd->blocks_left > 0) { | |
222 | while (blocks_left > 0) { | 379 | PDEBUG(D_STREAM, "%d blocks remaining for frame", |
223 | if (!gspca_dev->present) | 380 | sd->blocks_left); |
224 | goto quit_stream; | 381 | sd->blocks_left -= 1; |
225 | ret = usb_bulk_msg(gspca_dev->dev, | 382 | if (sd->blocks_left == 0) |
226 | usb_rcvbulkpipe(gspca_dev->dev, 0x82), | 383 | packet_type = LAST_PACKET; |
227 | buffer, JEILINJ_MAX_TRANSFER, &act_len, | 384 | else |
228 | JEILINJ_DATA_TIMEOUT); | 385 | packet_type = INTER_PACKET; |
229 | if (ret < 0 || act_len < JEILINJ_MAX_TRANSFER) | 386 | gspca_frame_add(gspca_dev, packet_type, |
230 | goto quit_stream; | 387 | data, JEILINJ_MAX_TRANSFER); |
231 | PDEBUG(D_STREAM, | 388 | } else |
232 | "%d blocks remaining for frame", blocks_left); | 389 | goto discard; |
233 | blocks_left -= 1; | 390 | return; |
234 | if (blocks_left == 0) | 391 | discard: |
235 | packet_type = LAST_PACKET; | 392 | /* Discard data until a new frame starts. */ |
236 | else | 393 | gspca_dev->last_packet_type = DISCARD_PACKET; |
237 | packet_type = INTER_PACKET; | ||
238 | gspca_frame_add(gspca_dev, packet_type, | ||
239 | buffer, JEILINJ_MAX_TRANSFER); | ||
240 | } | ||
241 | } | ||
242 | quit_stream: | ||
243 | mutex_lock(&gspca_dev->usb_lock); | ||
244 | if (gspca_dev->present) | ||
245 | jlj_stop(gspca_dev); | ||
246 | mutex_unlock(&gspca_dev->usb_lock); | ||
247 | kfree(buffer); | ||
248 | } | 394 | } |
249 | 395 | ||
250 | /* This function is called at probe time just before sd_init */ | 396 | /* This function is called at probe time just before sd_init */ |
@@ -254,78 +400,169 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
254 | struct cam *cam = &gspca_dev->cam; | 400 | struct cam *cam = &gspca_dev->cam; |
255 | struct sd *dev = (struct sd *) gspca_dev; | 401 | struct sd *dev = (struct sd *) gspca_dev; |
256 | 402 | ||
257 | dev->quality = 85; | 403 | dev->type = id->driver_info; |
258 | dev->jpegqual = 85; | 404 | gspca_dev->cam.ctrls = dev->ctrls; |
405 | dev->quality = QUALITY_DEF; | ||
406 | dev->ctrls[LIGHTFREQ].def = V4L2_CID_POWER_LINE_FREQUENCY_60HZ; | ||
407 | dev->ctrls[RED].def = RED_BALANCE_DEF; | ||
408 | dev->ctrls[GREEN].def = GREEN_BALANCE_DEF; | ||
409 | dev->ctrls[BLUE].def = BLUE_BALANCE_DEF; | ||
259 | PDEBUG(D_PROBE, | 410 | PDEBUG(D_PROBE, |
260 | "JEILINJ camera detected" | 411 | "JEILINJ camera detected" |
261 | " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | 412 | " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
262 | cam->cam_mode = jlj_mode; | 413 | cam->cam_mode = jlj_mode; |
263 | cam->nmodes = 1; | 414 | cam->nmodes = ARRAY_SIZE(jlj_mode); |
264 | cam->bulk = 1; | 415 | cam->bulk = 1; |
265 | /* We don't use the buffer gspca allocates so make it small. */ | 416 | cam->bulk_nurbs = 1; |
266 | cam->bulk_size = 32; | 417 | cam->bulk_size = JEILINJ_MAX_TRANSFER; |
267 | INIT_WORK(&dev->work_struct, jlj_dostream); | ||
268 | return 0; | 418 | return 0; |
269 | } | 419 | } |
270 | 420 | ||
271 | /* called on streamoff with alt==0 and on disconnect */ | 421 | static void sd_stopN(struct gspca_dev *gspca_dev) |
272 | /* the usb_lock is held at entry - restore on exit */ | ||
273 | static void sd_stop0(struct gspca_dev *gspca_dev) | ||
274 | { | 422 | { |
275 | struct sd *dev = (struct sd *) gspca_dev; | 423 | int i; |
424 | u8 *buf; | ||
425 | u8 stop_commands[][2] = { | ||
426 | {0x71, 0x00}, | ||
427 | {0x70, 0x09}, | ||
428 | {0x71, 0x80}, | ||
429 | {0x70, 0x05} | ||
430 | }; | ||
431 | |||
432 | for (;;) { | ||
433 | /* get the image remaining blocks */ | ||
434 | usb_bulk_msg(gspca_dev->dev, | ||
435 | gspca_dev->urb[0]->pipe, | ||
436 | gspca_dev->urb[0]->transfer_buffer, | ||
437 | JEILINJ_MAX_TRANSFER, NULL, | ||
438 | JEILINJ_DATA_TIMEOUT); | ||
439 | |||
440 | /* search for 0xff 0xd9 (EOF for JPEG) */ | ||
441 | i = 0; | ||
442 | buf = gspca_dev->urb[0]->transfer_buffer; | ||
443 | while ((i < (JEILINJ_MAX_TRANSFER - 1)) && | ||
444 | ((buf[i] != 0xff) || (buf[i+1] != 0xd9))) | ||
445 | i++; | ||
276 | 446 | ||
277 | /* wait for the work queue to terminate */ | 447 | if (i != (JEILINJ_MAX_TRANSFER - 1)) |
278 | mutex_unlock(&gspca_dev->usb_lock); | 448 | /* last remaining block found */ |
279 | /* This waits for jlj_dostream to finish */ | 449 | break; |
280 | destroy_workqueue(dev->work_thread); | 450 | } |
281 | dev->work_thread = NULL; | 451 | |
282 | mutex_lock(&gspca_dev->usb_lock); | 452 | for (i = 0; i < ARRAY_SIZE(stop_commands); i++) |
453 | jlj_write2(gspca_dev, stop_commands[i]); | ||
283 | } | 454 | } |
284 | 455 | ||
285 | /* this function is called at probe and resume time */ | 456 | /* this function is called at probe and resume time */ |
286 | static int sd_init(struct gspca_dev *gspca_dev) | 457 | static int sd_init(struct gspca_dev *gspca_dev) |
287 | { | 458 | { |
288 | return 0; | 459 | return gspca_dev->usb_err; |
289 | } | 460 | } |
290 | 461 | ||
291 | /* Set up for getting frames. */ | 462 | /* Set up for getting frames. */ |
292 | static int sd_start(struct gspca_dev *gspca_dev) | 463 | static int sd_start(struct gspca_dev *gspca_dev) |
293 | { | 464 | { |
294 | struct sd *dev = (struct sd *) gspca_dev; | 465 | struct sd *dev = (struct sd *) gspca_dev; |
295 | int ret; | ||
296 | 466 | ||
297 | /* create the JPEG header */ | 467 | /* create the JPEG header */ |
298 | jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width, | 468 | jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width, |
299 | 0x21); /* JPEG 422 */ | 469 | 0x21); /* JPEG 422 */ |
300 | jpeg_set_qual(dev->jpeg_hdr, dev->quality); | 470 | jpeg_set_qual(dev->jpeg_hdr, dev->quality); |
301 | PDEBUG(D_STREAM, "Start streaming at 320x240"); | 471 | PDEBUG(D_STREAM, "Start streaming at %dx%d", |
302 | ret = jlj_start(gspca_dev); | 472 | gspca_dev->height, gspca_dev->width); |
303 | if (ret < 0) { | 473 | jlj_start(gspca_dev); |
304 | PDEBUG(D_ERR, "Start streaming command failed"); | 474 | return gspca_dev->usb_err; |
305 | return ret; | ||
306 | } | ||
307 | /* Start the workqueue function to do the streaming */ | ||
308 | dev->work_thread = create_singlethread_workqueue(MODULE_NAME); | ||
309 | queue_work(dev->work_thread, &dev->work_struct); | ||
310 | |||
311 | return 0; | ||
312 | } | 475 | } |
313 | 476 | ||
314 | /* Table of supported USB devices */ | 477 | /* Table of supported USB devices */ |
315 | static const struct usb_device_id device_table[] = { | 478 | static const struct usb_device_id device_table[] = { |
316 | {USB_DEVICE(0x0979, 0x0280)}, | 479 | {USB_DEVICE(0x0979, 0x0280), .driver_info = SAKAR_57379}, |
480 | {USB_DEVICE(0x0979, 0x0270), .driver_info = SPORTSCAM_DV15}, | ||
317 | {} | 481 | {} |
318 | }; | 482 | }; |
319 | 483 | ||
320 | MODULE_DEVICE_TABLE(usb, device_table); | 484 | MODULE_DEVICE_TABLE(usb, device_table); |
321 | 485 | ||
486 | static int sd_querymenu(struct gspca_dev *gspca_dev, | ||
487 | struct v4l2_querymenu *menu) | ||
488 | { | ||
489 | switch (menu->id) { | ||
490 | case V4L2_CID_POWER_LINE_FREQUENCY: | ||
491 | switch (menu->index) { | ||
492 | case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ | ||
493 | strcpy((char *) menu->name, "disable"); | ||
494 | return 0; | ||
495 | case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ | ||
496 | strcpy((char *) menu->name, "50 Hz"); | ||
497 | return 0; | ||
498 | case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ | ||
499 | strcpy((char *) menu->name, "60 Hz"); | ||
500 | return 0; | ||
501 | } | ||
502 | break; | ||
503 | } | ||
504 | return -EINVAL; | ||
505 | } | ||
506 | |||
507 | static int sd_set_jcomp(struct gspca_dev *gspca_dev, | ||
508 | struct v4l2_jpegcompression *jcomp) | ||
509 | { | ||
510 | struct sd *sd = (struct sd *) gspca_dev; | ||
511 | |||
512 | if (jcomp->quality < QUALITY_MIN) | ||
513 | sd->quality = QUALITY_MIN; | ||
514 | else if (jcomp->quality > QUALITY_MAX) | ||
515 | sd->quality = QUALITY_MAX; | ||
516 | else | ||
517 | sd->quality = jcomp->quality; | ||
518 | if (gspca_dev->streaming) { | ||
519 | jpeg_set_qual(sd->jpeg_hdr, sd->quality); | ||
520 | setcamquality(gspca_dev); | ||
521 | } | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static int sd_get_jcomp(struct gspca_dev *gspca_dev, | ||
526 | struct v4l2_jpegcompression *jcomp) | ||
527 | { | ||
528 | struct sd *sd = (struct sd *) gspca_dev; | ||
529 | |||
530 | memset(jcomp, 0, sizeof *jcomp); | ||
531 | jcomp->quality = sd->quality; | ||
532 | jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | ||
533 | | V4L2_JPEG_MARKER_DQT; | ||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | |||
322 | /* sub-driver description */ | 538 | /* sub-driver description */ |
323 | static const struct sd_desc sd_desc = { | 539 | static const struct sd_desc sd_desc_sakar_57379 = { |
324 | .name = MODULE_NAME, | 540 | .name = MODULE_NAME, |
325 | .config = sd_config, | 541 | .config = sd_config, |
326 | .init = sd_init, | 542 | .init = sd_init, |
327 | .start = sd_start, | 543 | .start = sd_start, |
328 | .stop0 = sd_stop0, | 544 | .stopN = sd_stopN, |
545 | .pkt_scan = sd_pkt_scan, | ||
546 | }; | ||
547 | |||
548 | /* sub-driver description */ | ||
549 | static const struct sd_desc sd_desc_sportscam_dv15 = { | ||
550 | .name = MODULE_NAME, | ||
551 | .config = sd_config, | ||
552 | .init = sd_init, | ||
553 | .start = sd_start, | ||
554 | .stopN = sd_stopN, | ||
555 | .pkt_scan = sd_pkt_scan, | ||
556 | .ctrls = sd_ctrls, | ||
557 | .nctrls = ARRAY_SIZE(sd_ctrls), | ||
558 | .querymenu = sd_querymenu, | ||
559 | .get_jcomp = sd_get_jcomp, | ||
560 | .set_jcomp = sd_set_jcomp, | ||
561 | }; | ||
562 | |||
563 | static const struct sd_desc *sd_desc[2] = { | ||
564 | &sd_desc_sakar_57379, | ||
565 | &sd_desc_sportscam_dv15 | ||
329 | }; | 566 | }; |
330 | 567 | ||
331 | /* -- device connect -- */ | 568 | /* -- device connect -- */ |
@@ -333,7 +570,7 @@ static int sd_probe(struct usb_interface *intf, | |||
333 | const struct usb_device_id *id) | 570 | const struct usb_device_id *id) |
334 | { | 571 | { |
335 | return gspca_dev_probe(intf, id, | 572 | return gspca_dev_probe(intf, id, |
336 | &sd_desc, | 573 | sd_desc[id->driver_info], |
337 | sizeof(struct sd), | 574 | sizeof(struct sd), |
338 | THIS_MODULE); | 575 | THIS_MODULE); |
339 | } | 576 | } |
diff --git a/drivers/media/video/gspca/kinect.c b/drivers/media/video/gspca/kinect.c new file mode 100644 index 000000000000..66671a4092e4 --- /dev/null +++ b/drivers/media/video/gspca/kinect.c | |||
@@ -0,0 +1,429 @@ | |||
1 | /* | ||
2 | * kinect sensor device camera, gspca driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Antonio Ospite <ospite@studenti.unina.it> | ||
5 | * | ||
6 | * Based on the OpenKinect project and libfreenect | ||
7 | * http://openkinect.org/wiki/Init_Analysis | ||
8 | * | ||
9 | * Special thanks to Steven Toth and kernellabs.com for sponsoring a Kinect | ||
10 | * sensor device which I tested the driver on. | ||
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 | * 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 | #define MODULE_NAME "kinect" | ||
28 | |||
29 | #include "gspca.h" | ||
30 | |||
31 | #define CTRL_TIMEOUT 500 | ||
32 | |||
33 | MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); | ||
34 | MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver"); | ||
35 | MODULE_LICENSE("GPL"); | ||
36 | |||
37 | #ifdef DEBUG | ||
38 | int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK | | ||
39 | D_USBI | D_USBO | D_V4L2; | ||
40 | #endif | ||
41 | |||
42 | struct pkt_hdr { | ||
43 | uint8_t magic[2]; | ||
44 | uint8_t pad; | ||
45 | uint8_t flag; | ||
46 | uint8_t unk1; | ||
47 | uint8_t seq; | ||
48 | uint8_t unk2; | ||
49 | uint8_t unk3; | ||
50 | uint32_t timestamp; | ||
51 | }; | ||
52 | |||
53 | struct cam_hdr { | ||
54 | uint8_t magic[2]; | ||
55 | uint16_t len; | ||
56 | uint16_t cmd; | ||
57 | uint16_t tag; | ||
58 | }; | ||
59 | |||
60 | /* specific webcam descriptor */ | ||
61 | struct sd { | ||
62 | struct gspca_dev gspca_dev; /* !! must be the first item */ | ||
63 | uint16_t cam_tag; /* a sequence number for packets */ | ||
64 | uint8_t stream_flag; /* to identify different stream types */ | ||
65 | uint8_t obuf[0x400]; /* output buffer for control commands */ | ||
66 | uint8_t ibuf[0x200]; /* input buffer for control commands */ | ||
67 | }; | ||
68 | |||
69 | /* V4L2 controls supported by the driver */ | ||
70 | /* controls prototypes here */ | ||
71 | |||
72 | static const struct ctrl sd_ctrls[] = { | ||
73 | }; | ||
74 | |||
75 | #define MODE_640x480 0x0001 | ||
76 | #define MODE_640x488 0x0002 | ||
77 | #define MODE_1280x1024 0x0004 | ||
78 | |||
79 | #define FORMAT_BAYER 0x0010 | ||
80 | #define FORMAT_UYVY 0x0020 | ||
81 | #define FORMAT_Y10B 0x0040 | ||
82 | |||
83 | #define FPS_HIGH 0x0100 | ||
84 | |||
85 | static const struct v4l2_pix_format video_camera_mode[] = { | ||
86 | {640, 480, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, | ||
87 | .bytesperline = 640, | ||
88 | .sizeimage = 640 * 480, | ||
89 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
90 | .priv = MODE_640x480 | FORMAT_BAYER | FPS_HIGH}, | ||
91 | {640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, | ||
92 | .bytesperline = 640 * 2, | ||
93 | .sizeimage = 640 * 480 * 2, | ||
94 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
95 | .priv = MODE_640x480 | FORMAT_UYVY}, | ||
96 | {1280, 1024, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, | ||
97 | .bytesperline = 1280, | ||
98 | .sizeimage = 1280 * 1024, | ||
99 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
100 | .priv = MODE_1280x1024 | FORMAT_BAYER}, | ||
101 | {640, 488, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE, | ||
102 | .bytesperline = 640 * 10 / 8, | ||
103 | .sizeimage = 640 * 488 * 10 / 8, | ||
104 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
105 | .priv = MODE_640x488 | FORMAT_Y10B | FPS_HIGH}, | ||
106 | {1280, 1024, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE, | ||
107 | .bytesperline = 1280 * 10 / 8, | ||
108 | .sizeimage = 1280 * 1024 * 10 / 8, | ||
109 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
110 | .priv = MODE_1280x1024 | FORMAT_Y10B}, | ||
111 | }; | ||
112 | |||
113 | static int kinect_write(struct usb_device *udev, uint8_t *data, | ||
114 | uint16_t wLength) | ||
115 | { | ||
116 | return usb_control_msg(udev, | ||
117 | usb_sndctrlpipe(udev, 0), | ||
118 | 0x00, | ||
119 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
120 | 0, 0, data, wLength, CTRL_TIMEOUT); | ||
121 | } | ||
122 | |||
123 | static int kinect_read(struct usb_device *udev, uint8_t *data, uint16_t wLength) | ||
124 | { | ||
125 | return usb_control_msg(udev, | ||
126 | usb_rcvctrlpipe(udev, 0), | ||
127 | 0x00, | ||
128 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
129 | 0, 0, data, wLength, CTRL_TIMEOUT); | ||
130 | } | ||
131 | |||
132 | static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf, | ||
133 | unsigned int cmd_len, void *replybuf, unsigned int reply_len) | ||
134 | { | ||
135 | struct sd *sd = (struct sd *) gspca_dev; | ||
136 | struct usb_device *udev = gspca_dev->dev; | ||
137 | int res, actual_len; | ||
138 | uint8_t *obuf = sd->obuf; | ||
139 | uint8_t *ibuf = sd->ibuf; | ||
140 | struct cam_hdr *chdr = (void *)obuf; | ||
141 | struct cam_hdr *rhdr = (void *)ibuf; | ||
142 | |||
143 | if (cmd_len & 1 || cmd_len > (0x400 - sizeof(*chdr))) { | ||
144 | err("send_cmd: Invalid command length (0x%x)", cmd_len); | ||
145 | return -1; | ||
146 | } | ||
147 | |||
148 | chdr->magic[0] = 0x47; | ||
149 | chdr->magic[1] = 0x4d; | ||
150 | chdr->cmd = cpu_to_le16(cmd); | ||
151 | chdr->tag = cpu_to_le16(sd->cam_tag); | ||
152 | chdr->len = cpu_to_le16(cmd_len / 2); | ||
153 | |||
154 | memcpy(obuf+sizeof(*chdr), cmdbuf, cmd_len); | ||
155 | |||
156 | res = kinect_write(udev, obuf, cmd_len + sizeof(*chdr)); | ||
157 | PDEBUG(D_USBO, "Control cmd=%04x tag=%04x len=%04x: %d", cmd, | ||
158 | sd->cam_tag, cmd_len, res); | ||
159 | if (res < 0) { | ||
160 | err("send_cmd: Output control transfer failed (%d)", res); | ||
161 | return res; | ||
162 | } | ||
163 | |||
164 | do { | ||
165 | actual_len = kinect_read(udev, ibuf, 0x200); | ||
166 | } while (actual_len == 0); | ||
167 | PDEBUG(D_USBO, "Control reply: %d", res); | ||
168 | if (actual_len < sizeof(*rhdr)) { | ||
169 | err("send_cmd: Input control transfer failed (%d)", res); | ||
170 | return res; | ||
171 | } | ||
172 | actual_len -= sizeof(*rhdr); | ||
173 | |||
174 | if (rhdr->magic[0] != 0x52 || rhdr->magic[1] != 0x42) { | ||
175 | err("send_cmd: Bad magic %02x %02x", rhdr->magic[0], | ||
176 | rhdr->magic[1]); | ||
177 | return -1; | ||
178 | } | ||
179 | if (rhdr->cmd != chdr->cmd) { | ||
180 | err("send_cmd: Bad cmd %02x != %02x", rhdr->cmd, chdr->cmd); | ||
181 | return -1; | ||
182 | } | ||
183 | if (rhdr->tag != chdr->tag) { | ||
184 | err("send_cmd: Bad tag %04x != %04x", rhdr->tag, chdr->tag); | ||
185 | return -1; | ||
186 | } | ||
187 | if (cpu_to_le16(rhdr->len) != (actual_len/2)) { | ||
188 | err("send_cmd: Bad len %04x != %04x", | ||
189 | cpu_to_le16(rhdr->len), (int)(actual_len/2)); | ||
190 | return -1; | ||
191 | } | ||
192 | |||
193 | if (actual_len > reply_len) { | ||
194 | warn("send_cmd: Data buffer is %d bytes long, but got %d bytes", | ||
195 | reply_len, actual_len); | ||
196 | memcpy(replybuf, ibuf+sizeof(*rhdr), reply_len); | ||
197 | } else { | ||
198 | memcpy(replybuf, ibuf+sizeof(*rhdr), actual_len); | ||
199 | } | ||
200 | |||
201 | sd->cam_tag++; | ||
202 | |||
203 | return actual_len; | ||
204 | } | ||
205 | |||
206 | static int write_register(struct gspca_dev *gspca_dev, uint16_t reg, | ||
207 | uint16_t data) | ||
208 | { | ||
209 | uint16_t reply[2]; | ||
210 | uint16_t cmd[2]; | ||
211 | int res; | ||
212 | |||
213 | cmd[0] = cpu_to_le16(reg); | ||
214 | cmd[1] = cpu_to_le16(data); | ||
215 | |||
216 | PDEBUG(D_USBO, "Write Reg 0x%04x <= 0x%02x", reg, data); | ||
217 | res = send_cmd(gspca_dev, 0x03, cmd, 4, reply, 4); | ||
218 | if (res < 0) | ||
219 | return res; | ||
220 | if (res != 2) { | ||
221 | warn("send_cmd returned %d [%04x %04x], 0000 expected", | ||
222 | res, reply[0], reply[1]); | ||
223 | } | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | /* this function is called at probe time */ | ||
228 | static int sd_config(struct gspca_dev *gspca_dev, | ||
229 | const struct usb_device_id *id) | ||
230 | { | ||
231 | struct sd *sd = (struct sd *) gspca_dev; | ||
232 | struct cam *cam; | ||
233 | |||
234 | sd->cam_tag = 0; | ||
235 | |||
236 | /* Only video stream is supported for now, | ||
237 | * which has stream flag = 0x80 */ | ||
238 | sd->stream_flag = 0x80; | ||
239 | |||
240 | cam = &gspca_dev->cam; | ||
241 | |||
242 | cam->cam_mode = video_camera_mode; | ||
243 | cam->nmodes = ARRAY_SIZE(video_camera_mode); | ||
244 | |||
245 | #if 0 | ||
246 | /* Setting those values is not needed for video stream */ | ||
247 | cam->npkt = 15; | ||
248 | gspca_dev->pkt_size = 960 * 2; | ||
249 | #endif | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | /* this function is called at probe and resume time */ | ||
255 | static int sd_init(struct gspca_dev *gspca_dev) | ||
256 | { | ||
257 | PDEBUG(D_PROBE, "Kinect Camera device."); | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static int sd_start(struct gspca_dev *gspca_dev) | ||
263 | { | ||
264 | int mode; | ||
265 | uint8_t fmt_reg, fmt_val; | ||
266 | uint8_t res_reg, res_val; | ||
267 | uint8_t fps_reg, fps_val; | ||
268 | uint8_t mode_val; | ||
269 | |||
270 | mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; | ||
271 | |||
272 | if (mode & FORMAT_Y10B) { | ||
273 | fmt_reg = 0x19; | ||
274 | res_reg = 0x1a; | ||
275 | fps_reg = 0x1b; | ||
276 | mode_val = 0x03; | ||
277 | } else { | ||
278 | fmt_reg = 0x0c; | ||
279 | res_reg = 0x0d; | ||
280 | fps_reg = 0x0e; | ||
281 | mode_val = 0x01; | ||
282 | } | ||
283 | |||
284 | /* format */ | ||
285 | if (mode & FORMAT_UYVY) | ||
286 | fmt_val = 0x05; | ||
287 | else | ||
288 | fmt_val = 0x00; | ||
289 | |||
290 | if (mode & MODE_1280x1024) | ||
291 | res_val = 0x02; | ||
292 | else | ||
293 | res_val = 0x01; | ||
294 | |||
295 | if (mode & FPS_HIGH) | ||
296 | fps_val = 0x1e; | ||
297 | else | ||
298 | fps_val = 0x0f; | ||
299 | |||
300 | |||
301 | /* turn off IR-reset function */ | ||
302 | write_register(gspca_dev, 0x105, 0x00); | ||
303 | |||
304 | /* Reset video stream */ | ||
305 | write_register(gspca_dev, 0x05, 0x00); | ||
306 | |||
307 | /* Due to some ridiculous condition in the firmware, we have to start | ||
308 | * and stop the depth stream before the camera will hand us 1280x1024 | ||
309 | * IR. This is a stupid workaround, but we've yet to find a better | ||
310 | * solution. | ||
311 | * | ||
312 | * Thanks to Drew Fisher for figuring this out. | ||
313 | */ | ||
314 | if (mode & (FORMAT_Y10B | MODE_1280x1024)) { | ||
315 | write_register(gspca_dev, 0x13, 0x01); | ||
316 | write_register(gspca_dev, 0x14, 0x1e); | ||
317 | write_register(gspca_dev, 0x06, 0x02); | ||
318 | write_register(gspca_dev, 0x06, 0x00); | ||
319 | } | ||
320 | |||
321 | write_register(gspca_dev, fmt_reg, fmt_val); | ||
322 | write_register(gspca_dev, res_reg, res_val); | ||
323 | write_register(gspca_dev, fps_reg, fps_val); | ||
324 | |||
325 | /* Start video stream */ | ||
326 | write_register(gspca_dev, 0x05, mode_val); | ||
327 | |||
328 | /* disable Hflip */ | ||
329 | write_register(gspca_dev, 0x47, 0x00); | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static void sd_stopN(struct gspca_dev *gspca_dev) | ||
335 | { | ||
336 | /* reset video stream */ | ||
337 | write_register(gspca_dev, 0x05, 0x00); | ||
338 | } | ||
339 | |||
340 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len) | ||
341 | { | ||
342 | struct sd *sd = (struct sd *) gspca_dev; | ||
343 | |||
344 | struct pkt_hdr *hdr = (void *)__data; | ||
345 | uint8_t *data = __data + sizeof(*hdr); | ||
346 | int datalen = len - sizeof(*hdr); | ||
347 | |||
348 | uint8_t sof = sd->stream_flag | 1; | ||
349 | uint8_t mof = sd->stream_flag | 2; | ||
350 | uint8_t eof = sd->stream_flag | 5; | ||
351 | |||
352 | if (len < 12) | ||
353 | return; | ||
354 | |||
355 | if (hdr->magic[0] != 'R' || hdr->magic[1] != 'B') { | ||
356 | warn("[Stream %02x] Invalid magic %02x%02x", sd->stream_flag, | ||
357 | hdr->magic[0], hdr->magic[1]); | ||
358 | return; | ||
359 | } | ||
360 | |||
361 | if (hdr->flag == sof) | ||
362 | gspca_frame_add(gspca_dev, FIRST_PACKET, data, datalen); | ||
363 | |||
364 | else if (hdr->flag == mof) | ||
365 | gspca_frame_add(gspca_dev, INTER_PACKET, data, datalen); | ||
366 | |||
367 | else if (hdr->flag == eof) | ||
368 | gspca_frame_add(gspca_dev, LAST_PACKET, data, datalen); | ||
369 | |||
370 | else | ||
371 | warn("Packet type not recognized..."); | ||
372 | } | ||
373 | |||
374 | /* sub-driver description */ | ||
375 | static const struct sd_desc sd_desc = { | ||
376 | .name = MODULE_NAME, | ||
377 | .ctrls = sd_ctrls, | ||
378 | .nctrls = ARRAY_SIZE(sd_ctrls), | ||
379 | .config = sd_config, | ||
380 | .init = sd_init, | ||
381 | .start = sd_start, | ||
382 | .stopN = sd_stopN, | ||
383 | .pkt_scan = sd_pkt_scan, | ||
384 | /* | ||
385 | .querymenu = sd_querymenu, | ||
386 | .get_streamparm = sd_get_streamparm, | ||
387 | .set_streamparm = sd_set_streamparm, | ||
388 | */ | ||
389 | }; | ||
390 | |||
391 | /* -- module initialisation -- */ | ||
392 | static const struct usb_device_id device_table[] = { | ||
393 | {USB_DEVICE(0x045e, 0x02ae)}, | ||
394 | {} | ||
395 | }; | ||
396 | |||
397 | MODULE_DEVICE_TABLE(usb, device_table); | ||
398 | |||
399 | /* -- device connect -- */ | ||
400 | static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
401 | { | ||
402 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | ||
403 | THIS_MODULE); | ||
404 | } | ||
405 | |||
406 | static struct usb_driver sd_driver = { | ||
407 | .name = MODULE_NAME, | ||
408 | .id_table = device_table, | ||
409 | .probe = sd_probe, | ||
410 | .disconnect = gspca_disconnect, | ||
411 | #ifdef CONFIG_PM | ||
412 | .suspend = gspca_suspend, | ||
413 | .resume = gspca_resume, | ||
414 | #endif | ||
415 | }; | ||
416 | |||
417 | /* -- module insert / remove -- */ | ||
418 | static int __init sd_mod_init(void) | ||
419 | { | ||
420 | return usb_register(&sd_driver); | ||
421 | } | ||
422 | |||
423 | static void __exit sd_mod_exit(void) | ||
424 | { | ||
425 | usb_deregister(&sd_driver); | ||
426 | } | ||
427 | |||
428 | module_init(sd_mod_init); | ||
429 | module_exit(sd_mod_exit); | ||
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index 41dce49fb43d..9d0b46027b93 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c | |||
@@ -1375,7 +1375,6 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
1375 | { | 1375 | { |
1376 | struct sd *sd = (struct sd *) gspca_dev; | 1376 | struct sd *sd = (struct sd *) gspca_dev; |
1377 | struct cam *cam; | 1377 | struct cam *cam; |
1378 | int data1, data2; | ||
1379 | const u16 (*init_data)[2]; | 1378 | const u16 (*init_data)[2]; |
1380 | static const u16 (*(init_data_tb[]))[2] = { | 1379 | static const u16 (*(init_data_tb[]))[2] = { |
1381 | spca508_vista_init_data, /* CreativeVista 0 */ | 1380 | spca508_vista_init_data, /* CreativeVista 0 */ |
@@ -1386,6 +1385,9 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
1386 | spca508_init_data, /* ViewQuestVQ110 5 */ | 1385 | spca508_init_data, /* ViewQuestVQ110 5 */ |
1387 | }; | 1386 | }; |
1388 | 1387 | ||
1388 | #ifdef GSPCA_DEBUG | ||
1389 | int data1, data2; | ||
1390 | |||
1389 | /* Read from global register the USB product and vendor IDs, just to | 1391 | /* Read from global register the USB product and vendor IDs, just to |
1390 | * prove that we can communicate with the device. This works, which | 1392 | * prove that we can communicate with the device. This works, which |
1391 | * confirms at we are communicating properly and that the device | 1393 | * confirms at we are communicating properly and that the device |
@@ -1400,6 +1402,7 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
1400 | 1402 | ||
1401 | data1 = reg_read(gspca_dev, 0x8621); | 1403 | data1 = reg_read(gspca_dev, 0x8621); |
1402 | PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1); | 1404 | PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1); |
1405 | #endif | ||
1403 | 1406 | ||
1404 | cam = &gspca_dev->cam; | 1407 | cam = &gspca_dev->cam; |
1405 | cam->cam_mode = sif_mode; | 1408 | cam->cam_mode = sif_mode; |
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c index 87be52b5e1e3..763747700f10 100644 --- a/drivers/media/video/gspca/stk014.c +++ b/drivers/media/video/gspca/stk014.c | |||
@@ -436,17 +436,14 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |||
436 | static int sd_querymenu(struct gspca_dev *gspca_dev, | 436 | static int sd_querymenu(struct gspca_dev *gspca_dev, |
437 | struct v4l2_querymenu *menu) | 437 | struct v4l2_querymenu *menu) |
438 | { | 438 | { |
439 | static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"}; | ||
440 | |||
439 | switch (menu->id) { | 441 | switch (menu->id) { |
440 | case V4L2_CID_POWER_LINE_FREQUENCY: | 442 | case V4L2_CID_POWER_LINE_FREQUENCY: |
441 | switch (menu->index) { | 443 | if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm)) |
442 | case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ | 444 | break; |
443 | strcpy((char *) menu->name, "50 Hz"); | 445 | strcpy((char *) menu->name, freq_nm[menu->index]); |
444 | return 0; | 446 | return 0; |
445 | case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ | ||
446 | strcpy((char *) menu->name, "60 Hz"); | ||
447 | return 0; | ||
448 | } | ||
449 | break; | ||
450 | } | 447 | } |
451 | return -EINVAL; | 448 | return -EINVAL; |
452 | } | 449 | } |
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c index ac47b4c94388..75a5b9c2f15f 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c | |||
@@ -217,6 +217,8 @@ static int pb0100_start(struct sd *sd) | |||
217 | 217 | ||
218 | intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); | 218 | intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); |
219 | alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); | 219 | alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); |
220 | if (!alt) | ||
221 | return -ENODEV; | ||
220 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); | 222 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); |
221 | 223 | ||
222 | /* If we don't have enough bandwidth use a lower framerate */ | 224 | /* If we don't have enough bandwidth use a lower framerate */ |
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index 543542af2720..b089c0d3ee9f 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c | |||
@@ -396,57 +396,6 @@ static void reg_w_riv(struct gspca_dev *gspca_dev, | |||
396 | req, index, value); | 396 | req, index, value); |
397 | } | 397 | } |
398 | 398 | ||
399 | /* read 1 byte */ | ||
400 | static u8 reg_r_1(struct gspca_dev *gspca_dev, | ||
401 | u16 value) /* wValue */ | ||
402 | { | ||
403 | int ret; | ||
404 | |||
405 | if (gspca_dev->usb_err < 0) | ||
406 | return 0; | ||
407 | ret = usb_control_msg(gspca_dev->dev, | ||
408 | usb_rcvctrlpipe(gspca_dev->dev, 0), | ||
409 | 0x20, /* request */ | ||
410 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
411 | value, | ||
412 | 0, /* index */ | ||
413 | gspca_dev->usb_buf, 1, | ||
414 | 500); /* timeout */ | ||
415 | if (ret < 0) { | ||
416 | err("reg_r_1 err %d", ret); | ||
417 | gspca_dev->usb_err = ret; | ||
418 | return 0; | ||
419 | } | ||
420 | return gspca_dev->usb_buf[0]; | ||
421 | } | ||
422 | |||
423 | /* read 1 or 2 bytes */ | ||
424 | static u16 reg_r_12(struct gspca_dev *gspca_dev, | ||
425 | u8 req, /* bRequest */ | ||
426 | u16 index, /* wIndex */ | ||
427 | u16 length) /* wLength (1 or 2 only) */ | ||
428 | { | ||
429 | int ret; | ||
430 | |||
431 | if (gspca_dev->usb_err < 0) | ||
432 | return 0; | ||
433 | gspca_dev->usb_buf[1] = 0; | ||
434 | ret = usb_control_msg(gspca_dev->dev, | ||
435 | usb_rcvctrlpipe(gspca_dev->dev, 0), | ||
436 | req, | ||
437 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
438 | 0, /* value */ | ||
439 | index, | ||
440 | gspca_dev->usb_buf, length, | ||
441 | 500); | ||
442 | if (ret < 0) { | ||
443 | err("reg_r_12 err %d", ret); | ||
444 | gspca_dev->usb_err = ret; | ||
445 | return 0; | ||
446 | } | ||
447 | return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; | ||
448 | } | ||
449 | |||
450 | static void write_vector(struct gspca_dev *gspca_dev, | 399 | static void write_vector(struct gspca_dev *gspca_dev, |
451 | const struct cmd *data, int ncmds) | 400 | const struct cmd *data, int ncmds) |
452 | { | 401 | { |
@@ -473,44 +422,46 @@ static void setup_qtable(struct gspca_dev *gspca_dev, | |||
473 | static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, | 422 | static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, |
474 | u8 req, u16 idx, u16 val) | 423 | u8 req, u16 idx, u16 val) |
475 | { | 424 | { |
476 | u16 notdone; | ||
477 | |||
478 | reg_w_riv(gspca_dev, req, idx, val); | 425 | reg_w_riv(gspca_dev, req, idx, val); |
479 | notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); | 426 | reg_r(gspca_dev, 0x01, 0x0001, 1); |
427 | PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]); | ||
480 | reg_w_riv(gspca_dev, req, idx, val); | 428 | reg_w_riv(gspca_dev, req, idx, val); |
481 | 429 | ||
482 | PDEBUG(D_FRAM, "before wait 0x%04x", notdone); | ||
483 | |||
484 | msleep(200); | 430 | msleep(200); |
485 | notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); | 431 | reg_r(gspca_dev, 0x01, 0x0001, 1); |
486 | PDEBUG(D_FRAM, "after wait 0x%04x", notdone); | 432 | PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]); |
487 | } | 433 | } |
488 | 434 | ||
435 | #ifdef GSPCA_DEBUG | ||
489 | static void spca504_read_info(struct gspca_dev *gspca_dev) | 436 | static void spca504_read_info(struct gspca_dev *gspca_dev) |
490 | { | 437 | { |
491 | int i; | 438 | int i; |
492 | u8 info[6]; | 439 | u8 info[6]; |
493 | 440 | ||
494 | for (i = 0; i < 6; i++) | 441 | for (i = 0; i < 6; i++) { |
495 | info[i] = reg_r_1(gspca_dev, i); | 442 | reg_r(gspca_dev, 0, i, 1); |
443 | info[i] = gspca_dev->usb_buf[0]; | ||
444 | } | ||
496 | PDEBUG(D_STREAM, | 445 | PDEBUG(D_STREAM, |
497 | "Read info: %d %d %d %d %d %d." | 446 | "Read info: %d %d %d %d %d %d." |
498 | " Should be 1,0,2,2,0,0", | 447 | " Should be 1,0,2,2,0,0", |
499 | info[0], info[1], info[2], | 448 | info[0], info[1], info[2], |
500 | info[3], info[4], info[5]); | 449 | info[3], info[4], info[5]); |
501 | } | 450 | } |
451 | #endif | ||
502 | 452 | ||
503 | static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, | 453 | static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, |
504 | u8 req, | 454 | u8 req, |
505 | u16 idx, u16 val, u16 endcode, u8 count) | 455 | u16 idx, u16 val, u8 endcode, u8 count) |
506 | { | 456 | { |
507 | u16 status; | 457 | u16 status; |
508 | 458 | ||
509 | reg_w_riv(gspca_dev, req, idx, val); | 459 | reg_w_riv(gspca_dev, req, idx, val); |
510 | status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); | 460 | reg_r(gspca_dev, 0x01, 0x0001, 1); |
511 | if (gspca_dev->usb_err < 0) | 461 | if (gspca_dev->usb_err < 0) |
512 | return; | 462 | return; |
513 | PDEBUG(D_FRAM, "Status 0x%04x Need 0x%04x", status, endcode); | 463 | PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x", |
464 | gspca_dev->usb_buf[0], endcode); | ||
514 | if (!count) | 465 | if (!count) |
515 | return; | 466 | return; |
516 | count = 200; | 467 | count = 200; |
@@ -518,7 +469,8 @@ static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, | |||
518 | msleep(10); | 469 | msleep(10); |
519 | /* gsmart mini2 write a each wait setting 1 ms is enough */ | 470 | /* gsmart mini2 write a each wait setting 1 ms is enough */ |
520 | /* reg_w_riv(gspca_dev, req, idx, val); */ | 471 | /* reg_w_riv(gspca_dev, req, idx, val); */ |
521 | status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); | 472 | reg_r(gspca_dev, 0x01, 0x0001, 1); |
473 | status = gspca_dev->usb_buf[0]; | ||
522 | if (status == endcode) { | 474 | if (status == endcode) { |
523 | PDEBUG(D_FRAM, "status 0x%04x after wait %d", | 475 | PDEBUG(D_FRAM, "status 0x%04x after wait %d", |
524 | status, 200 - count); | 476 | status, 200 - count); |
@@ -555,17 +507,19 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) | |||
555 | } | 507 | } |
556 | } | 508 | } |
557 | 509 | ||
510 | #ifdef GSPCA_DEBUG | ||
558 | static void spca50x_GetFirmware(struct gspca_dev *gspca_dev) | 511 | static void spca50x_GetFirmware(struct gspca_dev *gspca_dev) |
559 | { | 512 | { |
560 | u8 *data; | 513 | u8 *data; |
561 | 514 | ||
562 | data = gspca_dev->usb_buf; | 515 | data = gspca_dev->usb_buf; |
563 | reg_r(gspca_dev, 0x20, 0, 5); | 516 | reg_r(gspca_dev, 0x20, 0, 5); |
564 | PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ", | 517 | PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d", |
565 | data[0], data[1], data[2], data[3], data[4]); | 518 | data[0], data[1], data[2], data[3], data[4]); |
566 | reg_r(gspca_dev, 0x23, 0, 64); | 519 | reg_r(gspca_dev, 0x23, 0, 64); |
567 | reg_r(gspca_dev, 0x23, 1, 64); | 520 | reg_r(gspca_dev, 0x23, 1, 64); |
568 | } | 521 | } |
522 | #endif | ||
569 | 523 | ||
570 | static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) | 524 | static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) |
571 | { | 525 | { |
@@ -578,7 +532,9 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) | |||
578 | reg_w_riv(gspca_dev, 0x31, 0, 0); | 532 | reg_w_riv(gspca_dev, 0x31, 0, 0); |
579 | spca504B_WaitCmdStatus(gspca_dev); | 533 | spca504B_WaitCmdStatus(gspca_dev); |
580 | spca504B_PollingDataReady(gspca_dev); | 534 | spca504B_PollingDataReady(gspca_dev); |
535 | #ifdef GSPCA_DEBUG | ||
581 | spca50x_GetFirmware(gspca_dev); | 536 | spca50x_GetFirmware(gspca_dev); |
537 | #endif | ||
582 | reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */ | 538 | reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */ |
583 | reg_r(gspca_dev, 0x24, 8, 1); | 539 | reg_r(gspca_dev, 0x24, 8, 1); |
584 | 540 | ||
@@ -628,7 +584,8 @@ static void spca504_wait_status(struct gspca_dev *gspca_dev) | |||
628 | cnt = 256; | 584 | cnt = 256; |
629 | while (--cnt > 0) { | 585 | while (--cnt > 0) { |
630 | /* With this we get the status, when return 0 it's all ok */ | 586 | /* With this we get the status, when return 0 it's all ok */ |
631 | if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0) | 587 | reg_r(gspca_dev, 0x06, 0x00, 1); |
588 | if (gspca_dev->usb_buf[0] == 0) | ||
632 | return; | 589 | return; |
633 | msleep(10); | 590 | msleep(10); |
634 | } | 591 | } |
@@ -772,10 +729,14 @@ static int sd_init(struct gspca_dev *gspca_dev) | |||
772 | /* fall thru */ | 729 | /* fall thru */ |
773 | case BRIDGE_SPCA533: | 730 | case BRIDGE_SPCA533: |
774 | spca504B_PollingDataReady(gspca_dev); | 731 | spca504B_PollingDataReady(gspca_dev); |
732 | #ifdef GSPCA_DEBUG | ||
775 | spca50x_GetFirmware(gspca_dev); | 733 | spca50x_GetFirmware(gspca_dev); |
734 | #endif | ||
776 | break; | 735 | break; |
777 | case BRIDGE_SPCA536: | 736 | case BRIDGE_SPCA536: |
737 | #ifdef GSPCA_DEBUG | ||
778 | spca50x_GetFirmware(gspca_dev); | 738 | spca50x_GetFirmware(gspca_dev); |
739 | #endif | ||
779 | reg_r(gspca_dev, 0x00, 0x5002, 1); | 740 | reg_r(gspca_dev, 0x00, 0x5002, 1); |
780 | reg_w_1(gspca_dev, 0x24, 0, 0, 0); | 741 | reg_w_1(gspca_dev, 0x24, 0, 0, 0); |
781 | reg_r(gspca_dev, 0x24, 0, 1); | 742 | reg_r(gspca_dev, 0x24, 0, 1); |
@@ -801,7 +762,9 @@ static int sd_init(struct gspca_dev *gspca_dev) | |||
801 | /* case BRIDGE_SPCA504: */ | 762 | /* case BRIDGE_SPCA504: */ |
802 | PDEBUG(D_STREAM, "Opening SPCA504"); | 763 | PDEBUG(D_STREAM, "Opening SPCA504"); |
803 | if (sd->subtype == AiptekMiniPenCam13) { | 764 | if (sd->subtype == AiptekMiniPenCam13) { |
765 | #ifdef GSPCA_DEBUG | ||
804 | spca504_read_info(gspca_dev); | 766 | spca504_read_info(gspca_dev); |
767 | #endif | ||
805 | 768 | ||
806 | /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ | 769 | /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ |
807 | spca504A_acknowledged_command(gspca_dev, 0x24, | 770 | spca504A_acknowledged_command(gspca_dev, 0x24, |
@@ -873,7 +836,9 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
873 | break; | 836 | break; |
874 | case BRIDGE_SPCA504: | 837 | case BRIDGE_SPCA504: |
875 | if (sd->subtype == AiptekMiniPenCam13) { | 838 | if (sd->subtype == AiptekMiniPenCam13) { |
839 | #ifdef GSPCA_DEBUG | ||
876 | spca504_read_info(gspca_dev); | 840 | spca504_read_info(gspca_dev); |
841 | #endif | ||
877 | 842 | ||
878 | /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ | 843 | /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ |
879 | spca504A_acknowledged_command(gspca_dev, 0x24, | 844 | spca504A_acknowledged_command(gspca_dev, 0x24, |
@@ -885,7 +850,9 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
885 | 0, 0, 0x9d, 1); | 850 | 0, 0, 0x9d, 1); |
886 | } else { | 851 | } else { |
887 | spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); | 852 | spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); |
853 | #ifdef GSPCA_DEBUG | ||
888 | spca504_read_info(gspca_dev); | 854 | spca504_read_info(gspca_dev); |
855 | #endif | ||
889 | spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); | 856 | spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); |
890 | spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); | 857 | spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); |
891 | } | 858 | } |
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index a3eccd815766..7e762d551099 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c | |||
@@ -92,8 +92,6 @@ static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val); | |||
92 | static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val); | 92 | static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val); |
93 | static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val); | 93 | static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val); |
94 | static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val); | 94 | static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val); |
95 | static int sd_querymenu(struct gspca_dev *gspca_dev, | ||
96 | struct v4l2_querymenu *menu); | ||
97 | 95 | ||
98 | static const struct ctrl sd_ctrls[] = { | 96 | static const struct ctrl sd_ctrls[] = { |
99 | { | 97 | { |
@@ -1379,17 +1377,14 @@ static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val) | |||
1379 | static int sd_querymenu(struct gspca_dev *gspca_dev, | 1377 | static int sd_querymenu(struct gspca_dev *gspca_dev, |
1380 | struct v4l2_querymenu *menu) | 1378 | struct v4l2_querymenu *menu) |
1381 | { | 1379 | { |
1380 | static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"}; | ||
1381 | |||
1382 | switch (menu->id) { | 1382 | switch (menu->id) { |
1383 | case V4L2_CID_POWER_LINE_FREQUENCY: | 1383 | case V4L2_CID_POWER_LINE_FREQUENCY: |
1384 | switch (menu->index) { | 1384 | if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm)) |
1385 | case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ | 1385 | break; |
1386 | strcpy((char *) menu->name, "50 Hz"); | 1386 | strcpy((char *) menu->name, freq_nm[menu->index]); |
1387 | return 0; | 1387 | return 0; |
1388 | case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ | ||
1389 | strcpy((char *) menu->name, "60 Hz"); | ||
1390 | return 0; | ||
1391 | } | ||
1392 | break; | ||
1393 | case V4L2_CID_EFFECTS: | 1388 | case V4L2_CID_EFFECTS: |
1394 | if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) { | 1389 | if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) { |
1395 | strncpy((char *) menu->name, | 1390 | strncpy((char *) menu->name, |
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index fa164e861cde..61cdd56a74a9 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c | |||
@@ -3065,15 +3065,10 @@ static const struct usb_action mc501cb_InitialScale[] = { /* 320x240 */ | |||
3065 | {0xaa, 0x55, 0x0010}, /* 00,55,10,aa */ | 3065 | {0xaa, 0x55, 0x0010}, /* 00,55,10,aa */ |
3066 | {0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */ | 3066 | {0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */ |
3067 | {0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */ | 3067 | {0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */ |
3068 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ | ||
3069 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ | ||
3070 | {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */ | ||
3071 | {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */ | ||
3072 | {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */ | ||
3073 | {} | 3068 | {} |
3074 | }; | 3069 | }; |
3075 | 3070 | ||
3076 | static const struct usb_action mc501cb_50HZScale[] = { | 3071 | static const struct usb_action mc501cb_50HZ[] = { |
3077 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ | 3072 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ |
3078 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ | 3073 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ |
3079 | {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */ | 3074 | {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */ |
@@ -3082,15 +3077,10 @@ static const struct usb_action mc501cb_50HZScale[] = { | |||
3082 | {0xaa, 0x3c, 0x004c}, /* 00,3C,4C,aa */ | 3077 | {0xaa, 0x3c, 0x004c}, /* 00,3C,4C,aa */ |
3083 | {0xaa, 0x3d, 0x001d}, /* 00,3D,1D,aa */ | 3078 | {0xaa, 0x3d, 0x001d}, /* 00,3D,1D,aa */ |
3084 | {0xaa, 0x3e, 0x004c}, /* 00,3E,4C,aa */ | 3079 | {0xaa, 0x3e, 0x004c}, /* 00,3E,4C,aa */ |
3085 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ | ||
3086 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ | ||
3087 | {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */ | ||
3088 | {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */ | ||
3089 | {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */ | ||
3090 | {} | 3080 | {} |
3091 | }; | 3081 | }; |
3092 | 3082 | ||
3093 | static const struct usb_action mc501cb_50HZ[] = { | 3083 | static const struct usb_action mc501cb_50HZScale[] = { |
3094 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ | 3084 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ |
3095 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ | 3085 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ |
3096 | {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */ | 3086 | {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */ |
@@ -3099,15 +3089,10 @@ static const struct usb_action mc501cb_50HZ[] = { | |||
3099 | {0xaa, 0x3c, 0x0098}, /* 00,3C,98,aa */ | 3089 | {0xaa, 0x3c, 0x0098}, /* 00,3C,98,aa */ |
3100 | {0xaa, 0x3d, 0x003a}, /* 00,3D,3A,aa */ | 3090 | {0xaa, 0x3d, 0x003a}, /* 00,3D,3A,aa */ |
3101 | {0xaa, 0x3e, 0x0098}, /* 00,3E,98,aa */ | 3091 | {0xaa, 0x3e, 0x0098}, /* 00,3E,98,aa */ |
3102 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ | ||
3103 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ | ||
3104 | {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ | ||
3105 | {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */ | ||
3106 | {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */ | ||
3107 | {} | 3092 | {} |
3108 | }; | 3093 | }; |
3109 | 3094 | ||
3110 | static const struct usb_action mc501cb_60HZScale[] = { | 3095 | static const struct usb_action mc501cb_60HZ[] = { |
3111 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ | 3096 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ |
3112 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ | 3097 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ |
3113 | {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ | 3098 | {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ |
@@ -3116,15 +3101,10 @@ static const struct usb_action mc501cb_60HZScale[] = { | |||
3116 | {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */ | 3101 | {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */ |
3117 | {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */ | 3102 | {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */ |
3118 | {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */ | 3103 | {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */ |
3119 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ | ||
3120 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ | ||
3121 | {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ | ||
3122 | {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */ | ||
3123 | {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */ | ||
3124 | {} | 3104 | {} |
3125 | }; | 3105 | }; |
3126 | 3106 | ||
3127 | static const struct usb_action mc501cb_60HZ[] = { | 3107 | static const struct usb_action mc501cb_60HZScale[] = { |
3128 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ | 3108 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ |
3129 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ | 3109 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ |
3130 | {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ | 3110 | {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ |
@@ -3133,15 +3113,10 @@ static const struct usb_action mc501cb_60HZ[] = { | |||
3133 | {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */ | 3113 | {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */ |
3134 | {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */ | 3114 | {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */ |
3135 | {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */ | 3115 | {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */ |
3136 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ | ||
3137 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ | ||
3138 | {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ | ||
3139 | {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */ | ||
3140 | {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */ | ||
3141 | {} | 3116 | {} |
3142 | }; | 3117 | }; |
3143 | 3118 | ||
3144 | static const struct usb_action mc501cb_NoFlikerScale[] = { | 3119 | static const struct usb_action mc501cb_NoFliker[] = { |
3145 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ | 3120 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ |
3146 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ | 3121 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ |
3147 | {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ | 3122 | {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ |
@@ -3150,15 +3125,10 @@ static const struct usb_action mc501cb_NoFlikerScale[] = { | |||
3150 | {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */ | 3125 | {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */ |
3151 | {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */ | 3126 | {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */ |
3152 | {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */ | 3127 | {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */ |
3153 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ | ||
3154 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ | ||
3155 | {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ | ||
3156 | {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */ | ||
3157 | {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */ | ||
3158 | {} | 3128 | {} |
3159 | }; | 3129 | }; |
3160 | 3130 | ||
3161 | static const struct usb_action mc501cb_NoFliker[] = { | 3131 | static const struct usb_action mc501cb_NoFlikerScale[] = { |
3162 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ | 3132 | {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ |
3163 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ | 3133 | {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ |
3164 | {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ | 3134 | {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ |
@@ -6296,7 +6266,6 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) | |||
6296 | { | 6266 | { |
6297 | struct sd *sd = (struct sd *) gspca_dev; | 6267 | struct sd *sd = (struct sd *) gspca_dev; |
6298 | int i; | 6268 | int i; |
6299 | u8 retbyte; | ||
6300 | u16 retword; | 6269 | u16 retword; |
6301 | 6270 | ||
6302 | /*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/ | 6271 | /*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/ |
@@ -6389,8 +6358,12 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) | |||
6389 | retword |= i2c_read(gspca_dev, 0x01); /* ID 1 */ | 6358 | retword |= i2c_read(gspca_dev, 0x01); /* ID 1 */ |
6390 | PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", retword); | 6359 | PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", retword); |
6391 | if (retword == 0x2030) { | 6360 | if (retword == 0x2030) { |
6361 | #ifdef GSPCA_DEBUG | ||
6362 | u8 retbyte; | ||
6363 | |||
6392 | retbyte = i2c_read(gspca_dev, 0x02); /* revision number */ | 6364 | retbyte = i2c_read(gspca_dev, 0x02); /* revision number */ |
6393 | PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte); | 6365 | PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte); |
6366 | #endif | ||
6394 | send_unknown(gspca_dev, SENSOR_PO2030); | 6367 | send_unknown(gspca_dev, SENSOR_PO2030); |
6395 | return retword; | 6368 | return retword; |
6396 | } | 6369 | } |
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 39946420b301..a4e4dfdbc2f2 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c | |||
@@ -810,7 +810,6 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev, | |||
810 | const struct pci_device_id *pci_id) | 810 | const struct pci_device_id *pci_id) |
811 | { | 811 | { |
812 | u16 cmd; | 812 | u16 cmd; |
813 | u8 card_rev; | ||
814 | unsigned char pci_latency; | 813 | unsigned char pci_latency; |
815 | 814 | ||
816 | IVTV_DEBUG_INFO("Enabling pci device\n"); | 815 | IVTV_DEBUG_INFO("Enabling pci device\n"); |
@@ -857,7 +856,6 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev, | |||
857 | } | 856 | } |
858 | IVTV_DEBUG_INFO("Bus Mastering Enabled.\n"); | 857 | IVTV_DEBUG_INFO("Bus Mastering Enabled.\n"); |
859 | 858 | ||
860 | pci_read_config_byte(pdev, PCI_CLASS_REVISION, &card_rev); | ||
861 | pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); | 859 | pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); |
862 | 860 | ||
863 | if (pci_latency < 64 && ivtv_pci_latency) { | 861 | if (pci_latency < 64 && ivtv_pci_latency) { |
@@ -874,7 +872,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev, | |||
874 | 872 | ||
875 | IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, " | 873 | IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, " |
876 | "irq: %d, latency: %d, memory: 0x%lx\n", | 874 | "irq: %d, latency: %d, memory: 0x%lx\n", |
877 | pdev->device, card_rev, pdev->bus->number, | 875 | pdev->device, pdev->revision, pdev->bus->number, |
878 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), | 876 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), |
879 | pdev->irq, pci_latency, (unsigned long)itv->base_addr); | 877 | pdev->irq, pci_latency, (unsigned long)itv->base_addr); |
880 | 878 | ||
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 53fa2a7bf156..ebebed929627 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c | |||
@@ -315,10 +315,20 @@ static int mt9m111_setup_rect(struct i2c_client *client, | |||
315 | static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt) | 315 | static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt) |
316 | { | 316 | { |
317 | int ret; | 317 | int ret; |
318 | u16 mask = MT9M111_OUTFMT_PROCESSED_BAYER | MT9M111_OUTFMT_RGB | | ||
319 | MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_SWAP_RGB_EVEN | | ||
320 | MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 | | ||
321 | MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr | | ||
322 | MT9M111_OUTFMT_SWAP_YCbCr_C_Y; | ||
318 | 323 | ||
319 | ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt); | 324 | ret = reg_read(OUTPUT_FORMAT_CTRL2_A); |
325 | if (ret >= 0) | ||
326 | ret = reg_write(OUTPUT_FORMAT_CTRL2_A, (ret & ~mask) | outfmt); | ||
320 | if (!ret) | 327 | if (!ret) |
321 | ret = reg_write(OUTPUT_FORMAT_CTRL2_B, outfmt); | 328 | ret = reg_read(OUTPUT_FORMAT_CTRL2_B); |
329 | if (ret >= 0) | ||
330 | ret = reg_write(OUTPUT_FORMAT_CTRL2_B, (ret & ~mask) | outfmt); | ||
331 | |||
322 | return ret; | 332 | return ret; |
323 | } | 333 | } |
324 | 334 | ||
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index e313d8390092..fc76ed1c08e5 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c | |||
@@ -228,7 +228,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd, | |||
228 | 228 | ||
229 | flags = soc_camera_apply_sensor_flags(icl, flags); | 229 | flags = soc_camera_apply_sensor_flags(icl, flags); |
230 | 230 | ||
231 | if (flags & SOCAM_PCLK_SAMPLE_RISING) | 231 | if (flags & SOCAM_PCLK_SAMPLE_FALLING) |
232 | pixclk |= 0x10; | 232 | pixclk |= 0x10; |
233 | 233 | ||
234 | if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH)) | 234 | if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH)) |
diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c new file mode 100644 index 000000000000..1319c2c48aff --- /dev/null +++ b/drivers/media/video/mt9v032.c | |||
@@ -0,0 +1,773 @@ | |||
1 | /* | ||
2 | * Driver for MT9V032 CMOS Image Sensor from Micron | ||
3 | * | ||
4 | * Copyright (C) 2010, Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
5 | * | ||
6 | * Based on the MT9M001 driver, | ||
7 | * | ||
8 | * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> | ||
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 version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/delay.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/log2.h> | ||
18 | #include <linux/mutex.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/videodev2.h> | ||
21 | #include <linux/v4l2-mediabus.h> | ||
22 | |||
23 | #include <media/mt9v032.h> | ||
24 | #include <media/v4l2-ctrls.h> | ||
25 | #include <media/v4l2-device.h> | ||
26 | #include <media/v4l2-subdev.h> | ||
27 | |||
28 | #define MT9V032_PIXEL_ARRAY_HEIGHT 492 | ||
29 | #define MT9V032_PIXEL_ARRAY_WIDTH 782 | ||
30 | |||
31 | #define MT9V032_CHIP_VERSION 0x00 | ||
32 | #define MT9V032_CHIP_ID_REV1 0x1311 | ||
33 | #define MT9V032_CHIP_ID_REV3 0x1313 | ||
34 | #define MT9V032_ROW_START 0x01 | ||
35 | #define MT9V032_ROW_START_MIN 4 | ||
36 | #define MT9V032_ROW_START_DEF 10 | ||
37 | #define MT9V032_ROW_START_MAX 482 | ||
38 | #define MT9V032_COLUMN_START 0x02 | ||
39 | #define MT9V032_COLUMN_START_MIN 1 | ||
40 | #define MT9V032_COLUMN_START_DEF 2 | ||
41 | #define MT9V032_COLUMN_START_MAX 752 | ||
42 | #define MT9V032_WINDOW_HEIGHT 0x03 | ||
43 | #define MT9V032_WINDOW_HEIGHT_MIN 1 | ||
44 | #define MT9V032_WINDOW_HEIGHT_DEF 480 | ||
45 | #define MT9V032_WINDOW_HEIGHT_MAX 480 | ||
46 | #define MT9V032_WINDOW_WIDTH 0x04 | ||
47 | #define MT9V032_WINDOW_WIDTH_MIN 1 | ||
48 | #define MT9V032_WINDOW_WIDTH_DEF 752 | ||
49 | #define MT9V032_WINDOW_WIDTH_MAX 752 | ||
50 | #define MT9V032_HORIZONTAL_BLANKING 0x05 | ||
51 | #define MT9V032_HORIZONTAL_BLANKING_MIN 43 | ||
52 | #define MT9V032_HORIZONTAL_BLANKING_MAX 1023 | ||
53 | #define MT9V032_VERTICAL_BLANKING 0x06 | ||
54 | #define MT9V032_VERTICAL_BLANKING_MIN 4 | ||
55 | #define MT9V032_VERTICAL_BLANKING_MAX 3000 | ||
56 | #define MT9V032_CHIP_CONTROL 0x07 | ||
57 | #define MT9V032_CHIP_CONTROL_MASTER_MODE (1 << 3) | ||
58 | #define MT9V032_CHIP_CONTROL_DOUT_ENABLE (1 << 7) | ||
59 | #define MT9V032_CHIP_CONTROL_SEQUENTIAL (1 << 8) | ||
60 | #define MT9V032_SHUTTER_WIDTH1 0x08 | ||
61 | #define MT9V032_SHUTTER_WIDTH2 0x09 | ||
62 | #define MT9V032_SHUTTER_WIDTH_CONTROL 0x0a | ||
63 | #define MT9V032_TOTAL_SHUTTER_WIDTH 0x0b | ||
64 | #define MT9V032_TOTAL_SHUTTER_WIDTH_MIN 1 | ||
65 | #define MT9V032_TOTAL_SHUTTER_WIDTH_DEF 480 | ||
66 | #define MT9V032_TOTAL_SHUTTER_WIDTH_MAX 32767 | ||
67 | #define MT9V032_RESET 0x0c | ||
68 | #define MT9V032_READ_MODE 0x0d | ||
69 | #define MT9V032_READ_MODE_ROW_BIN_MASK (3 << 0) | ||
70 | #define MT9V032_READ_MODE_ROW_BIN_SHIFT 0 | ||
71 | #define MT9V032_READ_MODE_COLUMN_BIN_MASK (3 << 2) | ||
72 | #define MT9V032_READ_MODE_COLUMN_BIN_SHIFT 2 | ||
73 | #define MT9V032_READ_MODE_ROW_FLIP (1 << 4) | ||
74 | #define MT9V032_READ_MODE_COLUMN_FLIP (1 << 5) | ||
75 | #define MT9V032_READ_MODE_DARK_COLUMNS (1 << 6) | ||
76 | #define MT9V032_READ_MODE_DARK_ROWS (1 << 7) | ||
77 | #define MT9V032_PIXEL_OPERATION_MODE 0x0f | ||
78 | #define MT9V032_PIXEL_OPERATION_MODE_COLOR (1 << 2) | ||
79 | #define MT9V032_PIXEL_OPERATION_MODE_HDR (1 << 6) | ||
80 | #define MT9V032_ANALOG_GAIN 0x35 | ||
81 | #define MT9V032_ANALOG_GAIN_MIN 16 | ||
82 | #define MT9V032_ANALOG_GAIN_DEF 16 | ||
83 | #define MT9V032_ANALOG_GAIN_MAX 64 | ||
84 | #define MT9V032_MAX_ANALOG_GAIN 0x36 | ||
85 | #define MT9V032_MAX_ANALOG_GAIN_MAX 127 | ||
86 | #define MT9V032_FRAME_DARK_AVERAGE 0x42 | ||
87 | #define MT9V032_DARK_AVG_THRESH 0x46 | ||
88 | #define MT9V032_DARK_AVG_LOW_THRESH_MASK (255 << 0) | ||
89 | #define MT9V032_DARK_AVG_LOW_THRESH_SHIFT 0 | ||
90 | #define MT9V032_DARK_AVG_HIGH_THRESH_MASK (255 << 8) | ||
91 | #define MT9V032_DARK_AVG_HIGH_THRESH_SHIFT 8 | ||
92 | #define MT9V032_ROW_NOISE_CORR_CONTROL 0x70 | ||
93 | #define MT9V032_ROW_NOISE_CORR_ENABLE (1 << 5) | ||
94 | #define MT9V032_ROW_NOISE_CORR_USE_BLK_AVG (1 << 7) | ||
95 | #define MT9V032_PIXEL_CLOCK 0x74 | ||
96 | #define MT9V032_PIXEL_CLOCK_INV_LINE (1 << 0) | ||
97 | #define MT9V032_PIXEL_CLOCK_INV_FRAME (1 << 1) | ||
98 | #define MT9V032_PIXEL_CLOCK_XOR_LINE (1 << 2) | ||
99 | #define MT9V032_PIXEL_CLOCK_CONT_LINE (1 << 3) | ||
100 | #define MT9V032_PIXEL_CLOCK_INV_PXL_CLK (1 << 4) | ||
101 | #define MT9V032_TEST_PATTERN 0x7f | ||
102 | #define MT9V032_TEST_PATTERN_DATA_MASK (1023 << 0) | ||
103 | #define MT9V032_TEST_PATTERN_DATA_SHIFT 0 | ||
104 | #define MT9V032_TEST_PATTERN_USE_DATA (1 << 10) | ||
105 | #define MT9V032_TEST_PATTERN_GRAY_MASK (3 << 11) | ||
106 | #define MT9V032_TEST_PATTERN_GRAY_NONE (0 << 11) | ||
107 | #define MT9V032_TEST_PATTERN_GRAY_VERTICAL (1 << 11) | ||
108 | #define MT9V032_TEST_PATTERN_GRAY_HORIZONTAL (2 << 11) | ||
109 | #define MT9V032_TEST_PATTERN_GRAY_DIAGONAL (3 << 11) | ||
110 | #define MT9V032_TEST_PATTERN_ENABLE (1 << 13) | ||
111 | #define MT9V032_TEST_PATTERN_FLIP (1 << 14) | ||
112 | #define MT9V032_AEC_AGC_ENABLE 0xaf | ||
113 | #define MT9V032_AEC_ENABLE (1 << 0) | ||
114 | #define MT9V032_AGC_ENABLE (1 << 1) | ||
115 | #define MT9V032_THERMAL_INFO 0xc1 | ||
116 | |||
117 | struct mt9v032 { | ||
118 | struct v4l2_subdev subdev; | ||
119 | struct media_pad pad; | ||
120 | |||
121 | struct v4l2_mbus_framefmt format; | ||
122 | struct v4l2_rect crop; | ||
123 | |||
124 | struct v4l2_ctrl_handler ctrls; | ||
125 | |||
126 | struct mutex power_lock; | ||
127 | int power_count; | ||
128 | |||
129 | struct mt9v032_platform_data *pdata; | ||
130 | u16 chip_control; | ||
131 | u16 aec_agc; | ||
132 | }; | ||
133 | |||
134 | static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd) | ||
135 | { | ||
136 | return container_of(sd, struct mt9v032, subdev); | ||
137 | } | ||
138 | |||
139 | static int mt9v032_read(struct i2c_client *client, const u8 reg) | ||
140 | { | ||
141 | s32 data = i2c_smbus_read_word_data(client, reg); | ||
142 | dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__, | ||
143 | swab16(data), reg); | ||
144 | return data < 0 ? data : swab16(data); | ||
145 | } | ||
146 | |||
147 | static int mt9v032_write(struct i2c_client *client, const u8 reg, | ||
148 | const u16 data) | ||
149 | { | ||
150 | dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__, | ||
151 | data, reg); | ||
152 | return i2c_smbus_write_word_data(client, reg, swab16(data)); | ||
153 | } | ||
154 | |||
155 | static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set) | ||
156 | { | ||
157 | struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); | ||
158 | u16 value = (mt9v032->chip_control & ~clear) | set; | ||
159 | int ret; | ||
160 | |||
161 | ret = mt9v032_write(client, MT9V032_CHIP_CONTROL, value); | ||
162 | if (ret < 0) | ||
163 | return ret; | ||
164 | |||
165 | mt9v032->chip_control = value; | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static int | ||
170 | mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable) | ||
171 | { | ||
172 | struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); | ||
173 | u16 value = mt9v032->aec_agc; | ||
174 | int ret; | ||
175 | |||
176 | if (enable) | ||
177 | value |= which; | ||
178 | else | ||
179 | value &= ~which; | ||
180 | |||
181 | ret = mt9v032_write(client, MT9V032_AEC_AGC_ENABLE, value); | ||
182 | if (ret < 0) | ||
183 | return ret; | ||
184 | |||
185 | mt9v032->aec_agc = value; | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int mt9v032_power_on(struct mt9v032 *mt9v032) | ||
190 | { | ||
191 | struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); | ||
192 | int ret; | ||
193 | |||
194 | if (mt9v032->pdata->set_clock) { | ||
195 | mt9v032->pdata->set_clock(&mt9v032->subdev, 25000000); | ||
196 | udelay(1); | ||
197 | } | ||
198 | |||
199 | /* Reset the chip and stop data read out */ | ||
200 | ret = mt9v032_write(client, MT9V032_RESET, 1); | ||
201 | if (ret < 0) | ||
202 | return ret; | ||
203 | |||
204 | ret = mt9v032_write(client, MT9V032_RESET, 0); | ||
205 | if (ret < 0) | ||
206 | return ret; | ||
207 | |||
208 | return mt9v032_write(client, MT9V032_CHIP_CONTROL, 0); | ||
209 | } | ||
210 | |||
211 | static void mt9v032_power_off(struct mt9v032 *mt9v032) | ||
212 | { | ||
213 | if (mt9v032->pdata->set_clock) | ||
214 | mt9v032->pdata->set_clock(&mt9v032->subdev, 0); | ||
215 | } | ||
216 | |||
217 | static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on) | ||
218 | { | ||
219 | struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); | ||
220 | int ret; | ||
221 | |||
222 | if (!on) { | ||
223 | mt9v032_power_off(mt9v032); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | ret = mt9v032_power_on(mt9v032); | ||
228 | if (ret < 0) | ||
229 | return ret; | ||
230 | |||
231 | /* Configure the pixel clock polarity */ | ||
232 | if (mt9v032->pdata && mt9v032->pdata->clk_pol) { | ||
233 | ret = mt9v032_write(client, MT9V032_PIXEL_CLOCK, | ||
234 | MT9V032_PIXEL_CLOCK_INV_PXL_CLK); | ||
235 | if (ret < 0) | ||
236 | return ret; | ||
237 | } | ||
238 | |||
239 | /* Disable the noise correction algorithm and restore the controls. */ | ||
240 | ret = mt9v032_write(client, MT9V032_ROW_NOISE_CORR_CONTROL, 0); | ||
241 | if (ret < 0) | ||
242 | return ret; | ||
243 | |||
244 | return v4l2_ctrl_handler_setup(&mt9v032->ctrls); | ||
245 | } | ||
246 | |||
247 | /* ----------------------------------------------------------------------------- | ||
248 | * V4L2 subdev video operations | ||
249 | */ | ||
250 | |||
251 | static struct v4l2_mbus_framefmt * | ||
252 | __mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh, | ||
253 | unsigned int pad, enum v4l2_subdev_format_whence which) | ||
254 | { | ||
255 | switch (which) { | ||
256 | case V4L2_SUBDEV_FORMAT_TRY: | ||
257 | return v4l2_subdev_get_try_format(fh, pad); | ||
258 | case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
259 | return &mt9v032->format; | ||
260 | default: | ||
261 | return NULL; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | static struct v4l2_rect * | ||
266 | __mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh, | ||
267 | unsigned int pad, enum v4l2_subdev_format_whence which) | ||
268 | { | ||
269 | switch (which) { | ||
270 | case V4L2_SUBDEV_FORMAT_TRY: | ||
271 | return v4l2_subdev_get_try_crop(fh, pad); | ||
272 | case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
273 | return &mt9v032->crop; | ||
274 | default: | ||
275 | return NULL; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable) | ||
280 | { | ||
281 | const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE | ||
282 | | MT9V032_CHIP_CONTROL_DOUT_ENABLE | ||
283 | | MT9V032_CHIP_CONTROL_SEQUENTIAL; | ||
284 | struct i2c_client *client = v4l2_get_subdevdata(subdev); | ||
285 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | ||
286 | struct v4l2_mbus_framefmt *format = &mt9v032->format; | ||
287 | struct v4l2_rect *crop = &mt9v032->crop; | ||
288 | unsigned int hratio; | ||
289 | unsigned int vratio; | ||
290 | int ret; | ||
291 | |||
292 | if (!enable) | ||
293 | return mt9v032_set_chip_control(mt9v032, mode, 0); | ||
294 | |||
295 | /* Configure the window size and row/column bin */ | ||
296 | hratio = DIV_ROUND_CLOSEST(crop->width, format->width); | ||
297 | vratio = DIV_ROUND_CLOSEST(crop->height, format->height); | ||
298 | |||
299 | ret = mt9v032_write(client, MT9V032_READ_MODE, | ||
300 | (hratio - 1) << MT9V032_READ_MODE_ROW_BIN_SHIFT | | ||
301 | (vratio - 1) << MT9V032_READ_MODE_COLUMN_BIN_SHIFT); | ||
302 | if (ret < 0) | ||
303 | return ret; | ||
304 | |||
305 | ret = mt9v032_write(client, MT9V032_COLUMN_START, crop->left); | ||
306 | if (ret < 0) | ||
307 | return ret; | ||
308 | |||
309 | ret = mt9v032_write(client, MT9V032_ROW_START, crop->top); | ||
310 | if (ret < 0) | ||
311 | return ret; | ||
312 | |||
313 | ret = mt9v032_write(client, MT9V032_WINDOW_WIDTH, crop->width); | ||
314 | if (ret < 0) | ||
315 | return ret; | ||
316 | |||
317 | ret = mt9v032_write(client, MT9V032_WINDOW_HEIGHT, crop->height); | ||
318 | if (ret < 0) | ||
319 | return ret; | ||
320 | |||
321 | ret = mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING, | ||
322 | max(43, 660 - crop->width)); | ||
323 | if (ret < 0) | ||
324 | return ret; | ||
325 | |||
326 | /* Switch to master "normal" mode */ | ||
327 | return mt9v032_set_chip_control(mt9v032, 0, mode); | ||
328 | } | ||
329 | |||
330 | static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev, | ||
331 | struct v4l2_subdev_fh *fh, | ||
332 | struct v4l2_subdev_mbus_code_enum *code) | ||
333 | { | ||
334 | if (code->index > 0) | ||
335 | return -EINVAL; | ||
336 | |||
337 | code->code = V4L2_MBUS_FMT_SGRBG10_1X10; | ||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev, | ||
342 | struct v4l2_subdev_fh *fh, | ||
343 | struct v4l2_subdev_frame_size_enum *fse) | ||
344 | { | ||
345 | if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10) | ||
346 | return -EINVAL; | ||
347 | |||
348 | fse->min_width = MT9V032_WINDOW_WIDTH_DEF / fse->index; | ||
349 | fse->max_width = fse->min_width; | ||
350 | fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / fse->index; | ||
351 | fse->max_height = fse->min_height; | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static int mt9v032_get_format(struct v4l2_subdev *subdev, | ||
357 | struct v4l2_subdev_fh *fh, | ||
358 | struct v4l2_subdev_format *format) | ||
359 | { | ||
360 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | ||
361 | |||
362 | format->format = *__mt9v032_get_pad_format(mt9v032, fh, format->pad, | ||
363 | format->which); | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | static int mt9v032_set_format(struct v4l2_subdev *subdev, | ||
368 | struct v4l2_subdev_fh *fh, | ||
369 | struct v4l2_subdev_format *format) | ||
370 | { | ||
371 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | ||
372 | struct v4l2_mbus_framefmt *__format; | ||
373 | struct v4l2_rect *__crop; | ||
374 | unsigned int width; | ||
375 | unsigned int height; | ||
376 | unsigned int hratio; | ||
377 | unsigned int vratio; | ||
378 | |||
379 | __crop = __mt9v032_get_pad_crop(mt9v032, fh, format->pad, | ||
380 | format->which); | ||
381 | |||
382 | /* Clamp the width and height to avoid dividing by zero. */ | ||
383 | width = clamp_t(unsigned int, ALIGN(format->format.width, 2), | ||
384 | max(__crop->width / 8, MT9V032_WINDOW_WIDTH_MIN), | ||
385 | __crop->width); | ||
386 | height = clamp_t(unsigned int, ALIGN(format->format.height, 2), | ||
387 | max(__crop->height / 8, MT9V032_WINDOW_HEIGHT_MIN), | ||
388 | __crop->height); | ||
389 | |||
390 | hratio = DIV_ROUND_CLOSEST(__crop->width, width); | ||
391 | vratio = DIV_ROUND_CLOSEST(__crop->height, height); | ||
392 | |||
393 | __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad, | ||
394 | format->which); | ||
395 | __format->width = __crop->width / hratio; | ||
396 | __format->height = __crop->height / vratio; | ||
397 | |||
398 | format->format = *__format; | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | static int mt9v032_get_crop(struct v4l2_subdev *subdev, | ||
404 | struct v4l2_subdev_fh *fh, | ||
405 | struct v4l2_subdev_crop *crop) | ||
406 | { | ||
407 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | ||
408 | |||
409 | crop->rect = *__mt9v032_get_pad_crop(mt9v032, fh, crop->pad, | ||
410 | crop->which); | ||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static int mt9v032_set_crop(struct v4l2_subdev *subdev, | ||
415 | struct v4l2_subdev_fh *fh, | ||
416 | struct v4l2_subdev_crop *crop) | ||
417 | { | ||
418 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | ||
419 | struct v4l2_mbus_framefmt *__format; | ||
420 | struct v4l2_rect *__crop; | ||
421 | struct v4l2_rect rect; | ||
422 | |||
423 | /* Clamp the crop rectangle boundaries and align them to a multiple of 2 | ||
424 | * pixels. | ||
425 | */ | ||
426 | rect.left = clamp(ALIGN(crop->rect.left, 2), | ||
427 | MT9V032_COLUMN_START_MIN, | ||
428 | MT9V032_COLUMN_START_MAX); | ||
429 | rect.top = clamp(ALIGN(crop->rect.top, 2), | ||
430 | MT9V032_ROW_START_MIN, | ||
431 | MT9V032_ROW_START_MAX); | ||
432 | rect.width = clamp(ALIGN(crop->rect.width, 2), | ||
433 | MT9V032_WINDOW_WIDTH_MIN, | ||
434 | MT9V032_WINDOW_WIDTH_MAX); | ||
435 | rect.height = clamp(ALIGN(crop->rect.height, 2), | ||
436 | MT9V032_WINDOW_HEIGHT_MIN, | ||
437 | MT9V032_WINDOW_HEIGHT_MAX); | ||
438 | |||
439 | rect.width = min(rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left); | ||
440 | rect.height = min(rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top); | ||
441 | |||
442 | __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which); | ||
443 | |||
444 | if (rect.width != __crop->width || rect.height != __crop->height) { | ||
445 | /* Reset the output image size if the crop rectangle size has | ||
446 | * been modified. | ||
447 | */ | ||
448 | __format = __mt9v032_get_pad_format(mt9v032, fh, crop->pad, | ||
449 | crop->which); | ||
450 | __format->width = rect.width; | ||
451 | __format->height = rect.height; | ||
452 | } | ||
453 | |||
454 | *__crop = rect; | ||
455 | crop->rect = rect; | ||
456 | |||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | /* ----------------------------------------------------------------------------- | ||
461 | * V4L2 subdev control operations | ||
462 | */ | ||
463 | |||
464 | #define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001) | ||
465 | |||
466 | static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) | ||
467 | { | ||
468 | struct mt9v032 *mt9v032 = | ||
469 | container_of(ctrl->handler, struct mt9v032, ctrls); | ||
470 | struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); | ||
471 | u16 data; | ||
472 | |||
473 | switch (ctrl->id) { | ||
474 | case V4L2_CID_AUTOGAIN: | ||
475 | return mt9v032_update_aec_agc(mt9v032, MT9V032_AGC_ENABLE, | ||
476 | ctrl->val); | ||
477 | |||
478 | case V4L2_CID_GAIN: | ||
479 | return mt9v032_write(client, MT9V032_ANALOG_GAIN, ctrl->val); | ||
480 | |||
481 | case V4L2_CID_EXPOSURE_AUTO: | ||
482 | return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE, | ||
483 | ctrl->val); | ||
484 | |||
485 | case V4L2_CID_EXPOSURE: | ||
486 | return mt9v032_write(client, MT9V032_TOTAL_SHUTTER_WIDTH, | ||
487 | ctrl->val); | ||
488 | |||
489 | case V4L2_CID_TEST_PATTERN: | ||
490 | switch (ctrl->val) { | ||
491 | case 0: | ||
492 | data = 0; | ||
493 | break; | ||
494 | case 1: | ||
495 | data = MT9V032_TEST_PATTERN_GRAY_VERTICAL | ||
496 | | MT9V032_TEST_PATTERN_ENABLE; | ||
497 | break; | ||
498 | case 2: | ||
499 | data = MT9V032_TEST_PATTERN_GRAY_HORIZONTAL | ||
500 | | MT9V032_TEST_PATTERN_ENABLE; | ||
501 | break; | ||
502 | case 3: | ||
503 | data = MT9V032_TEST_PATTERN_GRAY_DIAGONAL | ||
504 | | MT9V032_TEST_PATTERN_ENABLE; | ||
505 | break; | ||
506 | default: | ||
507 | data = (ctrl->val << MT9V032_TEST_PATTERN_DATA_SHIFT) | ||
508 | | MT9V032_TEST_PATTERN_USE_DATA | ||
509 | | MT9V032_TEST_PATTERN_ENABLE | ||
510 | | MT9V032_TEST_PATTERN_FLIP; | ||
511 | break; | ||
512 | } | ||
513 | |||
514 | return mt9v032_write(client, MT9V032_TEST_PATTERN, data); | ||
515 | } | ||
516 | |||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static struct v4l2_ctrl_ops mt9v032_ctrl_ops = { | ||
521 | .s_ctrl = mt9v032_s_ctrl, | ||
522 | }; | ||
523 | |||
524 | static const struct v4l2_ctrl_config mt9v032_ctrls[] = { | ||
525 | { | ||
526 | .ops = &mt9v032_ctrl_ops, | ||
527 | .id = V4L2_CID_TEST_PATTERN, | ||
528 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
529 | .name = "Test pattern", | ||
530 | .min = 0, | ||
531 | .max = 1023, | ||
532 | .step = 1, | ||
533 | .def = 0, | ||
534 | .flags = 0, | ||
535 | } | ||
536 | }; | ||
537 | |||
538 | /* ----------------------------------------------------------------------------- | ||
539 | * V4L2 subdev core operations | ||
540 | */ | ||
541 | |||
542 | static int mt9v032_set_power(struct v4l2_subdev *subdev, int on) | ||
543 | { | ||
544 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | ||
545 | int ret = 0; | ||
546 | |||
547 | mutex_lock(&mt9v032->power_lock); | ||
548 | |||
549 | /* If the power count is modified from 0 to != 0 or from != 0 to 0, | ||
550 | * update the power state. | ||
551 | */ | ||
552 | if (mt9v032->power_count == !on) { | ||
553 | ret = __mt9v032_set_power(mt9v032, !!on); | ||
554 | if (ret < 0) | ||
555 | goto done; | ||
556 | } | ||
557 | |||
558 | /* Update the power count. */ | ||
559 | mt9v032->power_count += on ? 1 : -1; | ||
560 | WARN_ON(mt9v032->power_count < 0); | ||
561 | |||
562 | done: | ||
563 | mutex_unlock(&mt9v032->power_lock); | ||
564 | return ret; | ||
565 | } | ||
566 | |||
567 | /* ----------------------------------------------------------------------------- | ||
568 | * V4L2 subdev internal operations | ||
569 | */ | ||
570 | |||
571 | static int mt9v032_registered(struct v4l2_subdev *subdev) | ||
572 | { | ||
573 | struct i2c_client *client = v4l2_get_subdevdata(subdev); | ||
574 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | ||
575 | s32 data; | ||
576 | int ret; | ||
577 | |||
578 | dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n", | ||
579 | client->addr); | ||
580 | |||
581 | ret = mt9v032_power_on(mt9v032); | ||
582 | if (ret < 0) { | ||
583 | dev_err(&client->dev, "MT9V032 power up failed\n"); | ||
584 | return ret; | ||
585 | } | ||
586 | |||
587 | /* Read and check the sensor version */ | ||
588 | data = mt9v032_read(client, MT9V032_CHIP_VERSION); | ||
589 | if (data != MT9V032_CHIP_ID_REV1 && data != MT9V032_CHIP_ID_REV3) { | ||
590 | dev_err(&client->dev, "MT9V032 not detected, wrong version " | ||
591 | "0x%04x\n", data); | ||
592 | return -ENODEV; | ||
593 | } | ||
594 | |||
595 | mt9v032_power_off(mt9v032); | ||
596 | |||
597 | dev_info(&client->dev, "MT9V032 detected at address 0x%02x\n", | ||
598 | client->addr); | ||
599 | |||
600 | return ret; | ||
601 | } | ||
602 | |||
603 | static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) | ||
604 | { | ||
605 | struct v4l2_mbus_framefmt *format; | ||
606 | struct v4l2_rect *crop; | ||
607 | |||
608 | crop = v4l2_subdev_get_try_crop(fh, 0); | ||
609 | crop->left = MT9V032_COLUMN_START_DEF; | ||
610 | crop->top = MT9V032_ROW_START_DEF; | ||
611 | crop->width = MT9V032_WINDOW_WIDTH_DEF; | ||
612 | crop->height = MT9V032_WINDOW_HEIGHT_DEF; | ||
613 | |||
614 | format = v4l2_subdev_get_try_format(fh, 0); | ||
615 | format->code = V4L2_MBUS_FMT_SGRBG10_1X10; | ||
616 | format->width = MT9V032_WINDOW_WIDTH_DEF; | ||
617 | format->height = MT9V032_WINDOW_HEIGHT_DEF; | ||
618 | format->field = V4L2_FIELD_NONE; | ||
619 | format->colorspace = V4L2_COLORSPACE_SRGB; | ||
620 | |||
621 | return mt9v032_set_power(subdev, 1); | ||
622 | } | ||
623 | |||
624 | static int mt9v032_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) | ||
625 | { | ||
626 | return mt9v032_set_power(subdev, 0); | ||
627 | } | ||
628 | |||
629 | static struct v4l2_subdev_core_ops mt9v032_subdev_core_ops = { | ||
630 | .s_power = mt9v032_set_power, | ||
631 | }; | ||
632 | |||
633 | static struct v4l2_subdev_video_ops mt9v032_subdev_video_ops = { | ||
634 | .s_stream = mt9v032_s_stream, | ||
635 | }; | ||
636 | |||
637 | static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = { | ||
638 | .enum_mbus_code = mt9v032_enum_mbus_code, | ||
639 | .enum_frame_size = mt9v032_enum_frame_size, | ||
640 | .get_fmt = mt9v032_get_format, | ||
641 | .set_fmt = mt9v032_set_format, | ||
642 | .get_crop = mt9v032_get_crop, | ||
643 | .set_crop = mt9v032_set_crop, | ||
644 | }; | ||
645 | |||
646 | static struct v4l2_subdev_ops mt9v032_subdev_ops = { | ||
647 | .core = &mt9v032_subdev_core_ops, | ||
648 | .video = &mt9v032_subdev_video_ops, | ||
649 | .pad = &mt9v032_subdev_pad_ops, | ||
650 | }; | ||
651 | |||
652 | static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops = { | ||
653 | .registered = mt9v032_registered, | ||
654 | .open = mt9v032_open, | ||
655 | .close = mt9v032_close, | ||
656 | }; | ||
657 | |||
658 | /* ----------------------------------------------------------------------------- | ||
659 | * Driver initialization and probing | ||
660 | */ | ||
661 | |||
662 | static int mt9v032_probe(struct i2c_client *client, | ||
663 | const struct i2c_device_id *did) | ||
664 | { | ||
665 | struct mt9v032 *mt9v032; | ||
666 | unsigned int i; | ||
667 | int ret; | ||
668 | |||
669 | if (!i2c_check_functionality(client->adapter, | ||
670 | I2C_FUNC_SMBUS_WORD_DATA)) { | ||
671 | dev_warn(&client->adapter->dev, | ||
672 | "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); | ||
673 | return -EIO; | ||
674 | } | ||
675 | |||
676 | mt9v032 = kzalloc(sizeof(*mt9v032), GFP_KERNEL); | ||
677 | if (!mt9v032) | ||
678 | return -ENOMEM; | ||
679 | |||
680 | mutex_init(&mt9v032->power_lock); | ||
681 | mt9v032->pdata = client->dev.platform_data; | ||
682 | |||
683 | v4l2_ctrl_handler_init(&mt9v032->ctrls, ARRAY_SIZE(mt9v032_ctrls) + 4); | ||
684 | |||
685 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, | ||
686 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); | ||
687 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, | ||
688 | V4L2_CID_GAIN, MT9V032_ANALOG_GAIN_MIN, | ||
689 | MT9V032_ANALOG_GAIN_MAX, 1, MT9V032_ANALOG_GAIN_DEF); | ||
690 | v4l2_ctrl_new_std_menu(&mt9v032->ctrls, &mt9v032_ctrl_ops, | ||
691 | V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0, | ||
692 | V4L2_EXPOSURE_AUTO); | ||
693 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, | ||
694 | V4L2_CID_EXPOSURE, MT9V032_TOTAL_SHUTTER_WIDTH_MIN, | ||
695 | MT9V032_TOTAL_SHUTTER_WIDTH_MAX, 1, | ||
696 | MT9V032_TOTAL_SHUTTER_WIDTH_DEF); | ||
697 | |||
698 | for (i = 0; i < ARRAY_SIZE(mt9v032_ctrls); ++i) | ||
699 | v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_ctrls[i], NULL); | ||
700 | |||
701 | mt9v032->subdev.ctrl_handler = &mt9v032->ctrls; | ||
702 | |||
703 | if (mt9v032->ctrls.error) | ||
704 | printk(KERN_INFO "%s: control initialization error %d\n", | ||
705 | __func__, mt9v032->ctrls.error); | ||
706 | |||
707 | mt9v032->crop.left = MT9V032_COLUMN_START_DEF; | ||
708 | mt9v032->crop.top = MT9V032_ROW_START_DEF; | ||
709 | mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF; | ||
710 | mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF; | ||
711 | |||
712 | mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10; | ||
713 | mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF; | ||
714 | mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF; | ||
715 | mt9v032->format.field = V4L2_FIELD_NONE; | ||
716 | mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB; | ||
717 | |||
718 | mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE; | ||
719 | |||
720 | v4l2_i2c_subdev_init(&mt9v032->subdev, client, &mt9v032_subdev_ops); | ||
721 | mt9v032->subdev.internal_ops = &mt9v032_subdev_internal_ops; | ||
722 | mt9v032->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
723 | |||
724 | mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
725 | ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0); | ||
726 | if (ret < 0) | ||
727 | kfree(mt9v032); | ||
728 | |||
729 | return ret; | ||
730 | } | ||
731 | |||
732 | static int mt9v032_remove(struct i2c_client *client) | ||
733 | { | ||
734 | struct v4l2_subdev *subdev = i2c_get_clientdata(client); | ||
735 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | ||
736 | |||
737 | v4l2_device_unregister_subdev(subdev); | ||
738 | media_entity_cleanup(&subdev->entity); | ||
739 | kfree(mt9v032); | ||
740 | return 0; | ||
741 | } | ||
742 | |||
743 | static const struct i2c_device_id mt9v032_id[] = { | ||
744 | { "mt9v032", 0 }, | ||
745 | { } | ||
746 | }; | ||
747 | MODULE_DEVICE_TABLE(i2c, mt9v032_id); | ||
748 | |||
749 | static struct i2c_driver mt9v032_driver = { | ||
750 | .driver = { | ||
751 | .name = "mt9v032", | ||
752 | }, | ||
753 | .probe = mt9v032_probe, | ||
754 | .remove = mt9v032_remove, | ||
755 | .id_table = mt9v032_id, | ||
756 | }; | ||
757 | |||
758 | static int __init mt9v032_init(void) | ||
759 | { | ||
760 | return i2c_add_driver(&mt9v032_driver); | ||
761 | } | ||
762 | |||
763 | static void __exit mt9v032_exit(void) | ||
764 | { | ||
765 | i2c_del_driver(&mt9v032_driver); | ||
766 | } | ||
767 | |||
768 | module_init(mt9v032_init); | ||
769 | module_exit(mt9v032_exit); | ||
770 | |||
771 | MODULE_DESCRIPTION("Aptina MT9V032 Camera driver"); | ||
772 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); | ||
773 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index 502e2a40964c..c7680eb83664 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c | |||
@@ -400,6 +400,35 @@ static int mx3_videobuf_init(struct vb2_buffer *vb) | |||
400 | return 0; | 400 | return 0; |
401 | } | 401 | } |
402 | 402 | ||
403 | static int mx3_stop_streaming(struct vb2_queue *q) | ||
404 | { | ||
405 | struct soc_camera_device *icd = soc_camera_from_vb2q(q); | ||
406 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
407 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
408 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; | ||
409 | struct dma_chan *chan; | ||
410 | struct mx3_camera_buffer *buf, *tmp; | ||
411 | unsigned long flags; | ||
412 | |||
413 | if (ichan) { | ||
414 | chan = &ichan->dma_chan; | ||
415 | chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); | ||
416 | } | ||
417 | |||
418 | spin_lock_irqsave(&mx3_cam->lock, flags); | ||
419 | |||
420 | mx3_cam->active = NULL; | ||
421 | |||
422 | list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) { | ||
423 | buf->state = CSI_BUF_NEEDS_INIT; | ||
424 | list_del_init(&buf->queue); | ||
425 | } | ||
426 | |||
427 | spin_unlock_irqrestore(&mx3_cam->lock, flags); | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
403 | static struct vb2_ops mx3_videobuf_ops = { | 432 | static struct vb2_ops mx3_videobuf_ops = { |
404 | .queue_setup = mx3_videobuf_setup, | 433 | .queue_setup = mx3_videobuf_setup, |
405 | .buf_prepare = mx3_videobuf_prepare, | 434 | .buf_prepare = mx3_videobuf_prepare, |
@@ -408,6 +437,7 @@ static struct vb2_ops mx3_videobuf_ops = { | |||
408 | .buf_init = mx3_videobuf_init, | 437 | .buf_init = mx3_videobuf_init, |
409 | .wait_prepare = soc_camera_unlock, | 438 | .wait_prepare = soc_camera_unlock, |
410 | .wait_finish = soc_camera_lock, | 439 | .wait_finish = soc_camera_lock, |
440 | .stop_streaming = mx3_stop_streaming, | ||
411 | }; | 441 | }; |
412 | 442 | ||
413 | static int mx3_camera_init_videobuf(struct vb2_queue *q, | 443 | static int mx3_camera_init_videobuf(struct vb2_queue *q, |
@@ -658,8 +688,8 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id | |||
658 | 688 | ||
659 | fmt = soc_mbus_get_fmtdesc(code); | 689 | fmt = soc_mbus_get_fmtdesc(code); |
660 | if (!fmt) { | 690 | if (!fmt) { |
661 | dev_err(icd->dev.parent, | 691 | dev_warn(icd->dev.parent, |
662 | "Invalid format code #%u: %d\n", idx, code); | 692 | "Unsupported format code #%u: %d\n", idx, code); |
663 | return 0; | 693 | return 0; |
664 | } | 694 | } |
665 | 695 | ||
@@ -712,13 +742,9 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id | |||
712 | 742 | ||
713 | static void configure_geometry(struct mx3_camera_dev *mx3_cam, | 743 | static void configure_geometry(struct mx3_camera_dev *mx3_cam, |
714 | unsigned int width, unsigned int height, | 744 | unsigned int width, unsigned int height, |
715 | enum v4l2_mbus_pixelcode code) | 745 | const struct soc_mbus_pixelfmt *fmt) |
716 | { | 746 | { |
717 | u32 ctrl, width_field, height_field; | 747 | u32 ctrl, width_field, height_field; |
718 | const struct soc_mbus_pixelfmt *fmt; | ||
719 | |||
720 | fmt = soc_mbus_get_fmtdesc(code); | ||
721 | BUG_ON(!fmt); | ||
722 | 748 | ||
723 | if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) { | 749 | if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) { |
724 | /* | 750 | /* |
@@ -726,8 +752,10 @@ static void configure_geometry(struct mx3_camera_dev *mx3_cam, | |||
726 | * the width parameter count the number of samples to | 752 | * the width parameter count the number of samples to |
727 | * capture to complete the whole image width. | 753 | * capture to complete the whole image width. |
728 | */ | 754 | */ |
729 | width *= soc_mbus_samples_per_pixel(fmt); | 755 | unsigned int num, den; |
730 | BUG_ON(width < 0); | 756 | int ret = soc_mbus_samples_per_pixel(fmt, &num, &den); |
757 | BUG_ON(ret < 0); | ||
758 | width = width * num / den; | ||
731 | } | 759 | } |
732 | 760 | ||
733 | /* Setup frame size - this cannot be changed on-the-fly... */ | 761 | /* Setup frame size - this cannot be changed on-the-fly... */ |
@@ -774,8 +802,8 @@ static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam) | |||
774 | */ | 802 | */ |
775 | static inline void stride_align(__u32 *width) | 803 | static inline void stride_align(__u32 *width) |
776 | { | 804 | { |
777 | if (((*width + 7) & ~7) < 4096) | 805 | if (ALIGN(*width, 8) < 4096) |
778 | *width = (*width + 7) & ~7; | 806 | *width = ALIGN(*width, 8); |
779 | else | 807 | else |
780 | *width = *width & ~7; | 808 | *width = *width & ~7; |
781 | } | 809 | } |
@@ -801,11 +829,14 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, | |||
801 | if (ret < 0) | 829 | if (ret < 0) |
802 | return ret; | 830 | return ret; |
803 | 831 | ||
804 | /* The capture device might have changed its output */ | 832 | /* The capture device might have changed its output sizes */ |
805 | ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); | 833 | ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); |
806 | if (ret < 0) | 834 | if (ret < 0) |
807 | return ret; | 835 | return ret; |
808 | 836 | ||
837 | if (mf.code != icd->current_fmt->code) | ||
838 | return -EINVAL; | ||
839 | |||
809 | if (mf.width & 7) { | 840 | if (mf.width & 7) { |
810 | /* Ouch! We can only handle 8-byte aligned width... */ | 841 | /* Ouch! We can only handle 8-byte aligned width... */ |
811 | stride_align(&mf.width); | 842 | stride_align(&mf.width); |
@@ -815,7 +846,8 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, | |||
815 | } | 846 | } |
816 | 847 | ||
817 | if (mf.width != icd->user_width || mf.height != icd->user_height) | 848 | if (mf.width != icd->user_width || mf.height != icd->user_height) |
818 | configure_geometry(mx3_cam, mf.width, mf.height, mf.code); | 849 | configure_geometry(mx3_cam, mf.width, mf.height, |
850 | icd->current_fmt->host_fmt); | ||
819 | 851 | ||
820 | dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", | 852 | dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", |
821 | mf.width, mf.height); | 853 | mf.width, mf.height); |
@@ -853,7 +885,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, | |||
853 | * mxc_v4l2_s_fmt() | 885 | * mxc_v4l2_s_fmt() |
854 | */ | 886 | */ |
855 | 887 | ||
856 | configure_geometry(mx3_cam, pix->width, pix->height, xlate->code); | 888 | configure_geometry(mx3_cam, pix->width, pix->height, xlate->host_fmt); |
857 | 889 | ||
858 | mf.width = pix->width; | 890 | mf.width = pix->width; |
859 | mf.height = pix->height; | 891 | mf.height = pix->height; |
diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c index 5954b9306630..e7cfc85b0a1c 100644 --- a/drivers/media/video/omap1_camera.c +++ b/drivers/media/video/omap1_camera.c | |||
@@ -990,63 +990,80 @@ static void omap1_cam_remove_device(struct soc_camera_device *icd) | |||
990 | } | 990 | } |
991 | 991 | ||
992 | /* Duplicate standard formats based on host capability of byte swapping */ | 992 | /* Duplicate standard formats based on host capability of byte swapping */ |
993 | static const struct soc_mbus_pixelfmt omap1_cam_formats[] = { | 993 | static const struct soc_mbus_lookup omap1_cam_formats[] = { |
994 | [V4L2_MBUS_FMT_UYVY8_2X8] = { | 994 | { |
995 | .code = V4L2_MBUS_FMT_UYVY8_2X8, | ||
996 | .fmt = { | ||
995 | .fourcc = V4L2_PIX_FMT_YUYV, | 997 | .fourcc = V4L2_PIX_FMT_YUYV, |
996 | .name = "YUYV", | 998 | .name = "YUYV", |
997 | .bits_per_sample = 8, | 999 | .bits_per_sample = 8, |
998 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 1000 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
999 | .order = SOC_MBUS_ORDER_BE, | 1001 | .order = SOC_MBUS_ORDER_BE, |
1000 | }, | 1002 | }, |
1001 | [V4L2_MBUS_FMT_VYUY8_2X8] = { | 1003 | }, { |
1004 | .code = V4L2_MBUS_FMT_VYUY8_2X8, | ||
1005 | .fmt = { | ||
1002 | .fourcc = V4L2_PIX_FMT_YVYU, | 1006 | .fourcc = V4L2_PIX_FMT_YVYU, |
1003 | .name = "YVYU", | 1007 | .name = "YVYU", |
1004 | .bits_per_sample = 8, | 1008 | .bits_per_sample = 8, |
1005 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 1009 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
1006 | .order = SOC_MBUS_ORDER_BE, | 1010 | .order = SOC_MBUS_ORDER_BE, |
1007 | }, | 1011 | }, |
1008 | [V4L2_MBUS_FMT_YUYV8_2X8] = { | 1012 | }, { |
1013 | .code = V4L2_MBUS_FMT_YUYV8_2X8, | ||
1014 | .fmt = { | ||
1009 | .fourcc = V4L2_PIX_FMT_UYVY, | 1015 | .fourcc = V4L2_PIX_FMT_UYVY, |
1010 | .name = "UYVY", | 1016 | .name = "UYVY", |
1011 | .bits_per_sample = 8, | 1017 | .bits_per_sample = 8, |
1012 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 1018 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
1013 | .order = SOC_MBUS_ORDER_BE, | 1019 | .order = SOC_MBUS_ORDER_BE, |
1014 | }, | 1020 | }, |
1015 | [V4L2_MBUS_FMT_YVYU8_2X8] = { | 1021 | }, { |
1022 | .code = V4L2_MBUS_FMT_YVYU8_2X8, | ||
1023 | .fmt = { | ||
1016 | .fourcc = V4L2_PIX_FMT_VYUY, | 1024 | .fourcc = V4L2_PIX_FMT_VYUY, |
1017 | .name = "VYUY", | 1025 | .name = "VYUY", |
1018 | .bits_per_sample = 8, | 1026 | .bits_per_sample = 8, |
1019 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 1027 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
1020 | .order = SOC_MBUS_ORDER_BE, | 1028 | .order = SOC_MBUS_ORDER_BE, |
1021 | }, | 1029 | }, |
1022 | [V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE] = { | 1030 | }, { |
1031 | .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, | ||
1032 | .fmt = { | ||
1023 | .fourcc = V4L2_PIX_FMT_RGB555, | 1033 | .fourcc = V4L2_PIX_FMT_RGB555, |
1024 | .name = "RGB555", | 1034 | .name = "RGB555", |
1025 | .bits_per_sample = 8, | 1035 | .bits_per_sample = 8, |
1026 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 1036 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
1027 | .order = SOC_MBUS_ORDER_BE, | 1037 | .order = SOC_MBUS_ORDER_BE, |
1028 | }, | 1038 | }, |
1029 | [V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE] = { | 1039 | }, { |
1040 | .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, | ||
1041 | .fmt = { | ||
1030 | .fourcc = V4L2_PIX_FMT_RGB555X, | 1042 | .fourcc = V4L2_PIX_FMT_RGB555X, |
1031 | .name = "RGB555X", | 1043 | .name = "RGB555X", |
1032 | .bits_per_sample = 8, | 1044 | .bits_per_sample = 8, |
1033 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 1045 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
1034 | .order = SOC_MBUS_ORDER_BE, | 1046 | .order = SOC_MBUS_ORDER_BE, |
1035 | }, | 1047 | }, |
1036 | [V4L2_MBUS_FMT_RGB565_2X8_BE] = { | 1048 | }, { |
1049 | .code = V4L2_MBUS_FMT_RGB565_2X8_BE, | ||
1050 | .fmt = { | ||
1037 | .fourcc = V4L2_PIX_FMT_RGB565, | 1051 | .fourcc = V4L2_PIX_FMT_RGB565, |
1038 | .name = "RGB565", | 1052 | .name = "RGB565", |
1039 | .bits_per_sample = 8, | 1053 | .bits_per_sample = 8, |
1040 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 1054 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
1041 | .order = SOC_MBUS_ORDER_BE, | 1055 | .order = SOC_MBUS_ORDER_BE, |
1042 | }, | 1056 | }, |
1043 | [V4L2_MBUS_FMT_RGB565_2X8_LE] = { | 1057 | }, { |
1058 | .code = V4L2_MBUS_FMT_RGB565_2X8_LE, | ||
1059 | .fmt = { | ||
1044 | .fourcc = V4L2_PIX_FMT_RGB565X, | 1060 | .fourcc = V4L2_PIX_FMT_RGB565X, |
1045 | .name = "RGB565X", | 1061 | .name = "RGB565X", |
1046 | .bits_per_sample = 8, | 1062 | .bits_per_sample = 8, |
1047 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 1063 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
1048 | .order = SOC_MBUS_ORDER_BE, | 1064 | .order = SOC_MBUS_ORDER_BE, |
1049 | }, | 1065 | }, |
1066 | }, | ||
1050 | }; | 1067 | }; |
1051 | 1068 | ||
1052 | static int omap1_cam_get_formats(struct soc_camera_device *icd, | 1069 | static int omap1_cam_get_formats(struct soc_camera_device *icd, |
@@ -1065,7 +1082,7 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd, | |||
1065 | 1082 | ||
1066 | fmt = soc_mbus_get_fmtdesc(code); | 1083 | fmt = soc_mbus_get_fmtdesc(code); |
1067 | if (!fmt) { | 1084 | if (!fmt) { |
1068 | dev_err(dev, "%s: invalid format code #%d: %d\n", __func__, | 1085 | dev_warn(dev, "%s: unsupported format code #%d: %d\n", __func__, |
1069 | idx, code); | 1086 | idx, code); |
1070 | return 0; | 1087 | return 0; |
1071 | } | 1088 | } |
@@ -1085,12 +1102,14 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd, | |||
1085 | case V4L2_MBUS_FMT_RGB565_2X8_LE: | 1102 | case V4L2_MBUS_FMT_RGB565_2X8_LE: |
1086 | formats++; | 1103 | formats++; |
1087 | if (xlate) { | 1104 | if (xlate) { |
1088 | xlate->host_fmt = &omap1_cam_formats[code]; | 1105 | xlate->host_fmt = soc_mbus_find_fmtdesc(code, |
1106 | omap1_cam_formats, | ||
1107 | ARRAY_SIZE(omap1_cam_formats)); | ||
1089 | xlate->code = code; | 1108 | xlate->code = code; |
1090 | xlate++; | 1109 | xlate++; |
1091 | dev_dbg(dev, | 1110 | dev_dbg(dev, |
1092 | "%s: providing format %s as byte swapped code #%d\n", | 1111 | "%s: providing format %s as byte swapped code #%d\n", |
1093 | __func__, omap1_cam_formats[code].name, code); | 1112 | __func__, xlate->host_fmt->name, code); |
1094 | } | 1113 | } |
1095 | default: | 1114 | default: |
1096 | if (xlate) | 1115 | if (xlate) |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c index ca9f83a85ca5..453627b07833 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-std.c +++ b/drivers/media/video/pvrusb2/pvrusb2-std.c | |||
@@ -278,12 +278,10 @@ static struct v4l2_standard generic_standards[] = { | |||
278 | } | 278 | } |
279 | }; | 279 | }; |
280 | 280 | ||
281 | #define generic_standards_cnt ARRAY_SIZE(generic_standards) | ||
282 | |||
283 | static struct v4l2_standard *match_std(v4l2_std_id id) | 281 | static struct v4l2_standard *match_std(v4l2_std_id id) |
284 | { | 282 | { |
285 | unsigned int idx; | 283 | unsigned int idx; |
286 | for (idx = 0; idx < generic_standards_cnt; idx++) { | 284 | for (idx = 0; idx < ARRAY_SIZE(generic_standards); idx++) { |
287 | if (generic_standards[idx].id & id) { | 285 | if (generic_standards[idx].id & id) { |
288 | return generic_standards + idx; | 286 | return generic_standards + idx; |
289 | } | 287 | } |
@@ -370,7 +368,11 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, | |||
370 | 368 | ||
371 | stddefs = kzalloc(sizeof(struct v4l2_standard) * std_cnt, | 369 | stddefs = kzalloc(sizeof(struct v4l2_standard) * std_cnt, |
372 | GFP_KERNEL); | 370 | GFP_KERNEL); |
373 | for (idx = 0; idx < std_cnt; idx++) stddefs[idx].index = idx; | 371 | if (!stddefs) |
372 | return NULL; | ||
373 | |||
374 | for (idx = 0; idx < std_cnt; idx++) | ||
375 | stddefs[idx].index = idx; | ||
374 | 376 | ||
375 | idx = 0; | 377 | idx = 0; |
376 | 378 | ||
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 780af5f81642..356cd42b593b 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c | |||
@@ -1850,7 +1850,6 @@ static void usb_pwc_disconnect(struct usb_interface *intf) | |||
1850 | } else { | 1850 | } else { |
1851 | /* Device is closed, so we can safely unregister it */ | 1851 | /* Device is closed, so we can safely unregister it */ |
1852 | PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n"); | 1852 | PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n"); |
1853 | pwc_cleanup(pdev); | ||
1854 | 1853 | ||
1855 | disconnect_out: | 1854 | disconnect_out: |
1856 | /* search device_hint[] table if we occupy a slot, by any chance */ | 1855 | /* search device_hint[] table if we occupy a slot, by any chance */ |
@@ -1860,6 +1859,7 @@ disconnect_out: | |||
1860 | } | 1859 | } |
1861 | 1860 | ||
1862 | mutex_unlock(&pdev->modlock); | 1861 | mutex_unlock(&pdev->modlock); |
1862 | pwc_cleanup(pdev); | ||
1863 | } | 1863 | } |
1864 | 1864 | ||
1865 | 1865 | ||
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index aa87e462a958..f85c51249c7b 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c | |||
@@ -379,8 +379,27 @@ static int pwc_s_input(struct file *file, void *fh, unsigned int i) | |||
379 | 379 | ||
380 | static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) | 380 | static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) |
381 | { | 381 | { |
382 | int i; | 382 | int i, idx; |
383 | 383 | u32 id; | |
384 | |||
385 | id = c->id; | ||
386 | if (id & V4L2_CTRL_FLAG_NEXT_CTRL) { | ||
387 | id &= V4L2_CTRL_ID_MASK; | ||
388 | id++; | ||
389 | idx = -1; | ||
390 | for (i = 0; i < ARRAY_SIZE(pwc_controls); i++) { | ||
391 | if (pwc_controls[i].id < id) | ||
392 | continue; | ||
393 | if (idx >= 0 | ||
394 | && pwc_controls[i].id > pwc_controls[idx].id) | ||
395 | continue; | ||
396 | idx = i; | ||
397 | } | ||
398 | if (idx < 0) | ||
399 | return -EINVAL; | ||
400 | memcpy(c, &pwc_controls[idx], sizeof pwc_controls[0]); | ||
401 | return 0; | ||
402 | } | ||
384 | for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) { | 403 | for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) { |
385 | if (pwc_controls[i].id == c->id) { | 404 | if (pwc_controls[i].id == c->id) { |
386 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n"); | 405 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n"); |
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index c1ee09a043ba..b42bfa5ccdf2 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
@@ -1155,15 +1155,11 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1155 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 1155 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
1156 | struct pxa_camera_dev *pcdev = ici->priv; | 1156 | struct pxa_camera_dev *pcdev = ici->priv; |
1157 | unsigned long bus_flags, camera_flags, common_flags; | 1157 | unsigned long bus_flags, camera_flags, common_flags; |
1158 | const struct soc_mbus_pixelfmt *fmt; | ||
1159 | int ret; | 1158 | int ret; |
1160 | struct pxa_cam *cam = icd->host_priv; | 1159 | struct pxa_cam *cam = icd->host_priv; |
1161 | 1160 | ||
1162 | fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code); | 1161 | ret = test_platform_param(pcdev, icd->current_fmt->host_fmt->bits_per_sample, |
1163 | if (!fmt) | 1162 | &bus_flags); |
1164 | return -EINVAL; | ||
1165 | |||
1166 | ret = test_platform_param(pcdev, fmt->bits_per_sample, &bus_flags); | ||
1167 | if (ret < 0) | 1163 | if (ret < 0) |
1168 | return ret; | 1164 | return ret; |
1169 | 1165 | ||
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index 561909b65ce6..5b9dce85645c 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c | |||
@@ -394,12 +394,17 @@ static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ | |||
394 | /* start video number */ | 394 | /* start video number */ |
395 | static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ | 395 | static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ |
396 | 396 | ||
397 | /* Enable jpeg capture. */ | ||
398 | static int jpeg_enable = 1; | ||
399 | |||
397 | module_param(debug, int, 0644); | 400 | module_param(debug, int, 0644); |
398 | MODULE_PARM_DESC(debug, "Debug level(0-100) default 0"); | 401 | MODULE_PARM_DESC(debug, "Debug level(0-100) default 0"); |
399 | module_param(vid_limit, int, 0644); | 402 | module_param(vid_limit, int, 0644); |
400 | MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)"); | 403 | MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)"); |
401 | module_param(video_nr, int, 0644); | 404 | module_param(video_nr, int, 0644); |
402 | MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)"); | 405 | MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)"); |
406 | module_param(jpeg_enable, int, 0644); | ||
407 | MODULE_PARM_DESC(jpeg_enable, "Jpeg enable(1-on 0-off) default 1"); | ||
403 | 408 | ||
404 | /* USB device table */ | 409 | /* USB device table */ |
405 | #define USB_SENSORAY_VID 0x1943 | 410 | #define USB_SENSORAY_VID 0x1943 |
@@ -413,6 +418,7 @@ MODULE_DEVICE_TABLE(usb, s2255_table); | |||
413 | #define BUFFER_TIMEOUT msecs_to_jiffies(400) | 418 | #define BUFFER_TIMEOUT msecs_to_jiffies(400) |
414 | 419 | ||
415 | /* image formats. */ | 420 | /* image formats. */ |
421 | /* JPEG formats must be defined last to support jpeg_enable parameter */ | ||
416 | static const struct s2255_fmt formats[] = { | 422 | static const struct s2255_fmt formats[] = { |
417 | { | 423 | { |
418 | .name = "4:2:2, planar, YUV422P", | 424 | .name = "4:2:2, planar, YUV422P", |
@@ -429,13 +435,17 @@ static const struct s2255_fmt formats[] = { | |||
429 | .fourcc = V4L2_PIX_FMT_UYVY, | 435 | .fourcc = V4L2_PIX_FMT_UYVY, |
430 | .depth = 16 | 436 | .depth = 16 |
431 | }, { | 437 | }, { |
438 | .name = "8bpp GREY", | ||
439 | .fourcc = V4L2_PIX_FMT_GREY, | ||
440 | .depth = 8 | ||
441 | }, { | ||
432 | .name = "JPG", | 442 | .name = "JPG", |
433 | .fourcc = V4L2_PIX_FMT_JPEG, | 443 | .fourcc = V4L2_PIX_FMT_JPEG, |
434 | .depth = 24 | 444 | .depth = 24 |
435 | }, { | 445 | }, { |
436 | .name = "8bpp GREY", | 446 | .name = "MJPG", |
437 | .fourcc = V4L2_PIX_FMT_GREY, | 447 | .fourcc = V4L2_PIX_FMT_MJPEG, |
438 | .depth = 8 | 448 | .depth = 24 |
439 | } | 449 | } |
440 | }; | 450 | }; |
441 | 451 | ||
@@ -610,6 +620,9 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc) | |||
610 | for (i = 0; i < ARRAY_SIZE(formats); i++) { | 620 | for (i = 0; i < ARRAY_SIZE(formats); i++) { |
611 | if (-1 == formats[i].fourcc) | 621 | if (-1 == formats[i].fourcc) |
612 | continue; | 622 | continue; |
623 | if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) || | ||
624 | (formats[i].fourcc == V4L2_PIX_FMT_MJPEG))) | ||
625 | continue; | ||
613 | if (formats[i].fourcc == fourcc) | 626 | if (formats[i].fourcc == fourcc) |
614 | return formats + i; | 627 | return formats + i; |
615 | } | 628 | } |
@@ -653,6 +666,7 @@ static void s2255_fillbuff(struct s2255_channel *channel, | |||
653 | memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height); | 666 | memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height); |
654 | break; | 667 | break; |
655 | case V4L2_PIX_FMT_JPEG: | 668 | case V4L2_PIX_FMT_JPEG: |
669 | case V4L2_PIX_FMT_MJPEG: | ||
656 | buf->vb.size = jpgsize; | 670 | buf->vb.size = jpgsize; |
657 | memcpy(vbuf, tmpbuf, buf->vb.size); | 671 | memcpy(vbuf, tmpbuf, buf->vb.size); |
658 | break; | 672 | break; |
@@ -856,7 +870,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | |||
856 | 870 | ||
857 | if (index >= ARRAY_SIZE(formats)) | 871 | if (index >= ARRAY_SIZE(formats)) |
858 | return -EINVAL; | 872 | return -EINVAL; |
859 | 873 | if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) || | |
874 | (formats[index].fourcc == V4L2_PIX_FMT_MJPEG))) | ||
875 | return -EINVAL; | ||
860 | dprintk(4, "name %s\n", formats[index].name); | 876 | dprintk(4, "name %s\n", formats[index].name); |
861 | strlcpy(f->description, formats[index].name, sizeof(f->description)); | 877 | strlcpy(f->description, formats[index].name, sizeof(f->description)); |
862 | f->pixelformat = formats[index].fourcc; | 878 | f->pixelformat = formats[index].fourcc; |
@@ -1037,6 +1053,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | |||
1037 | mode.color |= COLOR_Y8; | 1053 | mode.color |= COLOR_Y8; |
1038 | break; | 1054 | break; |
1039 | case V4L2_PIX_FMT_JPEG: | 1055 | case V4L2_PIX_FMT_JPEG: |
1056 | case V4L2_PIX_FMT_MJPEG: | ||
1040 | mode.color &= ~MASK_COLOR; | 1057 | mode.color &= ~MASK_COLOR; |
1041 | mode.color |= COLOR_JPG; | 1058 | mode.color |= COLOR_JPG; |
1042 | mode.color |= (channel->jc.quality << 8); | 1059 | mode.color |= (channel->jc.quality << 8); |
@@ -2382,7 +2399,7 @@ static void read_pipe_completion(struct urb *purb) | |||
2382 | read_pipe_completion, pipe_info); | 2399 | read_pipe_completion, pipe_info); |
2383 | 2400 | ||
2384 | if (pipe_info->state != 0) { | 2401 | if (pipe_info->state != 0) { |
2385 | if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) { | 2402 | if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) { |
2386 | dev_err(&dev->udev->dev, "error submitting urb\n"); | 2403 | dev_err(&dev->udev->dev, "error submitting urb\n"); |
2387 | } | 2404 | } |
2388 | } else { | 2405 | } else { |
diff --git a/drivers/media/video/s5p-fimc/Makefile b/drivers/media/video/s5p-fimc/Makefile index 7ea1b1403b1e..df6954ab1d99 100644 --- a/drivers/media/video/s5p-fimc/Makefile +++ b/drivers/media/video/s5p-fimc/Makefile | |||
@@ -1,3 +1,5 @@ | |||
1 | s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-capture.o | ||
2 | s5p-csis-objs := mipi-csis.o | ||
1 | 3 | ||
2 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) := s5p-fimc.o | 4 | obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS) += s5p-csis.o |
3 | s5p-fimc-y := fimc-core.o fimc-reg.o fimc-capture.o | 5 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc.o |
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c new file mode 100644 index 000000000000..ef056d6605ca --- /dev/null +++ b/drivers/media/video/s5p-fimc/mipi-csis.c | |||
@@ -0,0 +1,724 @@ | |||
1 | /* | ||
2 | * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
5 | * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com> | ||
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 version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/irq.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/memory.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/pm_runtime.h> | ||
24 | #include <linux/regulator/consumer.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/videodev2.h> | ||
28 | #include <media/v4l2-subdev.h> | ||
29 | #include <plat/mipi_csis.h> | ||
30 | #include "mipi-csis.h" | ||
31 | |||
32 | static int debug; | ||
33 | module_param(debug, int, 0644); | ||
34 | MODULE_PARM_DESC(debug, "Debug level (0-1)"); | ||
35 | |||
36 | /* Register map definition */ | ||
37 | |||
38 | /* CSIS global control */ | ||
39 | #define S5PCSIS_CTRL 0x00 | ||
40 | #define S5PCSIS_CTRL_DPDN_DEFAULT (0 << 31) | ||
41 | #define S5PCSIS_CTRL_DPDN_SWAP (1 << 31) | ||
42 | #define S5PCSIS_CTRL_ALIGN_32BIT (1 << 20) | ||
43 | #define S5PCSIS_CTRL_UPDATE_SHADOW (1 << 16) | ||
44 | #define S5PCSIS_CTRL_WCLK_EXTCLK (1 << 8) | ||
45 | #define S5PCSIS_CTRL_RESET (1 << 4) | ||
46 | #define S5PCSIS_CTRL_ENABLE (1 << 0) | ||
47 | |||
48 | /* D-PHY control */ | ||
49 | #define S5PCSIS_DPHYCTRL 0x04 | ||
50 | #define S5PCSIS_DPHYCTRL_HSS_MASK (0x1f << 27) | ||
51 | #define S5PCSIS_DPHYCTRL_ENABLE (0x1f << 0) | ||
52 | |||
53 | #define S5PCSIS_CONFIG 0x08 | ||
54 | #define S5PCSIS_CFG_FMT_YCBCR422_8BIT (0x1e << 2) | ||
55 | #define S5PCSIS_CFG_FMT_RAW8 (0x2a << 2) | ||
56 | #define S5PCSIS_CFG_FMT_RAW10 (0x2b << 2) | ||
57 | #define S5PCSIS_CFG_FMT_RAW12 (0x2c << 2) | ||
58 | /* User defined formats, x = 1...4 */ | ||
59 | #define S5PCSIS_CFG_FMT_USER(x) ((0x30 + x - 1) << 2) | ||
60 | #define S5PCSIS_CFG_FMT_MASK (0x3f << 2) | ||
61 | #define S5PCSIS_CFG_NR_LANE_MASK 3 | ||
62 | |||
63 | /* Interrupt mask. */ | ||
64 | #define S5PCSIS_INTMSK 0x10 | ||
65 | #define S5PCSIS_INTMSK_EN_ALL 0xf000003f | ||
66 | #define S5PCSIS_INTSRC 0x14 | ||
67 | |||
68 | /* Pixel resolution */ | ||
69 | #define S5PCSIS_RESOL 0x2c | ||
70 | #define CSIS_MAX_PIX_WIDTH 0xffff | ||
71 | #define CSIS_MAX_PIX_HEIGHT 0xffff | ||
72 | |||
73 | enum { | ||
74 | CSIS_CLK_MUX, | ||
75 | CSIS_CLK_GATE, | ||
76 | }; | ||
77 | |||
78 | static char *csi_clock_name[] = { | ||
79 | [CSIS_CLK_MUX] = "sclk_csis", | ||
80 | [CSIS_CLK_GATE] = "csis", | ||
81 | }; | ||
82 | #define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name) | ||
83 | |||
84 | enum { | ||
85 | ST_POWERED = 1, | ||
86 | ST_STREAMING = 2, | ||
87 | ST_SUSPENDED = 4, | ||
88 | }; | ||
89 | |||
90 | /** | ||
91 | * struct csis_state - the driver's internal state data structure | ||
92 | * @lock: mutex serializing the subdev and power management operations, | ||
93 | * protecting @format and @flags members | ||
94 | * @pads: CSIS pads array | ||
95 | * @sd: v4l2_subdev associated with CSIS device instance | ||
96 | * @pdev: CSIS platform device | ||
97 | * @regs_res: requested I/O register memory resource | ||
98 | * @regs: mmaped I/O registers memory | ||
99 | * @clock: CSIS clocks | ||
100 | * @irq: requested s5p-mipi-csis irq number | ||
101 | * @flags: the state variable for power and streaming control | ||
102 | * @csis_fmt: current CSIS pixel format | ||
103 | * @format: common media bus format for the source and sink pad | ||
104 | */ | ||
105 | struct csis_state { | ||
106 | struct mutex lock; | ||
107 | struct media_pad pads[CSIS_PADS_NUM]; | ||
108 | struct v4l2_subdev sd; | ||
109 | struct platform_device *pdev; | ||
110 | struct resource *regs_res; | ||
111 | void __iomem *regs; | ||
112 | struct clk *clock[NUM_CSIS_CLOCKS]; | ||
113 | int irq; | ||
114 | struct regulator *supply; | ||
115 | u32 flags; | ||
116 | const struct csis_pix_format *csis_fmt; | ||
117 | struct v4l2_mbus_framefmt format; | ||
118 | }; | ||
119 | |||
120 | /** | ||
121 | * struct csis_pix_format - CSIS pixel format description | ||
122 | * @pix_width_alignment: horizontal pixel alignment, width will be | ||
123 | * multiple of 2^pix_width_alignment | ||
124 | * @code: corresponding media bus code | ||
125 | * @fmt_reg: S5PCSIS_CONFIG register value | ||
126 | */ | ||
127 | struct csis_pix_format { | ||
128 | unsigned int pix_width_alignment; | ||
129 | enum v4l2_mbus_pixelcode code; | ||
130 | u32 fmt_reg; | ||
131 | }; | ||
132 | |||
133 | static const struct csis_pix_format s5pcsis_formats[] = { | ||
134 | { | ||
135 | .code = V4L2_MBUS_FMT_VYUY8_2X8, | ||
136 | .fmt_reg = S5PCSIS_CFG_FMT_YCBCR422_8BIT, | ||
137 | }, { | ||
138 | .code = V4L2_MBUS_FMT_JPEG_1X8, | ||
139 | .fmt_reg = S5PCSIS_CFG_FMT_USER(1), | ||
140 | }, | ||
141 | }; | ||
142 | |||
143 | #define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r) | ||
144 | #define s5pcsis_read(__csis, __r) readl(__csis->regs + __r) | ||
145 | |||
146 | static struct csis_state *sd_to_csis_state(struct v4l2_subdev *sdev) | ||
147 | { | ||
148 | return container_of(sdev, struct csis_state, sd); | ||
149 | } | ||
150 | |||
151 | static const struct csis_pix_format *find_csis_format( | ||
152 | struct v4l2_mbus_framefmt *mf) | ||
153 | { | ||
154 | int i; | ||
155 | |||
156 | for (i = 0; i < ARRAY_SIZE(s5pcsis_formats); i++) | ||
157 | if (mf->code == s5pcsis_formats[i].code) | ||
158 | return &s5pcsis_formats[i]; | ||
159 | return NULL; | ||
160 | } | ||
161 | |||
162 | static void s5pcsis_enable_interrupts(struct csis_state *state, bool on) | ||
163 | { | ||
164 | u32 val = s5pcsis_read(state, S5PCSIS_INTMSK); | ||
165 | |||
166 | val = on ? val | S5PCSIS_INTMSK_EN_ALL : | ||
167 | val & ~S5PCSIS_INTMSK_EN_ALL; | ||
168 | s5pcsis_write(state, S5PCSIS_INTMSK, val); | ||
169 | } | ||
170 | |||
171 | static void s5pcsis_reset(struct csis_state *state) | ||
172 | { | ||
173 | u32 val = s5pcsis_read(state, S5PCSIS_CTRL); | ||
174 | |||
175 | s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_RESET); | ||
176 | udelay(10); | ||
177 | } | ||
178 | |||
179 | static void s5pcsis_system_enable(struct csis_state *state, int on) | ||
180 | { | ||
181 | u32 val; | ||
182 | |||
183 | val = s5pcsis_read(state, S5PCSIS_CTRL); | ||
184 | if (on) | ||
185 | val |= S5PCSIS_CTRL_ENABLE; | ||
186 | else | ||
187 | val &= ~S5PCSIS_CTRL_ENABLE; | ||
188 | s5pcsis_write(state, S5PCSIS_CTRL, val); | ||
189 | |||
190 | val = s5pcsis_read(state, S5PCSIS_DPHYCTRL); | ||
191 | if (on) | ||
192 | val |= S5PCSIS_DPHYCTRL_ENABLE; | ||
193 | else | ||
194 | val &= ~S5PCSIS_DPHYCTRL_ENABLE; | ||
195 | s5pcsis_write(state, S5PCSIS_DPHYCTRL, val); | ||
196 | } | ||
197 | |||
198 | /* Called with the state.lock mutex held */ | ||
199 | static void __s5pcsis_set_format(struct csis_state *state) | ||
200 | { | ||
201 | struct v4l2_mbus_framefmt *mf = &state->format; | ||
202 | u32 val; | ||
203 | |||
204 | v4l2_dbg(1, debug, &state->sd, "fmt: %d, %d x %d\n", | ||
205 | mf->code, mf->width, mf->height); | ||
206 | |||
207 | /* Color format */ | ||
208 | val = s5pcsis_read(state, S5PCSIS_CONFIG); | ||
209 | val = (val & ~S5PCSIS_CFG_FMT_MASK) | state->csis_fmt->fmt_reg; | ||
210 | s5pcsis_write(state, S5PCSIS_CONFIG, val); | ||
211 | |||
212 | /* Pixel resolution */ | ||
213 | val = (mf->width << 16) | mf->height; | ||
214 | s5pcsis_write(state, S5PCSIS_RESOL, val); | ||
215 | } | ||
216 | |||
217 | static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle) | ||
218 | { | ||
219 | u32 val = s5pcsis_read(state, S5PCSIS_DPHYCTRL); | ||
220 | |||
221 | val = (val & ~S5PCSIS_DPHYCTRL_HSS_MASK) | (settle << 27); | ||
222 | s5pcsis_write(state, S5PCSIS_DPHYCTRL, val); | ||
223 | } | ||
224 | |||
225 | static void s5pcsis_set_params(struct csis_state *state) | ||
226 | { | ||
227 | struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data; | ||
228 | u32 val; | ||
229 | |||
230 | val = s5pcsis_read(state, S5PCSIS_CONFIG); | ||
231 | val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (pdata->lanes - 1); | ||
232 | s5pcsis_write(state, S5PCSIS_CONFIG, val); | ||
233 | |||
234 | __s5pcsis_set_format(state); | ||
235 | s5pcsis_set_hsync_settle(state, pdata->hs_settle); | ||
236 | |||
237 | val = s5pcsis_read(state, S5PCSIS_CTRL); | ||
238 | if (pdata->alignment == 32) | ||
239 | val |= S5PCSIS_CTRL_ALIGN_32BIT; | ||
240 | else /* 24-bits */ | ||
241 | val &= ~S5PCSIS_CTRL_ALIGN_32BIT; | ||
242 | /* Not using external clock. */ | ||
243 | val &= ~S5PCSIS_CTRL_WCLK_EXTCLK; | ||
244 | s5pcsis_write(state, S5PCSIS_CTRL, val); | ||
245 | |||
246 | /* Update the shadow register. */ | ||
247 | val = s5pcsis_read(state, S5PCSIS_CTRL); | ||
248 | s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_UPDATE_SHADOW); | ||
249 | } | ||
250 | |||
251 | static void s5pcsis_clk_put(struct csis_state *state) | ||
252 | { | ||
253 | int i; | ||
254 | |||
255 | for (i = 0; i < NUM_CSIS_CLOCKS; i++) | ||
256 | if (!IS_ERR_OR_NULL(state->clock[i])) | ||
257 | clk_put(state->clock[i]); | ||
258 | } | ||
259 | |||
260 | static int s5pcsis_clk_get(struct csis_state *state) | ||
261 | { | ||
262 | struct device *dev = &state->pdev->dev; | ||
263 | int i; | ||
264 | |||
265 | for (i = 0; i < NUM_CSIS_CLOCKS; i++) { | ||
266 | state->clock[i] = clk_get(dev, csi_clock_name[i]); | ||
267 | if (IS_ERR(state->clock[i])) { | ||
268 | s5pcsis_clk_put(state); | ||
269 | dev_err(dev, "failed to get clock: %s\n", | ||
270 | csi_clock_name[i]); | ||
271 | return -ENXIO; | ||
272 | } | ||
273 | } | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | static int s5pcsis_s_power(struct v4l2_subdev *sd, int on) | ||
278 | { | ||
279 | struct csis_state *state = sd_to_csis_state(sd); | ||
280 | struct device *dev = &state->pdev->dev; | ||
281 | |||
282 | if (on) | ||
283 | return pm_runtime_get_sync(dev); | ||
284 | |||
285 | return pm_runtime_put_sync(dev); | ||
286 | } | ||
287 | |||
288 | static void s5pcsis_start_stream(struct csis_state *state) | ||
289 | { | ||
290 | s5pcsis_reset(state); | ||
291 | s5pcsis_set_params(state); | ||
292 | s5pcsis_system_enable(state, true); | ||
293 | s5pcsis_enable_interrupts(state, true); | ||
294 | } | ||
295 | |||
296 | static void s5pcsis_stop_stream(struct csis_state *state) | ||
297 | { | ||
298 | s5pcsis_enable_interrupts(state, false); | ||
299 | s5pcsis_system_enable(state, false); | ||
300 | } | ||
301 | |||
302 | /* v4l2_subdev operations */ | ||
303 | static int s5pcsis_s_stream(struct v4l2_subdev *sd, int enable) | ||
304 | { | ||
305 | struct csis_state *state = sd_to_csis_state(sd); | ||
306 | int ret = 0; | ||
307 | |||
308 | v4l2_dbg(1, debug, sd, "%s: %d, state: 0x%x\n", | ||
309 | __func__, enable, state->flags); | ||
310 | |||
311 | if (enable) { | ||
312 | ret = pm_runtime_get_sync(&state->pdev->dev); | ||
313 | if (ret && ret != 1) | ||
314 | return ret; | ||
315 | } | ||
316 | mutex_lock(&state->lock); | ||
317 | if (enable) { | ||
318 | if (state->flags & ST_SUSPENDED) { | ||
319 | ret = -EBUSY; | ||
320 | goto unlock; | ||
321 | } | ||
322 | s5pcsis_start_stream(state); | ||
323 | state->flags |= ST_STREAMING; | ||
324 | } else { | ||
325 | s5pcsis_stop_stream(state); | ||
326 | state->flags &= ~ST_STREAMING; | ||
327 | } | ||
328 | unlock: | ||
329 | mutex_unlock(&state->lock); | ||
330 | if (!enable) | ||
331 | pm_runtime_put(&state->pdev->dev); | ||
332 | |||
333 | return ret == 1 ? 0 : ret; | ||
334 | } | ||
335 | |||
336 | static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd, | ||
337 | struct v4l2_subdev_fh *fh, | ||
338 | struct v4l2_subdev_mbus_code_enum *code) | ||
339 | { | ||
340 | if (code->index >= ARRAY_SIZE(s5pcsis_formats)) | ||
341 | return -EINVAL; | ||
342 | |||
343 | code->code = s5pcsis_formats[code->index].code; | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static struct csis_pix_format const *s5pcsis_try_format( | ||
348 | struct v4l2_mbus_framefmt *mf) | ||
349 | { | ||
350 | struct csis_pix_format const *csis_fmt; | ||
351 | |||
352 | csis_fmt = find_csis_format(mf); | ||
353 | if (csis_fmt == NULL) | ||
354 | csis_fmt = &s5pcsis_formats[0]; | ||
355 | |||
356 | mf->code = csis_fmt->code; | ||
357 | v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH, | ||
358 | csis_fmt->pix_width_alignment, | ||
359 | &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1, | ||
360 | 0); | ||
361 | return csis_fmt; | ||
362 | } | ||
363 | |||
364 | static struct v4l2_mbus_framefmt *__s5pcsis_get_format( | ||
365 | struct csis_state *state, struct v4l2_subdev_fh *fh, | ||
366 | u32 pad, enum v4l2_subdev_format_whence which) | ||
367 | { | ||
368 | if (which == V4L2_SUBDEV_FORMAT_TRY) | ||
369 | return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL; | ||
370 | |||
371 | return &state->format; | ||
372 | } | ||
373 | |||
374 | static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
375 | struct v4l2_subdev_format *fmt) | ||
376 | { | ||
377 | struct csis_state *state = sd_to_csis_state(sd); | ||
378 | struct csis_pix_format const *csis_fmt; | ||
379 | struct v4l2_mbus_framefmt *mf; | ||
380 | |||
381 | if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK) | ||
382 | return -EINVAL; | ||
383 | |||
384 | mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which); | ||
385 | |||
386 | if (fmt->pad == CSIS_PAD_SOURCE) { | ||
387 | if (mf) { | ||
388 | mutex_lock(&state->lock); | ||
389 | fmt->format = *mf; | ||
390 | mutex_unlock(&state->lock); | ||
391 | } | ||
392 | return 0; | ||
393 | } | ||
394 | csis_fmt = s5pcsis_try_format(&fmt->format); | ||
395 | if (mf) { | ||
396 | mutex_lock(&state->lock); | ||
397 | *mf = fmt->format; | ||
398 | if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) | ||
399 | state->csis_fmt = csis_fmt; | ||
400 | mutex_unlock(&state->lock); | ||
401 | } | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
406 | struct v4l2_subdev_format *fmt) | ||
407 | { | ||
408 | struct csis_state *state = sd_to_csis_state(sd); | ||
409 | struct v4l2_mbus_framefmt *mf; | ||
410 | |||
411 | if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK) | ||
412 | return -EINVAL; | ||
413 | |||
414 | mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which); | ||
415 | if (!mf) | ||
416 | return -EINVAL; | ||
417 | |||
418 | mutex_lock(&state->lock); | ||
419 | fmt->format = *mf; | ||
420 | mutex_unlock(&state->lock); | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static struct v4l2_subdev_core_ops s5pcsis_core_ops = { | ||
425 | .s_power = s5pcsis_s_power, | ||
426 | }; | ||
427 | |||
428 | static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = { | ||
429 | .enum_mbus_code = s5pcsis_enum_mbus_code, | ||
430 | .get_fmt = s5pcsis_get_fmt, | ||
431 | .set_fmt = s5pcsis_set_fmt, | ||
432 | }; | ||
433 | |||
434 | static struct v4l2_subdev_video_ops s5pcsis_video_ops = { | ||
435 | .s_stream = s5pcsis_s_stream, | ||
436 | }; | ||
437 | |||
438 | static struct v4l2_subdev_ops s5pcsis_subdev_ops = { | ||
439 | .core = &s5pcsis_core_ops, | ||
440 | .pad = &s5pcsis_pad_ops, | ||
441 | .video = &s5pcsis_video_ops, | ||
442 | }; | ||
443 | |||
444 | static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id) | ||
445 | { | ||
446 | struct csis_state *state = dev_id; | ||
447 | u32 val; | ||
448 | |||
449 | /* Just clear the interrupt pending bits. */ | ||
450 | val = s5pcsis_read(state, S5PCSIS_INTSRC); | ||
451 | s5pcsis_write(state, S5PCSIS_INTSRC, val); | ||
452 | |||
453 | return IRQ_HANDLED; | ||
454 | } | ||
455 | |||
456 | static int __devinit s5pcsis_probe(struct platform_device *pdev) | ||
457 | { | ||
458 | struct s5p_platform_mipi_csis *pdata; | ||
459 | struct resource *mem_res; | ||
460 | struct resource *regs_res; | ||
461 | struct csis_state *state; | ||
462 | int ret = -ENOMEM; | ||
463 | |||
464 | state = kzalloc(sizeof(*state), GFP_KERNEL); | ||
465 | if (!state) | ||
466 | return -ENOMEM; | ||
467 | |||
468 | mutex_init(&state->lock); | ||
469 | state->pdev = pdev; | ||
470 | |||
471 | pdata = pdev->dev.platform_data; | ||
472 | if (pdata == NULL || pdata->phy_enable == NULL) { | ||
473 | dev_err(&pdev->dev, "Platform data not fully specified\n"); | ||
474 | goto e_free; | ||
475 | } | ||
476 | |||
477 | if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) || | ||
478 | pdata->lanes > CSIS0_MAX_LANES) { | ||
479 | ret = -EINVAL; | ||
480 | dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n", | ||
481 | pdata->lanes); | ||
482 | goto e_free; | ||
483 | } | ||
484 | |||
485 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
486 | if (!mem_res) { | ||
487 | dev_err(&pdev->dev, "Failed to get IO memory region\n"); | ||
488 | goto e_free; | ||
489 | } | ||
490 | |||
491 | regs_res = request_mem_region(mem_res->start, resource_size(mem_res), | ||
492 | pdev->name); | ||
493 | if (!regs_res) { | ||
494 | dev_err(&pdev->dev, "Failed to request IO memory region\n"); | ||
495 | goto e_free; | ||
496 | } | ||
497 | state->regs_res = regs_res; | ||
498 | |||
499 | state->regs = ioremap(mem_res->start, resource_size(mem_res)); | ||
500 | if (!state->regs) { | ||
501 | dev_err(&pdev->dev, "Failed to remap IO region\n"); | ||
502 | goto e_reqmem; | ||
503 | } | ||
504 | |||
505 | ret = s5pcsis_clk_get(state); | ||
506 | if (ret) | ||
507 | goto e_unmap; | ||
508 | |||
509 | clk_enable(state->clock[CSIS_CLK_MUX]); | ||
510 | if (pdata->clk_rate) | ||
511 | clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate); | ||
512 | else | ||
513 | dev_WARN(&pdev->dev, "No clock frequency specified!\n"); | ||
514 | |||
515 | state->irq = platform_get_irq(pdev, 0); | ||
516 | if (state->irq < 0) { | ||
517 | ret = state->irq; | ||
518 | dev_err(&pdev->dev, "Failed to get irq\n"); | ||
519 | goto e_clkput; | ||
520 | } | ||
521 | |||
522 | if (!pdata->fixed_phy_vdd) { | ||
523 | state->supply = regulator_get(&pdev->dev, "vdd"); | ||
524 | if (IS_ERR(state->supply)) { | ||
525 | ret = PTR_ERR(state->supply); | ||
526 | state->supply = NULL; | ||
527 | goto e_clkput; | ||
528 | } | ||
529 | } | ||
530 | |||
531 | ret = request_irq(state->irq, s5pcsis_irq_handler, 0, | ||
532 | dev_name(&pdev->dev), state); | ||
533 | if (ret) { | ||
534 | dev_err(&pdev->dev, "request_irq failed\n"); | ||
535 | goto e_regput; | ||
536 | } | ||
537 | |||
538 | v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops); | ||
539 | state->sd.owner = THIS_MODULE; | ||
540 | strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name)); | ||
541 | state->csis_fmt = &s5pcsis_formats[0]; | ||
542 | |||
543 | state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | ||
544 | state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; | ||
545 | ret = media_entity_init(&state->sd.entity, | ||
546 | CSIS_PADS_NUM, state->pads, 0); | ||
547 | if (ret < 0) | ||
548 | goto e_irqfree; | ||
549 | |||
550 | /* This allows to retrieve the platform device id by the host driver */ | ||
551 | v4l2_set_subdevdata(&state->sd, pdev); | ||
552 | |||
553 | /* .. and a pointer to the subdev. */ | ||
554 | platform_set_drvdata(pdev, &state->sd); | ||
555 | |||
556 | state->flags = ST_SUSPENDED; | ||
557 | pm_runtime_enable(&pdev->dev); | ||
558 | |||
559 | return 0; | ||
560 | |||
561 | e_irqfree: | ||
562 | free_irq(state->irq, state); | ||
563 | e_regput: | ||
564 | if (state->supply) | ||
565 | regulator_put(state->supply); | ||
566 | e_clkput: | ||
567 | clk_disable(state->clock[CSIS_CLK_MUX]); | ||
568 | s5pcsis_clk_put(state); | ||
569 | e_unmap: | ||
570 | iounmap(state->regs); | ||
571 | e_reqmem: | ||
572 | release_mem_region(regs_res->start, resource_size(regs_res)); | ||
573 | e_free: | ||
574 | kfree(state); | ||
575 | return ret; | ||
576 | } | ||
577 | |||
578 | static int s5pcsis_suspend(struct device *dev) | ||
579 | { | ||
580 | struct s5p_platform_mipi_csis *pdata = dev->platform_data; | ||
581 | struct platform_device *pdev = to_platform_device(dev); | ||
582 | struct v4l2_subdev *sd = platform_get_drvdata(pdev); | ||
583 | struct csis_state *state = sd_to_csis_state(sd); | ||
584 | int ret = 0; | ||
585 | |||
586 | v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n", | ||
587 | __func__, state->flags); | ||
588 | |||
589 | mutex_lock(&state->lock); | ||
590 | if (state->flags & ST_POWERED) { | ||
591 | s5pcsis_stop_stream(state); | ||
592 | ret = pdata->phy_enable(state->pdev, false); | ||
593 | if (ret) | ||
594 | goto unlock; | ||
595 | if (state->supply) { | ||
596 | ret = regulator_disable(state->supply); | ||
597 | if (ret) | ||
598 | goto unlock; | ||
599 | } | ||
600 | clk_disable(state->clock[CSIS_CLK_GATE]); | ||
601 | state->flags &= ~ST_POWERED; | ||
602 | } | ||
603 | state->flags |= ST_SUSPENDED; | ||
604 | unlock: | ||
605 | mutex_unlock(&state->lock); | ||
606 | return ret ? -EAGAIN : 0; | ||
607 | } | ||
608 | |||
609 | static int s5pcsis_resume(struct device *dev) | ||
610 | { | ||
611 | struct s5p_platform_mipi_csis *pdata = dev->platform_data; | ||
612 | struct platform_device *pdev = to_platform_device(dev); | ||
613 | struct v4l2_subdev *sd = platform_get_drvdata(pdev); | ||
614 | struct csis_state *state = sd_to_csis_state(sd); | ||
615 | int ret = 0; | ||
616 | |||
617 | v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n", | ||
618 | __func__, state->flags); | ||
619 | |||
620 | mutex_lock(&state->lock); | ||
621 | if (!(state->flags & ST_SUSPENDED)) | ||
622 | goto unlock; | ||
623 | |||
624 | if (!(state->flags & ST_POWERED)) { | ||
625 | if (state->supply) | ||
626 | ret = regulator_enable(state->supply); | ||
627 | if (ret) | ||
628 | goto unlock; | ||
629 | |||
630 | ret = pdata->phy_enable(state->pdev, true); | ||
631 | if (!ret) { | ||
632 | state->flags |= ST_POWERED; | ||
633 | } else if (state->supply) { | ||
634 | regulator_disable(state->supply); | ||
635 | goto unlock; | ||
636 | } | ||
637 | clk_enable(state->clock[CSIS_CLK_GATE]); | ||
638 | } | ||
639 | if (state->flags & ST_STREAMING) | ||
640 | s5pcsis_start_stream(state); | ||
641 | |||
642 | state->flags &= ~ST_SUSPENDED; | ||
643 | unlock: | ||
644 | mutex_unlock(&state->lock); | ||
645 | return ret ? -EAGAIN : 0; | ||
646 | } | ||
647 | |||
648 | #ifdef CONFIG_PM_SLEEP | ||
649 | static int s5pcsis_pm_suspend(struct device *dev) | ||
650 | { | ||
651 | return s5pcsis_suspend(dev); | ||
652 | } | ||
653 | |||
654 | static int s5pcsis_pm_resume(struct device *dev) | ||
655 | { | ||
656 | int ret; | ||
657 | |||
658 | ret = s5pcsis_resume(dev); | ||
659 | |||
660 | if (!ret) { | ||
661 | pm_runtime_disable(dev); | ||
662 | ret = pm_runtime_set_active(dev); | ||
663 | pm_runtime_enable(dev); | ||
664 | } | ||
665 | |||
666 | return ret; | ||
667 | } | ||
668 | #endif | ||
669 | |||
670 | static int __devexit s5pcsis_remove(struct platform_device *pdev) | ||
671 | { | ||
672 | struct v4l2_subdev *sd = platform_get_drvdata(pdev); | ||
673 | struct csis_state *state = sd_to_csis_state(sd); | ||
674 | struct resource *res = state->regs_res; | ||
675 | |||
676 | pm_runtime_disable(&pdev->dev); | ||
677 | s5pcsis_suspend(&pdev->dev); | ||
678 | clk_disable(state->clock[CSIS_CLK_MUX]); | ||
679 | pm_runtime_set_suspended(&pdev->dev); | ||
680 | |||
681 | s5pcsis_clk_put(state); | ||
682 | if (state->supply) | ||
683 | regulator_put(state->supply); | ||
684 | |||
685 | media_entity_cleanup(&state->sd.entity); | ||
686 | free_irq(state->irq, state); | ||
687 | iounmap(state->regs); | ||
688 | release_mem_region(res->start, resource_size(res)); | ||
689 | kfree(state); | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | static const struct dev_pm_ops s5pcsis_pm_ops = { | ||
695 | SET_RUNTIME_PM_OPS(s5pcsis_suspend, s5pcsis_resume, NULL) | ||
696 | SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_pm_suspend, s5pcsis_pm_resume) | ||
697 | }; | ||
698 | |||
699 | static struct platform_driver s5pcsis_driver = { | ||
700 | .probe = s5pcsis_probe, | ||
701 | .remove = __devexit_p(s5pcsis_remove), | ||
702 | .driver = { | ||
703 | .name = CSIS_DRIVER_NAME, | ||
704 | .owner = THIS_MODULE, | ||
705 | .pm = &s5pcsis_pm_ops, | ||
706 | }, | ||
707 | }; | ||
708 | |||
709 | static int __init s5pcsis_init(void) | ||
710 | { | ||
711 | return platform_driver_probe(&s5pcsis_driver, s5pcsis_probe); | ||
712 | } | ||
713 | |||
714 | static void __exit s5pcsis_exit(void) | ||
715 | { | ||
716 | platform_driver_unregister(&s5pcsis_driver); | ||
717 | } | ||
718 | |||
719 | module_init(s5pcsis_init); | ||
720 | module_exit(s5pcsis_exit); | ||
721 | |||
722 | MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); | ||
723 | MODULE_DESCRIPTION("S5P/EXYNOS4 MIPI CSI receiver driver"); | ||
724 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.h b/drivers/media/video/s5p-fimc/mipi-csis.h new file mode 100644 index 000000000000..f5691336dd5c --- /dev/null +++ b/drivers/media/video/s5p-fimc/mipi-csis.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
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 version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #ifndef S5P_MIPI_CSIS_H_ | ||
11 | #define S5P_MIPI_CSIS_H_ | ||
12 | |||
13 | #define CSIS_DRIVER_NAME "s5p-mipi-csis" | ||
14 | #define CSIS_MAX_ENTITIES 2 | ||
15 | #define CSIS0_MAX_LANES 4 | ||
16 | #define CSIS1_MAX_LANES 2 | ||
17 | |||
18 | #define CSIS_PAD_SINK 0 | ||
19 | #define CSIS_PAD_SOURCE 1 | ||
20 | #define CSIS_PADS_NUM 2 | ||
21 | |||
22 | #endif | ||
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 50f1be05ebd3..e2062b240e32 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c | |||
@@ -5591,6 +5591,105 @@ struct saa7134_board saa7134_boards[] = { | |||
5591 | .amux = TV, | 5591 | .amux = TV, |
5592 | }, | 5592 | }, |
5593 | }, | 5593 | }, |
5594 | [SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2] = { | ||
5595 | /* Timothy Lee <timothy.lee@siriushk.com> */ | ||
5596 | .name = "MagicPro ProHDTV Pro2 DMB-TH/Hybrid", | ||
5597 | .audio_clock = 0x00187de7, | ||
5598 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
5599 | .radio_type = UNSET, | ||
5600 | .tuner_config = 3, | ||
5601 | .tuner_addr = ADDR_UNSET, | ||
5602 | .radio_addr = ADDR_UNSET, | ||
5603 | .gpiomask = 0x02050000, | ||
5604 | .mpeg = SAA7134_MPEG_DVB, | ||
5605 | .ts_type = SAA7134_MPEG_TS_PARALLEL, | ||
5606 | .inputs = { { | ||
5607 | .name = name_tv, | ||
5608 | .vmux = 1, | ||
5609 | .amux = TV, | ||
5610 | .tv = 1, | ||
5611 | .gpio = 0x00050000, | ||
5612 | }, { | ||
5613 | .name = name_comp1, | ||
5614 | .vmux = 3, | ||
5615 | .amux = LINE1, | ||
5616 | .gpio = 0x00050000, | ||
5617 | }, { | ||
5618 | .name = name_svideo, | ||
5619 | .vmux = 8, | ||
5620 | .amux = LINE1, | ||
5621 | .gpio = 0x00050000, | ||
5622 | } }, | ||
5623 | .radio = { | ||
5624 | .name = name_radio, | ||
5625 | .amux = TV, | ||
5626 | .gpio = 0x00050000, | ||
5627 | }, | ||
5628 | .mute = { | ||
5629 | .name = name_mute, | ||
5630 | .vmux = 0, | ||
5631 | .amux = TV, | ||
5632 | .gpio = 0x00050000, | ||
5633 | }, | ||
5634 | }, | ||
5635 | [SAA7134_BOARD_BEHOLD_501] = { | ||
5636 | /* Beholder Intl. Ltd. 2010 */ | ||
5637 | /* Dmitry Belimov <d.belimov@gmail.com> */ | ||
5638 | .name = "Beholder BeholdTV 501", | ||
5639 | .audio_clock = 0x00200000, | ||
5640 | .tuner_type = TUNER_ABSENT, | ||
5641 | .radio_type = UNSET, | ||
5642 | .tuner_addr = ADDR_UNSET, | ||
5643 | .radio_addr = ADDR_UNSET, | ||
5644 | .gpiomask = 0x00008000, | ||
5645 | .inputs = { { | ||
5646 | .name = name_tv, | ||
5647 | .vmux = 3, | ||
5648 | .amux = LINE2, | ||
5649 | .tv = 1, | ||
5650 | }, { | ||
5651 | .name = name_comp1, | ||
5652 | .vmux = 1, | ||
5653 | .amux = LINE1, | ||
5654 | }, { | ||
5655 | .name = name_svideo, | ||
5656 | .vmux = 8, | ||
5657 | .amux = LINE1, | ||
5658 | } }, | ||
5659 | .mute = { | ||
5660 | .name = name_mute, | ||
5661 | .amux = LINE1, | ||
5662 | }, | ||
5663 | }, | ||
5664 | [SAA7134_BOARD_BEHOLD_503FM] = { | ||
5665 | /* Beholder Intl. Ltd. 2010 */ | ||
5666 | /* Dmitry Belimov <d.belimov@gmail.com> */ | ||
5667 | .name = "Beholder BeholdTV 503 FM", | ||
5668 | .audio_clock = 0x00200000, | ||
5669 | .tuner_type = TUNER_ABSENT, | ||
5670 | .radio_type = UNSET, | ||
5671 | .tuner_addr = ADDR_UNSET, | ||
5672 | .radio_addr = ADDR_UNSET, | ||
5673 | .gpiomask = 0x00008000, | ||
5674 | .inputs = { { | ||
5675 | .name = name_tv, | ||
5676 | .vmux = 3, | ||
5677 | .amux = LINE2, | ||
5678 | .tv = 1, | ||
5679 | }, { | ||
5680 | .name = name_comp1, | ||
5681 | .vmux = 1, | ||
5682 | .amux = LINE1, | ||
5683 | }, { | ||
5684 | .name = name_svideo, | ||
5685 | .vmux = 8, | ||
5686 | .amux = LINE1, | ||
5687 | } }, | ||
5688 | .mute = { | ||
5689 | .name = name_mute, | ||
5690 | .amux = LINE1, | ||
5691 | }, | ||
5692 | }, | ||
5594 | 5693 | ||
5595 | }; | 5694 | }; |
5596 | 5695 | ||
@@ -6796,6 +6895,24 @@ struct pci_device_id saa7134_pci_tbl[] = { | |||
6796 | .subdevice = 0xc900, | 6895 | .subdevice = 0xc900, |
6797 | .driver_data = SAA7134_BOARD_VIDEOMATE_M1F, | 6896 | .driver_data = SAA7134_BOARD_VIDEOMATE_M1F, |
6798 | }, { | 6897 | }, { |
6898 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
6899 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
6900 | .subvendor = 0x5ace, | ||
6901 | .subdevice = 0x5030, | ||
6902 | .driver_data = SAA7134_BOARD_BEHOLD_503FM, | ||
6903 | }, { | ||
6904 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
6905 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
6906 | .subvendor = 0x5ace, | ||
6907 | .subdevice = 0x5010, | ||
6908 | .driver_data = SAA7134_BOARD_BEHOLD_501, | ||
6909 | }, { | ||
6910 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
6911 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
6912 | .subvendor = 0x17de, | ||
6913 | .subdevice = 0xd136, | ||
6914 | .driver_data = SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2, | ||
6915 | }, { | ||
6799 | /* --- boards without eeprom + subsystem ID --- */ | 6916 | /* --- boards without eeprom + subsystem ID --- */ |
6800 | .vendor = PCI_VENDOR_ID_PHILIPS, | 6917 | .vendor = PCI_VENDOR_ID_PHILIPS, |
6801 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | 6918 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, |
@@ -6988,6 +7105,7 @@ static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev, | |||
6988 | switch (dev->board) { | 7105 | switch (dev->board) { |
6989 | case SAA7134_BOARD_HAUPPAUGE_HVR1150: | 7106 | case SAA7134_BOARD_HAUPPAUGE_HVR1150: |
6990 | case SAA7134_BOARD_HAUPPAUGE_HVR1120: | 7107 | case SAA7134_BOARD_HAUPPAUGE_HVR1120: |
7108 | case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2: | ||
6991 | ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg); | 7109 | ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg); |
6992 | break; | 7110 | break; |
6993 | case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: | 7111 | case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: |
@@ -7014,6 +7132,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev, | |||
7014 | case SAA7134_BOARD_HAUPPAUGE_HVR1120: | 7132 | case SAA7134_BOARD_HAUPPAUGE_HVR1120: |
7015 | case SAA7134_BOARD_AVERMEDIA_M733A: | 7133 | case SAA7134_BOARD_AVERMEDIA_M733A: |
7016 | case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: | 7134 | case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: |
7135 | case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2: | ||
7017 | /* tda8290 + tda18271 */ | 7136 | /* tda8290 + tda18271 */ |
7018 | ret = saa7134_tda8290_18271_callback(dev, command, arg); | 7137 | ret = saa7134_tda8290_18271_callback(dev, command, arg); |
7019 | break; | 7138 | break; |
@@ -7264,6 +7383,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) | |||
7264 | break; | 7383 | break; |
7265 | case SAA7134_BOARD_HAUPPAUGE_HVR1150: | 7384 | case SAA7134_BOARD_HAUPPAUGE_HVR1150: |
7266 | case SAA7134_BOARD_HAUPPAUGE_HVR1120: | 7385 | case SAA7134_BOARD_HAUPPAUGE_HVR1120: |
7386 | dev->has_remote = SAA7134_REMOTE_GPIO; | ||
7267 | /* GPIO 26 high for digital, low for analog */ | 7387 | /* GPIO 26 high for digital, low for analog */ |
7268 | saa7134_set_gpio(dev, 26, 0); | 7388 | saa7134_set_gpio(dev, 26, 0); |
7269 | msleep(1); | 7389 | msleep(1); |
@@ -7326,6 +7446,11 @@ int saa7134_board_init1(struct saa7134_dev *dev) | |||
7326 | saa7134_set_gpio(dev, 1, 1); | 7446 | saa7134_set_gpio(dev, 1, 1); |
7327 | dev->has_remote = SAA7134_REMOTE_GPIO; | 7447 | dev->has_remote = SAA7134_REMOTE_GPIO; |
7328 | break; | 7448 | break; |
7449 | case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2: | ||
7450 | /* enable LGS-8G75 */ | ||
7451 | saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0e050000, 0x0c050000); | ||
7452 | saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0e050000, 0x0c050000); | ||
7453 | break; | ||
7329 | } | 7454 | } |
7330 | return 0; | 7455 | return 0; |
7331 | } | 7456 | } |
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 41f836fc93ec..f9be737ba6f4 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c | |||
@@ -927,7 +927,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, | |||
927 | } | 927 | } |
928 | 928 | ||
929 | /* print pci info */ | 929 | /* print pci info */ |
930 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); | 930 | dev->pci_rev = pci_dev->revision; |
931 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); | 931 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); |
932 | printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " | 932 | printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " |
933 | "latency: %d, mmio: 0x%llx\n", dev->name, | 933 | "latency: %d, mmio: 0x%llx\n", dev->name, |
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index f65cad287b83..996a206c6d79 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include "lgdt3305.h" | 53 | #include "lgdt3305.h" |
54 | #include "tda8290.h" | 54 | #include "tda8290.h" |
55 | #include "mb86a20s.h" | 55 | #include "mb86a20s.h" |
56 | #include "lgs8gxx.h" | ||
56 | 57 | ||
57 | #include "zl10353.h" | 58 | #include "zl10353.h" |
58 | 59 | ||
@@ -1123,6 +1124,26 @@ static struct tda18271_config dtv1000s_tda18271_config = { | |||
1123 | .gate = TDA18271_GATE_ANALOG, | 1124 | .gate = TDA18271_GATE_ANALOG, |
1124 | }; | 1125 | }; |
1125 | 1126 | ||
1127 | static struct lgs8gxx_config prohdtv_pro2_lgs8g75_config = { | ||
1128 | .prod = LGS8GXX_PROD_LGS8G75, | ||
1129 | .demod_address = 0x1d, | ||
1130 | .serial_ts = 0, | ||
1131 | .ts_clk_pol = 1, | ||
1132 | .ts_clk_gated = 0, | ||
1133 | .if_clk_freq = 30400, /* 30.4 MHz */ | ||
1134 | .if_freq = 4000, /* 4.00 MHz */ | ||
1135 | .if_neg_center = 0, | ||
1136 | .ext_adc = 0, | ||
1137 | .adc_signed = 1, | ||
1138 | .adc_vpp = 3, /* 2.0 Vpp */ | ||
1139 | .if_neg_edge = 1, | ||
1140 | }; | ||
1141 | |||
1142 | static struct tda18271_config prohdtv_pro2_tda18271_config = { | ||
1143 | .gate = TDA18271_GATE_ANALOG, | ||
1144 | .output_opt = TDA18271_OUTPUT_LT_OFF, | ||
1145 | }; | ||
1146 | |||
1126 | /* ================================================================== | 1147 | /* ================================================================== |
1127 | * Core code | 1148 | * Core code |
1128 | */ | 1149 | */ |
@@ -1674,6 +1695,19 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1674 | 1695 | ||
1675 | /* mb86a20s need to use the I2C gateway */ | 1696 | /* mb86a20s need to use the I2C gateway */ |
1676 | break; | 1697 | break; |
1698 | case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2: | ||
1699 | fe0->dvb.frontend = dvb_attach(lgs8gxx_attach, | ||
1700 | &prohdtv_pro2_lgs8g75_config, | ||
1701 | &dev->i2c_adap); | ||
1702 | if (fe0->dvb.frontend != NULL) { | ||
1703 | dvb_attach(tda829x_attach, fe0->dvb.frontend, | ||
1704 | &dev->i2c_adap, 0x4b, | ||
1705 | &tda829x_no_probe); | ||
1706 | dvb_attach(tda18271_attach, fe0->dvb.frontend, | ||
1707 | 0x60, &dev->i2c_adap, | ||
1708 | &prohdtv_pro2_tda18271_config); | ||
1709 | } | ||
1710 | break; | ||
1677 | default: | 1711 | default: |
1678 | wprintk("Huh? unknown DVB card?\n"); | 1712 | wprintk("Huh? unknown DVB card?\n"); |
1679 | break; | 1713 | break; |
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index be1c2a2de27c..ff6c0e97563e 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c | |||
@@ -756,6 +756,14 @@ int saa7134_input_init1(struct saa7134_dev *dev) | |||
756 | mask_keycode = 0x0ff00; | 756 | mask_keycode = 0x0ff00; |
757 | mask_keyup = 0x040000; | 757 | mask_keyup = 0x040000; |
758 | break; | 758 | break; |
759 | case SAA7134_BOARD_HAUPPAUGE_HVR1150: | ||
760 | case SAA7134_BOARD_HAUPPAUGE_HVR1120: | ||
761 | ir_codes = RC_MAP_HAUPPAUGE; | ||
762 | mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */ | ||
763 | mask_keyup = 0x0040000; | ||
764 | mask_keycode = 0xffff; | ||
765 | raw_decode = true; | ||
766 | break; | ||
759 | } | 767 | } |
760 | if (NULL == ir_codes) { | 768 | if (NULL == ir_codes) { |
761 | printk("%s: Oops: IR config error [card=%d]\n", | 769 | printk("%s: Oops: IR config error [card=%d]\n", |
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index f96cd5d761f9..28eb10398323 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h | |||
@@ -328,6 +328,9 @@ struct saa7134_card_ir { | |||
328 | #define SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG 182 | 328 | #define SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG 182 |
329 | #define SAA7134_BOARD_VIDEOMATE_M1F 183 | 329 | #define SAA7134_BOARD_VIDEOMATE_M1F 183 |
330 | #define SAA7134_BOARD_ENCORE_ENLTV_FM3 184 | 330 | #define SAA7134_BOARD_ENCORE_ENLTV_FM3 184 |
331 | #define SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2 185 | ||
332 | #define SAA7134_BOARD_BEHOLD_501 186 | ||
333 | #define SAA7134_BOARD_BEHOLD_503FM 187 | ||
331 | 334 | ||
332 | #define SAA7134_MAXBOARDS 32 | 335 | #define SAA7134_MAXBOARDS 32 |
333 | #define SAA7134_INPUT_MAX 8 | 336 | #define SAA7134_INPUT_MAX 8 |
diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c index b813aec1e456..3b7d7b4e3034 100644 --- a/drivers/media/video/saa7164/saa7164-core.c +++ b/drivers/media/video/saa7164/saa7164-core.c | |||
@@ -1247,7 +1247,7 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev, | |||
1247 | } | 1247 | } |
1248 | 1248 | ||
1249 | /* print pci info */ | 1249 | /* print pci info */ |
1250 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); | 1250 | dev->pci_rev = pci_dev->revision; |
1251 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); | 1251 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); |
1252 | printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " | 1252 | printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " |
1253 | "latency: %d, mmio: 0x%llx\n", dev->name, | 1253 | "latency: %d, mmio: 0x%llx\n", dev->name, |
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 134e86bf6d97..3ae5c9c58cba 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | #include <linux/completion.h> | ||
20 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
21 | #include <linux/dma-mapping.h> | 22 | #include <linux/dma-mapping.h> |
22 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
@@ -106,6 +107,7 @@ struct sh_mobile_ceu_dev { | |||
106 | struct vb2_alloc_ctx *alloc_ctx; | 107 | struct vb2_alloc_ctx *alloc_ctx; |
107 | 108 | ||
108 | struct sh_mobile_ceu_info *pdata; | 109 | struct sh_mobile_ceu_info *pdata; |
110 | struct completion complete; | ||
109 | 111 | ||
110 | u32 cflcr; | 112 | u32 cflcr; |
111 | 113 | ||
@@ -114,6 +116,7 @@ struct sh_mobile_ceu_dev { | |||
114 | 116 | ||
115 | unsigned int image_mode:1; | 117 | unsigned int image_mode:1; |
116 | unsigned int is_16bit:1; | 118 | unsigned int is_16bit:1; |
119 | unsigned int frozen:1; | ||
117 | }; | 120 | }; |
118 | 121 | ||
119 | struct sh_mobile_ceu_cam { | 122 | struct sh_mobile_ceu_cam { |
@@ -273,7 +276,8 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
273 | ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_MASK); | 276 | ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_MASK); |
274 | status = ceu_read(pcdev, CETCR); | 277 | status = ceu_read(pcdev, CETCR); |
275 | ceu_write(pcdev, CETCR, ~status & CEU_CETCR_MAGIC); | 278 | ceu_write(pcdev, CETCR, ~status & CEU_CETCR_MAGIC); |
276 | ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK); | 279 | if (!pcdev->frozen) |
280 | ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK); | ||
277 | ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP); | 281 | ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP); |
278 | ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW); | 282 | ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW); |
279 | 283 | ||
@@ -287,6 +291,11 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
287 | ret = -EIO; | 291 | ret = -EIO; |
288 | } | 292 | } |
289 | 293 | ||
294 | if (pcdev->frozen) { | ||
295 | complete(&pcdev->complete); | ||
296 | return ret; | ||
297 | } | ||
298 | |||
290 | if (!pcdev->active) | 299 | if (!pcdev->active) |
291 | return ret; | 300 | return ret; |
292 | 301 | ||
@@ -378,12 +387,11 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) | |||
378 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 387 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
379 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 388 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
380 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); | 389 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); |
381 | unsigned long flags; | ||
382 | 390 | ||
383 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | 391 | dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, |
384 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | 392 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); |
385 | 393 | ||
386 | spin_lock_irqsave(&pcdev->lock, flags); | 394 | spin_lock_irq(&pcdev->lock); |
387 | list_add_tail(&buf->queue, &pcdev->capture); | 395 | list_add_tail(&buf->queue, &pcdev->capture); |
388 | 396 | ||
389 | if (!pcdev->active) { | 397 | if (!pcdev->active) { |
@@ -395,7 +403,7 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) | |||
395 | pcdev->active = vb; | 403 | pcdev->active = vb; |
396 | sh_mobile_ceu_capture(pcdev); | 404 | sh_mobile_ceu_capture(pcdev); |
397 | } | 405 | } |
398 | spin_unlock_irqrestore(&pcdev->lock, flags); | 406 | spin_unlock_irq(&pcdev->lock); |
399 | } | 407 | } |
400 | 408 | ||
401 | static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) | 409 | static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) |
@@ -404,9 +412,8 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) | |||
404 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 412 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
405 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); | 413 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); |
406 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 414 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
407 | unsigned long flags; | ||
408 | 415 | ||
409 | spin_lock_irqsave(&pcdev->lock, flags); | 416 | spin_lock_irq(&pcdev->lock); |
410 | 417 | ||
411 | if (pcdev->active == vb) { | 418 | if (pcdev->active == vb) { |
412 | /* disable capture (release DMA buffer), reset */ | 419 | /* disable capture (release DMA buffer), reset */ |
@@ -417,7 +424,7 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) | |||
417 | /* Doesn't hurt also if the list is empty */ | 424 | /* Doesn't hurt also if the list is empty */ |
418 | list_del_init(&buf->queue); | 425 | list_del_init(&buf->queue); |
419 | 426 | ||
420 | spin_unlock_irqrestore(&pcdev->lock, flags); | 427 | spin_unlock_irq(&pcdev->lock); |
421 | } | 428 | } |
422 | 429 | ||
423 | static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) | 430 | static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) |
@@ -427,6 +434,25 @@ static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) | |||
427 | return 0; | 434 | return 0; |
428 | } | 435 | } |
429 | 436 | ||
437 | static int sh_mobile_ceu_stop_streaming(struct vb2_queue *q) | ||
438 | { | ||
439 | struct soc_camera_device *icd = container_of(q, struct soc_camera_device, vb2_vidq); | ||
440 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
441 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
442 | struct list_head *buf_head, *tmp; | ||
443 | |||
444 | spin_lock_irq(&pcdev->lock); | ||
445 | |||
446 | pcdev->active = NULL; | ||
447 | |||
448 | list_for_each_safe(buf_head, tmp, &pcdev->capture) | ||
449 | list_del_init(buf_head); | ||
450 | |||
451 | spin_unlock_irq(&pcdev->lock); | ||
452 | |||
453 | return sh_mobile_ceu_soft_reset(pcdev); | ||
454 | } | ||
455 | |||
430 | static struct vb2_ops sh_mobile_ceu_videobuf_ops = { | 456 | static struct vb2_ops sh_mobile_ceu_videobuf_ops = { |
431 | .queue_setup = sh_mobile_ceu_videobuf_setup, | 457 | .queue_setup = sh_mobile_ceu_videobuf_setup, |
432 | .buf_prepare = sh_mobile_ceu_videobuf_prepare, | 458 | .buf_prepare = sh_mobile_ceu_videobuf_prepare, |
@@ -435,6 +461,7 @@ static struct vb2_ops sh_mobile_ceu_videobuf_ops = { | |||
435 | .buf_init = sh_mobile_ceu_videobuf_init, | 461 | .buf_init = sh_mobile_ceu_videobuf_init, |
436 | .wait_prepare = soc_camera_unlock, | 462 | .wait_prepare = soc_camera_unlock, |
437 | .wait_finish = soc_camera_lock, | 463 | .wait_finish = soc_camera_lock, |
464 | .stop_streaming = sh_mobile_ceu_stop_streaming, | ||
438 | }; | 465 | }; |
439 | 466 | ||
440 | static irqreturn_t sh_mobile_ceu_irq(int irq, void *data) | 467 | static irqreturn_t sh_mobile_ceu_irq(int irq, void *data) |
@@ -500,7 +527,6 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) | |||
500 | { | 527 | { |
501 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 528 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
502 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 529 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
503 | unsigned long flags; | ||
504 | 530 | ||
505 | BUG_ON(icd != pcdev->icd); | 531 | BUG_ON(icd != pcdev->icd); |
506 | 532 | ||
@@ -509,13 +535,13 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) | |||
509 | sh_mobile_ceu_soft_reset(pcdev); | 535 | sh_mobile_ceu_soft_reset(pcdev); |
510 | 536 | ||
511 | /* make sure active buffer is canceled */ | 537 | /* make sure active buffer is canceled */ |
512 | spin_lock_irqsave(&pcdev->lock, flags); | 538 | spin_lock_irq(&pcdev->lock); |
513 | if (pcdev->active) { | 539 | if (pcdev->active) { |
514 | list_del_init(&to_ceu_vb(pcdev->active)->queue); | 540 | list_del_init(&to_ceu_vb(pcdev->active)->queue); |
515 | vb2_buffer_done(pcdev->active, VB2_BUF_STATE_ERROR); | 541 | vb2_buffer_done(pcdev->active, VB2_BUF_STATE_ERROR); |
516 | pcdev->active = NULL; | 542 | pcdev->active = NULL; |
517 | } | 543 | } |
518 | spin_unlock_irqrestore(&pcdev->lock, flags); | 544 | spin_unlock_irq(&pcdev->lock); |
519 | 545 | ||
520 | pm_runtime_put_sync(ici->v4l2_dev.dev); | 546 | pm_runtime_put_sync(ici->v4l2_dev.dev); |
521 | 547 | ||
@@ -891,8 +917,8 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int | |||
891 | 917 | ||
892 | fmt = soc_mbus_get_fmtdesc(code); | 918 | fmt = soc_mbus_get_fmtdesc(code); |
893 | if (!fmt) { | 919 | if (!fmt) { |
894 | dev_err(dev, "Invalid format code #%u: %d\n", idx, code); | 920 | dev_warn(dev, "unsupported format code #%u: %d\n", idx, code); |
895 | return -EINVAL; | 921 | return 0; |
896 | } | 922 | } |
897 | 923 | ||
898 | if (!pcdev->pdata->csi2_dev) { | 924 | if (!pcdev->pdata->csi2_dev) { |
@@ -1330,7 +1356,7 @@ static int client_scale(struct soc_camera_device *icd, | |||
1330 | /* | 1356 | /* |
1331 | * CEU can scale and crop, but we don't want to waste bandwidth and kill the | 1357 | * CEU can scale and crop, but we don't want to waste bandwidth and kill the |
1332 | * framerate by always requesting the maximum image from the client. See | 1358 | * framerate by always requesting the maximum image from the client. See |
1333 | * Documentation/video4linux/sh_mobile_camera_ceu.txt for a description of | 1359 | * Documentation/video4linux/sh_mobile_ceu_camera.txt for a description of |
1334 | * scaling and cropping algorithms and for the meaning of referenced here steps. | 1360 | * scaling and cropping algorithms and for the meaning of referenced here steps. |
1335 | */ | 1361 | */ |
1336 | static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | 1362 | static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, |
@@ -1377,10 +1403,6 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | |||
1377 | if (mf.width > 2560 || mf.height > 1920) | 1403 | if (mf.width > 2560 || mf.height > 1920) |
1378 | return -EINVAL; | 1404 | return -EINVAL; |
1379 | 1405 | ||
1380 | /* Cache camera output window */ | ||
1381 | cam->width = mf.width; | ||
1382 | cam->height = mf.height; | ||
1383 | |||
1384 | /* 4. Calculate camera scales */ | 1406 | /* 4. Calculate camera scales */ |
1385 | scale_cam_h = calc_generic_scale(cam_rect->width, mf.width); | 1407 | scale_cam_h = calc_generic_scale(cam_rect->width, mf.width); |
1386 | scale_cam_v = calc_generic_scale(cam_rect->height, mf.height); | 1408 | scale_cam_v = calc_generic_scale(cam_rect->height, mf.height); |
@@ -1389,6 +1411,39 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | |||
1389 | interm_width = scale_down(rect->width, scale_cam_h); | 1411 | interm_width = scale_down(rect->width, scale_cam_h); |
1390 | interm_height = scale_down(rect->height, scale_cam_v); | 1412 | interm_height = scale_down(rect->height, scale_cam_v); |
1391 | 1413 | ||
1414 | if (interm_width < icd->user_width) { | ||
1415 | u32 new_scale_h; | ||
1416 | |||
1417 | new_scale_h = calc_generic_scale(rect->width, icd->user_width); | ||
1418 | |||
1419 | mf.width = scale_down(cam_rect->width, new_scale_h); | ||
1420 | } | ||
1421 | |||
1422 | if (interm_height < icd->user_height) { | ||
1423 | u32 new_scale_v; | ||
1424 | |||
1425 | new_scale_v = calc_generic_scale(rect->height, icd->user_height); | ||
1426 | |||
1427 | mf.height = scale_down(cam_rect->height, new_scale_v); | ||
1428 | } | ||
1429 | |||
1430 | if (interm_width < icd->user_width || interm_height < icd->user_height) { | ||
1431 | ret = v4l2_device_call_until_err(sd->v4l2_dev, (int)icd, video, | ||
1432 | s_mbus_fmt, &mf); | ||
1433 | if (ret < 0) | ||
1434 | return ret; | ||
1435 | |||
1436 | dev_geo(dev, "New camera output %ux%u\n", mf.width, mf.height); | ||
1437 | scale_cam_h = calc_generic_scale(cam_rect->width, mf.width); | ||
1438 | scale_cam_v = calc_generic_scale(cam_rect->height, mf.height); | ||
1439 | interm_width = scale_down(rect->width, scale_cam_h); | ||
1440 | interm_height = scale_down(rect->height, scale_cam_v); | ||
1441 | } | ||
1442 | |||
1443 | /* Cache camera output window */ | ||
1444 | cam->width = mf.width; | ||
1445 | cam->height = mf.height; | ||
1446 | |||
1392 | if (pcdev->image_mode) { | 1447 | if (pcdev->image_mode) { |
1393 | out_width = min(interm_width, icd->user_width); | 1448 | out_width = min(interm_width, icd->user_width); |
1394 | out_height = min(interm_height, icd->user_height); | 1449 | out_height = min(interm_height, icd->user_height); |
@@ -1704,6 +1759,63 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
1704 | return ret; | 1759 | return ret; |
1705 | } | 1760 | } |
1706 | 1761 | ||
1762 | static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd, | ||
1763 | struct v4l2_crop *a) | ||
1764 | { | ||
1765 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1766 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
1767 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1768 | u32 out_width = icd->user_width, out_height = icd->user_height; | ||
1769 | int ret; | ||
1770 | |||
1771 | /* Freeze queue */ | ||
1772 | pcdev->frozen = 1; | ||
1773 | /* Wait for frame */ | ||
1774 | ret = wait_for_completion_interruptible(&pcdev->complete); | ||
1775 | /* Stop the client */ | ||
1776 | ret = v4l2_subdev_call(sd, video, s_stream, 0); | ||
1777 | if (ret < 0) | ||
1778 | dev_warn(icd->dev.parent, | ||
1779 | "Client failed to stop the stream: %d\n", ret); | ||
1780 | else | ||
1781 | /* Do the crop, if it fails, there's nothing more we can do */ | ||
1782 | sh_mobile_ceu_set_crop(icd, a); | ||
1783 | |||
1784 | dev_geo(icd->dev.parent, "Output after crop: %ux%u\n", icd->user_width, icd->user_height); | ||
1785 | |||
1786 | if (icd->user_width != out_width || icd->user_height != out_height) { | ||
1787 | struct v4l2_format f = { | ||
1788 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
1789 | .fmt.pix = { | ||
1790 | .width = out_width, | ||
1791 | .height = out_height, | ||
1792 | .pixelformat = icd->current_fmt->host_fmt->fourcc, | ||
1793 | .field = pcdev->field, | ||
1794 | .colorspace = icd->colorspace, | ||
1795 | }, | ||
1796 | }; | ||
1797 | ret = sh_mobile_ceu_set_fmt(icd, &f); | ||
1798 | if (!ret && (out_width != f.fmt.pix.width || | ||
1799 | out_height != f.fmt.pix.height)) | ||
1800 | ret = -EINVAL; | ||
1801 | if (!ret) { | ||
1802 | icd->user_width = out_width; | ||
1803 | icd->user_height = out_height; | ||
1804 | ret = sh_mobile_ceu_set_bus_param(icd, | ||
1805 | icd->current_fmt->host_fmt->fourcc); | ||
1806 | } | ||
1807 | } | ||
1808 | |||
1809 | /* Thaw the queue */ | ||
1810 | pcdev->frozen = 0; | ||
1811 | spin_lock_irq(&pcdev->lock); | ||
1812 | sh_mobile_ceu_capture(pcdev); | ||
1813 | spin_unlock_irq(&pcdev->lock); | ||
1814 | /* Start the client */ | ||
1815 | ret = v4l2_subdev_call(sd, video, s_stream, 1); | ||
1816 | return ret; | ||
1817 | } | ||
1818 | |||
1707 | static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt) | 1819 | static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt) |
1708 | { | 1820 | { |
1709 | struct soc_camera_device *icd = file->private_data; | 1821 | struct soc_camera_device *icd = file->private_data; |
@@ -1790,6 +1902,7 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { | |||
1790 | .put_formats = sh_mobile_ceu_put_formats, | 1902 | .put_formats = sh_mobile_ceu_put_formats, |
1791 | .get_crop = sh_mobile_ceu_get_crop, | 1903 | .get_crop = sh_mobile_ceu_get_crop, |
1792 | .set_crop = sh_mobile_ceu_set_crop, | 1904 | .set_crop = sh_mobile_ceu_set_crop, |
1905 | .set_livecrop = sh_mobile_ceu_set_livecrop, | ||
1793 | .set_fmt = sh_mobile_ceu_set_fmt, | 1906 | .set_fmt = sh_mobile_ceu_set_fmt, |
1794 | .try_fmt = sh_mobile_ceu_try_fmt, | 1907 | .try_fmt = sh_mobile_ceu_try_fmt, |
1795 | .set_ctrl = sh_mobile_ceu_set_ctrl, | 1908 | .set_ctrl = sh_mobile_ceu_set_ctrl, |
@@ -1856,6 +1969,7 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev) | |||
1856 | 1969 | ||
1857 | INIT_LIST_HEAD(&pcdev->capture); | 1970 | INIT_LIST_HEAD(&pcdev->capture); |
1858 | spin_lock_init(&pcdev->lock); | 1971 | spin_lock_init(&pcdev->lock); |
1972 | init_completion(&pcdev->complete); | ||
1859 | 1973 | ||
1860 | pcdev->pdata = pdev->dev.platform_data; | 1974 | pcdev->pdata = pdev->dev.platform_data; |
1861 | if (!pcdev->pdata) { | 1975 | if (!pcdev->pdata) { |
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index ddb4c091dedc..398864370267 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
@@ -41,6 +41,11 @@ | |||
41 | #define DEFAULT_WIDTH 640 | 41 | #define DEFAULT_WIDTH 640 |
42 | #define DEFAULT_HEIGHT 480 | 42 | #define DEFAULT_HEIGHT 480 |
43 | 43 | ||
44 | #define is_streaming(ici, icd) \ | ||
45 | (((ici)->ops->init_videobuf) ? \ | ||
46 | (icd)->vb_vidq.streaming : \ | ||
47 | vb2_is_streaming(&(icd)->vb2_vidq)) | ||
48 | |||
44 | static LIST_HEAD(hosts); | 49 | static LIST_HEAD(hosts); |
45 | static LIST_HEAD(devices); | 50 | static LIST_HEAD(devices); |
46 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ | 51 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ |
@@ -358,8 +363,6 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) | |||
358 | if (!icd->user_formats) | 363 | if (!icd->user_formats) |
359 | return -ENOMEM; | 364 | return -ENOMEM; |
360 | 365 | ||
361 | icd->num_user_formats = fmts; | ||
362 | |||
363 | dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts); | 366 | dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts); |
364 | 367 | ||
365 | /* Second pass - actually fill data formats */ | 368 | /* Second pass - actually fill data formats */ |
@@ -367,9 +370,10 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) | |||
367 | for (i = 0; i < raw_fmts; i++) | 370 | for (i = 0; i < raw_fmts; i++) |
368 | if (!ici->ops->get_formats) { | 371 | if (!ici->ops->get_formats) { |
369 | v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code); | 372 | v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code); |
370 | icd->user_formats[i].host_fmt = | 373 | icd->user_formats[fmts].host_fmt = |
371 | soc_mbus_get_fmtdesc(code); | 374 | soc_mbus_get_fmtdesc(code); |
372 | icd->user_formats[i].code = code; | 375 | if (icd->user_formats[fmts].host_fmt) |
376 | icd->user_formats[fmts++].code = code; | ||
373 | } else { | 377 | } else { |
374 | ret = ici->ops->get_formats(icd, i, | 378 | ret = ici->ops->get_formats(icd, i, |
375 | &icd->user_formats[fmts]); | 379 | &icd->user_formats[fmts]); |
@@ -378,12 +382,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) | |||
378 | fmts += ret; | 382 | fmts += ret; |
379 | } | 383 | } |
380 | 384 | ||
385 | icd->num_user_formats = fmts; | ||
381 | icd->current_fmt = &icd->user_formats[0]; | 386 | icd->current_fmt = &icd->user_formats[0]; |
382 | 387 | ||
383 | return 0; | 388 | return 0; |
384 | 389 | ||
385 | egfmt: | 390 | egfmt: |
386 | icd->num_user_formats = 0; | ||
387 | vfree(icd->user_formats); | 391 | vfree(icd->user_formats); |
388 | return ret; | 392 | return ret; |
389 | } | 393 | } |
@@ -662,7 +666,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, | |||
662 | if (icd->streamer && icd->streamer != file) | 666 | if (icd->streamer && icd->streamer != file) |
663 | return -EBUSY; | 667 | return -EBUSY; |
664 | 668 | ||
665 | if (icd->vb_vidq.bufs[0]) { | 669 | if (is_streaming(to_soc_camera_host(icd->dev.parent), icd)) { |
666 | dev_err(&icd->dev, "S_FMT denied: queue initialised\n"); | 670 | dev_err(&icd->dev, "S_FMT denied: queue initialised\n"); |
667 | return -EBUSY; | 671 | return -EBUSY; |
668 | } | 672 | } |
@@ -903,14 +907,17 @@ static int soc_camera_s_crop(struct file *file, void *fh, | |||
903 | if (ret < 0) { | 907 | if (ret < 0) { |
904 | dev_err(&icd->dev, | 908 | dev_err(&icd->dev, |
905 | "S_CROP denied: getting current crop failed\n"); | 909 | "S_CROP denied: getting current crop failed\n"); |
906 | } else if (icd->vb_vidq.bufs[0] && | 910 | } else if ((a->c.width == current_crop.c.width && |
907 | (a->c.width != current_crop.c.width || | 911 | a->c.height == current_crop.c.height) || |
908 | a->c.height != current_crop.c.height)) { | 912 | !is_streaming(ici, icd)) { |
913 | /* same size or not streaming - use .set_crop() */ | ||
914 | ret = ici->ops->set_crop(icd, a); | ||
915 | } else if (ici->ops->set_livecrop) { | ||
916 | ret = ici->ops->set_livecrop(icd, a); | ||
917 | } else { | ||
909 | dev_err(&icd->dev, | 918 | dev_err(&icd->dev, |
910 | "S_CROP denied: queue initialised and sizes differ\n"); | 919 | "S_CROP denied: queue initialised and sizes differ\n"); |
911 | ret = -EBUSY; | 920 | ret = -EBUSY; |
912 | } else { | ||
913 | ret = ici->ops->set_crop(icd, a); | ||
914 | } | 921 | } |
915 | 922 | ||
916 | return ret; | 923 | return ret; |
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c index ed77aa055b63..bea7c9cf4f88 100644 --- a/drivers/media/video/soc_mediabus.c +++ b/drivers/media/video/soc_mediabus.c | |||
@@ -15,132 +15,329 @@ | |||
15 | #include <media/v4l2-mediabus.h> | 15 | #include <media/v4l2-mediabus.h> |
16 | #include <media/soc_mediabus.h> | 16 | #include <media/soc_mediabus.h> |
17 | 17 | ||
18 | #define MBUS_IDX(f) (V4L2_MBUS_FMT_ ## f - V4L2_MBUS_FMT_FIXED - 1) | 18 | static const struct soc_mbus_lookup mbus_fmt[] = { |
19 | 19 | { | |
20 | static const struct soc_mbus_pixelfmt mbus_fmt[] = { | 20 | .code = V4L2_MBUS_FMT_YUYV8_2X8, |
21 | [MBUS_IDX(YUYV8_2X8)] = { | 21 | .fmt = { |
22 | .fourcc = V4L2_PIX_FMT_YUYV, | 22 | .fourcc = V4L2_PIX_FMT_YUYV, |
23 | .name = "YUYV", | 23 | .name = "YUYV", |
24 | .bits_per_sample = 8, | 24 | .bits_per_sample = 8, |
25 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 25 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
26 | .order = SOC_MBUS_ORDER_LE, | 26 | .order = SOC_MBUS_ORDER_LE, |
27 | }, | 27 | }, |
28 | [MBUS_IDX(YVYU8_2X8)] = { | 28 | }, { |
29 | .code = V4L2_MBUS_FMT_YVYU8_2X8, | ||
30 | .fmt = { | ||
29 | .fourcc = V4L2_PIX_FMT_YVYU, | 31 | .fourcc = V4L2_PIX_FMT_YVYU, |
30 | .name = "YVYU", | 32 | .name = "YVYU", |
31 | .bits_per_sample = 8, | 33 | .bits_per_sample = 8, |
32 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 34 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
33 | .order = SOC_MBUS_ORDER_LE, | 35 | .order = SOC_MBUS_ORDER_LE, |
34 | }, | 36 | }, |
35 | [MBUS_IDX(UYVY8_2X8)] = { | 37 | }, { |
38 | .code = V4L2_MBUS_FMT_UYVY8_2X8, | ||
39 | .fmt = { | ||
36 | .fourcc = V4L2_PIX_FMT_UYVY, | 40 | .fourcc = V4L2_PIX_FMT_UYVY, |
37 | .name = "UYVY", | 41 | .name = "UYVY", |
38 | .bits_per_sample = 8, | 42 | .bits_per_sample = 8, |
39 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 43 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
40 | .order = SOC_MBUS_ORDER_LE, | 44 | .order = SOC_MBUS_ORDER_LE, |
41 | }, | 45 | }, |
42 | [MBUS_IDX(VYUY8_2X8)] = { | 46 | }, { |
47 | .code = V4L2_MBUS_FMT_VYUY8_2X8, | ||
48 | .fmt = { | ||
43 | .fourcc = V4L2_PIX_FMT_VYUY, | 49 | .fourcc = V4L2_PIX_FMT_VYUY, |
44 | .name = "VYUY", | 50 | .name = "VYUY", |
45 | .bits_per_sample = 8, | 51 | .bits_per_sample = 8, |
46 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 52 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
47 | .order = SOC_MBUS_ORDER_LE, | 53 | .order = SOC_MBUS_ORDER_LE, |
48 | }, | 54 | }, |
49 | [MBUS_IDX(RGB555_2X8_PADHI_LE)] = { | 55 | }, { |
56 | .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, | ||
57 | .fmt = { | ||
50 | .fourcc = V4L2_PIX_FMT_RGB555, | 58 | .fourcc = V4L2_PIX_FMT_RGB555, |
51 | .name = "RGB555", | 59 | .name = "RGB555", |
52 | .bits_per_sample = 8, | 60 | .bits_per_sample = 8, |
53 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 61 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
54 | .order = SOC_MBUS_ORDER_LE, | 62 | .order = SOC_MBUS_ORDER_LE, |
55 | }, | 63 | }, |
56 | [MBUS_IDX(RGB555_2X8_PADHI_BE)] = { | 64 | }, { |
65 | .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, | ||
66 | .fmt = { | ||
57 | .fourcc = V4L2_PIX_FMT_RGB555X, | 67 | .fourcc = V4L2_PIX_FMT_RGB555X, |
58 | .name = "RGB555X", | 68 | .name = "RGB555X", |
59 | .bits_per_sample = 8, | 69 | .bits_per_sample = 8, |
60 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 70 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
61 | .order = SOC_MBUS_ORDER_LE, | 71 | .order = SOC_MBUS_ORDER_LE, |
62 | }, | 72 | }, |
63 | [MBUS_IDX(RGB565_2X8_LE)] = { | 73 | }, { |
74 | .code = V4L2_MBUS_FMT_RGB565_2X8_LE, | ||
75 | .fmt = { | ||
64 | .fourcc = V4L2_PIX_FMT_RGB565, | 76 | .fourcc = V4L2_PIX_FMT_RGB565, |
65 | .name = "RGB565", | 77 | .name = "RGB565", |
66 | .bits_per_sample = 8, | 78 | .bits_per_sample = 8, |
67 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 79 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
68 | .order = SOC_MBUS_ORDER_LE, | 80 | .order = SOC_MBUS_ORDER_LE, |
69 | }, | 81 | }, |
70 | [MBUS_IDX(RGB565_2X8_BE)] = { | 82 | }, { |
83 | .code = V4L2_MBUS_FMT_RGB565_2X8_BE, | ||
84 | .fmt = { | ||
71 | .fourcc = V4L2_PIX_FMT_RGB565X, | 85 | .fourcc = V4L2_PIX_FMT_RGB565X, |
72 | .name = "RGB565X", | 86 | .name = "RGB565X", |
73 | .bits_per_sample = 8, | 87 | .bits_per_sample = 8, |
74 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 88 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
75 | .order = SOC_MBUS_ORDER_LE, | 89 | .order = SOC_MBUS_ORDER_LE, |
76 | }, | 90 | }, |
77 | [MBUS_IDX(SBGGR8_1X8)] = { | 91 | }, { |
92 | .code = V4L2_MBUS_FMT_SBGGR8_1X8, | ||
93 | .fmt = { | ||
78 | .fourcc = V4L2_PIX_FMT_SBGGR8, | 94 | .fourcc = V4L2_PIX_FMT_SBGGR8, |
79 | .name = "Bayer 8 BGGR", | 95 | .name = "Bayer 8 BGGR", |
80 | .bits_per_sample = 8, | 96 | .bits_per_sample = 8, |
81 | .packing = SOC_MBUS_PACKING_NONE, | 97 | .packing = SOC_MBUS_PACKING_NONE, |
82 | .order = SOC_MBUS_ORDER_LE, | 98 | .order = SOC_MBUS_ORDER_LE, |
83 | }, | 99 | }, |
84 | [MBUS_IDX(SBGGR10_1X10)] = { | 100 | }, { |
101 | .code = V4L2_MBUS_FMT_SBGGR10_1X10, | ||
102 | .fmt = { | ||
85 | .fourcc = V4L2_PIX_FMT_SBGGR10, | 103 | .fourcc = V4L2_PIX_FMT_SBGGR10, |
86 | .name = "Bayer 10 BGGR", | 104 | .name = "Bayer 10 BGGR", |
87 | .bits_per_sample = 10, | 105 | .bits_per_sample = 10, |
88 | .packing = SOC_MBUS_PACKING_EXTEND16, | 106 | .packing = SOC_MBUS_PACKING_EXTEND16, |
89 | .order = SOC_MBUS_ORDER_LE, | 107 | .order = SOC_MBUS_ORDER_LE, |
90 | }, | 108 | }, |
91 | [MBUS_IDX(Y8_1X8)] = { | 109 | }, { |
110 | .code = V4L2_MBUS_FMT_Y8_1X8, | ||
111 | .fmt = { | ||
92 | .fourcc = V4L2_PIX_FMT_GREY, | 112 | .fourcc = V4L2_PIX_FMT_GREY, |
93 | .name = "Grey", | 113 | .name = "Grey", |
94 | .bits_per_sample = 8, | 114 | .bits_per_sample = 8, |
95 | .packing = SOC_MBUS_PACKING_NONE, | 115 | .packing = SOC_MBUS_PACKING_NONE, |
96 | .order = SOC_MBUS_ORDER_LE, | 116 | .order = SOC_MBUS_ORDER_LE, |
97 | }, | 117 | }, |
98 | [MBUS_IDX(Y10_1X10)] = { | 118 | }, { |
119 | .code = V4L2_MBUS_FMT_Y10_1X10, | ||
120 | .fmt = { | ||
99 | .fourcc = V4L2_PIX_FMT_Y10, | 121 | .fourcc = V4L2_PIX_FMT_Y10, |
100 | .name = "Grey 10bit", | 122 | .name = "Grey 10bit", |
101 | .bits_per_sample = 10, | 123 | .bits_per_sample = 10, |
102 | .packing = SOC_MBUS_PACKING_EXTEND16, | 124 | .packing = SOC_MBUS_PACKING_EXTEND16, |
103 | .order = SOC_MBUS_ORDER_LE, | 125 | .order = SOC_MBUS_ORDER_LE, |
104 | }, | 126 | }, |
105 | [MBUS_IDX(SBGGR10_2X8_PADHI_LE)] = { | 127 | }, { |
128 | .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, | ||
129 | .fmt = { | ||
106 | .fourcc = V4L2_PIX_FMT_SBGGR10, | 130 | .fourcc = V4L2_PIX_FMT_SBGGR10, |
107 | .name = "Bayer 10 BGGR", | 131 | .name = "Bayer 10 BGGR", |
108 | .bits_per_sample = 8, | 132 | .bits_per_sample = 8, |
109 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 133 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
110 | .order = SOC_MBUS_ORDER_LE, | 134 | .order = SOC_MBUS_ORDER_LE, |
111 | }, | 135 | }, |
112 | [MBUS_IDX(SBGGR10_2X8_PADLO_LE)] = { | 136 | }, { |
137 | .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE, | ||
138 | .fmt = { | ||
113 | .fourcc = V4L2_PIX_FMT_SBGGR10, | 139 | .fourcc = V4L2_PIX_FMT_SBGGR10, |
114 | .name = "Bayer 10 BGGR", | 140 | .name = "Bayer 10 BGGR", |
115 | .bits_per_sample = 8, | 141 | .bits_per_sample = 8, |
116 | .packing = SOC_MBUS_PACKING_2X8_PADLO, | 142 | .packing = SOC_MBUS_PACKING_2X8_PADLO, |
117 | .order = SOC_MBUS_ORDER_LE, | 143 | .order = SOC_MBUS_ORDER_LE, |
118 | }, | 144 | }, |
119 | [MBUS_IDX(SBGGR10_2X8_PADHI_BE)] = { | 145 | }, { |
146 | .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE, | ||
147 | .fmt = { | ||
120 | .fourcc = V4L2_PIX_FMT_SBGGR10, | 148 | .fourcc = V4L2_PIX_FMT_SBGGR10, |
121 | .name = "Bayer 10 BGGR", | 149 | .name = "Bayer 10 BGGR", |
122 | .bits_per_sample = 8, | 150 | .bits_per_sample = 8, |
123 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | 151 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
124 | .order = SOC_MBUS_ORDER_BE, | 152 | .order = SOC_MBUS_ORDER_BE, |
125 | }, | 153 | }, |
126 | [MBUS_IDX(SBGGR10_2X8_PADLO_BE)] = { | 154 | }, { |
155 | .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE, | ||
156 | .fmt = { | ||
127 | .fourcc = V4L2_PIX_FMT_SBGGR10, | 157 | .fourcc = V4L2_PIX_FMT_SBGGR10, |
128 | .name = "Bayer 10 BGGR", | 158 | .name = "Bayer 10 BGGR", |
129 | .bits_per_sample = 8, | 159 | .bits_per_sample = 8, |
130 | .packing = SOC_MBUS_PACKING_2X8_PADLO, | 160 | .packing = SOC_MBUS_PACKING_2X8_PADLO, |
131 | .order = SOC_MBUS_ORDER_BE, | 161 | .order = SOC_MBUS_ORDER_BE, |
132 | }, | 162 | }, |
163 | }, { | ||
164 | .code = V4L2_MBUS_FMT_JPEG_1X8, | ||
165 | .fmt = { | ||
166 | .fourcc = V4L2_PIX_FMT_JPEG, | ||
167 | .name = "JPEG", | ||
168 | .bits_per_sample = 8, | ||
169 | .packing = SOC_MBUS_PACKING_VARIABLE, | ||
170 | .order = SOC_MBUS_ORDER_LE, | ||
171 | }, | ||
172 | }, { | ||
173 | .code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE, | ||
174 | .fmt = { | ||
175 | .fourcc = V4L2_PIX_FMT_RGB444, | ||
176 | .name = "RGB444", | ||
177 | .bits_per_sample = 8, | ||
178 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
179 | .order = SOC_MBUS_ORDER_BE, | ||
180 | }, | ||
181 | }, { | ||
182 | .code = V4L2_MBUS_FMT_YUYV8_1_5X8, | ||
183 | .fmt = { | ||
184 | .fourcc = V4L2_PIX_FMT_YUV420, | ||
185 | .name = "YUYV 4:2:0", | ||
186 | .bits_per_sample = 8, | ||
187 | .packing = SOC_MBUS_PACKING_1_5X8, | ||
188 | .order = SOC_MBUS_ORDER_LE, | ||
189 | }, | ||
190 | }, { | ||
191 | .code = V4L2_MBUS_FMT_YVYU8_1_5X8, | ||
192 | .fmt = { | ||
193 | .fourcc = V4L2_PIX_FMT_YVU420, | ||
194 | .name = "YVYU 4:2:0", | ||
195 | .bits_per_sample = 8, | ||
196 | .packing = SOC_MBUS_PACKING_1_5X8, | ||
197 | .order = SOC_MBUS_ORDER_LE, | ||
198 | }, | ||
199 | }, { | ||
200 | .code = V4L2_MBUS_FMT_UYVY8_1X16, | ||
201 | .fmt = { | ||
202 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
203 | .name = "UYVY 16bit", | ||
204 | .bits_per_sample = 16, | ||
205 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
206 | .order = SOC_MBUS_ORDER_LE, | ||
207 | }, | ||
208 | }, { | ||
209 | .code = V4L2_MBUS_FMT_VYUY8_1X16, | ||
210 | .fmt = { | ||
211 | .fourcc = V4L2_PIX_FMT_VYUY, | ||
212 | .name = "VYUY 16bit", | ||
213 | .bits_per_sample = 16, | ||
214 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
215 | .order = SOC_MBUS_ORDER_LE, | ||
216 | }, | ||
217 | }, { | ||
218 | .code = V4L2_MBUS_FMT_YUYV8_1X16, | ||
219 | .fmt = { | ||
220 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
221 | .name = "YUYV 16bit", | ||
222 | .bits_per_sample = 16, | ||
223 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
224 | .order = SOC_MBUS_ORDER_LE, | ||
225 | }, | ||
226 | }, { | ||
227 | .code = V4L2_MBUS_FMT_YVYU8_1X16, | ||
228 | .fmt = { | ||
229 | .fourcc = V4L2_PIX_FMT_YVYU, | ||
230 | .name = "YVYU 16bit", | ||
231 | .bits_per_sample = 16, | ||
232 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
233 | .order = SOC_MBUS_ORDER_LE, | ||
234 | }, | ||
235 | }, { | ||
236 | .code = V4L2_MBUS_FMT_SGRBG8_1X8, | ||
237 | .fmt = { | ||
238 | .fourcc = V4L2_PIX_FMT_SGRBG8, | ||
239 | .name = "Bayer 8 GRBG", | ||
240 | .bits_per_sample = 8, | ||
241 | .packing = SOC_MBUS_PACKING_NONE, | ||
242 | .order = SOC_MBUS_ORDER_LE, | ||
243 | }, | ||
244 | }, { | ||
245 | .code = V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, | ||
246 | .fmt = { | ||
247 | .fourcc = V4L2_PIX_FMT_SGRBG10DPCM8, | ||
248 | .name = "Bayer 10 BGGR DPCM 8", | ||
249 | .bits_per_sample = 8, | ||
250 | .packing = SOC_MBUS_PACKING_NONE, | ||
251 | .order = SOC_MBUS_ORDER_LE, | ||
252 | }, | ||
253 | }, { | ||
254 | .code = V4L2_MBUS_FMT_SGBRG10_1X10, | ||
255 | .fmt = { | ||
256 | .fourcc = V4L2_PIX_FMT_SGBRG10, | ||
257 | .name = "Bayer 10 GBRG", | ||
258 | .bits_per_sample = 10, | ||
259 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
260 | .order = SOC_MBUS_ORDER_LE, | ||
261 | }, | ||
262 | }, { | ||
263 | .code = V4L2_MBUS_FMT_SGRBG10_1X10, | ||
264 | .fmt = { | ||
265 | .fourcc = V4L2_PIX_FMT_SGRBG10, | ||
266 | .name = "Bayer 10 GRBG", | ||
267 | .bits_per_sample = 10, | ||
268 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
269 | .order = SOC_MBUS_ORDER_LE, | ||
270 | }, | ||
271 | }, { | ||
272 | .code = V4L2_MBUS_FMT_SRGGB10_1X10, | ||
273 | .fmt = { | ||
274 | .fourcc = V4L2_PIX_FMT_SRGGB10, | ||
275 | .name = "Bayer 10 RGGB", | ||
276 | .bits_per_sample = 10, | ||
277 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
278 | .order = SOC_MBUS_ORDER_LE, | ||
279 | }, | ||
280 | }, { | ||
281 | .code = V4L2_MBUS_FMT_SBGGR12_1X12, | ||
282 | .fmt = { | ||
283 | .fourcc = V4L2_PIX_FMT_SBGGR12, | ||
284 | .name = "Bayer 12 BGGR", | ||
285 | .bits_per_sample = 12, | ||
286 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
287 | .order = SOC_MBUS_ORDER_LE, | ||
288 | }, | ||
289 | }, { | ||
290 | .code = V4L2_MBUS_FMT_SGBRG12_1X12, | ||
291 | .fmt = { | ||
292 | .fourcc = V4L2_PIX_FMT_SGBRG12, | ||
293 | .name = "Bayer 12 GBRG", | ||
294 | .bits_per_sample = 12, | ||
295 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
296 | .order = SOC_MBUS_ORDER_LE, | ||
297 | }, | ||
298 | }, { | ||
299 | .code = V4L2_MBUS_FMT_SGRBG12_1X12, | ||
300 | .fmt = { | ||
301 | .fourcc = V4L2_PIX_FMT_SGRBG12, | ||
302 | .name = "Bayer 12 GRBG", | ||
303 | .bits_per_sample = 12, | ||
304 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
305 | .order = SOC_MBUS_ORDER_LE, | ||
306 | }, | ||
307 | }, { | ||
308 | .code = V4L2_MBUS_FMT_SRGGB12_1X12, | ||
309 | .fmt = { | ||
310 | .fourcc = V4L2_PIX_FMT_SRGGB12, | ||
311 | .name = "Bayer 12 RGGB", | ||
312 | .bits_per_sample = 12, | ||
313 | .packing = SOC_MBUS_PACKING_EXTEND16, | ||
314 | .order = SOC_MBUS_ORDER_LE, | ||
315 | }, | ||
316 | }, | ||
133 | }; | 317 | }; |
134 | 318 | ||
135 | int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf) | 319 | int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf, |
320 | unsigned int *numerator, unsigned int *denominator) | ||
136 | { | 321 | { |
137 | switch (mf->packing) { | 322 | switch (mf->packing) { |
138 | case SOC_MBUS_PACKING_NONE: | 323 | case SOC_MBUS_PACKING_NONE: |
139 | case SOC_MBUS_PACKING_EXTEND16: | 324 | case SOC_MBUS_PACKING_EXTEND16: |
140 | return 1; | 325 | *numerator = 1; |
326 | *denominator = 1; | ||
327 | return 0; | ||
141 | case SOC_MBUS_PACKING_2X8_PADHI: | 328 | case SOC_MBUS_PACKING_2X8_PADHI: |
142 | case SOC_MBUS_PACKING_2X8_PADLO: | 329 | case SOC_MBUS_PACKING_2X8_PADLO: |
143 | return 2; | 330 | *numerator = 2; |
331 | *denominator = 1; | ||
332 | return 0; | ||
333 | case SOC_MBUS_PACKING_1_5X8: | ||
334 | *numerator = 3; | ||
335 | *denominator = 2; | ||
336 | return 0; | ||
337 | case SOC_MBUS_PACKING_VARIABLE: | ||
338 | *numerator = 0; | ||
339 | *denominator = 1; | ||
340 | return 0; | ||
144 | } | 341 | } |
145 | return -EINVAL; | 342 | return -EINVAL; |
146 | } | 343 | } |
@@ -155,18 +352,34 @@ s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf) | |||
155 | case SOC_MBUS_PACKING_2X8_PADLO: | 352 | case SOC_MBUS_PACKING_2X8_PADLO: |
156 | case SOC_MBUS_PACKING_EXTEND16: | 353 | case SOC_MBUS_PACKING_EXTEND16: |
157 | return width * 2; | 354 | return width * 2; |
355 | case SOC_MBUS_PACKING_1_5X8: | ||
356 | return width * 3 / 2; | ||
357 | case SOC_MBUS_PACKING_VARIABLE: | ||
358 | return 0; | ||
158 | } | 359 | } |
159 | return -EINVAL; | 360 | return -EINVAL; |
160 | } | 361 | } |
161 | EXPORT_SYMBOL(soc_mbus_bytes_per_line); | 362 | EXPORT_SYMBOL(soc_mbus_bytes_per_line); |
162 | 363 | ||
364 | const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc( | ||
365 | enum v4l2_mbus_pixelcode code, | ||
366 | const struct soc_mbus_lookup *lookup, | ||
367 | int n) | ||
368 | { | ||
369 | int i; | ||
370 | |||
371 | for (i = 0; i < n; i++) | ||
372 | if (lookup[i].code == code) | ||
373 | return &lookup[i].fmt; | ||
374 | |||
375 | return NULL; | ||
376 | } | ||
377 | EXPORT_SYMBOL(soc_mbus_find_fmtdesc); | ||
378 | |||
163 | const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( | 379 | const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( |
164 | enum v4l2_mbus_pixelcode code) | 380 | enum v4l2_mbus_pixelcode code) |
165 | { | 381 | { |
166 | if (code - V4L2_MBUS_FMT_FIXED > ARRAY_SIZE(mbus_fmt) || | 382 | return soc_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt)); |
167 | code <= V4L2_MBUS_FMT_FIXED) | ||
168 | return NULL; | ||
169 | return mbus_fmt + code - V4L2_MBUS_FMT_FIXED - 1; | ||
170 | } | 383 | } |
171 | EXPORT_SYMBOL(soc_mbus_get_fmtdesc); | 384 | EXPORT_SYMBOL(soc_mbus_get_fmtdesc); |
172 | 385 | ||
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 07fabdd9b465..6103d1b1081e 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c | |||
@@ -267,21 +267,27 @@ hauppauge_tuner[] = | |||
267 | { TUNER_ABSENT, "Xceive XC4000"}, | 267 | { TUNER_ABSENT, "Xceive XC4000"}, |
268 | { TUNER_ABSENT, "Dibcom 7070"}, | 268 | { TUNER_ABSENT, "Dibcom 7070"}, |
269 | { TUNER_PHILIPS_TDA8290, "NXP 18271C2"}, | 269 | { TUNER_PHILIPS_TDA8290, "NXP 18271C2"}, |
270 | { TUNER_ABSENT, "unknown"}, | 270 | { TUNER_ABSENT, "Siano SMS1010"}, |
271 | { TUNER_ABSENT, "unknown"}, | 271 | { TUNER_ABSENT, "Siano SMS1150"}, |
272 | { TUNER_ABSENT, "unknown"}, | 272 | { TUNER_ABSENT, "MaxLinear 5007"}, |
273 | { TUNER_ABSENT, "unknown"}, | 273 | { TUNER_ABSENT, "TCL M09WPP_2P_E"}, |
274 | /* 160-169 */ | 274 | /* 160-169 */ |
275 | { TUNER_ABSENT, "unknown"}, | 275 | { TUNER_ABSENT, "Siano SMS1180"}, |
276 | { TUNER_ABSENT, "unknown"}, | 276 | { TUNER_ABSENT, "Maxim_MAX2165"}, |
277 | { TUNER_ABSENT, "unknown"}, | 277 | { TUNER_ABSENT, "Siano SMS1140"}, |
278 | { TUNER_ABSENT, "unknown"}, | 278 | { TUNER_ABSENT, "Siano SMS1150 B1"}, |
279 | { TUNER_ABSENT, "unknown"}, | 279 | { TUNER_ABSENT, "MaxLinear 111"}, |
280 | { TUNER_ABSENT, "unknown"}, | 280 | { TUNER_ABSENT, "Dibcom 7770"}, |
281 | { TUNER_ABSENT, "unknown"}, | 281 | { TUNER_ABSENT, "Siano SMS1180VNS"}, |
282 | { TUNER_ABSENT, "unknown"}, | 282 | { TUNER_ABSENT, "Siano SMS1184"}, |
283 | { TUNER_PHILIPS_FQ1236_MK5, "TCL M30WTP-4N-E"}, | 283 | { TUNER_PHILIPS_FQ1236_MK5, "TCL M30WTP-4N-E"}, |
284 | { TUNER_ABSENT, "unknown"}, | 284 | { TUNER_ABSENT, "TCL_M11WPP_2PN_E"}, |
285 | /* 170-179 */ | ||
286 | { TUNER_ABSENT, "MaxLinear 301"}, | ||
287 | { TUNER_ABSENT, "Mirics MSi001"}, | ||
288 | { TUNER_ABSENT, "MaxLinear MxL241SF"}, | ||
289 | { TUNER_ABSENT, "Xceive XC5000C"}, | ||
290 | { TUNER_ABSENT, "Montage M68TS2020"}, | ||
285 | }; | 291 | }; |
286 | 292 | ||
287 | /* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are | 293 | /* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are |
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c index 68b998bd203f..8f5266157f15 100644 --- a/drivers/media/video/usbvision/usbvision-cards.c +++ b/drivers/media/video/usbvision/usbvision-cards.c | |||
@@ -1025,6 +1025,34 @@ struct usbvision_device_data_st usbvision_device_data[] = { | |||
1025 | .y_offset = -1, | 1025 | .y_offset = -1, |
1026 | .model_string = "Hauppauge WinTv-USB", | 1026 | .model_string = "Hauppauge WinTv-USB", |
1027 | }, | 1027 | }, |
1028 | [MICROCAM_NTSC] = { | ||
1029 | .interface = -1, | ||
1030 | .codec = CODEC_WEBCAM, | ||
1031 | .video_channels = 1, | ||
1032 | .video_norm = V4L2_STD_NTSC, | ||
1033 | .audio_channels = 0, | ||
1034 | .radio = 0, | ||
1035 | .vbi = 0, | ||
1036 | .tuner = 0, | ||
1037 | .tuner_type = 0, | ||
1038 | .x_offset = 71, | ||
1039 | .y_offset = 15, | ||
1040 | .model_string = "Nogatech USB MicroCam NTSC (NV3000N)", | ||
1041 | }, | ||
1042 | [MICROCAM_PAL] = { | ||
1043 | .interface = -1, | ||
1044 | .codec = CODEC_WEBCAM, | ||
1045 | .video_channels = 1, | ||
1046 | .video_norm = V4L2_STD_PAL, | ||
1047 | .audio_channels = 0, | ||
1048 | .radio = 0, | ||
1049 | .vbi = 0, | ||
1050 | .tuner = 0, | ||
1051 | .tuner_type = 0, | ||
1052 | .x_offset = 71, | ||
1053 | .y_offset = 18, | ||
1054 | .model_string = "Nogatech USB MicroCam PAL (NV3001P)", | ||
1055 | }, | ||
1028 | }; | 1056 | }; |
1029 | const int usbvision_device_data_size = ARRAY_SIZE(usbvision_device_data); | 1057 | const int usbvision_device_data_size = ARRAY_SIZE(usbvision_device_data); |
1030 | 1058 | ||
@@ -1042,6 +1070,8 @@ struct usb_device_id usbvision_table[] = { | |||
1042 | { USB_DEVICE(0x0573, 0x2d00), .driver_info = HPG_WINTV_LIVE_PAL_BG }, | 1070 | { USB_DEVICE(0x0573, 0x2d00), .driver_info = HPG_WINTV_LIVE_PAL_BG }, |
1043 | { USB_DEVICE(0x0573, 0x2d01), .driver_info = HPG_WINTV_LIVE_PRO_NTSC_MN }, | 1071 | { USB_DEVICE(0x0573, 0x2d01), .driver_info = HPG_WINTV_LIVE_PRO_NTSC_MN }, |
1044 | { USB_DEVICE(0x0573, 0x2101), .driver_info = ZORAN_PMD_NOGATECH }, | 1072 | { USB_DEVICE(0x0573, 0x2101), .driver_info = ZORAN_PMD_NOGATECH }, |
1073 | { USB_DEVICE(0x0573, 0x3000), .driver_info = MICROCAM_NTSC }, | ||
1074 | { USB_DEVICE(0x0573, 0x3001), .driver_info = MICROCAM_PAL }, | ||
1045 | { USB_DEVICE(0x0573, 0x4100), .driver_info = NOGATECH_USB_TV_NTSC_FM }, | 1075 | { USB_DEVICE(0x0573, 0x4100), .driver_info = NOGATECH_USB_TV_NTSC_FM }, |
1046 | { USB_DEVICE(0x0573, 0x4110), .driver_info = PNY_USB_TV_NTSC_FM }, | 1076 | { USB_DEVICE(0x0573, 0x4110), .driver_info = PNY_USB_TV_NTSC_FM }, |
1047 | { USB_DEVICE(0x0573, 0x4450), .driver_info = PV_PLAYTV_USB_PRO_PAL_FM }, | 1077 | { USB_DEVICE(0x0573, 0x4450), .driver_info = PV_PLAYTV_USB_PRO_PAL_FM }, |
@@ -1088,8 +1118,7 @@ struct usb_device_id usbvision_table[] = { | |||
1088 | { USB_DEVICE(0x2304, 0x0110), .driver_info = PINNA_PCTV_USB_PAL_FM }, | 1118 | { USB_DEVICE(0x2304, 0x0110), .driver_info = PINNA_PCTV_USB_PAL_FM }, |
1089 | { USB_DEVICE(0x2304, 0x0111), .driver_info = MIRO_PCTV_USB }, | 1119 | { USB_DEVICE(0x2304, 0x0111), .driver_info = MIRO_PCTV_USB }, |
1090 | { USB_DEVICE(0x2304, 0x0112), .driver_info = PINNA_PCTV_USB_NTSC_FM }, | 1120 | { USB_DEVICE(0x2304, 0x0112), .driver_info = PINNA_PCTV_USB_NTSC_FM }, |
1091 | { USB_DEVICE(0x2304, 0x0113), | 1121 | { USB_DEVICE(0x2304, 0x0113), .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 }, |
1092 | .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 }, | ||
1093 | { USB_DEVICE(0x2304, 0x0210), .driver_info = PINNA_PCTV_USB_PAL_FM_V2 }, | 1122 | { USB_DEVICE(0x2304, 0x0210), .driver_info = PINNA_PCTV_USB_PAL_FM_V2 }, |
1094 | { USB_DEVICE(0x2304, 0x0212), .driver_info = PINNA_PCTV_USB_NTSC_FM_V2 }, | 1123 | { USB_DEVICE(0x2304, 0x0212), .driver_info = PINNA_PCTV_USB_NTSC_FM_V2 }, |
1095 | { USB_DEVICE(0x2304, 0x0214), .driver_info = PINNA_PCTV_USB_PAL_FM_V3 }, | 1124 | { USB_DEVICE(0x2304, 0x0214), .driver_info = PINNA_PCTV_USB_PAL_FM_V3 }, |
diff --git a/drivers/media/video/usbvision/usbvision-cards.h b/drivers/media/video/usbvision/usbvision-cards.h index 9c6ad22960d8..a51cc1185cce 100644 --- a/drivers/media/video/usbvision/usbvision-cards.h +++ b/drivers/media/video/usbvision/usbvision-cards.h | |||
@@ -63,5 +63,7 @@ | |||
63 | #define PINNA_PCTV_BUNGEE_PAL_FM 62 | 63 | #define PINNA_PCTV_BUNGEE_PAL_FM 62 |
64 | #define HPG_WINTV 63 | 64 | #define HPG_WINTV 63 |
65 | #define PINNA_PCTV_USB_NTSC_FM_V3 64 | 65 | #define PINNA_PCTV_USB_NTSC_FM_V3 64 |
66 | #define MICROCAM_NTSC 65 | ||
67 | #define MICROCAM_PAL 66 | ||
66 | 68 | ||
67 | extern const int usbvision_device_data_size; | 69 | extern const int usbvision_device_data_size; |
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index c8feb0d6fccf..f344411a4578 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c | |||
@@ -49,10 +49,6 @@ static unsigned int core_debug; | |||
49 | module_param(core_debug, int, 0644); | 49 | module_param(core_debug, int, 0644); |
50 | MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); | 50 | MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); |
51 | 51 | ||
52 | static unsigned int force_testpattern; | ||
53 | module_param(force_testpattern, int, 0644); | ||
54 | MODULE_PARM_DESC(force_testpattern, "enable test pattern display [core]"); | ||
55 | |||
56 | static int adjust_compression = 1; /* Set the compression to be adaptive */ | 52 | static int adjust_compression = 1; /* Set the compression to be adaptive */ |
57 | module_param(adjust_compression, int, 0444); | 53 | module_param(adjust_compression, int, 0444); |
58 | MODULE_PARM_DESC(adjust_compression, " Set the ADPCM compression for the device. Default: 1 (On)"); | 54 | MODULE_PARM_DESC(adjust_compression, " Set the ADPCM compression for the device. Default: 1 (On)"); |
@@ -388,90 +384,6 @@ void usbvision_scratch_free(struct usb_usbvision *usbvision) | |||
388 | } | 384 | } |
389 | 385 | ||
390 | /* | 386 | /* |
391 | * usbvision_testpattern() | ||
392 | * | ||
393 | * Procedure forms a test pattern (yellow grid on blue background). | ||
394 | * | ||
395 | * Parameters: | ||
396 | * fullframe: if TRUE then entire frame is filled, otherwise the procedure | ||
397 | * continues from the current scanline. | ||
398 | * pmode 0: fill the frame with solid blue color (like on VCR or TV) | ||
399 | * 1: Draw a colored grid | ||
400 | * | ||
401 | */ | ||
402 | static void usbvision_testpattern(struct usb_usbvision *usbvision, | ||
403 | int fullframe, int pmode) | ||
404 | { | ||
405 | static const char proc[] = "usbvision_testpattern"; | ||
406 | struct usbvision_frame *frame; | ||
407 | unsigned char *f; | ||
408 | int num_cell = 0; | ||
409 | int scan_length = 0; | ||
410 | static int num_pass; | ||
411 | |||
412 | if (usbvision == NULL) { | ||
413 | printk(KERN_ERR "%s: usbvision == NULL\n", proc); | ||
414 | return; | ||
415 | } | ||
416 | if (usbvision->cur_frame == NULL) { | ||
417 | printk(KERN_ERR "%s: usbvision->cur_frame is NULL.\n", proc); | ||
418 | return; | ||
419 | } | ||
420 | |||
421 | /* Grab the current frame */ | ||
422 | frame = usbvision->cur_frame; | ||
423 | |||
424 | /* Optionally start at the beginning */ | ||
425 | if (fullframe) { | ||
426 | frame->curline = 0; | ||
427 | frame->scanlength = 0; | ||
428 | } | ||
429 | |||
430 | /* Form every scan line */ | ||
431 | for (; frame->curline < frame->frmheight; frame->curline++) { | ||
432 | int i; | ||
433 | |||
434 | f = frame->data + (usbvision->curwidth * 3 * frame->curline); | ||
435 | for (i = 0; i < usbvision->curwidth; i++) { | ||
436 | unsigned char cb = 0x80; | ||
437 | unsigned char cg = 0; | ||
438 | unsigned char cr = 0; | ||
439 | |||
440 | if (pmode == 1) { | ||
441 | if (frame->curline % 32 == 0) | ||
442 | cb = 0, cg = cr = 0xFF; | ||
443 | else if (i % 32 == 0) { | ||
444 | if (frame->curline % 32 == 1) | ||
445 | num_cell++; | ||
446 | cb = 0, cg = cr = 0xFF; | ||
447 | } else { | ||
448 | cb = | ||
449 | ((num_cell * 7) + | ||
450 | num_pass) & 0xFF; | ||
451 | cg = | ||
452 | ((num_cell * 5) + | ||
453 | num_pass * 2) & 0xFF; | ||
454 | cr = | ||
455 | ((num_cell * 3) + | ||
456 | num_pass * 3) & 0xFF; | ||
457 | } | ||
458 | } else { | ||
459 | /* Just the blue screen */ | ||
460 | } | ||
461 | |||
462 | *f++ = cb; | ||
463 | *f++ = cg; | ||
464 | *f++ = cr; | ||
465 | scan_length += 3; | ||
466 | } | ||
467 | } | ||
468 | |||
469 | frame->grabstate = frame_state_done; | ||
470 | frame->scanlength += scan_length; | ||
471 | ++num_pass; | ||
472 | } | ||
473 | |||
474 | /* | ||
475 | * usbvision_decompress_alloc() | 387 | * usbvision_decompress_alloc() |
476 | * | 388 | * |
477 | * allocates intermediate buffer for decompression | 389 | * allocates intermediate buffer for decompression |
@@ -571,10 +483,6 @@ static enum parse_state usbvision_find_header(struct usb_usbvision *usbvision) | |||
571 | frame->scanstate = scan_state_lines; | 483 | frame->scanstate = scan_state_lines; |
572 | frame->curline = 0; | 484 | frame->curline = 0; |
573 | 485 | ||
574 | if (force_testpattern) { | ||
575 | usbvision_testpattern(usbvision, 1, 1); | ||
576 | return parse_state_next_frame; | ||
577 | } | ||
578 | return parse_state_continue; | 486 | return parse_state_continue; |
579 | } | 487 | } |
580 | 488 | ||
@@ -1679,6 +1587,55 @@ int usbvision_power_off(struct usb_usbvision *usbvision) | |||
1679 | return err_code; | 1587 | return err_code; |
1680 | } | 1588 | } |
1681 | 1589 | ||
1590 | /* configure webcam image sensor using the serial port */ | ||
1591 | static int usbvision_init_webcam(struct usb_usbvision *usbvision) | ||
1592 | { | ||
1593 | int rc; | ||
1594 | int i; | ||
1595 | static char init_values[38][3] = { | ||
1596 | { 0x04, 0x12, 0x08 }, { 0x05, 0xff, 0xc8 }, { 0x06, 0x18, 0x07 }, { 0x07, 0x90, 0x00 }, | ||
1597 | { 0x09, 0x00, 0x00 }, { 0x0a, 0x00, 0x00 }, { 0x0b, 0x08, 0x00 }, { 0x0d, 0xcc, 0xcc }, | ||
1598 | { 0x0e, 0x13, 0x14 }, { 0x10, 0x9b, 0x83 }, { 0x11, 0x5a, 0x3f }, { 0x12, 0xe4, 0x73 }, | ||
1599 | { 0x13, 0x88, 0x84 }, { 0x14, 0x89, 0x80 }, { 0x15, 0x00, 0x20 }, { 0x16, 0x00, 0x00 }, | ||
1600 | { 0x17, 0xff, 0xa0 }, { 0x18, 0x6b, 0x20 }, { 0x19, 0x22, 0x40 }, { 0x1a, 0x10, 0x07 }, | ||
1601 | { 0x1b, 0x00, 0x47 }, { 0x1c, 0x03, 0xe0 }, { 0x1d, 0x00, 0x00 }, { 0x1e, 0x00, 0x00 }, | ||
1602 | { 0x1f, 0x00, 0x00 }, { 0x20, 0x00, 0x00 }, { 0x21, 0x00, 0x00 }, { 0x22, 0x00, 0x00 }, | ||
1603 | { 0x23, 0x00, 0x00 }, { 0x24, 0x00, 0x00 }, { 0x25, 0x00, 0x00 }, { 0x26, 0x00, 0x00 }, | ||
1604 | { 0x27, 0x00, 0x00 }, { 0x28, 0x00, 0x00 }, { 0x29, 0x00, 0x00 }, { 0x08, 0x80, 0x60 }, | ||
1605 | { 0x0f, 0x2d, 0x24 }, { 0x0c, 0x80, 0x80 } | ||
1606 | }; | ||
1607 | char value[3]; | ||
1608 | |||
1609 | /* the only difference between PAL and NTSC init_values */ | ||
1610 | if (usbvision_device_data[usbvision->dev_model].video_norm == V4L2_STD_NTSC) | ||
1611 | init_values[4][1] = 0x34; | ||
1612 | |||
1613 | for (i = 0; i < sizeof(init_values) / 3; i++) { | ||
1614 | usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT); | ||
1615 | memcpy(value, init_values[i], 3); | ||
1616 | rc = usb_control_msg(usbvision->dev, | ||
1617 | usb_sndctrlpipe(usbvision->dev, 1), | ||
1618 | USBVISION_OP_CODE, | ||
1619 | USB_DIR_OUT | USB_TYPE_VENDOR | | ||
1620 | USB_RECIP_ENDPOINT, 0, | ||
1621 | (__u16) USBVISION_SER_DAT1, value, | ||
1622 | 3, HZ); | ||
1623 | if (rc < 0) | ||
1624 | return rc; | ||
1625 | usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SIO); | ||
1626 | /* write 3 bytes to the serial port using SIO mode */ | ||
1627 | usbvision_write_reg(usbvision, USBVISION_SER_CONT, 3 | 0x10); | ||
1628 | usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, 0); | ||
1629 | usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT); | ||
1630 | usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, USBVISION_IO_2); | ||
1631 | usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_CLK_OUT); | ||
1632 | usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_DAT_IO); | ||
1633 | usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_CLK_OUT | USBVISION_DAT_IO); | ||
1634 | } | ||
1635 | |||
1636 | return 0; | ||
1637 | } | ||
1638 | |||
1682 | /* | 1639 | /* |
1683 | * usbvision_set_video_format() | 1640 | * usbvision_set_video_format() |
1684 | * | 1641 | * |
@@ -1797,6 +1754,13 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width, | |||
1797 | 1754 | ||
1798 | frame_drop = FRAMERATE_MAX; /* We can allow the maximum here, because dropping is controlled */ | 1755 | frame_drop = FRAMERATE_MAX; /* We can allow the maximum here, because dropping is controlled */ |
1799 | 1756 | ||
1757 | if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) { | ||
1758 | if (usbvision_device_data[usbvision->dev_model].video_norm == V4L2_STD_PAL) | ||
1759 | frame_drop = 25; | ||
1760 | else | ||
1761 | frame_drop = 30; | ||
1762 | } | ||
1763 | |||
1800 | /* frame_drop = 7; => frame_phase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ... | 1764 | /* frame_drop = 7; => frame_phase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ... |
1801 | => frame_skip = 4; | 1765 | => frame_skip = 4; |
1802 | => frame_rate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25; | 1766 | => frame_rate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25; |
@@ -2046,6 +2010,12 @@ int usbvision_set_input(struct usb_usbvision *usbvision) | |||
2046 | value[7] = 0x00; /* 0x0010 -> 16 Input video v offset */ | 2010 | value[7] = 0x00; /* 0x0010 -> 16 Input video v offset */ |
2047 | } | 2011 | } |
2048 | 2012 | ||
2013 | /* webcam is only 480 pixels wide, both PAL and NTSC version */ | ||
2014 | if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) { | ||
2015 | value[0] = 0xe0; | ||
2016 | value[1] = 0x01; /* 0x01E0 -> 480 Input video line length */ | ||
2017 | } | ||
2018 | |||
2049 | if (usbvision_device_data[usbvision->dev_model].x_offset >= 0) { | 2019 | if (usbvision_device_data[usbvision->dev_model].x_offset >= 0) { |
2050 | value[4] = usbvision_device_data[usbvision->dev_model].x_offset & 0xff; | 2020 | value[4] = usbvision_device_data[usbvision->dev_model].x_offset & 0xff; |
2051 | value[5] = (usbvision_device_data[usbvision->dev_model].x_offset & 0x0300) >> 8; | 2021 | value[5] = (usbvision_device_data[usbvision->dev_model].x_offset & 0x0300) >> 8; |
@@ -2148,7 +2118,7 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision) | |||
2148 | (__u16) USBVISION_DRM_PRM1, value, 8, HZ); | 2118 | (__u16) USBVISION_DRM_PRM1, value, 8, HZ); |
2149 | 2119 | ||
2150 | if (rc < 0) { | 2120 | if (rc < 0) { |
2151 | dev_err(&usbvision->dev->dev, "%sERROR=%d\n", __func__, rc); | 2121 | dev_err(&usbvision->dev->dev, "%s: ERROR=%d\n", __func__, rc); |
2152 | return rc; | 2122 | return rc; |
2153 | } | 2123 | } |
2154 | 2124 | ||
@@ -2180,8 +2150,15 @@ int usbvision_power_on(struct usb_usbvision *usbvision) | |||
2180 | usbvision_write_reg(usbvision, USBVISION_PWR_REG, | 2150 | usbvision_write_reg(usbvision, USBVISION_PWR_REG, |
2181 | USBVISION_SSPND_EN | USBVISION_RES2); | 2151 | USBVISION_SSPND_EN | USBVISION_RES2); |
2182 | 2152 | ||
2153 | if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) { | ||
2154 | usbvision_write_reg(usbvision, USBVISION_VIN_REG1, | ||
2155 | USBVISION_16_422_SYNC | USBVISION_HVALID_PO); | ||
2156 | usbvision_write_reg(usbvision, USBVISION_VIN_REG2, | ||
2157 | USBVISION_NOHVALID | USBVISION_KEEP_BLANK); | ||
2158 | } | ||
2183 | usbvision_write_reg(usbvision, USBVISION_PWR_REG, | 2159 | usbvision_write_reg(usbvision, USBVISION_PWR_REG, |
2184 | USBVISION_SSPND_EN | USBVISION_PWR_VID); | 2160 | USBVISION_SSPND_EN | USBVISION_PWR_VID); |
2161 | mdelay(10); | ||
2185 | err_code = usbvision_write_reg(usbvision, USBVISION_PWR_REG, | 2162 | err_code = usbvision_write_reg(usbvision, USBVISION_PWR_REG, |
2186 | USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2); | 2163 | USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2); |
2187 | if (err_code == 1) | 2164 | if (err_code == 1) |
@@ -2310,6 +2287,8 @@ int usbvision_set_audio(struct usb_usbvision *usbvision, int audio_channel) | |||
2310 | 2287 | ||
2311 | int usbvision_setup(struct usb_usbvision *usbvision, int format) | 2288 | int usbvision_setup(struct usb_usbvision *usbvision, int format) |
2312 | { | 2289 | { |
2290 | if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) | ||
2291 | usbvision_init_webcam(usbvision); | ||
2313 | usbvision_set_video_format(usbvision, format); | 2292 | usbvision_set_video_format(usbvision, format); |
2314 | usbvision_set_dram_settings(usbvision); | 2293 | usbvision_set_dram_settings(usbvision); |
2315 | usbvision_set_compress_params(usbvision); | 2294 | usbvision_set_compress_params(usbvision); |
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 05b1344181cd..d7f97513b289 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c | |||
@@ -222,7 +222,7 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision) | |||
222 | i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev); | 222 | i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev); |
223 | 223 | ||
224 | if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) { | 224 | if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) { |
225 | printk(KERN_ERR "usbvision_register: can't write reg\n"); | 225 | printk(KERN_ERR "usbvision_i2c_register: can't write reg\n"); |
226 | return -EBUSY; | 226 | return -EBUSY; |
227 | } | 227 | } |
228 | 228 | ||
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 9855fbe5927a..ea8ea8a48dfe 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c | |||
@@ -1471,7 +1471,8 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) | |||
1471 | 1471 | ||
1472 | /* This should be here to make i2c clients to be able to register */ | 1472 | /* This should be here to make i2c clients to be able to register */ |
1473 | /* first switch off audio */ | 1473 | /* first switch off audio */ |
1474 | usbvision_audio_off(usbvision); | 1474 | if (usbvision_device_data[model].audio_channels > 0) |
1475 | usbvision_audio_off(usbvision); | ||
1475 | if (!power_on_at_open) { | 1476 | if (!power_on_at_open) { |
1476 | /* and then power up the noisy tuner */ | 1477 | /* and then power up the noisy tuner */ |
1477 | usbvision_power_on(usbvision); | 1478 | usbvision_power_on(usbvision); |
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index 8074787fd1ac..43cf61fe4943 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h | |||
@@ -59,6 +59,11 @@ | |||
59 | #define USBVISION_AUDIO_RADIO 2 | 59 | #define USBVISION_AUDIO_RADIO 2 |
60 | #define USBVISION_AUDIO_MUTE 3 | 60 | #define USBVISION_AUDIO_MUTE 3 |
61 | #define USBVISION_SER_MODE 0x07 | 61 | #define USBVISION_SER_MODE 0x07 |
62 | #define USBVISION_CLK_OUT (1 << 0) | ||
63 | #define USBVISION_DAT_IO (1 << 1) | ||
64 | #define USBVISION_SENS_OUT (1 << 2) | ||
65 | #define USBVISION_SER_MODE_SOFT (0 << 4) | ||
66 | #define USBVISION_SER_MODE_SIO (1 << 4) | ||
62 | #define USBVISION_SER_ADRS 0x08 | 67 | #define USBVISION_SER_ADRS 0x08 |
63 | #define USBVISION_SER_CONT 0x09 | 68 | #define USBVISION_SER_CONT 0x09 |
64 | #define USBVISION_SER_DAT1 0x0A | 69 | #define USBVISION_SER_DAT1 0x0A |
@@ -328,6 +333,7 @@ struct usbvision_frame { | |||
328 | 333 | ||
329 | #define CODEC_SAA7113 7113 | 334 | #define CODEC_SAA7113 7113 |
330 | #define CODEC_SAA7111 7111 | 335 | #define CODEC_SAA7111 7111 |
336 | #define CODEC_WEBCAM 3000 | ||
331 | #define BRIDGE_NT1003 1003 | 337 | #define BRIDGE_NT1003 1003 |
332 | #define BRIDGE_NT1004 1004 | 338 | #define BRIDGE_NT1004 1004 |
333 | #define BRIDGE_NT1005 1005 | 339 | #define BRIDGE_NT1005 1005 |
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index 59f8a9ad3796..a4db26fa2f53 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c | |||
@@ -42,281 +42,313 @@ static struct uvc_control_info uvc_ctrls[] = { | |||
42 | .selector = UVC_PU_BRIGHTNESS_CONTROL, | 42 | .selector = UVC_PU_BRIGHTNESS_CONTROL, |
43 | .index = 0, | 43 | .index = 0, |
44 | .size = 2, | 44 | .size = 2, |
45 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 45 | .flags = UVC_CTRL_FLAG_SET_CUR |
46 | | UVC_CONTROL_RESTORE, | 46 | | UVC_CTRL_FLAG_GET_RANGE |
47 | | UVC_CTRL_FLAG_RESTORE, | ||
47 | }, | 48 | }, |
48 | { | 49 | { |
49 | .entity = UVC_GUID_UVC_PROCESSING, | 50 | .entity = UVC_GUID_UVC_PROCESSING, |
50 | .selector = UVC_PU_CONTRAST_CONTROL, | 51 | .selector = UVC_PU_CONTRAST_CONTROL, |
51 | .index = 1, | 52 | .index = 1, |
52 | .size = 2, | 53 | .size = 2, |
53 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 54 | .flags = UVC_CTRL_FLAG_SET_CUR |
54 | | UVC_CONTROL_RESTORE, | 55 | | UVC_CTRL_FLAG_GET_RANGE |
56 | | UVC_CTRL_FLAG_RESTORE, | ||
55 | }, | 57 | }, |
56 | { | 58 | { |
57 | .entity = UVC_GUID_UVC_PROCESSING, | 59 | .entity = UVC_GUID_UVC_PROCESSING, |
58 | .selector = UVC_PU_HUE_CONTROL, | 60 | .selector = UVC_PU_HUE_CONTROL, |
59 | .index = 2, | 61 | .index = 2, |
60 | .size = 2, | 62 | .size = 2, |
61 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 63 | .flags = UVC_CTRL_FLAG_SET_CUR |
62 | | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, | 64 | | UVC_CTRL_FLAG_GET_RANGE |
65 | | UVC_CTRL_FLAG_RESTORE | ||
66 | | UVC_CTRL_FLAG_AUTO_UPDATE, | ||
63 | }, | 67 | }, |
64 | { | 68 | { |
65 | .entity = UVC_GUID_UVC_PROCESSING, | 69 | .entity = UVC_GUID_UVC_PROCESSING, |
66 | .selector = UVC_PU_SATURATION_CONTROL, | 70 | .selector = UVC_PU_SATURATION_CONTROL, |
67 | .index = 3, | 71 | .index = 3, |
68 | .size = 2, | 72 | .size = 2, |
69 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 73 | .flags = UVC_CTRL_FLAG_SET_CUR |
70 | | UVC_CONTROL_RESTORE, | 74 | | UVC_CTRL_FLAG_GET_RANGE |
75 | | UVC_CTRL_FLAG_RESTORE, | ||
71 | }, | 76 | }, |
72 | { | 77 | { |
73 | .entity = UVC_GUID_UVC_PROCESSING, | 78 | .entity = UVC_GUID_UVC_PROCESSING, |
74 | .selector = UVC_PU_SHARPNESS_CONTROL, | 79 | .selector = UVC_PU_SHARPNESS_CONTROL, |
75 | .index = 4, | 80 | .index = 4, |
76 | .size = 2, | 81 | .size = 2, |
77 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 82 | .flags = UVC_CTRL_FLAG_SET_CUR |
78 | | UVC_CONTROL_RESTORE, | 83 | | UVC_CTRL_FLAG_GET_RANGE |
84 | | UVC_CTRL_FLAG_RESTORE, | ||
79 | }, | 85 | }, |
80 | { | 86 | { |
81 | .entity = UVC_GUID_UVC_PROCESSING, | 87 | .entity = UVC_GUID_UVC_PROCESSING, |
82 | .selector = UVC_PU_GAMMA_CONTROL, | 88 | .selector = UVC_PU_GAMMA_CONTROL, |
83 | .index = 5, | 89 | .index = 5, |
84 | .size = 2, | 90 | .size = 2, |
85 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 91 | .flags = UVC_CTRL_FLAG_SET_CUR |
86 | | UVC_CONTROL_RESTORE, | 92 | | UVC_CTRL_FLAG_GET_RANGE |
93 | | UVC_CTRL_FLAG_RESTORE, | ||
87 | }, | 94 | }, |
88 | { | 95 | { |
89 | .entity = UVC_GUID_UVC_PROCESSING, | 96 | .entity = UVC_GUID_UVC_PROCESSING, |
90 | .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL, | 97 | .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL, |
91 | .index = 6, | 98 | .index = 6, |
92 | .size = 2, | 99 | .size = 2, |
93 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 100 | .flags = UVC_CTRL_FLAG_SET_CUR |
94 | | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, | 101 | | UVC_CTRL_FLAG_GET_RANGE |
102 | | UVC_CTRL_FLAG_RESTORE | ||
103 | | UVC_CTRL_FLAG_AUTO_UPDATE, | ||
95 | }, | 104 | }, |
96 | { | 105 | { |
97 | .entity = UVC_GUID_UVC_PROCESSING, | 106 | .entity = UVC_GUID_UVC_PROCESSING, |
98 | .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL, | 107 | .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL, |
99 | .index = 7, | 108 | .index = 7, |
100 | .size = 4, | 109 | .size = 4, |
101 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 110 | .flags = UVC_CTRL_FLAG_SET_CUR |
102 | | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, | 111 | | UVC_CTRL_FLAG_GET_RANGE |
112 | | UVC_CTRL_FLAG_RESTORE | ||
113 | | UVC_CTRL_FLAG_AUTO_UPDATE, | ||
103 | }, | 114 | }, |
104 | { | 115 | { |
105 | .entity = UVC_GUID_UVC_PROCESSING, | 116 | .entity = UVC_GUID_UVC_PROCESSING, |
106 | .selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL, | 117 | .selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL, |
107 | .index = 8, | 118 | .index = 8, |
108 | .size = 2, | 119 | .size = 2, |
109 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 120 | .flags = UVC_CTRL_FLAG_SET_CUR |
110 | | UVC_CONTROL_RESTORE, | 121 | | UVC_CTRL_FLAG_GET_RANGE |
122 | | UVC_CTRL_FLAG_RESTORE, | ||
111 | }, | 123 | }, |
112 | { | 124 | { |
113 | .entity = UVC_GUID_UVC_PROCESSING, | 125 | .entity = UVC_GUID_UVC_PROCESSING, |
114 | .selector = UVC_PU_GAIN_CONTROL, | 126 | .selector = UVC_PU_GAIN_CONTROL, |
115 | .index = 9, | 127 | .index = 9, |
116 | .size = 2, | 128 | .size = 2, |
117 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 129 | .flags = UVC_CTRL_FLAG_SET_CUR |
118 | | UVC_CONTROL_RESTORE, | 130 | | UVC_CTRL_FLAG_GET_RANGE |
131 | | UVC_CTRL_FLAG_RESTORE, | ||
119 | }, | 132 | }, |
120 | { | 133 | { |
121 | .entity = UVC_GUID_UVC_PROCESSING, | 134 | .entity = UVC_GUID_UVC_PROCESSING, |
122 | .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, | 135 | .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, |
123 | .index = 10, | 136 | .index = 10, |
124 | .size = 1, | 137 | .size = 1, |
125 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | 138 | .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR |
126 | | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, | 139 | | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE, |
127 | }, | 140 | }, |
128 | { | 141 | { |
129 | .entity = UVC_GUID_UVC_PROCESSING, | 142 | .entity = UVC_GUID_UVC_PROCESSING, |
130 | .selector = UVC_PU_HUE_AUTO_CONTROL, | 143 | .selector = UVC_PU_HUE_AUTO_CONTROL, |
131 | .index = 11, | 144 | .index = 11, |
132 | .size = 1, | 145 | .size = 1, |
133 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | 146 | .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR |
134 | | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, | 147 | | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE, |
135 | }, | 148 | }, |
136 | { | 149 | { |
137 | .entity = UVC_GUID_UVC_PROCESSING, | 150 | .entity = UVC_GUID_UVC_PROCESSING, |
138 | .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, | 151 | .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, |
139 | .index = 12, | 152 | .index = 12, |
140 | .size = 1, | 153 | .size = 1, |
141 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | 154 | .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR |
142 | | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, | 155 | | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE, |
143 | }, | 156 | }, |
144 | { | 157 | { |
145 | .entity = UVC_GUID_UVC_PROCESSING, | 158 | .entity = UVC_GUID_UVC_PROCESSING, |
146 | .selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL, | 159 | .selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL, |
147 | .index = 13, | 160 | .index = 13, |
148 | .size = 1, | 161 | .size = 1, |
149 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | 162 | .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR |
150 | | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, | 163 | | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE, |
151 | }, | 164 | }, |
152 | { | 165 | { |
153 | .entity = UVC_GUID_UVC_PROCESSING, | 166 | .entity = UVC_GUID_UVC_PROCESSING, |
154 | .selector = UVC_PU_DIGITAL_MULTIPLIER_CONTROL, | 167 | .selector = UVC_PU_DIGITAL_MULTIPLIER_CONTROL, |
155 | .index = 14, | 168 | .index = 14, |
156 | .size = 2, | 169 | .size = 2, |
157 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 170 | .flags = UVC_CTRL_FLAG_SET_CUR |
158 | | UVC_CONTROL_RESTORE, | 171 | | UVC_CTRL_FLAG_GET_RANGE |
172 | | UVC_CTRL_FLAG_RESTORE, | ||
159 | }, | 173 | }, |
160 | { | 174 | { |
161 | .entity = UVC_GUID_UVC_PROCESSING, | 175 | .entity = UVC_GUID_UVC_PROCESSING, |
162 | .selector = UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL, | 176 | .selector = UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL, |
163 | .index = 15, | 177 | .index = 15, |
164 | .size = 2, | 178 | .size = 2, |
165 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 179 | .flags = UVC_CTRL_FLAG_SET_CUR |
166 | | UVC_CONTROL_RESTORE, | 180 | | UVC_CTRL_FLAG_GET_RANGE |
181 | | UVC_CTRL_FLAG_RESTORE, | ||
167 | }, | 182 | }, |
168 | { | 183 | { |
169 | .entity = UVC_GUID_UVC_PROCESSING, | 184 | .entity = UVC_GUID_UVC_PROCESSING, |
170 | .selector = UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL, | 185 | .selector = UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL, |
171 | .index = 16, | 186 | .index = 16, |
172 | .size = 1, | 187 | .size = 1, |
173 | .flags = UVC_CONTROL_GET_CUR, | 188 | .flags = UVC_CTRL_FLAG_GET_CUR, |
174 | }, | 189 | }, |
175 | { | 190 | { |
176 | .entity = UVC_GUID_UVC_PROCESSING, | 191 | .entity = UVC_GUID_UVC_PROCESSING, |
177 | .selector = UVC_PU_ANALOG_LOCK_STATUS_CONTROL, | 192 | .selector = UVC_PU_ANALOG_LOCK_STATUS_CONTROL, |
178 | .index = 17, | 193 | .index = 17, |
179 | .size = 1, | 194 | .size = 1, |
180 | .flags = UVC_CONTROL_GET_CUR, | 195 | .flags = UVC_CTRL_FLAG_GET_CUR, |
181 | }, | 196 | }, |
182 | { | 197 | { |
183 | .entity = UVC_GUID_UVC_CAMERA, | 198 | .entity = UVC_GUID_UVC_CAMERA, |
184 | .selector = UVC_CT_SCANNING_MODE_CONTROL, | 199 | .selector = UVC_CT_SCANNING_MODE_CONTROL, |
185 | .index = 0, | 200 | .index = 0, |
186 | .size = 1, | 201 | .size = 1, |
187 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | 202 | .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR |
188 | | UVC_CONTROL_RESTORE, | 203 | | UVC_CTRL_FLAG_RESTORE, |
189 | }, | 204 | }, |
190 | { | 205 | { |
191 | .entity = UVC_GUID_UVC_CAMERA, | 206 | .entity = UVC_GUID_UVC_CAMERA, |
192 | .selector = UVC_CT_AE_MODE_CONTROL, | 207 | .selector = UVC_CT_AE_MODE_CONTROL, |
193 | .index = 1, | 208 | .index = 1, |
194 | .size = 1, | 209 | .size = 1, |
195 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | 210 | .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR |
196 | | UVC_CONTROL_GET_DEF | UVC_CONTROL_GET_RES | 211 | | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_GET_RES |
197 | | UVC_CONTROL_RESTORE, | 212 | | UVC_CTRL_FLAG_RESTORE, |
198 | }, | 213 | }, |
199 | { | 214 | { |
200 | .entity = UVC_GUID_UVC_CAMERA, | 215 | .entity = UVC_GUID_UVC_CAMERA, |
201 | .selector = UVC_CT_AE_PRIORITY_CONTROL, | 216 | .selector = UVC_CT_AE_PRIORITY_CONTROL, |
202 | .index = 2, | 217 | .index = 2, |
203 | .size = 1, | 218 | .size = 1, |
204 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | 219 | .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR |
205 | | UVC_CONTROL_RESTORE, | 220 | | UVC_CTRL_FLAG_RESTORE, |
206 | }, | 221 | }, |
207 | { | 222 | { |
208 | .entity = UVC_GUID_UVC_CAMERA, | 223 | .entity = UVC_GUID_UVC_CAMERA, |
209 | .selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL, | 224 | .selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL, |
210 | .index = 3, | 225 | .index = 3, |
211 | .size = 4, | 226 | .size = 4, |
212 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 227 | .flags = UVC_CTRL_FLAG_SET_CUR |
213 | | UVC_CONTROL_RESTORE, | 228 | | UVC_CTRL_FLAG_GET_RANGE |
229 | | UVC_CTRL_FLAG_RESTORE, | ||
214 | }, | 230 | }, |
215 | { | 231 | { |
216 | .entity = UVC_GUID_UVC_CAMERA, | 232 | .entity = UVC_GUID_UVC_CAMERA, |
217 | .selector = UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL, | 233 | .selector = UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL, |
218 | .index = 4, | 234 | .index = 4, |
219 | .size = 1, | 235 | .size = 1, |
220 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_RESTORE, | 236 | .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_RESTORE, |
221 | }, | 237 | }, |
222 | { | 238 | { |
223 | .entity = UVC_GUID_UVC_CAMERA, | 239 | .entity = UVC_GUID_UVC_CAMERA, |
224 | .selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL, | 240 | .selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL, |
225 | .index = 5, | 241 | .index = 5, |
226 | .size = 2, | 242 | .size = 2, |
227 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 243 | .flags = UVC_CTRL_FLAG_SET_CUR |
228 | | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, | 244 | | UVC_CTRL_FLAG_GET_RANGE |
245 | | UVC_CTRL_FLAG_RESTORE | ||
246 | | UVC_CTRL_FLAG_AUTO_UPDATE, | ||
229 | }, | 247 | }, |
230 | { | 248 | { |
231 | .entity = UVC_GUID_UVC_CAMERA, | 249 | .entity = UVC_GUID_UVC_CAMERA, |
232 | .selector = UVC_CT_FOCUS_RELATIVE_CONTROL, | 250 | .selector = UVC_CT_FOCUS_RELATIVE_CONTROL, |
233 | .index = 6, | 251 | .index = 6, |
234 | .size = 2, | 252 | .size = 2, |
235 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN | 253 | .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN |
236 | | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | 254 | | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES |
237 | | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE, | 255 | | UVC_CTRL_FLAG_GET_DEF |
256 | | UVC_CTRL_FLAG_AUTO_UPDATE, | ||
238 | }, | 257 | }, |
239 | { | 258 | { |
240 | .entity = UVC_GUID_UVC_CAMERA, | 259 | .entity = UVC_GUID_UVC_CAMERA, |
241 | .selector = UVC_CT_IRIS_ABSOLUTE_CONTROL, | 260 | .selector = UVC_CT_IRIS_ABSOLUTE_CONTROL, |
242 | .index = 7, | 261 | .index = 7, |
243 | .size = 2, | 262 | .size = 2, |
244 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 263 | .flags = UVC_CTRL_FLAG_SET_CUR |
245 | | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, | 264 | | UVC_CTRL_FLAG_GET_RANGE |
265 | | UVC_CTRL_FLAG_RESTORE | ||
266 | | UVC_CTRL_FLAG_AUTO_UPDATE, | ||
246 | }, | 267 | }, |
247 | { | 268 | { |
248 | .entity = UVC_GUID_UVC_CAMERA, | 269 | .entity = UVC_GUID_UVC_CAMERA, |
249 | .selector = UVC_CT_IRIS_RELATIVE_CONTROL, | 270 | .selector = UVC_CT_IRIS_RELATIVE_CONTROL, |
250 | .index = 8, | 271 | .index = 8, |
251 | .size = 1, | 272 | .size = 1, |
252 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_AUTO_UPDATE, | 273 | .flags = UVC_CTRL_FLAG_SET_CUR |
274 | | UVC_CTRL_FLAG_AUTO_UPDATE, | ||
253 | }, | 275 | }, |
254 | { | 276 | { |
255 | .entity = UVC_GUID_UVC_CAMERA, | 277 | .entity = UVC_GUID_UVC_CAMERA, |
256 | .selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL, | 278 | .selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL, |
257 | .index = 9, | 279 | .index = 9, |
258 | .size = 2, | 280 | .size = 2, |
259 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 281 | .flags = UVC_CTRL_FLAG_SET_CUR |
260 | | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, | 282 | | UVC_CTRL_FLAG_GET_RANGE |
283 | | UVC_CTRL_FLAG_RESTORE | ||
284 | | UVC_CTRL_FLAG_AUTO_UPDATE, | ||
261 | }, | 285 | }, |
262 | { | 286 | { |
263 | .entity = UVC_GUID_UVC_CAMERA, | 287 | .entity = UVC_GUID_UVC_CAMERA, |
264 | .selector = UVC_CT_ZOOM_RELATIVE_CONTROL, | 288 | .selector = UVC_CT_ZOOM_RELATIVE_CONTROL, |
265 | .index = 10, | 289 | .index = 10, |
266 | .size = 3, | 290 | .size = 3, |
267 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN | 291 | .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN |
268 | | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | 292 | | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES |
269 | | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE, | 293 | | UVC_CTRL_FLAG_GET_DEF |
294 | | UVC_CTRL_FLAG_AUTO_UPDATE, | ||
270 | }, | 295 | }, |
271 | { | 296 | { |
272 | .entity = UVC_GUID_UVC_CAMERA, | 297 | .entity = UVC_GUID_UVC_CAMERA, |
273 | .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL, | 298 | .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL, |
274 | .index = 11, | 299 | .index = 11, |
275 | .size = 8, | 300 | .size = 8, |
276 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 301 | .flags = UVC_CTRL_FLAG_SET_CUR |
277 | | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, | 302 | | UVC_CTRL_FLAG_GET_RANGE |
303 | | UVC_CTRL_FLAG_RESTORE | ||
304 | | UVC_CTRL_FLAG_AUTO_UPDATE, | ||
278 | }, | 305 | }, |
279 | { | 306 | { |
280 | .entity = UVC_GUID_UVC_CAMERA, | 307 | .entity = UVC_GUID_UVC_CAMERA, |
281 | .selector = UVC_CT_PANTILT_RELATIVE_CONTROL, | 308 | .selector = UVC_CT_PANTILT_RELATIVE_CONTROL, |
282 | .index = 12, | 309 | .index = 12, |
283 | .size = 4, | 310 | .size = 4, |
284 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN | 311 | .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN |
285 | | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | 312 | | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES |
286 | | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE, | 313 | | UVC_CTRL_FLAG_GET_DEF |
314 | | UVC_CTRL_FLAG_AUTO_UPDATE, | ||
287 | }, | 315 | }, |
288 | { | 316 | { |
289 | .entity = UVC_GUID_UVC_CAMERA, | 317 | .entity = UVC_GUID_UVC_CAMERA, |
290 | .selector = UVC_CT_ROLL_ABSOLUTE_CONTROL, | 318 | .selector = UVC_CT_ROLL_ABSOLUTE_CONTROL, |
291 | .index = 13, | 319 | .index = 13, |
292 | .size = 2, | 320 | .size = 2, |
293 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE | 321 | .flags = UVC_CTRL_FLAG_SET_CUR |
294 | | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, | 322 | | UVC_CTRL_FLAG_GET_RANGE |
323 | | UVC_CTRL_FLAG_RESTORE | ||
324 | | UVC_CTRL_FLAG_AUTO_UPDATE, | ||
295 | }, | 325 | }, |
296 | { | 326 | { |
297 | .entity = UVC_GUID_UVC_CAMERA, | 327 | .entity = UVC_GUID_UVC_CAMERA, |
298 | .selector = UVC_CT_ROLL_RELATIVE_CONTROL, | 328 | .selector = UVC_CT_ROLL_RELATIVE_CONTROL, |
299 | .index = 14, | 329 | .index = 14, |
300 | .size = 2, | 330 | .size = 2, |
301 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN | 331 | .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN |
302 | | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | 332 | | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES |
303 | | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE, | 333 | | UVC_CTRL_FLAG_GET_DEF |
334 | | UVC_CTRL_FLAG_AUTO_UPDATE, | ||
304 | }, | 335 | }, |
305 | { | 336 | { |
306 | .entity = UVC_GUID_UVC_CAMERA, | 337 | .entity = UVC_GUID_UVC_CAMERA, |
307 | .selector = UVC_CT_FOCUS_AUTO_CONTROL, | 338 | .selector = UVC_CT_FOCUS_AUTO_CONTROL, |
308 | .index = 17, | 339 | .index = 17, |
309 | .size = 1, | 340 | .size = 1, |
310 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | 341 | .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR |
311 | | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE, | 342 | | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE, |
312 | }, | 343 | }, |
313 | { | 344 | { |
314 | .entity = UVC_GUID_UVC_CAMERA, | 345 | .entity = UVC_GUID_UVC_CAMERA, |
315 | .selector = UVC_CT_PRIVACY_CONTROL, | 346 | .selector = UVC_CT_PRIVACY_CONTROL, |
316 | .index = 18, | 347 | .index = 18, |
317 | .size = 1, | 348 | .size = 1, |
318 | .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | 349 | .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR |
319 | | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE, | 350 | | UVC_CTRL_FLAG_RESTORE |
351 | | UVC_CTRL_FLAG_AUTO_UPDATE, | ||
320 | }, | 352 | }, |
321 | }; | 353 | }; |
322 | 354 | ||
@@ -816,7 +848,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, | |||
816 | { | 848 | { |
817 | int ret; | 849 | int ret; |
818 | 850 | ||
819 | if (ctrl->info.flags & UVC_CONTROL_GET_DEF) { | 851 | if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) { |
820 | ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id, | 852 | ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id, |
821 | chain->dev->intfnum, ctrl->info.selector, | 853 | chain->dev->intfnum, ctrl->info.selector, |
822 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF), | 854 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF), |
@@ -825,7 +857,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, | |||
825 | return ret; | 857 | return ret; |
826 | } | 858 | } |
827 | 859 | ||
828 | if (ctrl->info.flags & UVC_CONTROL_GET_MIN) { | 860 | if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) { |
829 | ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id, | 861 | ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id, |
830 | chain->dev->intfnum, ctrl->info.selector, | 862 | chain->dev->intfnum, ctrl->info.selector, |
831 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN), | 863 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN), |
@@ -833,7 +865,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, | |||
833 | if (ret < 0) | 865 | if (ret < 0) |
834 | return ret; | 866 | return ret; |
835 | } | 867 | } |
836 | if (ctrl->info.flags & UVC_CONTROL_GET_MAX) { | 868 | if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) { |
837 | ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id, | 869 | ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id, |
838 | chain->dev->intfnum, ctrl->info.selector, | 870 | chain->dev->intfnum, ctrl->info.selector, |
839 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX), | 871 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX), |
@@ -841,7 +873,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, | |||
841 | if (ret < 0) | 873 | if (ret < 0) |
842 | return ret; | 874 | return ret; |
843 | } | 875 | } |
844 | if (ctrl->info.flags & UVC_CONTROL_GET_RES) { | 876 | if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) { |
845 | ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id, | 877 | ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id, |
846 | chain->dev->intfnum, ctrl->info.selector, | 878 | chain->dev->intfnum, ctrl->info.selector, |
847 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), | 879 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), |
@@ -879,9 +911,9 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, | |||
879 | strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name); | 911 | strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name); |
880 | v4l2_ctrl->flags = 0; | 912 | v4l2_ctrl->flags = 0; |
881 | 913 | ||
882 | if (!(ctrl->info.flags & UVC_CONTROL_GET_CUR)) | 914 | if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) |
883 | v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY; | 915 | v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY; |
884 | if (!(ctrl->info.flags & UVC_CONTROL_SET_CUR)) | 916 | if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) |
885 | v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; | 917 | v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
886 | 918 | ||
887 | if (!ctrl->cached) { | 919 | if (!ctrl->cached) { |
@@ -890,7 +922,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, | |||
890 | goto done; | 922 | goto done; |
891 | } | 923 | } |
892 | 924 | ||
893 | if (ctrl->info.flags & UVC_CONTROL_GET_DEF) { | 925 | if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) { |
894 | v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF, | 926 | v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF, |
895 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); | 927 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); |
896 | } | 928 | } |
@@ -927,15 +959,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, | |||
927 | break; | 959 | break; |
928 | } | 960 | } |
929 | 961 | ||
930 | if (ctrl->info.flags & UVC_CONTROL_GET_MIN) | 962 | if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) |
931 | v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, | 963 | v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, |
932 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); | 964 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); |
933 | 965 | ||
934 | if (ctrl->info.flags & UVC_CONTROL_GET_MAX) | 966 | if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) |
935 | v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, | 967 | v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, |
936 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); | 968 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); |
937 | 969 | ||
938 | if (ctrl->info.flags & UVC_CONTROL_GET_RES) | 970 | if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) |
939 | v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, | 971 | v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, |
940 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); | 972 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); |
941 | 973 | ||
@@ -983,6 +1015,24 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain, | |||
983 | } | 1015 | } |
984 | 1016 | ||
985 | menu_info = &mapping->menu_info[query_menu->index]; | 1017 | menu_info = &mapping->menu_info[query_menu->index]; |
1018 | |||
1019 | if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) { | ||
1020 | s32 bitmap; | ||
1021 | |||
1022 | if (!ctrl->cached) { | ||
1023 | ret = uvc_ctrl_populate_cache(chain, ctrl); | ||
1024 | if (ret < 0) | ||
1025 | goto done; | ||
1026 | } | ||
1027 | |||
1028 | bitmap = mapping->get(mapping, UVC_GET_RES, | ||
1029 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); | ||
1030 | if (!(bitmap & menu_info->value)) { | ||
1031 | ret = -EINVAL; | ||
1032 | goto done; | ||
1033 | } | ||
1034 | } | ||
1035 | |||
986 | strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name); | 1036 | strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name); |
987 | 1037 | ||
988 | done: | 1038 | done: |
@@ -1039,7 +1089,7 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, | |||
1039 | * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent | 1089 | * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent |
1040 | * uvc_ctrl_get from using the cached value. | 1090 | * uvc_ctrl_get from using the cached value. |
1041 | */ | 1091 | */ |
1042 | if (ctrl->info.flags & UVC_CONTROL_AUTO_UPDATE) | 1092 | if (ctrl->info.flags & UVC_CTRL_FLAG_AUTO_UPDATE) |
1043 | ctrl->loaded = 0; | 1093 | ctrl->loaded = 0; |
1044 | 1094 | ||
1045 | if (!ctrl->dirty) | 1095 | if (!ctrl->dirty) |
@@ -1094,7 +1144,7 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, | |||
1094 | int ret; | 1144 | int ret; |
1095 | 1145 | ||
1096 | ctrl = uvc_find_control(chain, xctrl->id, &mapping); | 1146 | ctrl = uvc_find_control(chain, xctrl->id, &mapping); |
1097 | if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0) | 1147 | if (ctrl == NULL || (ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) |
1098 | return -EINVAL; | 1148 | return -EINVAL; |
1099 | 1149 | ||
1100 | if (!ctrl->loaded) { | 1150 | if (!ctrl->loaded) { |
@@ -1136,7 +1186,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain, | |||
1136 | int ret; | 1186 | int ret; |
1137 | 1187 | ||
1138 | ctrl = uvc_find_control(chain, xctrl->id, &mapping); | 1188 | ctrl = uvc_find_control(chain, xctrl->id, &mapping); |
1139 | if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_SET_CUR) == 0) | 1189 | if (ctrl == NULL || (ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) == 0) |
1140 | return -EINVAL; | 1190 | return -EINVAL; |
1141 | 1191 | ||
1142 | /* Clamp out of range values. */ | 1192 | /* Clamp out of range values. */ |
@@ -1171,6 +1221,23 @@ int uvc_ctrl_set(struct uvc_video_chain *chain, | |||
1171 | if (xctrl->value < 0 || xctrl->value >= mapping->menu_count) | 1221 | if (xctrl->value < 0 || xctrl->value >= mapping->menu_count) |
1172 | return -ERANGE; | 1222 | return -ERANGE; |
1173 | value = mapping->menu_info[xctrl->value].value; | 1223 | value = mapping->menu_info[xctrl->value].value; |
1224 | |||
1225 | /* Valid menu indices are reported by the GET_RES request for | ||
1226 | * UVC controls that support it. | ||
1227 | */ | ||
1228 | if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) { | ||
1229 | if (!ctrl->cached) { | ||
1230 | ret = uvc_ctrl_populate_cache(chain, ctrl); | ||
1231 | if (ret < 0) | ||
1232 | return ret; | ||
1233 | } | ||
1234 | |||
1235 | step = mapping->get(mapping, UVC_GET_RES, | ||
1236 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); | ||
1237 | if (!(step & value)) | ||
1238 | return -ERANGE; | ||
1239 | } | ||
1240 | |||
1174 | break; | 1241 | break; |
1175 | 1242 | ||
1176 | default: | 1243 | default: |
@@ -1183,7 +1250,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain, | |||
1183 | * operation. | 1250 | * operation. |
1184 | */ | 1251 | */ |
1185 | if (!ctrl->loaded && (ctrl->info.size * 8) != mapping->size) { | 1252 | if (!ctrl->loaded && (ctrl->info.size * 8) != mapping->size) { |
1186 | if ((ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0) { | 1253 | if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) { |
1187 | memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), | 1254 | memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), |
1188 | 0, ctrl->info.size); | 1255 | 0, ctrl->info.size); |
1189 | } else { | 1256 | } else { |
@@ -1230,17 +1297,17 @@ static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev, | |||
1230 | 1297 | ||
1231 | static const struct uvc_ctrl_fixup fixups[] = { | 1298 | static const struct uvc_ctrl_fixup fixups[] = { |
1232 | { { USB_DEVICE(0x046d, 0x08c2) }, 9, 1, | 1299 | { { USB_DEVICE(0x046d, 0x08c2) }, 9, 1, |
1233 | UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | | 1300 | UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX | |
1234 | UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR | | 1301 | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR | |
1235 | UVC_CONTROL_AUTO_UPDATE }, | 1302 | UVC_CTRL_FLAG_AUTO_UPDATE }, |
1236 | { { USB_DEVICE(0x046d, 0x08cc) }, 9, 1, | 1303 | { { USB_DEVICE(0x046d, 0x08cc) }, 9, 1, |
1237 | UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | | 1304 | UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX | |
1238 | UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR | | 1305 | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR | |
1239 | UVC_CONTROL_AUTO_UPDATE }, | 1306 | UVC_CTRL_FLAG_AUTO_UPDATE }, |
1240 | { { USB_DEVICE(0x046d, 0x0994) }, 9, 1, | 1307 | { { USB_DEVICE(0x046d, 0x0994) }, 9, 1, |
1241 | UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | | 1308 | UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX | |
1242 | UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR | | 1309 | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR | |
1243 | UVC_CONTROL_AUTO_UPDATE }, | 1310 | UVC_CTRL_FLAG_AUTO_UPDATE }, |
1244 | }; | 1311 | }; |
1245 | 1312 | ||
1246 | unsigned int i; | 1313 | unsigned int i; |
@@ -1297,21 +1364,23 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev, | |||
1297 | goto done; | 1364 | goto done; |
1298 | } | 1365 | } |
1299 | 1366 | ||
1300 | info->flags = UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | 1367 | info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
1301 | | UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF | 1368 | | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF |
1302 | | (data[0] & UVC_CONTROL_CAP_GET ? UVC_CONTROL_GET_CUR : 0) | 1369 | | (data[0] & UVC_CONTROL_CAP_GET ? |
1303 | | (data[0] & UVC_CONTROL_CAP_SET ? UVC_CONTROL_SET_CUR : 0) | 1370 | UVC_CTRL_FLAG_GET_CUR : 0) |
1371 | | (data[0] & UVC_CONTROL_CAP_SET ? | ||
1372 | UVC_CTRL_FLAG_SET_CUR : 0) | ||
1304 | | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ? | 1373 | | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ? |
1305 | UVC_CONTROL_AUTO_UPDATE : 0); | 1374 | UVC_CTRL_FLAG_AUTO_UPDATE : 0); |
1306 | 1375 | ||
1307 | uvc_ctrl_fixup_xu_info(dev, ctrl, info); | 1376 | uvc_ctrl_fixup_xu_info(dev, ctrl, info); |
1308 | 1377 | ||
1309 | uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, " | 1378 | uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, " |
1310 | "flags { get %u set %u auto %u }.\n", | 1379 | "flags { get %u set %u auto %u }.\n", |
1311 | info->entity, info->selector, info->size, | 1380 | info->entity, info->selector, info->size, |
1312 | (info->flags & UVC_CONTROL_GET_CUR) ? 1 : 0, | 1381 | (info->flags & UVC_CTRL_FLAG_GET_CUR) ? 1 : 0, |
1313 | (info->flags & UVC_CONTROL_SET_CUR) ? 1 : 0, | 1382 | (info->flags & UVC_CTRL_FLAG_SET_CUR) ? 1 : 0, |
1314 | (info->flags & UVC_CONTROL_AUTO_UPDATE) ? 1 : 0); | 1383 | (info->flags & UVC_CTRL_FLAG_AUTO_UPDATE) ? 1 : 0); |
1315 | 1384 | ||
1316 | done: | 1385 | done: |
1317 | kfree(data); | 1386 | kfree(data); |
@@ -1344,32 +1413,33 @@ static int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev, | |||
1344 | } | 1413 | } |
1345 | 1414 | ||
1346 | int uvc_xu_ctrl_query(struct uvc_video_chain *chain, | 1415 | int uvc_xu_ctrl_query(struct uvc_video_chain *chain, |
1347 | struct uvc_xu_control *xctrl, int set) | 1416 | struct uvc_xu_control_query *xqry) |
1348 | { | 1417 | { |
1349 | struct uvc_entity *entity; | 1418 | struct uvc_entity *entity; |
1350 | struct uvc_control *ctrl = NULL; | 1419 | struct uvc_control *ctrl; |
1351 | unsigned int i, found = 0; | 1420 | unsigned int i, found = 0; |
1352 | int restore = 0; | 1421 | __u32 reqflags; |
1353 | __u8 *data; | 1422 | __u16 size; |
1423 | __u8 *data = NULL; | ||
1354 | int ret; | 1424 | int ret; |
1355 | 1425 | ||
1356 | /* Find the extension unit. */ | 1426 | /* Find the extension unit. */ |
1357 | list_for_each_entry(entity, &chain->entities, chain) { | 1427 | list_for_each_entry(entity, &chain->entities, chain) { |
1358 | if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT && | 1428 | if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT && |
1359 | entity->id == xctrl->unit) | 1429 | entity->id == xqry->unit) |
1360 | break; | 1430 | break; |
1361 | } | 1431 | } |
1362 | 1432 | ||
1363 | if (entity->id != xctrl->unit) { | 1433 | if (entity->id != xqry->unit) { |
1364 | uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n", | 1434 | uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n", |
1365 | xctrl->unit); | 1435 | xqry->unit); |
1366 | return -EINVAL; | 1436 | return -ENOENT; |
1367 | } | 1437 | } |
1368 | 1438 | ||
1369 | /* Find the control and perform delayed initialization if needed. */ | 1439 | /* Find the control and perform delayed initialization if needed. */ |
1370 | for (i = 0; i < entity->ncontrols; ++i) { | 1440 | for (i = 0; i < entity->ncontrols; ++i) { |
1371 | ctrl = &entity->controls[i]; | 1441 | ctrl = &entity->controls[i]; |
1372 | if (ctrl->index == xctrl->selector - 1) { | 1442 | if (ctrl->index == xqry->selector - 1) { |
1373 | found = 1; | 1443 | found = 1; |
1374 | break; | 1444 | break; |
1375 | } | 1445 | } |
@@ -1377,8 +1447,8 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain, | |||
1377 | 1447 | ||
1378 | if (!found) { | 1448 | if (!found) { |
1379 | uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u not found.\n", | 1449 | uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u not found.\n", |
1380 | entity->extension.guidExtensionCode, xctrl->selector); | 1450 | entity->extension.guidExtensionCode, xqry->selector); |
1381 | return -EINVAL; | 1451 | return -ENOENT; |
1382 | } | 1452 | } |
1383 | 1453 | ||
1384 | if (mutex_lock_interruptible(&chain->ctrl_mutex)) | 1454 | if (mutex_lock_interruptible(&chain->ctrl_mutex)) |
@@ -1390,43 +1460,72 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain, | |||
1390 | goto done; | 1460 | goto done; |
1391 | } | 1461 | } |
1392 | 1462 | ||
1393 | /* Validate control data size. */ | 1463 | /* Validate the required buffer size and flags for the request */ |
1394 | if (ctrl->info.size != xctrl->size) { | 1464 | reqflags = 0; |
1465 | size = ctrl->info.size; | ||
1466 | |||
1467 | switch (xqry->query) { | ||
1468 | case UVC_GET_CUR: | ||
1469 | reqflags = UVC_CTRL_FLAG_GET_CUR; | ||
1470 | break; | ||
1471 | case UVC_GET_MIN: | ||
1472 | reqflags = UVC_CTRL_FLAG_GET_MIN; | ||
1473 | break; | ||
1474 | case UVC_GET_MAX: | ||
1475 | reqflags = UVC_CTRL_FLAG_GET_MAX; | ||
1476 | break; | ||
1477 | case UVC_GET_DEF: | ||
1478 | reqflags = UVC_CTRL_FLAG_GET_DEF; | ||
1479 | break; | ||
1480 | case UVC_GET_RES: | ||
1481 | reqflags = UVC_CTRL_FLAG_GET_RES; | ||
1482 | break; | ||
1483 | case UVC_SET_CUR: | ||
1484 | reqflags = UVC_CTRL_FLAG_SET_CUR; | ||
1485 | break; | ||
1486 | case UVC_GET_LEN: | ||
1487 | size = 2; | ||
1488 | break; | ||
1489 | case UVC_GET_INFO: | ||
1490 | size = 1; | ||
1491 | break; | ||
1492 | default: | ||
1395 | ret = -EINVAL; | 1493 | ret = -EINVAL; |
1396 | goto done; | 1494 | goto done; |
1397 | } | 1495 | } |
1398 | 1496 | ||
1399 | if ((set && !(ctrl->info.flags & UVC_CONTROL_SET_CUR)) || | 1497 | if (size != xqry->size) { |
1400 | (!set && !(ctrl->info.flags & UVC_CONTROL_GET_CUR))) { | 1498 | ret = -ENOBUFS; |
1401 | ret = -EINVAL; | ||
1402 | goto done; | 1499 | goto done; |
1403 | } | 1500 | } |
1404 | 1501 | ||
1405 | memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), | 1502 | if (reqflags && !(ctrl->info.flags & reqflags)) { |
1406 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), | 1503 | ret = -EBADRQC; |
1407 | ctrl->info.size); | 1504 | goto done; |
1408 | data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT); | 1505 | } |
1409 | restore = set; | ||
1410 | 1506 | ||
1411 | if (set && copy_from_user(data, xctrl->data, xctrl->size)) { | 1507 | data = kmalloc(size, GFP_KERNEL); |
1508 | if (data == NULL) { | ||
1509 | ret = -ENOMEM; | ||
1510 | goto done; | ||
1511 | } | ||
1512 | |||
1513 | if (xqry->query == UVC_SET_CUR && | ||
1514 | copy_from_user(data, xqry->data, size)) { | ||
1412 | ret = -EFAULT; | 1515 | ret = -EFAULT; |
1413 | goto done; | 1516 | goto done; |
1414 | } | 1517 | } |
1415 | 1518 | ||
1416 | ret = uvc_query_ctrl(chain->dev, set ? UVC_SET_CUR : UVC_GET_CUR, | 1519 | ret = uvc_query_ctrl(chain->dev, xqry->query, xqry->unit, |
1417 | xctrl->unit, chain->dev->intfnum, xctrl->selector, | 1520 | chain->dev->intfnum, xqry->selector, data, size); |
1418 | data, xctrl->size); | ||
1419 | if (ret < 0) | 1521 | if (ret < 0) |
1420 | goto done; | 1522 | goto done; |
1421 | 1523 | ||
1422 | if (!set && copy_to_user(xctrl->data, data, xctrl->size)) | 1524 | if (xqry->query != UVC_SET_CUR && |
1525 | copy_to_user(xqry->data, data, size)) | ||
1423 | ret = -EFAULT; | 1526 | ret = -EFAULT; |
1424 | done: | 1527 | done: |
1425 | if (ret && restore) | 1528 | kfree(data); |
1426 | memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), | ||
1427 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), | ||
1428 | xctrl->size); | ||
1429 | |||
1430 | mutex_unlock(&chain->ctrl_mutex); | 1529 | mutex_unlock(&chain->ctrl_mutex); |
1431 | return ret; | 1530 | return ret; |
1432 | } | 1531 | } |
@@ -1458,7 +1557,7 @@ int uvc_ctrl_resume_device(struct uvc_device *dev) | |||
1458 | ctrl = &entity->controls[i]; | 1557 | ctrl = &entity->controls[i]; |
1459 | 1558 | ||
1460 | if (!ctrl->initialized || !ctrl->modified || | 1559 | if (!ctrl->initialized || !ctrl->modified || |
1461 | (ctrl->info.flags & UVC_CONTROL_RESTORE) == 0) | 1560 | (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0) |
1462 | continue; | 1561 | continue; |
1463 | 1562 | ||
1464 | printk(KERN_INFO "restoring control %pUl/%u/%u\n", | 1563 | printk(KERN_INFO "restoring control %pUl/%u/%u\n", |
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 6459b8cba223..823f4b389745 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c | |||
@@ -84,6 +84,11 @@ static struct uvc_format_desc uvc_fmts[] = { | |||
84 | .fcc = V4L2_PIX_FMT_YUV420, | 84 | .fcc = V4L2_PIX_FMT_YUV420, |
85 | }, | 85 | }, |
86 | { | 86 | { |
87 | .name = "YUV 4:2:0 (M420)", | ||
88 | .guid = UVC_GUID_FORMAT_M420, | ||
89 | .fcc = V4L2_PIX_FMT_M420, | ||
90 | }, | ||
91 | { | ||
87 | .name = "YUV 4:2:2 (UYVY)", | 92 | .name = "YUV 4:2:2 (UYVY)", |
88 | .guid = UVC_GUID_FORMAT_UYVY, | 93 | .guid = UVC_GUID_FORMAT_UYVY, |
89 | .fcc = V4L2_PIX_FMT_UYVY, | 94 | .fcc = V4L2_PIX_FMT_UYVY, |
@@ -103,6 +108,11 @@ static struct uvc_format_desc uvc_fmts[] = { | |||
103 | .guid = UVC_GUID_FORMAT_BY8, | 108 | .guid = UVC_GUID_FORMAT_BY8, |
104 | .fcc = V4L2_PIX_FMT_SBGGR8, | 109 | .fcc = V4L2_PIX_FMT_SBGGR8, |
105 | }, | 110 | }, |
111 | { | ||
112 | .name = "RGB565", | ||
113 | .guid = UVC_GUID_FORMAT_RGBP, | ||
114 | .fcc = V4L2_PIX_FMT_RGB565, | ||
115 | }, | ||
106 | }; | 116 | }; |
107 | 117 | ||
108 | /* ------------------------------------------------------------------------ | 118 | /* ------------------------------------------------------------------------ |
@@ -2077,6 +2087,15 @@ static struct usb_device_id uvc_ids[] = { | |||
2077 | .bInterfaceSubClass = 1, | 2087 | .bInterfaceSubClass = 1, |
2078 | .bInterfaceProtocol = 0, | 2088 | .bInterfaceProtocol = 0, |
2079 | .driver_info = UVC_QUIRK_STREAM_NO_FID }, | 2089 | .driver_info = UVC_QUIRK_STREAM_NO_FID }, |
2090 | /* Hercules Classic Silver */ | ||
2091 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | ||
2092 | | USB_DEVICE_ID_MATCH_INT_INFO, | ||
2093 | .idVendor = 0x06f8, | ||
2094 | .idProduct = 0x300c, | ||
2095 | .bInterfaceClass = USB_CLASS_VIDEO, | ||
2096 | .bInterfaceSubClass = 1, | ||
2097 | .bInterfaceProtocol = 0, | ||
2098 | .driver_info = UVC_QUIRK_FIX_BANDWIDTH }, | ||
2080 | /* ViMicro Vega */ | 2099 | /* ViMicro Vega */ |
2081 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | 2100 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
2082 | | USB_DEVICE_ID_MATCH_INT_INFO, | 2101 | | USB_DEVICE_ID_MATCH_INT_INFO, |
@@ -2123,6 +2142,15 @@ static struct usb_device_id uvc_ids[] = { | |||
2123 | .bInterfaceSubClass = 1, | 2142 | .bInterfaceSubClass = 1, |
2124 | .bInterfaceProtocol = 0, | 2143 | .bInterfaceProtocol = 0, |
2125 | .driver_info = UVC_QUIRK_STREAM_NO_FID }, | 2144 | .driver_info = UVC_QUIRK_STREAM_NO_FID }, |
2145 | /* JMicron USB2.0 XGA WebCam */ | ||
2146 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | ||
2147 | | USB_DEVICE_ID_MATCH_INT_INFO, | ||
2148 | .idVendor = 0x152d, | ||
2149 | .idProduct = 0x0310, | ||
2150 | .bInterfaceClass = USB_CLASS_VIDEO, | ||
2151 | .bInterfaceSubClass = 1, | ||
2152 | .bInterfaceProtocol = 0, | ||
2153 | .driver_info = UVC_QUIRK_PROBE_MINMAX }, | ||
2126 | /* Syntek (HP Spartan) */ | 2154 | /* Syntek (HP Spartan) */ |
2127 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | 2155 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
2128 | | USB_DEVICE_ID_MATCH_INT_INFO, | 2156 | | USB_DEVICE_ID_MATCH_INT_INFO, |
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index f14581bd707f..109a06384a8f 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c | |||
@@ -424,7 +424,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) | |||
424 | break; | 424 | break; |
425 | } | 425 | } |
426 | 426 | ||
427 | if (i == queue->count || size != queue->buf_size) { | 427 | if (i == queue->count || PAGE_ALIGN(size) != queue->buf_size) { |
428 | ret = -EINVAL; | 428 | ret = -EINVAL; |
429 | goto done; | 429 | goto done; |
430 | } | 430 | } |
@@ -436,6 +436,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) | |||
436 | vma->vm_flags |= VM_IO; | 436 | vma->vm_flags |= VM_IO; |
437 | 437 | ||
438 | addr = (unsigned long)queue->mem + buffer->buf.m.offset; | 438 | addr = (unsigned long)queue->mem + buffer->buf.m.offset; |
439 | #ifdef CONFIG_MMU | ||
439 | while (size > 0) { | 440 | while (size > 0) { |
440 | page = vmalloc_to_page((void *)addr); | 441 | page = vmalloc_to_page((void *)addr); |
441 | if ((ret = vm_insert_page(vma, start, page)) < 0) | 442 | if ((ret = vm_insert_page(vma, start, page)) < 0) |
@@ -445,6 +446,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) | |||
445 | addr += PAGE_SIZE; | 446 | addr += PAGE_SIZE; |
446 | size -= PAGE_SIZE; | 447 | size -= PAGE_SIZE; |
447 | } | 448 | } |
449 | #endif | ||
448 | 450 | ||
449 | vma->vm_ops = &uvc_vm_ops; | 451 | vma->vm_ops = &uvc_vm_ops; |
450 | vma->vm_private_data = buffer; | 452 | vma->vm_private_data = buffer; |
@@ -488,6 +490,36 @@ done: | |||
488 | return mask; | 490 | return mask; |
489 | } | 491 | } |
490 | 492 | ||
493 | #ifndef CONFIG_MMU | ||
494 | /* | ||
495 | * Get unmapped area. | ||
496 | * | ||
497 | * NO-MMU arch need this function to make mmap() work correctly. | ||
498 | */ | ||
499 | unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, | ||
500 | unsigned long pgoff) | ||
501 | { | ||
502 | struct uvc_buffer *buffer; | ||
503 | unsigned int i; | ||
504 | unsigned long ret; | ||
505 | |||
506 | mutex_lock(&queue->mutex); | ||
507 | for (i = 0; i < queue->count; ++i) { | ||
508 | buffer = &queue->buffer[i]; | ||
509 | if ((buffer->buf.m.offset >> PAGE_SHIFT) == pgoff) | ||
510 | break; | ||
511 | } | ||
512 | if (i == queue->count) { | ||
513 | ret = -EINVAL; | ||
514 | goto done; | ||
515 | } | ||
516 | ret = (unsigned long)queue->mem + buffer->buf.m.offset; | ||
517 | done: | ||
518 | mutex_unlock(&queue->mutex); | ||
519 | return ret; | ||
520 | } | ||
521 | #endif | ||
522 | |||
491 | /* | 523 | /* |
492 | * Enable or disable the video buffers queue. | 524 | * Enable or disable the video buffers queue. |
493 | * | 525 | * |
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 9005a8d9d5f8..543a80395b7f 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c | |||
@@ -538,6 +538,20 @@ static int uvc_v4l2_release(struct file *file) | |||
538 | return 0; | 538 | return 0; |
539 | } | 539 | } |
540 | 540 | ||
541 | static void uvc_v4l2_ioctl_warn(void) | ||
542 | { | ||
543 | static int warned; | ||
544 | |||
545 | if (warned) | ||
546 | return; | ||
547 | |||
548 | uvc_printk(KERN_INFO, "Deprecated UVCIOC_CTRL_{ADD,MAP_OLD,GET,SET} " | ||
549 | "ioctls will be removed in 2.6.42.\n"); | ||
550 | uvc_printk(KERN_INFO, "See http://www.ideasonboard.org/uvc/upgrade/ " | ||
551 | "for upgrade instructions.\n"); | ||
552 | warned = 1; | ||
553 | } | ||
554 | |||
541 | static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | 555 | static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) |
542 | { | 556 | { |
543 | struct video_device *vdev = video_devdata(file); | 557 | struct video_device *vdev = video_devdata(file); |
@@ -1018,21 +1032,40 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
1018 | uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd); | 1032 | uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd); |
1019 | return -EINVAL; | 1033 | return -EINVAL; |
1020 | 1034 | ||
1021 | /* Dynamic controls. */ | 1035 | /* Dynamic controls. UVCIOC_CTRL_ADD, UVCIOC_CTRL_MAP_OLD, |
1022 | case UVCIOC_CTRL_ADD: | 1036 | * UVCIOC_CTRL_GET and UVCIOC_CTRL_SET are deprecated and scheduled for |
1023 | /* Legacy ioctl, kept for API compatibility reasons */ | 1037 | * removal in 2.6.42. |
1038 | */ | ||
1039 | case __UVCIOC_CTRL_ADD: | ||
1040 | uvc_v4l2_ioctl_warn(); | ||
1024 | return -EEXIST; | 1041 | return -EEXIST; |
1025 | 1042 | ||
1026 | case UVCIOC_CTRL_MAP_OLD: | 1043 | case __UVCIOC_CTRL_MAP_OLD: |
1044 | uvc_v4l2_ioctl_warn(); | ||
1045 | case __UVCIOC_CTRL_MAP: | ||
1027 | case UVCIOC_CTRL_MAP: | 1046 | case UVCIOC_CTRL_MAP: |
1028 | return uvc_ioctl_ctrl_map(chain, arg, | 1047 | return uvc_ioctl_ctrl_map(chain, arg, |
1029 | cmd == UVCIOC_CTRL_MAP_OLD); | 1048 | cmd == __UVCIOC_CTRL_MAP_OLD); |
1030 | 1049 | ||
1031 | case UVCIOC_CTRL_GET: | 1050 | case __UVCIOC_CTRL_GET: |
1032 | return uvc_xu_ctrl_query(chain, arg, 0); | 1051 | case __UVCIOC_CTRL_SET: |
1052 | { | ||
1053 | struct uvc_xu_control *xctrl = arg; | ||
1054 | struct uvc_xu_control_query xqry = { | ||
1055 | .unit = xctrl->unit, | ||
1056 | .selector = xctrl->selector, | ||
1057 | .query = cmd == __UVCIOC_CTRL_GET | ||
1058 | ? UVC_GET_CUR : UVC_SET_CUR, | ||
1059 | .size = xctrl->size, | ||
1060 | .data = xctrl->data, | ||
1061 | }; | ||
1062 | |||
1063 | uvc_v4l2_ioctl_warn(); | ||
1064 | return uvc_xu_ctrl_query(chain, &xqry); | ||
1065 | } | ||
1033 | 1066 | ||
1034 | case UVCIOC_CTRL_SET: | 1067 | case UVCIOC_CTRL_QUERY: |
1035 | return uvc_xu_ctrl_query(chain, arg, 1); | 1068 | return uvc_xu_ctrl_query(chain, arg); |
1036 | 1069 | ||
1037 | default: | 1070 | default: |
1038 | uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd); | 1071 | uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd); |
@@ -1081,6 +1114,20 @@ static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait) | |||
1081 | return uvc_queue_poll(&stream->queue, file, wait); | 1114 | return uvc_queue_poll(&stream->queue, file, wait); |
1082 | } | 1115 | } |
1083 | 1116 | ||
1117 | #ifndef CONFIG_MMU | ||
1118 | static unsigned long uvc_v4l2_get_unmapped_area(struct file *file, | ||
1119 | unsigned long addr, unsigned long len, unsigned long pgoff, | ||
1120 | unsigned long flags) | ||
1121 | { | ||
1122 | struct uvc_fh *handle = file->private_data; | ||
1123 | struct uvc_streaming *stream = handle->stream; | ||
1124 | |||
1125 | uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_get_unmapped_area\n"); | ||
1126 | |||
1127 | return uvc_queue_get_unmapped_area(&stream->queue, pgoff); | ||
1128 | } | ||
1129 | #endif | ||
1130 | |||
1084 | const struct v4l2_file_operations uvc_fops = { | 1131 | const struct v4l2_file_operations uvc_fops = { |
1085 | .owner = THIS_MODULE, | 1132 | .owner = THIS_MODULE, |
1086 | .open = uvc_v4l2_open, | 1133 | .open = uvc_v4l2_open, |
@@ -1089,5 +1136,8 @@ const struct v4l2_file_operations uvc_fops = { | |||
1089 | .read = uvc_v4l2_read, | 1136 | .read = uvc_v4l2_read, |
1090 | .mmap = uvc_v4l2_mmap, | 1137 | .mmap = uvc_v4l2_mmap, |
1091 | .poll = uvc_v4l2_poll, | 1138 | .poll = uvc_v4l2_poll, |
1139 | #ifndef CONFIG_MMU | ||
1140 | .get_unmapped_area = uvc_v4l2_get_unmapped_area, | ||
1141 | #endif | ||
1092 | }; | 1142 | }; |
1093 | 1143 | ||
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index 45f01e7e13d2..7cf224bae2e5 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h | |||
@@ -4,6 +4,14 @@ | |||
4 | #include <linux/kernel.h> | 4 | #include <linux/kernel.h> |
5 | #include <linux/videodev2.h> | 5 | #include <linux/videodev2.h> |
6 | 6 | ||
7 | #ifndef __KERNEL__ | ||
8 | /* | ||
9 | * This header provides binary compatibility with applications using the private | ||
10 | * uvcvideo API. This API is deprecated and will be removed in 2.6.42. | ||
11 | * Applications should be recompiled against the public linux/uvcvideo.h header. | ||
12 | */ | ||
13 | #warn "The uvcvideo.h header is deprecated, use linux/uvcvideo.h instead." | ||
14 | |||
7 | /* | 15 | /* |
8 | * Dynamic controls | 16 | * Dynamic controls |
9 | */ | 17 | */ |
@@ -23,32 +31,18 @@ | |||
23 | #define UVC_CONTROL_GET_MAX (1 << 3) | 31 | #define UVC_CONTROL_GET_MAX (1 << 3) |
24 | #define UVC_CONTROL_GET_RES (1 << 4) | 32 | #define UVC_CONTROL_GET_RES (1 << 4) |
25 | #define UVC_CONTROL_GET_DEF (1 << 5) | 33 | #define UVC_CONTROL_GET_DEF (1 << 5) |
26 | /* Control should be saved at suspend and restored at resume. */ | ||
27 | #define UVC_CONTROL_RESTORE (1 << 6) | 34 | #define UVC_CONTROL_RESTORE (1 << 6) |
28 | /* Control can be updated by the camera. */ | ||
29 | #define UVC_CONTROL_AUTO_UPDATE (1 << 7) | 35 | #define UVC_CONTROL_AUTO_UPDATE (1 << 7) |
30 | 36 | ||
31 | #define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \ | 37 | #define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \ |
32 | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \ | 38 | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \ |
33 | UVC_CONTROL_GET_DEF) | 39 | UVC_CONTROL_GET_DEF) |
34 | 40 | ||
35 | struct uvc_xu_control_info { | ||
36 | __u8 entity[16]; | ||
37 | __u8 index; | ||
38 | __u8 selector; | ||
39 | __u16 size; | ||
40 | __u32 flags; | ||
41 | }; | ||
42 | |||
43 | struct uvc_menu_info { | 41 | struct uvc_menu_info { |
44 | __u32 value; | 42 | __u32 value; |
45 | __u8 name[32]; | 43 | __u8 name[32]; |
46 | }; | 44 | }; |
47 | 45 | ||
48 | struct uvc_xu_control_mapping_old { | ||
49 | __u8 reserved[64]; | ||
50 | }; | ||
51 | |||
52 | struct uvc_xu_control_mapping { | 46 | struct uvc_xu_control_mapping { |
53 | __u32 id; | 47 | __u32 id; |
54 | __u8 name[32]; | 48 | __u8 name[32]; |
@@ -57,7 +51,7 @@ struct uvc_xu_control_mapping { | |||
57 | 51 | ||
58 | __u8 size; | 52 | __u8 size; |
59 | __u8 offset; | 53 | __u8 offset; |
60 | enum v4l2_ctrl_type v4l2_type; | 54 | __u32 v4l2_type; |
61 | __u32 data_type; | 55 | __u32 data_type; |
62 | 56 | ||
63 | struct uvc_menu_info __user *menu_info; | 57 | struct uvc_menu_info __user *menu_info; |
@@ -66,6 +60,20 @@ struct uvc_xu_control_mapping { | |||
66 | __u32 reserved[4]; | 60 | __u32 reserved[4]; |
67 | }; | 61 | }; |
68 | 62 | ||
63 | #endif | ||
64 | |||
65 | struct uvc_xu_control_info { | ||
66 | __u8 entity[16]; | ||
67 | __u8 index; | ||
68 | __u8 selector; | ||
69 | __u16 size; | ||
70 | __u32 flags; | ||
71 | }; | ||
72 | |||
73 | struct uvc_xu_control_mapping_old { | ||
74 | __u8 reserved[64]; | ||
75 | }; | ||
76 | |||
69 | struct uvc_xu_control { | 77 | struct uvc_xu_control { |
70 | __u8 unit; | 78 | __u8 unit; |
71 | __u8 selector; | 79 | __u8 selector; |
@@ -73,16 +81,25 @@ struct uvc_xu_control { | |||
73 | __u8 __user *data; | 81 | __u8 __user *data; |
74 | }; | 82 | }; |
75 | 83 | ||
84 | #ifndef __KERNEL__ | ||
76 | #define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info) | 85 | #define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info) |
77 | #define UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old) | 86 | #define UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old) |
78 | #define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping) | 87 | #define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping) |
79 | #define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control) | 88 | #define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control) |
80 | #define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control) | 89 | #define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control) |
90 | #else | ||
91 | #define __UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info) | ||
92 | #define __UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old) | ||
93 | #define __UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping) | ||
94 | #define __UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control) | ||
95 | #define __UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control) | ||
96 | #endif | ||
81 | 97 | ||
82 | #ifdef __KERNEL__ | 98 | #ifdef __KERNEL__ |
83 | 99 | ||
84 | #include <linux/poll.h> | 100 | #include <linux/poll.h> |
85 | #include <linux/usb/video.h> | 101 | #include <linux/usb/video.h> |
102 | #include <linux/uvcvideo.h> | ||
86 | 103 | ||
87 | /* -------------------------------------------------------------------------- | 104 | /* -------------------------------------------------------------------------- |
88 | * UVC constants | 105 | * UVC constants |
@@ -152,13 +169,19 @@ struct uvc_xu_control { | |||
152 | #define UVC_GUID_FORMAT_BY8 \ | 169 | #define UVC_GUID_FORMAT_BY8 \ |
153 | { 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \ | 170 | { 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \ |
154 | 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} | 171 | 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} |
172 | #define UVC_GUID_FORMAT_RGBP \ | ||
173 | { 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \ | ||
174 | 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} | ||
175 | #define UVC_GUID_FORMAT_M420 \ | ||
176 | { 'M', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \ | ||
177 | 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} | ||
155 | 178 | ||
156 | /* ------------------------------------------------------------------------ | 179 | /* ------------------------------------------------------------------------ |
157 | * Driver specific constants. | 180 | * Driver specific constants. |
158 | */ | 181 | */ |
159 | 182 | ||
160 | #define DRIVER_VERSION_NUMBER KERNEL_VERSION(1, 0, 0) | 183 | #define DRIVER_VERSION_NUMBER KERNEL_VERSION(1, 1, 0) |
161 | #define DRIVER_VERSION "v1.0.0" | 184 | #define DRIVER_VERSION "v1.1.0" |
162 | 185 | ||
163 | /* Number of isochronous URBs. */ | 186 | /* Number of isochronous URBs. */ |
164 | #define UVC_URBS 5 | 187 | #define UVC_URBS 5 |
@@ -580,6 +603,10 @@ extern int uvc_queue_mmap(struct uvc_video_queue *queue, | |||
580 | struct vm_area_struct *vma); | 603 | struct vm_area_struct *vma); |
581 | extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue, | 604 | extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue, |
582 | struct file *file, poll_table *wait); | 605 | struct file *file, poll_table *wait); |
606 | #ifndef CONFIG_MMU | ||
607 | extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, | ||
608 | unsigned long pgoff); | ||
609 | #endif | ||
583 | extern int uvc_queue_allocated(struct uvc_video_queue *queue); | 610 | extern int uvc_queue_allocated(struct uvc_video_queue *queue); |
584 | static inline int uvc_queue_streaming(struct uvc_video_queue *queue) | 611 | static inline int uvc_queue_streaming(struct uvc_video_queue *queue) |
585 | { | 612 | { |
@@ -638,7 +665,7 @@ extern int uvc_ctrl_set(struct uvc_video_chain *chain, | |||
638 | struct v4l2_ext_control *xctrl); | 665 | struct v4l2_ext_control *xctrl); |
639 | 666 | ||
640 | extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain, | 667 | extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain, |
641 | struct uvc_xu_control *ctrl, int set); | 668 | struct uvc_xu_control_query *xqry); |
642 | 669 | ||
643 | /* Utility functions */ | 670 | /* Utility functions */ |
644 | extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator, | 671 | extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator, |
@@ -655,4 +682,3 @@ void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, | |||
655 | #endif /* __KERNEL__ */ | 682 | #endif /* __KERNEL__ */ |
656 | 683 | ||
657 | #endif | 684 | #endif |
658 | |||
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 6dc7196296b3..19d5ae293780 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c | |||
@@ -352,6 +352,23 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
352 | return ret; | 352 | return ret; |
353 | } | 353 | } |
354 | 354 | ||
355 | #ifdef CONFIG_MMU | ||
356 | #define v4l2_get_unmapped_area NULL | ||
357 | #else | ||
358 | static unsigned long v4l2_get_unmapped_area(struct file *filp, | ||
359 | unsigned long addr, unsigned long len, unsigned long pgoff, | ||
360 | unsigned long flags) | ||
361 | { | ||
362 | struct video_device *vdev = video_devdata(filp); | ||
363 | |||
364 | if (!vdev->fops->get_unmapped_area) | ||
365 | return -ENOSYS; | ||
366 | if (!video_is_registered(vdev)) | ||
367 | return -ENODEV; | ||
368 | return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags); | ||
369 | } | ||
370 | #endif | ||
371 | |||
355 | static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) | 372 | static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) |
356 | { | 373 | { |
357 | struct video_device *vdev = video_devdata(filp); | 374 | struct video_device *vdev = video_devdata(filp); |
@@ -454,6 +471,7 @@ static const struct file_operations v4l2_fops = { | |||
454 | .read = v4l2_read, | 471 | .read = v4l2_read, |
455 | .write = v4l2_write, | 472 | .write = v4l2_write, |
456 | .open = v4l2_open, | 473 | .open = v4l2_open, |
474 | .get_unmapped_area = v4l2_get_unmapped_area, | ||
457 | .mmap = v4l2_mmap, | 475 | .mmap = v4l2_mmap, |
458 | .unlocked_ioctl = v4l2_ioctl, | 476 | .unlocked_ioctl = v4l2_ioctl, |
459 | #ifdef CONFIG_COMPAT | 477 | #ifdef CONFIG_COMPAT |
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c index 8c780c2d937b..85d3048c1d67 100644 --- a/drivers/media/video/via-camera.c +++ b/drivers/media/video/via-camera.c | |||
@@ -29,6 +29,7 @@ | |||
29 | 29 | ||
30 | #include "via-camera.h" | 30 | #include "via-camera.h" |
31 | 31 | ||
32 | MODULE_ALIAS("platform:viafb-camera"); | ||
32 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); | 33 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); |
33 | MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver"); | 34 | MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver"); |
34 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c index 9f2bac519647..79b04ac0f1ad 100644 --- a/drivers/media/video/zoran/zoran_card.c +++ b/drivers/media/video/zoran/zoran_card.c | |||
@@ -64,14 +64,6 @@ static int card[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 }; | |||
64 | module_param_array(card, int, NULL, 0444); | 64 | module_param_array(card, int, NULL, 0444); |
65 | MODULE_PARM_DESC(card, "Card type"); | 65 | MODULE_PARM_DESC(card, "Card type"); |
66 | 66 | ||
67 | static int encoder[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 }; | ||
68 | module_param_array(encoder, int, NULL, 0444); | ||
69 | MODULE_PARM_DESC(encoder, "Video encoder chip"); | ||
70 | |||
71 | static int decoder[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 }; | ||
72 | module_param_array(decoder, int, NULL, 0444); | ||
73 | MODULE_PARM_DESC(decoder, "Video decoder chip"); | ||
74 | |||
75 | /* | 67 | /* |
76 | The video mem address of the video card. | 68 | The video mem address of the video card. |
77 | The driver has a little database for some videocards | 69 | The driver has a little database for some videocards |
@@ -1230,7 +1222,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev, | |||
1230 | mutex_init(&zr->other_lock); | 1222 | mutex_init(&zr->other_lock); |
1231 | if (pci_enable_device(pdev)) | 1223 | if (pci_enable_device(pdev)) |
1232 | goto zr_unreg; | 1224 | goto zr_unreg; |
1233 | pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision); | 1225 | zr->revision = zr->pci_dev->revision; |
1234 | 1226 | ||
1235 | dprintk(1, | 1227 | dprintk(1, |
1236 | KERN_INFO | 1228 | KERN_INFO |